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