Home | History | Annotate | Download | only in jni
      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 
     27 namespace android {
     28 
     29 static 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     int result = ashmem_create_region(namestr, length);
     34 
     35     if (name)
     36         env->ReleaseStringUTFChars(name, namestr);
     37 
     38     if (result < 0) {
     39         jniThrowException(env, "java/io/IOException", "ashmem_create_region failed");
     40         return NULL;
     41     }
     42 
     43     return jniCreateFileDescriptor(env, result);
     44 }
     45 
     46 static jlong android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jobject fileDescriptor,
     47         jint length, jint prot)
     48 {
     49     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     50     void* result = mmap(NULL, length, prot, MAP_SHARED, fd, 0);
     51     if (result == MAP_FAILED) {
     52         jniThrowException(env, "java/io/IOException", "mmap failed");
     53     }
     54     return reinterpret_cast<jlong>(result);
     55 }
     56 
     57 static void android_os_MemoryFile_munmap(JNIEnv* env, jobject clazz, jlong addr, jint length)
     58 {
     59     int result = munmap(reinterpret_cast<void *>(addr), length);
     60     if (result < 0)
     61         jniThrowException(env, "java/io/IOException", "munmap failed");
     62 }
     63 
     64 static void android_os_MemoryFile_close(JNIEnv* env, jobject clazz, jobject fileDescriptor)
     65 {
     66     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     67     if (fd >= 0) {
     68         jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
     69         close(fd);
     70     }
     71 }
     72 
     73 static jint android_os_MemoryFile_read(JNIEnv* env, jobject clazz,
     74         jobject fileDescriptor, jlong address, jbyteArray buffer, jint srcOffset, jint destOffset,
     75         jint count, jboolean unpinned)
     76 {
     77     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     78     if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
     79         ashmem_unpin_region(fd, 0, 0);
     80         jniThrowException(env, "java/io/IOException", "ashmem region was purged");
     81         return -1;
     82     }
     83 
     84     env->SetByteArrayRegion(buffer, destOffset, count, (const jbyte *)address + srcOffset);
     85 
     86     if (unpinned) {
     87         ashmem_unpin_region(fd, 0, 0);
     88     }
     89     return count;
     90 }
     91 
     92 static jint android_os_MemoryFile_write(JNIEnv* env, jobject clazz,
     93         jobject fileDescriptor, jlong address, jbyteArray buffer, jint srcOffset, jint destOffset,
     94         jint count, jboolean unpinned)
     95 {
     96     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     97     if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
     98         ashmem_unpin_region(fd, 0, 0);
     99         jniThrowException(env, "java/io/IOException", "ashmem region was purged");
    100         return -1;
    101     }
    102 
    103     env->GetByteArrayRegion(buffer, srcOffset, count, (jbyte *)address + destOffset);
    104 
    105     if (unpinned) {
    106         ashmem_unpin_region(fd, 0, 0);
    107     }
    108     return count;
    109 }
    110 
    111 static void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDescriptor, jboolean pin)
    112 {
    113     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    114     int result = (pin ? ashmem_pin_region(fd, 0, 0) : ashmem_unpin_region(fd, 0, 0));
    115     if (result < 0) {
    116         jniThrowException(env, "java/io/IOException", NULL);
    117     }
    118 }
    119 
    120 static jint android_os_MemoryFile_get_size(JNIEnv* env, jobject clazz,
    121         jobject fileDescriptor) {
    122     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    123     // Use ASHMEM_GET_SIZE to find out if the fd refers to an ashmem region.
    124     // ASHMEM_GET_SIZE should succeed for all ashmem regions, and the kernel
    125     // should return ENOTTY for all other valid file descriptors
    126     int result = ashmem_get_size_region(fd);
    127     if (result < 0) {
    128         if (errno == ENOTTY) {
    129             // ENOTTY means that the ioctl does not apply to this object,
    130             // i.e., it is not an ashmem region.
    131             return (jint) -1;
    132         }
    133         // Some other error, throw exception
    134         jniThrowIOException(env, errno);
    135         return (jint) -1;
    136     }
    137     return (jint) result;
    138 }
    139 
    140 static const JNINativeMethod methods[] = {
    141     {"native_open",  "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_MemoryFile_open},
    142     {"native_mmap",  "(Ljava/io/FileDescriptor;II)J", (void*)android_os_MemoryFile_mmap},
    143     {"native_munmap", "(JI)V", (void*)android_os_MemoryFile_munmap},
    144     {"native_close", "(Ljava/io/FileDescriptor;)V", (void*)android_os_MemoryFile_close},
    145     {"native_read",  "(Ljava/io/FileDescriptor;J[BIIIZ)I", (void*)android_os_MemoryFile_read},
    146     {"native_write", "(Ljava/io/FileDescriptor;J[BIIIZ)V", (void*)android_os_MemoryFile_write},
    147     {"native_pin",   "(Ljava/io/FileDescriptor;Z)V", (void*)android_os_MemoryFile_pin},
    148     {"native_get_size", "(Ljava/io/FileDescriptor;)I",
    149             (void*)android_os_MemoryFile_get_size}
    150 };
    151 
    152 int register_android_os_MemoryFile(JNIEnv* env)
    153 {
    154     return AndroidRuntime::registerNativeMethods(
    155         env, "android/os/MemoryFile",
    156         methods, NELEM(methods));
    157 }
    158 
    159 }
    160