blob: 9513c8b89596b52cec5be1b7eb74b0264e10323d [file] [log] [blame]
Svet Ganov53a441c2016-04-19 19:38:00 -07001/*
2 * Copyright (C) 2016 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
Svet Ganov53a441c2016-04-19 19:38:00 -070017#include "core_jni_helpers.h"
18#include <cutils/ashmem.h>
Svetoslav Ganov04df7382016-05-10 18:55:47 -070019#include <linux/ashmem.h>
Svet Ganov53a441c2016-04-19 19:38:00 -070020#include <sys/mman.h>
21
22namespace android {
23
24static jint android_util_MemoryIntArray_create(JNIEnv* env, jobject clazz, jstring name,
25 jint size)
26{
27 if (name == NULL) {
28 jniThrowException(env, "java/io/IOException", "bad name");
29 return -1;
30 }
31
32 if (size <= 0) {
33 jniThrowException(env, "java/io/IOException", "bad size");
34 return -1;
35 }
36
37 const char* nameStr = env->GetStringUTFChars(name, NULL);
38 const int ashmemSize = sizeof(std::atomic_int) * size;
39 int fd = ashmem_create_region(nameStr, ashmemSize);
40 env->ReleaseStringUTFChars(name, nameStr);
41
42 if (fd < 0) {
43 jniThrowException(env, "java/io/IOException", "ashmem creation failed");
44 return -1;
45 }
46
Svet Ganov53a441c2016-04-19 19:38:00 -070047 int setProtResult = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
48 if (setProtResult < 0) {
49 jniThrowException(env, "java/io/IOException", "cannot set ashmem prot mode");
50 return -1;
51 }
52
53 return fd;
54}
55
56static jlong android_util_MemoryIntArray_open(JNIEnv* env, jobject clazz, jint fd,
57 jboolean owner, jboolean writable)
58{
59 if (fd < 0) {
60 jniThrowException(env, "java/io/IOException", "bad file descriptor");
61 return -1;
62 }
63
Svet Ganov9d723d32016-08-27 11:05:56 -070064 if (!ashmem_valid(fd)) {
65 jniThrowIOException(env, errno);
66 return -1;
67 }
68
Svet Ganov53a441c2016-04-19 19:38:00 -070069 int ashmemSize = ashmem_get_size_region(fd);
70 if (ashmemSize <= 0) {
71 jniThrowException(env, "java/io/IOException", "bad ashmem size");
72 return -1;
73 }
74
75 int protMode = (owner || writable) ? (PROT_READ | PROT_WRITE) : PROT_READ;
76 void* ashmemAddr = mmap(NULL, ashmemSize, protMode, MAP_SHARED, fd, 0);
77 if (ashmemAddr == MAP_FAILED) {
78 jniThrowException(env, "java/io/IOException", "cannot mmap ashmem");
79 return -1;
80 }
81
82 if (owner) {
83 int size = ashmemSize / sizeof(std::atomic_int);
84 new (ashmemAddr) std::atomic_int[size];
85 }
86
87 if (owner && !writable) {
88 int setProtResult = ashmem_set_prot_region(fd, PROT_READ);
89 if (setProtResult < 0) {
90 jniThrowException(env, "java/io/IOException", "cannot set ashmem prot mode");
91 return -1;
92 }
93 }
94
95 return reinterpret_cast<jlong>(ashmemAddr);
96}
97
98static void android_util_MemoryIntArray_close(JNIEnv* env, jobject clazz, jint fd,
99 jlong ashmemAddr, jboolean owner)
100{
101 if (fd < 0) {
102 jniThrowException(env, "java/io/IOException", "bad file descriptor");
103 return;
104 }
105
Svet Ganov9d723d32016-08-27 11:05:56 -0700106 if (!ashmem_valid(fd)) {
107 jniThrowIOException(env, errno);
108 return;
109 }
110
Svet Ganov53a441c2016-04-19 19:38:00 -0700111 int ashmemSize = ashmem_get_size_region(fd);
112 if (ashmemSize <= 0) {
113 jniThrowException(env, "java/io/IOException", "bad ashmem size");
114 return;
115 }
116
117 int unmapResult = munmap(reinterpret_cast<void *>(ashmemAddr), ashmemSize);
118 if (unmapResult < 0) {
119 jniThrowException(env, "java/io/IOException", "munmap failed");
120 return;
121 }
122
123 // We don't deallocate the atomic ints we created with placement new in the ashmem
124 // region as the kernel we reclaim all pages when the ashmem region is destroyed.
125 if (owner && (ashmem_unpin_region(fd, 0, 0) != ASHMEM_IS_UNPINNED)) {
126 jniThrowException(env, "java/io/IOException", "ashmem unpinning failed");
127 return;
128 }
129
130 close(fd);
131}
132
133static jint android_util_MemoryIntArray_get(JNIEnv* env, jobject clazz,
134 jint fd, jlong address, jint index, jboolean owner)
135{
136 if (fd < 0) {
137 jniThrowException(env, "java/io/IOException", "bad file descriptor");
138 return -1;
139 }
140
Svet Ganov9d723d32016-08-27 11:05:56 -0700141 if (!ashmem_valid(fd)) {
142 jniThrowIOException(env, errno);
143 return -1;
144 }
145
Svetoslav Ganov04df7382016-05-10 18:55:47 -0700146 if (ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
147 jniThrowException(env, "java/io/IOException", "ashmem region was purged");
148 return -1;
Svet Ganov53a441c2016-04-19 19:38:00 -0700149 }
150
151 std::atomic_int* value = reinterpret_cast<std::atomic_int*>(address) + index;
Svetoslav Ganov04df7382016-05-10 18:55:47 -0700152 return value->load(std::memory_order_relaxed);
Svet Ganov53a441c2016-04-19 19:38:00 -0700153}
154
155static void android_util_MemoryIntArray_set(JNIEnv* env, jobject clazz,
156 jint fd, jlong address, jint index, jint newValue, jboolean owner)
157{
158 if (fd < 0) {
159 jniThrowException(env, "java/io/IOException", "bad file descriptor");
160 return;
161 }
162
Svet Ganov9d723d32016-08-27 11:05:56 -0700163 if (!ashmem_valid(fd)) {
164 jniThrowIOException(env, errno);
165 return;
166 }
167
Svetoslav Ganov04df7382016-05-10 18:55:47 -0700168 if (ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
169 jniThrowException(env, "java/io/IOException", "ashmem region was purged");
170 return;
Svet Ganov53a441c2016-04-19 19:38:00 -0700171 }
172
173 std::atomic_int* value = reinterpret_cast<std::atomic_int*>(address) + index;
174 value->store(newValue, std::memory_order_relaxed);
Svet Ganov53a441c2016-04-19 19:38:00 -0700175}
176
177static jint android_util_MemoryIntArray_size(JNIEnv* env, jobject clazz, jint fd) {
178 if (fd < 0) {
179 jniThrowException(env, "java/io/IOException", "bad file descriptor");
180 return -1;
181 }
182
Svet Ganov9d723d32016-08-27 11:05:56 -0700183 if (!ashmem_valid(fd)) {
184 jniThrowIOException(env, errno);
185 return -1;
186 }
187
Svet Ganov53a441c2016-04-19 19:38:00 -0700188 int ashmemSize = ashmem_get_size_region(fd);
189 if (ashmemSize < 0) {
Svet Ganov53a441c2016-04-19 19:38:00 -0700190 jniThrowIOException(env, errno);
191 return -1;
192 }
193 return ashmemSize / sizeof(std::atomic_int);
194}
195
196static const JNINativeMethod methods[] = {
197 {"nativeCreate", "(Ljava/lang/String;I)I", (void*)android_util_MemoryIntArray_create},
198 {"nativeOpen", "(IZZ)J", (void*)android_util_MemoryIntArray_open},
199 {"nativeClose", "(IJZ)V", (void*)android_util_MemoryIntArray_close},
200 {"nativeGet", "(IJIZ)I", (void*)android_util_MemoryIntArray_get},
201 {"nativeSet", "(IJIIZ)V", (void*) android_util_MemoryIntArray_set},
202 {"nativeSize", "(I)I", (void*) android_util_MemoryIntArray_size},
203};
204
205int register_android_util_MemoryIntArray(JNIEnv* env)
206{
207 return RegisterMethodsOrDie(env, "android/util/MemoryIntArray", methods, NELEM(methods));
208}
209
210}