android_os_MemoryFile.cpp revision 6ffb09171960e776466b963e51196565a033998c
1252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber/* 2252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber * Copyright (C) 2008 The Android Open Source Project 389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * 489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * you may not use this file except in compliance with the License. 689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * You may obtain a copy of the License at 789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * 889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * 1089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * See the License for the specific language governing permissions and 1489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * limitations under the License. 1589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project */ 1689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 1720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#define LOG_TAG "MemoryFile" 18252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber#include <utils/Log.h> 19252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 20252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber#include <cutils/ashmem.h> 21252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber#include <android_runtime/AndroidRuntime.h> 22252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber#include "JNIHelp.h" 23252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber#include <unistd.h> 24252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber#include <sys/mman.h> 25252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 26252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 27252353088a5ebf8508fbc01439ff417805ef1417Andreas Hubernamespace android { 28252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 29252353088a5ebf8508fbc01439ff417805ef1417Andreas Huberstatic jobject android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring name, jint length) 30252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber{ 31693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber const char* namestr = (name ? env->GetStringUTFChars(name, NULL) : NULL); 327a6b9e2eca7d20457ace3538c689640e5bfda4f3Andreas Huber 337a6b9e2eca7d20457ace3538c689640e5bfda4f3Andreas Huber int result = ashmem_create_region(namestr, length); 347a6b9e2eca7d20457ace3538c689640e5bfda4f3Andreas Huber 357a6b9e2eca7d20457ace3538c689640e5bfda4f3Andreas Huber if (name) 367a6b9e2eca7d20457ace3538c689640e5bfda4f3Andreas Huber env->ReleaseStringUTFChars(name, namestr); 377a6b9e2eca7d20457ace3538c689640e5bfda4f3Andreas Huber 387a6b9e2eca7d20457ace3538c689640e5bfda4f3Andreas Huber if (result < 0) { 397a6b9e2eca7d20457ace3538c689640e5bfda4f3Andreas Huber jniThrowException(env, "java/io/IOException", "ashmem_create_region failed"); 407a6b9e2eca7d20457ace3538c689640e5bfda4f3Andreas Huber return NULL; 41252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber } 42e3ec3cec3a2e27033249ff82964d2cbd441d9873Andreas Huber 43e3ec3cec3a2e27033249ff82964d2cbd441d9873Andreas Huber return jniCreateFileDescriptor(env, result); 44e3ec3cec3a2e27033249ff82964d2cbd441d9873Andreas Huber} 45252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 46252353088a5ebf8508fbc01439ff417805ef1417Andreas Huberstatic jlong android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jobject fileDescriptor, 47252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jint length, jint prot) 48252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber{ 49252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 50252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber void* result = mmap(NULL, length, prot, MAP_SHARED, fd, 0); 51252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber if (result == MAP_FAILED) { 52252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jniThrowException(env, "java/io/IOException", "mmap failed"); 53252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber } 54252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber return reinterpret_cast<jlong>(result); 55252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber} 56252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 57252353088a5ebf8508fbc01439ff417805ef1417Andreas Huberstatic void android_os_MemoryFile_munmap(JNIEnv* env, jobject clazz, jlong addr, jint length) 58252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber{ 59252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber int result = munmap(reinterpret_cast<void *>(addr), length); 60252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber if (result < 0) 61252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jniThrowException(env, "java/io/IOException", "munmap failed"); 62252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber} 63252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 64252353088a5ebf8508fbc01439ff417805ef1417Andreas Huberstatic void android_os_MemoryFile_close(JNIEnv* env, jobject clazz, jobject fileDescriptor) 65252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber{ 66252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 67252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber if (fd >= 0) { 68252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jniSetFileDescriptorOfFD(env, fileDescriptor, -1); 69252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber close(fd); 70252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber } 71252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber} 72252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 73252353088a5ebf8508fbc01439ff417805ef1417Andreas Huberstatic jint android_os_MemoryFile_read(JNIEnv* env, jobject clazz, 74252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jobject fileDescriptor, jlong address, jbyteArray buffer, jint srcOffset, jint destOffset, 75252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jint count, jboolean unpinned) 76252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber{ 77252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 78252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) { 79252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber ashmem_unpin_region(fd, 0, 0); 80252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jniThrowException(env, "java/io/IOException", "ashmem region was purged"); 81252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber return -1; 82252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber } 83252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 84252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber env->SetByteArrayRegion(buffer, destOffset, count, (const jbyte *)address + srcOffset); 85252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 86252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber if (unpinned) { 87252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber ashmem_unpin_region(fd, 0, 0); 88252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber } 89252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber return count; 90252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber} 91252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 92252353088a5ebf8508fbc01439ff417805ef1417Andreas Huberstatic jint android_os_MemoryFile_write(JNIEnv* env, jobject clazz, 93252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jobject fileDescriptor, jlong address, jbyteArray buffer, jint srcOffset, jint destOffset, 94252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jint count, jboolean unpinned) 95252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber{ 96252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 97252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) { 98252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber ashmem_unpin_region(fd, 0, 0); 99252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jniThrowException(env, "java/io/IOException", "ashmem region was purged"); 100252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber return -1; 101252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber } 102252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 103252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber env->GetByteArrayRegion(buffer, srcOffset, count, (jbyte *)address + destOffset); 104252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 105252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber if (unpinned) { 106252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber ashmem_unpin_region(fd, 0, 0); 107252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber } 108252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber return count; 109252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber} 110252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 111252353088a5ebf8508fbc01439ff417805ef1417Andreas Huberstatic void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDescriptor, jboolean pin) 112252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber{ 113252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 114252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber int result = (pin ? ashmem_pin_region(fd, 0, 0) : ashmem_unpin_region(fd, 0, 0)); 115252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber if (result < 0) { 116252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jniThrowException(env, "java/io/IOException", NULL); 117252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber } 118252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber} 119252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 120252353088a5ebf8508fbc01439ff417805ef1417Andreas Huberstatic jint android_os_MemoryFile_get_size(JNIEnv* env, jobject clazz, 121252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jobject fileDescriptor) { 122252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 123252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber // Use ASHMEM_GET_SIZE to find out if the fd refers to an ashmem region. 124252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber // ASHMEM_GET_SIZE should succeed for all ashmem regions, and the kernel 125252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber // should return ENOTTY for all other valid file descriptors 126252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber int result = ashmem_get_size_region(fd); 127252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber if (result < 0) { 128252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber if (errno == ENOTTY) { 129252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber // ENOTTY means that the ioctl does not apply to this object, 130252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber // i.e., it is not an ashmem region. 131252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber return (jint) -1; 132252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber } 133252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber // Some other error, throw exception 134252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber jniThrowIOException(env, errno); 135252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber return (jint) -1; 136252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber } 137252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber return (jint) result; 138252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber} 139252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 140252353088a5ebf8508fbc01439ff417805ef1417Andreas Huberstatic const JNINativeMethod methods[] = { 141252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber {"native_open", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_MemoryFile_open}, 142252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber {"native_mmap", "(Ljava/io/FileDescriptor;II)J", (void*)android_os_MemoryFile_mmap}, 143252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber {"native_munmap", "(JI)V", (void*)android_os_MemoryFile_munmap}, 144252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber {"native_close", "(Ljava/io/FileDescriptor;)V", (void*)android_os_MemoryFile_close}, 145252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber {"native_read", "(Ljava/io/FileDescriptor;J[BIIIZ)I", (void*)android_os_MemoryFile_read}, 146252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber {"native_write", "(Ljava/io/FileDescriptor;J[BIIIZ)V", (void*)android_os_MemoryFile_write}, 147252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber {"native_pin", "(Ljava/io/FileDescriptor;Z)V", (void*)android_os_MemoryFile_pin}, 148252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber {"native_get_size", "(Ljava/io/FileDescriptor;)I", 149252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber (void*)android_os_MemoryFile_get_size} 150252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber}; 151252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 152252353088a5ebf8508fbc01439ff417805ef1417Andreas Huberint register_android_os_MemoryFile(JNIEnv* env) 153252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber{ 154252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber return AndroidRuntime::registerNativeMethods( 155252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber env, "android/os/MemoryFile", 156252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber methods, NELEM(methods)); 157252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber} 158252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber 159252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber} 160252353088a5ebf8508fbc01439ff417805ef1417Andreas Huber