android_os_ParcelFileDescriptor.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/* //device/libs/android_runtime/android_os_ParcelFileDescriptor.cpp
2**
3** Copyright 2008, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "JNIHelp.h"
19
20#include <fcntl.h>
21#include <sys/stat.h>
22#include <stdio.h>
23
24#include <utils/Log.h>
25
26#include <android_runtime/AndroidRuntime.h>
27
28namespace android
29{
30
31static struct file_descriptor_offsets_t
32{
33    jclass mClass;
34    jmethodID mConstructor;
35    jfieldID mDescriptor;
36} gFileDescriptorOffsets;
37
38static struct socket_offsets_t
39{
40    jfieldID mSocketImpl;
41} gSocketOffsets;
42
43static struct socket_impl_offsets_t
44{
45    jfieldID mFileDescriptor;
46} gSocketImplOffsets;
47
48
49static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromSocket(JNIEnv* env,
50    jobject clazz, jobject object)
51{
52    jobject socketImpl = env->GetObjectField(object, gSocketOffsets.mSocketImpl);
53    jobject fileDescriptor = env->GetObjectField(socketImpl, gSocketImplOffsets.mFileDescriptor);
54    jint fd = env->GetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor);
55    jobject fileDescriptorClone = env->NewObject(gFileDescriptorOffsets.mClass,
56        gFileDescriptorOffsets.mConstructor);
57    if (fileDescriptorClone != NULL) {
58        env->SetIntField(fileDescriptorClone, gFileDescriptorOffsets.mDescriptor, dup(fd));
59    }
60    return fileDescriptorClone;
61}
62
63static jlong android_os_ParcelFileDescriptor_getStatSize(JNIEnv* env,
64    jobject clazz)
65{
66    jint fd = env->GetIntField(clazz, gFileDescriptorOffsets.mDescriptor);
67
68    struct stat st;
69    if (fstat(fd, &st) != 0) {
70        return -1;
71    }
72
73    if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
74        return st.st_size;
75    }
76
77    return -1;
78}
79
80static jlong android_os_ParcelFileDescriptor_seekTo(JNIEnv* env,
81    jobject clazz, jlong pos)
82{
83    jint fd = env->GetIntField(clazz, gFileDescriptorOffsets.mDescriptor);
84    return lseek(fd, pos, SEEK_SET);
85}
86
87static const JNINativeMethod gParcelFileDescriptorMethods[] = {
88    {"getFileDescriptorFromSocket", "(Ljava/net/Socket;)Ljava/io/FileDescriptor;",
89        (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket},
90    {"getStatSize", "()J",
91        (void*)android_os_ParcelFileDescriptor_getStatSize},
92    {"seekTo", "(J)J",
93        (void*)android_os_ParcelFileDescriptor_seekTo}
94};
95
96const char* const kParcelFileDescriptorPathName = "android/os/ParcelFileDescriptor";
97
98int register_android_os_ParcelFileDescriptor(JNIEnv* env)
99{
100    jclass clazz;
101
102    clazz = env->FindClass("java/net/Socket");
103    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.net.Socket");
104    gSocketOffsets.mSocketImpl = env->GetFieldID(clazz, "impl", "Ljava/net/SocketImpl;");
105    LOG_FATAL_IF(gSocketOffsets.mSocketImpl == NULL,
106        "Unable to find impl field in java.net.Socket");
107
108    clazz = env->FindClass("java/net/SocketImpl");
109    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.net.SocketImpl");
110    gSocketImplOffsets.mFileDescriptor = env->GetFieldID(clazz, "fd", "Ljava/io/FileDescriptor;");
111    LOG_FATAL_IF(gSocketImplOffsets.mFileDescriptor == NULL,
112                 "Unable to find fd field in java.net.SocketImpl");
113
114    clazz = env->FindClass("java/io/FileDescriptor");
115    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
116    gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
117    gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
118    gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
119    LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
120                 "Unable to find descriptor field in java.io.FileDescriptor");
121
122    clazz = env->FindClass(kParcelFileDescriptorPathName);
123    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
124
125    return AndroidRuntime::registerNativeMethods(
126        env, kParcelFileDescriptorPathName,
127        gParcelFileDescriptorMethods, NELEM(gParcelFileDescriptorMethods));
128}
129
130}
131