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