blob: 9f444bbfb470f27d3ac84423a3372d2111fd71b2 [file] [log] [blame]
Elliott Hughes87f62a82011-04-22 19:22:54 -07001/*
2 * Copyright (C) 2006 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 "JNIHelp"
18
Brian Carlstromdd8af232012-05-13 23:56:07 -070019#include "JniConstants.h"
Elliott Hughes87f62a82011-04-22 19:22:54 -070020#include "JNIHelp.h"
Elliott Hughesa6f951c2011-06-08 15:54:05 -070021#include "cutils/log.h"
Elliott Hughes87f62a82011-04-22 19:22:54 -070022
23#include <stdlib.h>
24#include <string.h>
25#include <assert.h>
26
Brian Carlstromdd8af232012-05-13 23:56:07 -070027#include <string>
28
Elliott Hughes87f62a82011-04-22 19:22:54 -070029/**
30 * Equivalent to ScopedLocalRef, but for C_JNIEnv instead. (And slightly more powerful.)
31 */
32template<typename T>
33class scoped_local_ref {
34public:
35 scoped_local_ref(C_JNIEnv* env, T localRef = NULL)
36 : mEnv(env), mLocalRef(localRef)
37 {
38 }
39
40 ~scoped_local_ref() {
41 reset();
42 }
43
44 void reset(T localRef = NULL) {
45 if (mLocalRef != NULL) {
46 (*mEnv)->DeleteLocalRef(reinterpret_cast<JNIEnv*>(mEnv), mLocalRef);
47 mLocalRef = localRef;
48 }
49 }
50
51 T get() const {
52 return mLocalRef;
53 }
54
55private:
56 C_JNIEnv* mEnv;
57 T mLocalRef;
58
59 // Disallow copy and assignment.
60 scoped_local_ref(const scoped_local_ref&);
61 void operator=(const scoped_local_ref&);
62};
63
64static jclass findClass(C_JNIEnv* env, const char* className) {
65 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
66 return (*env)->FindClass(e, className);
67}
68
69extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className,
70 const JNINativeMethod* gMethods, int numMethods)
71{
72 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
73
Brian Carlstromdd8af232012-05-13 23:56:07 -070074 ALOGV("Registering %s's %d native methods...", className, numMethods);
Elliott Hughes87f62a82011-04-22 19:22:54 -070075
76 scoped_local_ref<jclass> c(env, findClass(env, className));
77 if (c.get() == NULL) {
Elliott Hughesa3b57002013-01-22 09:35:09 -080078 char* msg;
Brian Carlstromdeb6d5d2013-05-10 09:50:08 -070079 asprintf(&msg, "Native registration unable to find class '%s'; aborting...", className);
Elliott Hughesa3b57002013-01-22 09:35:09 -080080 e->FatalError(msg);
Elliott Hughes87f62a82011-04-22 19:22:54 -070081 }
82
83 if ((*env)->RegisterNatives(e, c.get(), gMethods, numMethods) < 0) {
Elliott Hughesa3b57002013-01-22 09:35:09 -080084 char* msg;
Brian Carlstromdeb6d5d2013-05-10 09:50:08 -070085 asprintf(&msg, "RegisterNatives failed for '%s'; aborting...", className);
Elliott Hughesa3b57002013-01-22 09:35:09 -080086 e->FatalError(msg);
Elliott Hughes87f62a82011-04-22 19:22:54 -070087 }
88
89 return 0;
90}
91
92/*
93 * Returns a human-readable summary of an exception object. The buffer will
94 * be populated with the "binary" class name and, if present, the
95 * exception message.
96 */
Brian Carlstromdd8af232012-05-13 23:56:07 -070097static bool getExceptionSummary(C_JNIEnv* env, jthrowable exception, std::string& result) {
Elliott Hughes87f62a82011-04-22 19:22:54 -070098 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
99
100 /* get the name of the exception's class */
101 scoped_local_ref<jclass> exceptionClass(env, (*env)->GetObjectClass(e, exception)); // can't fail
102 scoped_local_ref<jclass> classClass(env,
103 (*env)->GetObjectClass(e, exceptionClass.get())); // java.lang.Class, can't fail
104 jmethodID classGetNameMethod =
105 (*env)->GetMethodID(e, classClass.get(), "getName", "()Ljava/lang/String;");
106 scoped_local_ref<jstring> classNameStr(env,
107 (jstring) (*env)->CallObjectMethod(e, exceptionClass.get(), classGetNameMethod));
108 if (classNameStr.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700109 (*env)->ExceptionClear(e);
110 result = "<error getting class name>";
111 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700112 }
Elliott Hughes87f62a82011-04-22 19:22:54 -0700113 const char* classNameChars = (*env)->GetStringUTFChars(e, classNameStr.get(), NULL);
114 if (classNameChars == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700115 (*env)->ExceptionClear(e);
116 result = "<error getting class name UTF-8>";
117 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700118 }
Brian Carlstromdd8af232012-05-13 23:56:07 -0700119 result += classNameChars;
120 (*env)->ReleaseStringUTFChars(e, classNameStr.get(), classNameChars);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700121
122 /* if the exception has a detail message, get that */
123 jmethodID getMessage =
124 (*env)->GetMethodID(e, exceptionClass.get(), "getMessage", "()Ljava/lang/String;");
125 scoped_local_ref<jstring> messageStr(env,
126 (jstring) (*env)->CallObjectMethod(e, exception, getMessage));
127 if (messageStr.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700128 return true;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700129 }
130
Brian Carlstromdd8af232012-05-13 23:56:07 -0700131 result += ": ";
132
Elliott Hughes87f62a82011-04-22 19:22:54 -0700133 const char* messageChars = (*env)->GetStringUTFChars(e, messageStr.get(), NULL);
134 if (messageChars != NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700135 result += messageChars;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700136 (*env)->ReleaseStringUTFChars(e, messageStr.get(), messageChars);
137 } else {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700138 result += "<error getting message>";
Elliott Hughes87f62a82011-04-22 19:22:54 -0700139 (*env)->ExceptionClear(e); // clear OOM
Elliott Hughes87f62a82011-04-22 19:22:54 -0700140 }
141
Brian Carlstromdd8af232012-05-13 23:56:07 -0700142 return true;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700143}
144
145/*
146 * Returns an exception (with stack trace) as a string.
147 */
Brian Carlstromdd8af232012-05-13 23:56:07 -0700148static bool getStackTrace(C_JNIEnv* env, jthrowable exception, std::string& result) {
Elliott Hughes87f62a82011-04-22 19:22:54 -0700149 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
150
151 scoped_local_ref<jclass> stringWriterClass(env, findClass(env, "java/io/StringWriter"));
152 if (stringWriterClass.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700153 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700154 }
155
156 jmethodID stringWriterCtor = (*env)->GetMethodID(e, stringWriterClass.get(), "<init>", "()V");
157 jmethodID stringWriterToStringMethod =
158 (*env)->GetMethodID(e, stringWriterClass.get(), "toString", "()Ljava/lang/String;");
159
160 scoped_local_ref<jclass> printWriterClass(env, findClass(env, "java/io/PrintWriter"));
161 if (printWriterClass.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700162 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700163 }
164
165 jmethodID printWriterCtor =
166 (*env)->GetMethodID(e, printWriterClass.get(), "<init>", "(Ljava/io/Writer;)V");
167
168 scoped_local_ref<jobject> stringWriter(env,
169 (*env)->NewObject(e, stringWriterClass.get(), stringWriterCtor));
170 if (stringWriter.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700171 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700172 }
173
174 jobject printWriter =
175 (*env)->NewObject(e, printWriterClass.get(), printWriterCtor, stringWriter.get());
176 if (printWriter == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700177 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700178 }
179
180 scoped_local_ref<jclass> exceptionClass(env, (*env)->GetObjectClass(e, exception)); // can't fail
181 jmethodID printStackTraceMethod =
182 (*env)->GetMethodID(e, exceptionClass.get(), "printStackTrace", "(Ljava/io/PrintWriter;)V");
183 (*env)->CallVoidMethod(e, exception, printStackTraceMethod, printWriter);
184
185 if ((*env)->ExceptionCheck(e)) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700186 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700187 }
188
189 scoped_local_ref<jstring> messageStr(env,
190 (jstring) (*env)->CallObjectMethod(e, stringWriter.get(), stringWriterToStringMethod));
191 if (messageStr.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700192 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700193 }
194
195 const char* utfChars = (*env)->GetStringUTFChars(e, messageStr.get(), NULL);
196 if (utfChars == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700197 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700198 }
199
Brian Carlstromdd8af232012-05-13 23:56:07 -0700200 result = utfChars;
201
Elliott Hughes87f62a82011-04-22 19:22:54 -0700202 (*env)->ReleaseStringUTFChars(e, messageStr.get(), utfChars);
Brian Carlstromdd8af232012-05-13 23:56:07 -0700203 return true;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700204}
205
206extern "C" int jniThrowException(C_JNIEnv* env, const char* className, const char* msg) {
207 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
208
209 if ((*env)->ExceptionCheck(e)) {
210 /* TODO: consider creating the new exception with this as "cause" */
211 scoped_local_ref<jthrowable> exception(env, (*env)->ExceptionOccurred(e));
212 (*env)->ExceptionClear(e);
213
214 if (exception.get() != NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700215 std::string text;
216 getExceptionSummary(env, exception.get(), text);
217 ALOGW("Discarding pending exception (%s) to throw %s", text.c_str(), className);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700218 }
219 }
220
221 scoped_local_ref<jclass> exceptionClass(env, findClass(env, className));
222 if (exceptionClass.get() == NULL) {
Steve Block79a0d9c2012-01-06 19:16:58 +0000223 ALOGE("Unable to find exception class %s", className);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700224 /* ClassNotFoundException now pending */
225 return -1;
226 }
227
228 if ((*env)->ThrowNew(e, exceptionClass.get(), msg) != JNI_OK) {
Steve Block79a0d9c2012-01-06 19:16:58 +0000229 ALOGE("Failed throwing '%s' '%s'", className, msg);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700230 /* an exception, most likely OOM, will now be pending */
231 return -1;
232 }
233
234 return 0;
235}
236
237int jniThrowExceptionFmt(C_JNIEnv* env, const char* className, const char* fmt, va_list args) {
238 char msgBuf[512];
239 vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
240 return jniThrowException(env, className, msgBuf);
241}
242
243int jniThrowNullPointerException(C_JNIEnv* env, const char* msg) {
244 return jniThrowException(env, "java/lang/NullPointerException", msg);
245}
246
247int jniThrowRuntimeException(C_JNIEnv* env, const char* msg) {
248 return jniThrowException(env, "java/lang/RuntimeException", msg);
249}
250
251int jniThrowIOException(C_JNIEnv* env, int errnum) {
252 char buffer[80];
253 const char* message = jniStrError(errnum, buffer, sizeof(buffer));
254 return jniThrowException(env, "java/io/IOException", message);
255}
256
Elliott Hughesa4e4e742013-09-03 17:47:18 -0700257static std::string jniGetStackTrace(C_JNIEnv* env, jthrowable exception) {
Elliott Hughes87f62a82011-04-22 19:22:54 -0700258 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
259
Jeff Browne2b11e72012-04-10 20:34:39 -0700260 scoped_local_ref<jthrowable> currentException(env, (*env)->ExceptionOccurred(e));
Elliott Hughes87f62a82011-04-22 19:22:54 -0700261 if (exception == NULL) {
Jeff Browne2b11e72012-04-10 20:34:39 -0700262 exception = currentException.get();
Elliott Hughes87f62a82011-04-22 19:22:54 -0700263 if (exception == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700264 return "<no pending exception>";
Elliott Hughes87f62a82011-04-22 19:22:54 -0700265 }
Jeff Browne2b11e72012-04-10 20:34:39 -0700266 }
Elliott Hughes87f62a82011-04-22 19:22:54 -0700267
Jeff Browne2b11e72012-04-10 20:34:39 -0700268 if (currentException.get() != NULL) {
Elliott Hughes87f62a82011-04-22 19:22:54 -0700269 (*env)->ExceptionClear(e);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700270 }
271
Brian Carlstromdd8af232012-05-13 23:56:07 -0700272 std::string trace;
273 if (!getStackTrace(env, exception, trace)) {
Elliott Hughes87f62a82011-04-22 19:22:54 -0700274 (*env)->ExceptionClear(e);
Brian Carlstromdd8af232012-05-13 23:56:07 -0700275 getExceptionSummary(env, exception, trace);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700276 }
277
Elliott Hughes87f62a82011-04-22 19:22:54 -0700278 if (currentException.get() != NULL) {
Jeff Browne2b11e72012-04-10 20:34:39 -0700279 (*env)->Throw(e, currentException.get()); // rethrow
Elliott Hughes87f62a82011-04-22 19:22:54 -0700280 }
Brian Carlstromdd8af232012-05-13 23:56:07 -0700281
282 return trace;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700283}
284
Elliott Hughesa4e4e742013-09-03 17:47:18 -0700285void jniLogException(C_JNIEnv* env, int priority, const char* tag, jthrowable exception) {
286 std::string trace(jniGetStackTrace(env, exception));
287 __android_log_write(priority, tag, trace.c_str());
288}
289
Elliott Hughes87f62a82011-04-22 19:22:54 -0700290const char* jniStrError(int errnum, char* buf, size_t buflen) {
Elliott Hughesd60512c2013-10-08 14:15:18 -0700291#if __GLIBC__
Elliott Hughes87f62a82011-04-22 19:22:54 -0700292 // Note: glibc has a nonstandard strerror_r that returns char* rather than POSIX's int.
293 // char *strerror_r(int errnum, char *buf, size_t n);
Elliott Hughesd60512c2013-10-08 14:15:18 -0700294 return strerror_r(errnum, buf, buflen);
295#else
296 int rc = strerror_r(errnum, buf, buflen);
297 if (rc != 0) {
298 // (POSIX only guarantees a value other than 0. The safest
Elliott Hughes87f62a82011-04-22 19:22:54 -0700299 // way to implement this function is to use C++ and overload on the
Elliott Hughesd60512c2013-10-08 14:15:18 -0700300 // type of strerror_r to accurately distinguish GNU from POSIX.)
Elliott Hughes87f62a82011-04-22 19:22:54 -0700301 snprintf(buf, buflen, "errno %d", errnum);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700302 }
Elliott Hughesd60512c2013-10-08 14:15:18 -0700303 return buf;
304#endif
Elliott Hughes87f62a82011-04-22 19:22:54 -0700305}
306
Elliott Hughes87f62a82011-04-22 19:22:54 -0700307jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd) {
308 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
Brian Carlstromdd8af232012-05-13 23:56:07 -0700309 static jmethodID ctor = e->GetMethodID(JniConstants::fileDescriptorClass, "<init>", "()V");
310 jobject fileDescriptor = (*env)->NewObject(e, JniConstants::fileDescriptorClass, ctor);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700311 jniSetFileDescriptorOfFD(env, fileDescriptor, fd);
312 return fileDescriptor;
313}
314
315int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor) {
316 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
Brian Carlstromdd8af232012-05-13 23:56:07 -0700317 static jfieldID fid = e->GetFieldID(JniConstants::fileDescriptorClass, "descriptor", "I");
318 return (*env)->GetIntField(e, fileDescriptor, fid);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700319}
320
321void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor, int value) {
322 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
Brian Carlstromdd8af232012-05-13 23:56:07 -0700323 static jfieldID fid = e->GetFieldID(JniConstants::fileDescriptorClass, "descriptor", "I");
324 (*env)->SetIntField(e, fileDescriptor, fid, value);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700325}
326
Jeff Browndc176c52013-04-02 18:09:29 -0700327jobject jniGetReferent(C_JNIEnv* env, jobject ref) {
328 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
329 static jmethodID get = e->GetMethodID(JniConstants::referenceClass, "get", "()Ljava/lang/Object;");
330 return (*env)->CallObjectMethod(e, ref, get);
331}
332
Elliott Hughes87f62a82011-04-22 19:22:54 -0700333/*
334 * DO NOT USE THIS FUNCTION
335 *
336 * Get a pointer to the elements of a non-movable array.
337 *
338 * The semantics are similar to GetDirectBufferAddress. Specifically, the VM
339 * guarantees that the array will not move, and the caller must ensure that
340 * it does not continue to use the pointer after the object is collected.
341 *
342 * We currently use an illegal sequence that trips up CheckJNI when
343 * the "forcecopy" mode is enabled. We pass in a magic value to work
344 * around the problem.
345 *
346 * Returns NULL if the array is movable.
347 */
348#define kNoCopyMagic 0xd5aab57f /* also in CheckJni.c */
349extern "C" jbyte* jniGetNonMovableArrayElements(C_JNIEnv* env, jarray arrayObj) {
350 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
351
352 jbyteArray byteArray = reinterpret_cast<jbyteArray>(arrayObj);
353
354 /*
355 * Normally the "isCopy" parameter is for a return value only, so the
356 * non-CheckJNI VM will ignore whatever we pass in.
357 */
358 uint32_t noCopy = kNoCopyMagic;
359 jbyte* result = (*env)->GetByteArrayElements(e, byteArray, reinterpret_cast<jboolean*>(&noCopy));
360
361 /*
362 * The non-CheckJNI implementation only cares about the array object,
363 * so we can replace the element pointer with the magic value.
364 */
365 (*env)->ReleaseByteArrayElements(e, byteArray, reinterpret_cast<jbyte*>(kNoCopyMagic), 0);
366 return result;
367}