blob: ee8d836c06d5d9f25bbc7c6aa863d4c111cae614 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Bjorn Bringert761e0912009-05-29 11:46:12 +010029static jobject android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring name, jint length)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030{
31 const char* namestr = (name ? env->GetStringUTFChars(name, NULL) : NULL);
32
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033 int result = ashmem_create_region(namestr, length);
34
35 if (name)
36 env->ReleaseStringUTFChars(name, namestr);
37
Bjorn Bringert761e0912009-05-29 11:46:12 +010038 if (result < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039 jniThrowException(env, "java/io/IOException", "ashmem_create_region failed");
Bjorn Bringert963cd0062009-05-29 14:05:12 +010040 return NULL;
Bjorn Bringert761e0912009-05-29 11:46:12 +010041 }
42
43 return jniCreateFileDescriptor(env, result);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044}
45
Bjorn Bringert761e0912009-05-29 11:46:12 +010046static jint android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jobject fileDescriptor,
Bjorn Bringert963cd0062009-05-29 14:05:12 +010047 jint length, jint prot)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048{
Bjorn Bringert761e0912009-05-29 11:46:12 +010049 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
Bjorn Bringert963cd0062009-05-29 14:05:12 +010050 jint result = (jint)mmap(NULL, length, prot, MAP_SHARED, fd, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 if (!result)
52 jniThrowException(env, "java/io/IOException", "mmap failed");
53 return result;
54}
55
Bjorn Bringert761e0912009-05-29 11:46:12 +010056static void android_os_MemoryFile_munmap(JNIEnv* env, jobject clazz, jint addr, jint length)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057{
Bjorn Bringert761e0912009-05-29 11:46:12 +010058 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070}
71
72static jint android_os_MemoryFile_read(JNIEnv* env, jobject clazz,
Bjorn Bringert761e0912009-05-29 11:46:12 +010073 jobject fileDescriptor, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 jint count, jboolean unpinned)
75{
Bjorn Bringert761e0912009-05-29 11:46:12 +010076 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 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
Bjorn Bringertad984f12009-06-01 18:33:33 +010083 env->SetByteArrayRegion(buffer, destOffset, count, (const jbyte *)address + srcOffset);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
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,
Bjorn Bringert761e0912009-05-29 11:46:12 +010092 jobject fileDescriptor, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 jint count, jboolean unpinned)
94{
Bjorn Bringert761e0912009-05-29 11:46:12 +010095 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 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
Bjorn Bringertad984f12009-06-01 18:33:33 +0100102 env->GetByteArrayRegion(buffer, srcOffset, count, (jbyte *)address + destOffset);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
104 if (unpinned) {
105 ashmem_unpin_region(fd, 0, 0);
106 }
107 return count;
108}
109
Bjorn Bringert761e0912009-05-29 11:46:12 +0100110static void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDescriptor, jboolean pin)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111{
Bjorn Bringert761e0912009-05-29 11:46:12 +0100112 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 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
Marco Nelissen7bcbd512009-06-23 10:34:55 -0700119static jint android_os_MemoryFile_get_size(JNIEnv* env, jobject clazz,
Bjorn Bringert963cd0062009-05-29 14:05:12 +0100120 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.
Marco Nelissenec100902009-06-17 08:56:59 -0700130 return (jint) -1;
Bjorn Bringert963cd0062009-05-29 14:05:12 +0100131 }
132 // Some other error, throw exception
133 jniThrowIOException(env, errno);
Marco Nelissenec100902009-06-17 08:56:59 -0700134 return (jint) -1;
Bjorn Bringert963cd0062009-05-29 14:05:12 +0100135 }
Marco Nelissenec100902009-06-17 08:56:59 -0700136 return (jint) result;
Bjorn Bringert963cd0062009-05-29 14:05:12 +0100137}
138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139static const JNINativeMethod methods[] = {
Bjorn Bringert761e0912009-05-29 11:46:12 +0100140 {"native_open", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_MemoryFile_open},
Bjorn Bringert963cd0062009-05-29 14:05:12 +0100141 {"native_mmap", "(Ljava/io/FileDescriptor;II)I", (void*)android_os_MemoryFile_mmap},
Bjorn Bringert761e0912009-05-29 11:46:12 +0100142 {"native_munmap", "(II)V", (void*)android_os_MemoryFile_munmap},
143 {"native_close", "(Ljava/io/FileDescriptor;)V", (void*)android_os_MemoryFile_close},
144 {"native_read", "(Ljava/io/FileDescriptor;I[BIIIZ)I", (void*)android_os_MemoryFile_read},
145 {"native_write", "(Ljava/io/FileDescriptor;I[BIIIZ)V", (void*)android_os_MemoryFile_write},
146 {"native_pin", "(Ljava/io/FileDescriptor;Z)V", (void*)android_os_MemoryFile_pin},
Marco Nelissen7bcbd512009-06-23 10:34:55 -0700147 {"native_get_size", "(Ljava/io/FileDescriptor;)I",
148 (void*)android_os_MemoryFile_get_size}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149};
150
151static const char* const kClassPathName = "android/os/MemoryFile";
152
153int register_android_os_MemoryFile(JNIEnv* env)
154{
155 jclass clazz;
156
157 clazz = env->FindClass(kClassPathName);
158 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.FileUtils");
159
160 return AndroidRuntime::registerNativeMethods(
161 env, kClassPathName,
162 methods, NELEM(methods));
163}
164
165}