1 /*
2 * Copyright (C) 2020 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 #include <iterator>
18
19 #include <dlfcn.h>
20 #include <jni.h>
21
22 #include <android/log.h>
23 #include <nativehelper/jni_macros.h>
24 #include <nativehelper/scoped_local_ref.h>
25 #include <nativehelper/scoped_string_chars.h>
26 #include <nativehelper/scoped_utf_chars.h>
27 #include <nativehelper/JNIPlatformHelp.h>
28
29 #include "libnativehelper_test.h"
30
31 extern "C" int jniGetFDFromFileDescriptor_QR(JNIEnv* env, jobject fileDescriptor);
32
33 namespace {
34
AssertionError(JNIEnv * env,const char * format,...)35 void AssertionError(JNIEnv* env, const char* format, ...) {
36 // There is some awkwardness with java/lang/AssertionError. It cannot be directly thrown
37 // by jniThrowException or the JNI ThrowNew methods because AssertionError(String) is not
38 // public so we instead use the AssertionError(String, Throwable) constructor.
39 va_list args;
40 va_start(args, format);
41 char messageBuffer[256];
42 vsnprintf(messageBuffer, sizeof(messageBuffer), format, args);
43 va_end(args);
44
45 ScopedLocalRef<jclass> jlaeClass(env, env->FindClass("java/lang/AssertionError"));
46 jmethodID init =
47 env->GetMethodID(jlaeClass.get(), "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
48 ScopedLocalRef<jstring> message(env, env->NewStringUTF(messageBuffer));
49 jobject jlae = env->NewObject(jlaeClass.get(), init, message.get(), nullptr);
50 env->Throw(reinterpret_cast<jthrowable>(jlae));
51 }
52
throwException(JNIEnv * env,jclass,jstring className,jstring message)53 static void throwException(JNIEnv* env, jclass /*clazz*/, jstring className, jstring message) {
54 ScopedUtfChars c(env, className);
55 ScopedUtfChars m(env, message);
56 jniThrowException(env, c.c_str(), m.c_str());
57 }
58
throwExceptionWithIntFormat(JNIEnv * env,jclass,jstring className,jstring format,jint value)59 static void throwExceptionWithIntFormat(JNIEnv* env,
60 jclass /*clazz*/,
61 jstring className,
62 jstring format,
63 jint value) {
64 ScopedUtfChars c(env, className);
65 ScopedUtfChars f(env, format);
66 jniThrowExceptionFmt(env, c.c_str(), f.c_str(), value);
67 }
68
throwNullPointerException(JNIEnv * env,jclass,jstring message)69 static void throwNullPointerException(JNIEnv* env,
70 jclass /*clazz*/,
71 jstring message) {
72 ScopedUtfChars m(env, message);
73 jniThrowNullPointerException(env, m.c_str());
74 }
75
throwRuntimeException(JNIEnv * env,jclass,jstring message)76 static void throwRuntimeException(JNIEnv* env, jclass /*clazz*/, jstring message) {
77 ScopedUtfChars m(env, message);
78 jniThrowRuntimeException(env, m.c_str());
79 }
80
throwIOException(JNIEnv * env,jclass,jint cause)81 static void throwIOException(JNIEnv* env, jclass /*clazz*/, jint cause) {
82 jniThrowIOException(env, cause);
83 }
84
logException(JNIEnv * env,jclass,jthrowable throwable)85 static void logException(JNIEnv* env, jclass /*clazz*/, jthrowable throwable) {
86 jniLogException(env, ANDROID_LOG_VERBOSE, __FILE__, throwable);
87 }
88
fileDescriptorCreate(JNIEnv * env,jclass,jint unix_fd)89 static jobject fileDescriptorCreate(JNIEnv* env, jclass /*clazz*/, jint unix_fd) {
90 return jniCreateFileDescriptor(env, unix_fd);
91 }
92
fileDescriptorGetFD(JNIEnv * env,jclass,jobject jiofd)93 static jint fileDescriptorGetFD(JNIEnv* env, jclass /*clazz*/, jobject jiofd) {
94 return jniGetFDFromFileDescriptor(env, jiofd);
95 }
96
fileDescriptorGetFDCompatQR(JNIEnv * env,jclass,jobject jiofd)97 static jint fileDescriptorGetFDCompatQR(JNIEnv* env, jclass /*clazz*/, jobject jiofd) {
98 // Compatibility version of jniGetFDFromFileDescriptor for NetworkStack and Tethering modules
99 // that need to run on Android versions back to Android Q and Android R. The symbol is exported
100 // by libnativehelper_compat_libc++.so.
101 return jniGetFDFromFileDescriptor_QR(env, jiofd);
102 }
103
fileDescriptorSetFD(JNIEnv * env,jclass,jobject jiofd,jint unix_fd)104 static void fileDescriptorSetFD(JNIEnv* env, jclass /*clazz*/, jobject jiofd, jint unix_fd) {
105 jniSetFileDescriptorOfFD(env, jiofd, unix_fd);
106 }
107
allocateDirectNonHeapBuffer(JNIEnv * env,jclass,jint length)108 static jobject allocateDirectNonHeapBuffer(JNIEnv* env, jclass /*clazz*/, jint length) {
109 static uint8_t raw_memory[4096];
110 if (length < 0 || length > sizeof(raw_memory)) {
111 return nullptr;
112 }
113 return env->NewDirectByteBuffer(&raw_memory, length);
114 }
115
116 static void
assertBufferBaseArrayOffsetBytes(JNIEnv * env,jclass,jobject jnb,jint offset)117 assertBufferBaseArrayOffsetBytes(JNIEnv* env, jclass /*clazz*/, jobject jnb, jint offset) {
118 int actualOffset = jniGetNioBufferBaseArrayOffset(env, jnb);
119 if (actualOffset != offset) {
120 AssertionError(env,
121 "Buffer offset incorrect (expected %d, actual %d)",
122 offset,
123 actualOffset);
124 }
125 }
126
assertBufferPosition(JNIEnv * env,jclass,jobject jnb,jint position)127 static void assertBufferPosition(JNIEnv* env, jclass /*clazz*/, jobject jnb, jint position) {
128 int actualPosition, actualLimit, actualElementSizeShift;
129 jniGetNioBufferFields(env, jnb, &actualPosition, &actualLimit, &actualElementSizeShift);
130 if (actualPosition != position) {
131 AssertionError(env,
132 "Buffer position incorrect (expected %d, actual %d)",
133 position,
134 actualPosition);
135 }
136 }
137
assertBufferLimit(JNIEnv * env,jclass,jobject jnb,jint limit)138 static void assertBufferLimit(JNIEnv* env, jclass /*clazz*/, jobject jnb, jint limit) {
139 int actualPosition, actualLimit, actualElementSizeShift;
140 jniGetNioBufferFields(env, jnb, &actualPosition, &actualLimit, &actualElementSizeShift);
141 if (actualLimit != limit) {
142 AssertionError(env,
143 "Buffer limit incorrect (expected %d, actual %d)",
144 limit,
145 actualLimit);
146 }
147 }
148
assertBufferElementSizeShift(JNIEnv * env,jclass,jobject jnb,jint ess)149 static void assertBufferElementSizeShift(JNIEnv* env, jclass /*clazz*/, jobject jnb, jint ess) {
150 int actualPosition, actualLimit, actualElementSizeShift;
151 jniGetNioBufferFields(env, jnb, &actualPosition, &actualLimit, &actualElementSizeShift);
152 if (actualElementSizeShift != ess) {
153 AssertionError(env,
154 "Buffer element size shift incorrect (expected %d, actual %d)",
155 ess,
156 actualElementSizeShift);
157 }
158 }
159
getBufferBaseAddress(JNIEnv * env,jclass,jobject jnb)160 static jlong getBufferBaseAddress(JNIEnv* env, jclass /*clazz*/, jobject jnb) {
161 int actualPosition, actualLimit, actualElementSizeShift;
162 return jniGetNioBufferFields(env, jnb, &actualPosition, &actualLimit, &actualElementSizeShift);
163 }
164
getDirectBufferAddress(JNIEnv * env,jclass,jobject jnb)165 static jlong getDirectBufferAddress(JNIEnv* env, jclass /*clazz*/, jobject jnb) {
166 void* directBufferAddress = env->GetDirectBufferAddress(jnb);
167 return reinterpret_cast<jlong>(directBufferAddress);
168 }
169
assertBufferPointer(JNIEnv * env,jclass,jobject jnb,jlong pointer)170 static void assertBufferPointer(JNIEnv* env, jclass /*clazz*/, jobject jnb, jlong pointer) {
171 jlong actualPointer = jniGetNioBufferPointer(env, jnb);
172 if (actualPointer != pointer) {
173 AssertionError(env,
174 "Buffer pointer incorrect (expected %p, actual %p)",
175 reinterpret_cast<void*>(pointer),
176 reinterpret_cast<void*>(actualPointer));
177 }
178 }
179
getReferent(JNIEnv * env,jclass,jobject reference)180 static jobject getReferent(JNIEnv* env, jclass /*clazz*/, jobject reference) {
181 return jniGetReferent(env, reference);
182 }
183
createString(JNIEnv * env,jclass,jstring value)184 static jstring createString(JNIEnv* env, jclass /*clazz*/, jstring value) {
185 ScopedStringChars ssc(env, value);
186 return jniCreateString(env, ssc.get(), ssc.size());
187 }
188
createStringArray(JNIEnv * env,jclass,jint length)189 static jobjectArray createStringArray(JNIEnv* env, jclass /*clazz*/, jint length) {
190 return jniCreateStringArray(&env->functions, length);
191 }
192
193 } // namespace
194
JNI_OnLoad(JavaVM * vm,void * reserved)195 JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
196 JNIEnv* env;
197 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
198 return JNI_ERR;
199 }
200
201 static const JNINativeMethod methods[] = {
202 MAKE_JNI_NATIVE_METHOD("throwException",
203 "(Ljava/lang/String;Ljava/lang/String;)V",
204 throwException),
205 MAKE_JNI_NATIVE_METHOD("throwExceptionWithIntFormat",
206 "(Ljava/lang/String;Ljava/lang/String;I)V",
207 throwExceptionWithIntFormat),
208 MAKE_JNI_NATIVE_METHOD("throwNullPointerException",
209 "(Ljava/lang/String;)V",
210 throwNullPointerException),
211 MAKE_JNI_NATIVE_METHOD("throwRuntimeException",
212 "(Ljava/lang/String;)V",
213 throwRuntimeException),
214 MAKE_JNI_NATIVE_METHOD("throwIOException",
215 "(I)V",
216 throwIOException),
217 MAKE_JNI_NATIVE_METHOD("logException",
218 "(Ljava/lang/Throwable;)V",
219 logException),
220 MAKE_JNI_NATIVE_METHOD("fileDescriptorCreate",
221 "(I)Ljava/io/FileDescriptor;",
222 fileDescriptorCreate),
223 MAKE_JNI_NATIVE_METHOD("fileDescriptorGetFD",
224 "(Ljava/io/FileDescriptor;)I",
225 fileDescriptorGetFD),
226 MAKE_JNI_NATIVE_METHOD("fileDescriptorGetFDCompatQR",
227 "(Ljava/io/FileDescriptor;)I",
228 fileDescriptorGetFDCompatQR),
229 MAKE_JNI_NATIVE_METHOD("fileDescriptorSetFD",
230 "(Ljava/io/FileDescriptor;I)V",
231 fileDescriptorSetFD),
232 MAKE_JNI_NATIVE_METHOD("allocateDirectNonHeapBuffer",
233 "(I)Ljava/nio/ByteBuffer;",
234 allocateDirectNonHeapBuffer),
235 MAKE_JNI_NATIVE_METHOD("assertBufferBaseArrayOffsetBytes",
236 "(Ljava/nio/Buffer;I)V",
237 assertBufferBaseArrayOffsetBytes),
238 MAKE_JNI_NATIVE_METHOD("assertBufferPosition",
239 "(Ljava/nio/Buffer;I)V",
240 assertBufferPosition),
241 MAKE_JNI_NATIVE_METHOD("assertBufferLimit",
242 "(Ljava/nio/Buffer;I)V",
243 assertBufferLimit),
244 MAKE_JNI_NATIVE_METHOD("assertBufferElementSizeShift",
245 "(Ljava/nio/Buffer;I)V",
246 assertBufferElementSizeShift),
247 MAKE_JNI_NATIVE_METHOD("getBufferBaseAddress",
248 "(Ljava/nio/Buffer;)J",
249 getBufferBaseAddress),
250 MAKE_JNI_NATIVE_METHOD("getDirectBufferAddress",
251 "(Ljava/nio/Buffer;)J",
252 getDirectBufferAddress),
253 MAKE_JNI_NATIVE_METHOD("assertBufferPointer",
254 "(Ljava/nio/Buffer;J)V",
255 assertBufferPointer),
256 MAKE_JNI_NATIVE_METHOD("getReferent",
257 "(Ljava/lang/ref/Reference;)Ljava/lang/Object;",
258 getReferent),
259 MAKE_JNI_NATIVE_METHOD("createString",
260 "(Ljava/lang/String;)Ljava/lang/String;",
261 createString),
262 MAKE_JNI_NATIVE_METHOD("createStringArray",
263 "(I)[Ljava/lang/String;",
264 createStringArray)
265 };
266 int rc = jniRegisterNativeMethods(env,
267 "android/libnativehelper/mts/JniHelpTest",
268 methods,
269 std::size(methods));
270 if (rc != JNI_OK) return rc;
271
272 return JNI_VERSION_1_6;
273 }
274