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