android_os_MemoryFile.cpp revision 963cd006c45716b034f656bf7e7179e6476f7e4d
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_TAG "MemoryFile" 18#include <utils/Log.h> 19 20#include <cutils/ashmem.h> 21#include <android_runtime/AndroidRuntime.h> 22#include "JNIHelp.h" 23#include <unistd.h> 24#include <sys/mman.h> 25 26 27namespace android { 28 29static jobject android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring name, jint length) 30{ 31 const char* namestr = (name ? env->GetStringUTFChars(name, NULL) : NULL); 32 33 // round up length to page boundary 34 length = (((length - 1) / getpagesize()) + 1) * getpagesize(); 35 int result = ashmem_create_region(namestr, length); 36 37 if (name) 38 env->ReleaseStringUTFChars(name, namestr); 39 40 if (result < 0) { 41 jniThrowException(env, "java/io/IOException", "ashmem_create_region failed"); 42 return NULL; 43 } 44 45 return jniCreateFileDescriptor(env, result); 46} 47 48static jint android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jobject fileDescriptor, 49 jint length, jint prot) 50{ 51 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 52 jint result = (jint)mmap(NULL, length, prot, MAP_SHARED, fd, 0); 53 if (!result) 54 jniThrowException(env, "java/io/IOException", "mmap failed"); 55 return result; 56} 57 58static void android_os_MemoryFile_munmap(JNIEnv* env, jobject clazz, jint addr, jint length) 59{ 60 int result = munmap((void *)addr, length); 61 if (result < 0) 62 jniThrowException(env, "java/io/IOException", "munmap failed"); 63} 64 65static void android_os_MemoryFile_close(JNIEnv* env, jobject clazz, jobject fileDescriptor) 66{ 67 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 68 if (fd >= 0) { 69 jniSetFileDescriptorOfFD(env, fileDescriptor, -1); 70 close(fd); 71 } 72} 73 74static jint android_os_MemoryFile_read(JNIEnv* env, jobject clazz, 75 jobject fileDescriptor, jint address, jbyteArray buffer, jint srcOffset, jint destOffset, 76 jint count, jboolean unpinned) 77{ 78 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 79 if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) { 80 ashmem_unpin_region(fd, 0, 0); 81 jniThrowException(env, "java/io/IOException", "ashmem region was purged"); 82 return -1; 83 } 84 85 env->SetByteArrayRegion(buffer, destOffset, count, (const jbyte *)address + srcOffset); 86 87 if (unpinned) { 88 ashmem_unpin_region(fd, 0, 0); 89 } 90 return count; 91} 92 93static jint android_os_MemoryFile_write(JNIEnv* env, jobject clazz, 94 jobject fileDescriptor, jint address, jbyteArray buffer, jint srcOffset, jint destOffset, 95 jint count, jboolean unpinned) 96{ 97 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 98 if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) { 99 ashmem_unpin_region(fd, 0, 0); 100 jniThrowException(env, "java/io/IOException", "ashmem region was purged"); 101 return -1; 102 } 103 104 env->GetByteArrayRegion(buffer, srcOffset, count, (jbyte *)address + destOffset); 105 106 if (unpinned) { 107 ashmem_unpin_region(fd, 0, 0); 108 } 109 return count; 110} 111 112static void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDescriptor, jboolean pin) 113{ 114 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 115 int result = (pin ? ashmem_pin_region(fd, 0, 0) : ashmem_unpin_region(fd, 0, 0)); 116 if (result < 0) { 117 jniThrowException(env, "java/io/IOException", NULL); 118 } 119} 120 121static jboolean android_os_MemoryFile_is_ashmem_region(JNIEnv* env, jobject clazz, 122 jobject fileDescriptor) { 123 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 124 // Use ASHMEM_GET_SIZE to find out if the fd refers to an ashmem region. 125 // ASHMEM_GET_SIZE should succeed for all ashmem regions, and the kernel 126 // should return ENOTTY for all other valid file descriptors 127 int result = ashmem_get_size_region(fd); 128 if (result < 0) { 129 if (errno == ENOTTY) { 130 // ENOTTY means that the ioctl does not apply to this object, 131 // i.e., it is not an ashmem region. 132 return JNI_FALSE; 133 } 134 // Some other error, throw exception 135 jniThrowIOException(env, errno); 136 return JNI_FALSE; 137 } 138 return JNI_TRUE; 139} 140 141static const JNINativeMethod methods[] = { 142 {"native_open", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_MemoryFile_open}, 143 {"native_mmap", "(Ljava/io/FileDescriptor;II)I", (void*)android_os_MemoryFile_mmap}, 144 {"native_munmap", "(II)V", (void*)android_os_MemoryFile_munmap}, 145 {"native_close", "(Ljava/io/FileDescriptor;)V", (void*)android_os_MemoryFile_close}, 146 {"native_read", "(Ljava/io/FileDescriptor;I[BIIIZ)I", (void*)android_os_MemoryFile_read}, 147 {"native_write", "(Ljava/io/FileDescriptor;I[BIIIZ)V", (void*)android_os_MemoryFile_write}, 148 {"native_pin", "(Ljava/io/FileDescriptor;Z)V", (void*)android_os_MemoryFile_pin}, 149 {"native_is_ashmem_region", "(Ljava/io/FileDescriptor;)Z", 150 (void*)android_os_MemoryFile_is_ashmem_region} 151}; 152 153static const char* const kClassPathName = "android/os/MemoryFile"; 154 155int register_android_os_MemoryFile(JNIEnv* env) 156{ 157 jclass clazz; 158 159 clazz = env->FindClass(kClassPathName); 160 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.FileUtils"); 161 162 return AndroidRuntime::registerNativeMethods( 163 env, kClassPathName, 164 methods, NELEM(methods)); 165} 166 167} 168