android_os_ParcelFileDescriptor.cpp revision ba87e3e6c985e7175152993b5efcc7dd2f0e1c93
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//#define LOG_NDEBUG 0
19
20#include "JNIHelp.h"
21
22#include <fcntl.h>
23#include <sys/stat.h>
24#include <stdio.h>
25
26#include <utils/Log.h>
27
28#include <android_runtime/AndroidRuntime.h>
29
30namespace android
31{
32
33static struct file_descriptor_offsets_t
34{
35    jclass mClass;
36    jmethodID mConstructor;
37    jfieldID mDescriptor;
38} gFileDescriptorOffsets;
39
40static struct socket_offsets_t
41{
42    jfieldID mSocketImpl;
43} gSocketOffsets;
44
45static struct socket_impl_offsets_t
46{
47    jfieldID mFileDescriptor;
48} gSocketImplOffsets;
49
50static struct parcel_file_descriptor_offsets_t
51{
52    jclass mClass;
53    jfieldID mFileDescriptor;
54} gParcelFileDescriptorOffsets;
55
56static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromSocket(JNIEnv* env,
57    jobject clazz, jobject object)
58{
59    jobject socketImpl = env->GetObjectField(object, gSocketOffsets.mSocketImpl);
60    jobject fileDescriptor = env->GetObjectField(socketImpl, gSocketImplOffsets.mFileDescriptor);
61    jint fd = env->GetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor);
62    jobject fileDescriptorClone = env->NewObject(gFileDescriptorOffsets.mClass,
63        gFileDescriptorOffsets.mConstructor);
64    if (fileDescriptorClone != NULL) {
65        env->SetIntField(fileDescriptorClone, gFileDescriptorOffsets.mDescriptor, dup(fd));
66    }
67    return fileDescriptorClone;
68}
69
70static jint getFd(JNIEnv* env, jobject clazz)
71{
72    jobject descriptor = env->GetObjectField(clazz, gParcelFileDescriptorOffsets.mFileDescriptor);
73    if (descriptor == NULL) return -1;
74    return env->GetIntField(descriptor, gFileDescriptorOffsets.mDescriptor);
75}
76
77static jlong android_os_ParcelFileDescriptor_getStatSize(JNIEnv* env,
78    jobject clazz)
79{
80    jint fd = getFd(env, clazz);
81    if (fd < 0) {
82        jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
83        return -1;
84    }
85
86    struct stat st;
87    if (fstat(fd, &st) != 0) {
88        return -1;
89    }
90
91    if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
92        return st.st_size;
93    }
94
95    return -1;
96}
97
98static jlong android_os_ParcelFileDescriptor_seekTo(JNIEnv* env,
99    jobject clazz, jlong pos)
100{
101    jint fd = getFd(env, clazz);
102    if (fd < 0) {
103        jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
104        return -1;
105    }
106
107    return lseek(fd, pos, SEEK_SET);
108}
109
110static const JNINativeMethod gParcelFileDescriptorMethods[] = {
111    {"getFileDescriptorFromSocket", "(Ljava/net/Socket;)Ljava/io/FileDescriptor;",
112        (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket},
113    {"getStatSize", "()J",
114        (void*)android_os_ParcelFileDescriptor_getStatSize},
115    {"seekTo", "(J)J",
116        (void*)android_os_ParcelFileDescriptor_seekTo}
117};
118
119const char* const kParcelFileDescriptorPathName = "android/os/ParcelFileDescriptor";
120
121int register_android_os_ParcelFileDescriptor(JNIEnv* env)
122{
123    jclass clazz;
124
125    clazz = env->FindClass("java/net/Socket");
126    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.net.Socket");
127    gSocketOffsets.mSocketImpl = env->GetFieldID(clazz, "impl", "Ljava/net/SocketImpl;");
128    LOG_FATAL_IF(gSocketOffsets.mSocketImpl == NULL,
129        "Unable to find impl field in java.net.Socket");
130
131    clazz = env->FindClass("java/net/SocketImpl");
132    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.net.SocketImpl");
133    gSocketImplOffsets.mFileDescriptor = env->GetFieldID(clazz, "fd", "Ljava/io/FileDescriptor;");
134    LOG_FATAL_IF(gSocketImplOffsets.mFileDescriptor == NULL,
135                 "Unable to find fd field in java.net.SocketImpl");
136
137    clazz = env->FindClass("java/io/FileDescriptor");
138    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
139    gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
140    gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
141    gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
142    LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
143                 "Unable to find descriptor field in java.io.FileDescriptor");
144
145    clazz = env->FindClass(kParcelFileDescriptorPathName);
146    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
147    gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
148    gParcelFileDescriptorOffsets.mFileDescriptor = env->GetFieldID(clazz, "mFileDescriptor", "Ljava/io/FileDescriptor;");
149    LOG_FATAL_IF(gParcelFileDescriptorOffsets.mFileDescriptor == NULL,
150                 "Unable to find mFileDescriptor field in android.os.ParcelFileDescriptor");
151
152    return AndroidRuntime::registerNativeMethods(
153        env, kParcelFileDescriptorPathName,
154        gParcelFileDescriptorMethods, NELEM(gParcelFileDescriptorMethods));
155}
156
157}
158