blob: bdecc093bdf9bdae11de4ec5c5a5892d2ba2d33e [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
Steven Moreland3544a932017-07-19 10:26:05 -070019#include <nativehelper/JniConstants.h>
20#include <nativehelper/JNIHelp.h>
Ruben Brunka77f3a22013-09-09 02:21:31 -070021#include "ALog-priv.h"
Elliott Hughes87f62a82011-04-22 19:22:54 -070022
Ruben Brunka77f3a22013-09-09 02:21:31 -070023#include <stdio.h>
Elliott Hughes87f62a82011-04-22 19:22:54 -070024#include <stdlib.h>
25#include <string.h>
26#include <assert.h>
27
Brian Carlstromdd8af232012-05-13 23:56:07 -070028#include <string>
29
Logan Chien63e49172016-06-08 11:33:36 +080030namespace {
31
32// java.io.FileDescriptor.descriptor.
33jfieldID fileDescriptorDescriptorField = nullptr;
Josh Gao669bc9e2018-06-25 16:22:11 -070034// java.io.FileDescriptor.ownerId.
35jfieldID fileDescriptorOwnerIdField = nullptr;
Logan Chien63e49172016-06-08 11:33:36 +080036
37// void java.io.FileDescriptor.<init>().
38jmethodID fileDescriptorInitMethod = nullptr;
39// Object java.lang.ref.Reference.get()
40jmethodID referenceGetMethod = nullptr;
41
42jfieldID FindField(JNIEnv* env, jclass klass, const char* name, const char* desc) {
43 jfieldID result = env->GetFieldID(klass, name, desc);
44 if (result == NULL) {
45 ALOGV("failed to find field '%s:%s'", name, desc);
46 abort();
47 }
48 return result;
49}
50
51jmethodID FindMethod(JNIEnv* env, jclass klass, const char* name, const char* signature) {
52 jmethodID result = env->GetMethodID(klass, name, signature);
53 if (result == NULL) {
54 ALOGV("failed to find method '%s%s'", name, signature);
55 abort();
56 }
57 return result;
58}
59
60void InitFieldsAndMethods(JNIEnv* env) {
61 JniConstants::init(env); // Ensure that classes are cached.
62 fileDescriptorDescriptorField = FindField(env, JniConstants::fileDescriptorClass, "descriptor",
63 "I");
Josh Gao669bc9e2018-06-25 16:22:11 -070064 fileDescriptorOwnerIdField = FindField(env, JniConstants::fileDescriptorClass, "ownerId",
65 "J");
Logan Chien63e49172016-06-08 11:33:36 +080066 fileDescriptorInitMethod = FindMethod(env, JniConstants::fileDescriptorClass, "<init>", "()V");
67 referenceGetMethod = FindMethod(env, JniConstants::referenceClass, "get",
68 "()Ljava/lang/Object;");
69}
70
71}
72
73namespace android {
74
75void ClearJNIHelpLocalCache() {
76 fileDescriptorDescriptorField = nullptr;
77 fileDescriptorInitMethod = nullptr;
78 referenceGetMethod = nullptr;
79}
80
81}
82
Elliott Hughes87f62a82011-04-22 19:22:54 -070083/**
84 * Equivalent to ScopedLocalRef, but for C_JNIEnv instead. (And slightly more powerful.)
85 */
86template<typename T>
87class scoped_local_ref {
88public:
Chih-Hung Hsieh01332142016-05-02 11:47:43 -070089 explicit scoped_local_ref(C_JNIEnv* env, T localRef = NULL)
Elliott Hughes87f62a82011-04-22 19:22:54 -070090 : mEnv(env), mLocalRef(localRef)
91 {
92 }
93
94 ~scoped_local_ref() {
95 reset();
96 }
97
98 void reset(T localRef = NULL) {
99 if (mLocalRef != NULL) {
100 (*mEnv)->DeleteLocalRef(reinterpret_cast<JNIEnv*>(mEnv), mLocalRef);
101 mLocalRef = localRef;
102 }
103 }
104
105 T get() const {
106 return mLocalRef;
107 }
108
109private:
Ian Rogers8288dde2014-11-04 11:42:02 -0800110 C_JNIEnv* const mEnv;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700111 T mLocalRef;
112
Ian Rogers8288dde2014-11-04 11:42:02 -0800113 DISALLOW_COPY_AND_ASSIGN(scoped_local_ref);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700114};
115
116static jclass findClass(C_JNIEnv* env, const char* className) {
117 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
118 return (*env)->FindClass(e, className);
119}
120
121extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className,
122 const JNINativeMethod* gMethods, int numMethods)
123{
124 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
125
Brian Carlstromdd8af232012-05-13 23:56:07 -0700126 ALOGV("Registering %s's %d native methods...", className, numMethods);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700127
128 scoped_local_ref<jclass> c(env, findClass(env, className));
129 if (c.get() == NULL) {
Andreas Gampe6c5be192015-08-03 10:31:52 -0700130 char* tmp;
131 const char* msg;
132 if (asprintf(&tmp,
133 "Native registration unable to find class '%s'; aborting...",
134 className) == -1) {
135 // Allocation failed, print default warning.
136 msg = "Native registration unable to find class; aborting...";
137 } else {
138 msg = tmp;
139 }
Elliott Hughesa3b57002013-01-22 09:35:09 -0800140 e->FatalError(msg);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700141 }
142
143 if ((*env)->RegisterNatives(e, c.get(), gMethods, numMethods) < 0) {
Andreas Gampe6c5be192015-08-03 10:31:52 -0700144 char* tmp;
145 const char* msg;
146 if (asprintf(&tmp, "RegisterNatives failed for '%s'; aborting...", className) == -1) {
147 // Allocation failed, print default warning.
148 msg = "RegisterNatives failed; aborting...";
149 } else {
150 msg = tmp;
151 }
Elliott Hughesa3b57002013-01-22 09:35:09 -0800152 e->FatalError(msg);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700153 }
154
155 return 0;
156}
157
158/*
159 * Returns a human-readable summary of an exception object. The buffer will
160 * be populated with the "binary" class name and, if present, the
161 * exception message.
162 */
Brian Carlstromdd8af232012-05-13 23:56:07 -0700163static bool getExceptionSummary(C_JNIEnv* env, jthrowable exception, std::string& result) {
Elliott Hughes87f62a82011-04-22 19:22:54 -0700164 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
165
166 /* get the name of the exception's class */
167 scoped_local_ref<jclass> exceptionClass(env, (*env)->GetObjectClass(e, exception)); // can't fail
168 scoped_local_ref<jclass> classClass(env,
169 (*env)->GetObjectClass(e, exceptionClass.get())); // java.lang.Class, can't fail
170 jmethodID classGetNameMethod =
171 (*env)->GetMethodID(e, classClass.get(), "getName", "()Ljava/lang/String;");
172 scoped_local_ref<jstring> classNameStr(env,
173 (jstring) (*env)->CallObjectMethod(e, exceptionClass.get(), classGetNameMethod));
174 if (classNameStr.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700175 (*env)->ExceptionClear(e);
176 result = "<error getting class name>";
177 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700178 }
Elliott Hughes87f62a82011-04-22 19:22:54 -0700179 const char* classNameChars = (*env)->GetStringUTFChars(e, classNameStr.get(), NULL);
180 if (classNameChars == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700181 (*env)->ExceptionClear(e);
182 result = "<error getting class name UTF-8>";
183 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700184 }
Brian Carlstromdd8af232012-05-13 23:56:07 -0700185 result += classNameChars;
186 (*env)->ReleaseStringUTFChars(e, classNameStr.get(), classNameChars);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700187
188 /* if the exception has a detail message, get that */
189 jmethodID getMessage =
190 (*env)->GetMethodID(e, exceptionClass.get(), "getMessage", "()Ljava/lang/String;");
191 scoped_local_ref<jstring> messageStr(env,
192 (jstring) (*env)->CallObjectMethod(e, exception, getMessage));
193 if (messageStr.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700194 return true;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700195 }
196
Brian Carlstromdd8af232012-05-13 23:56:07 -0700197 result += ": ";
198
Elliott Hughes87f62a82011-04-22 19:22:54 -0700199 const char* messageChars = (*env)->GetStringUTFChars(e, messageStr.get(), NULL);
200 if (messageChars != NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700201 result += messageChars;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700202 (*env)->ReleaseStringUTFChars(e, messageStr.get(), messageChars);
203 } else {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700204 result += "<error getting message>";
Elliott Hughes87f62a82011-04-22 19:22:54 -0700205 (*env)->ExceptionClear(e); // clear OOM
Elliott Hughes87f62a82011-04-22 19:22:54 -0700206 }
207
Brian Carlstromdd8af232012-05-13 23:56:07 -0700208 return true;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700209}
210
211/*
212 * Returns an exception (with stack trace) as a string.
213 */
Brian Carlstromdd8af232012-05-13 23:56:07 -0700214static bool getStackTrace(C_JNIEnv* env, jthrowable exception, std::string& result) {
Elliott Hughes87f62a82011-04-22 19:22:54 -0700215 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
216
217 scoped_local_ref<jclass> stringWriterClass(env, findClass(env, "java/io/StringWriter"));
218 if (stringWriterClass.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700219 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700220 }
221
222 jmethodID stringWriterCtor = (*env)->GetMethodID(e, stringWriterClass.get(), "<init>", "()V");
223 jmethodID stringWriterToStringMethod =
224 (*env)->GetMethodID(e, stringWriterClass.get(), "toString", "()Ljava/lang/String;");
225
226 scoped_local_ref<jclass> printWriterClass(env, findClass(env, "java/io/PrintWriter"));
227 if (printWriterClass.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700228 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700229 }
230
231 jmethodID printWriterCtor =
232 (*env)->GetMethodID(e, printWriterClass.get(), "<init>", "(Ljava/io/Writer;)V");
233
234 scoped_local_ref<jobject> stringWriter(env,
235 (*env)->NewObject(e, stringWriterClass.get(), stringWriterCtor));
236 if (stringWriter.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700237 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700238 }
239
Huanqi Chend47c3252014-06-24 13:31:31 +0200240 scoped_local_ref<jobject> printWriter(env,
241 (*env)->NewObject(e, printWriterClass.get(), printWriterCtor, stringWriter.get()));
242 if (printWriter.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700243 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700244 }
245
246 scoped_local_ref<jclass> exceptionClass(env, (*env)->GetObjectClass(e, exception)); // can't fail
247 jmethodID printStackTraceMethod =
248 (*env)->GetMethodID(e, exceptionClass.get(), "printStackTrace", "(Ljava/io/PrintWriter;)V");
Huanqi Chend47c3252014-06-24 13:31:31 +0200249 (*env)->CallVoidMethod(e, exception, printStackTraceMethod, printWriter.get());
Elliott Hughes87f62a82011-04-22 19:22:54 -0700250
251 if ((*env)->ExceptionCheck(e)) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700252 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700253 }
254
255 scoped_local_ref<jstring> messageStr(env,
256 (jstring) (*env)->CallObjectMethod(e, stringWriter.get(), stringWriterToStringMethod));
257 if (messageStr.get() == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700258 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700259 }
260
261 const char* utfChars = (*env)->GetStringUTFChars(e, messageStr.get(), NULL);
262 if (utfChars == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700263 return false;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700264 }
265
Brian Carlstromdd8af232012-05-13 23:56:07 -0700266 result = utfChars;
267
Elliott Hughes87f62a82011-04-22 19:22:54 -0700268 (*env)->ReleaseStringUTFChars(e, messageStr.get(), utfChars);
Brian Carlstromdd8af232012-05-13 23:56:07 -0700269 return true;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700270}
271
272extern "C" int jniThrowException(C_JNIEnv* env, const char* className, const char* msg) {
273 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
274
275 if ((*env)->ExceptionCheck(e)) {
276 /* TODO: consider creating the new exception with this as "cause" */
277 scoped_local_ref<jthrowable> exception(env, (*env)->ExceptionOccurred(e));
278 (*env)->ExceptionClear(e);
279
280 if (exception.get() != NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700281 std::string text;
282 getExceptionSummary(env, exception.get(), text);
283 ALOGW("Discarding pending exception (%s) to throw %s", text.c_str(), className);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700284 }
285 }
286
287 scoped_local_ref<jclass> exceptionClass(env, findClass(env, className));
288 if (exceptionClass.get() == NULL) {
Steve Block79a0d9c2012-01-06 19:16:58 +0000289 ALOGE("Unable to find exception class %s", className);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700290 /* ClassNotFoundException now pending */
291 return -1;
292 }
293
294 if ((*env)->ThrowNew(e, exceptionClass.get(), msg) != JNI_OK) {
Steve Block79a0d9c2012-01-06 19:16:58 +0000295 ALOGE("Failed throwing '%s' '%s'", className, msg);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700296 /* an exception, most likely OOM, will now be pending */
297 return -1;
298 }
299
300 return 0;
301}
302
303int jniThrowExceptionFmt(C_JNIEnv* env, const char* className, const char* fmt, va_list args) {
304 char msgBuf[512];
305 vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
306 return jniThrowException(env, className, msgBuf);
307}
308
309int jniThrowNullPointerException(C_JNIEnv* env, const char* msg) {
310 return jniThrowException(env, "java/lang/NullPointerException", msg);
311}
312
313int jniThrowRuntimeException(C_JNIEnv* env, const char* msg) {
314 return jniThrowException(env, "java/lang/RuntimeException", msg);
315}
316
317int jniThrowIOException(C_JNIEnv* env, int errnum) {
318 char buffer[80];
319 const char* message = jniStrError(errnum, buffer, sizeof(buffer));
320 return jniThrowException(env, "java/io/IOException", message);
321}
322
Elliott Hughesa4e4e742013-09-03 17:47:18 -0700323static std::string jniGetStackTrace(C_JNIEnv* env, jthrowable exception) {
Elliott Hughes87f62a82011-04-22 19:22:54 -0700324 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
325
Jeff Browne2b11e72012-04-10 20:34:39 -0700326 scoped_local_ref<jthrowable> currentException(env, (*env)->ExceptionOccurred(e));
Elliott Hughes87f62a82011-04-22 19:22:54 -0700327 if (exception == NULL) {
Jeff Browne2b11e72012-04-10 20:34:39 -0700328 exception = currentException.get();
Elliott Hughes87f62a82011-04-22 19:22:54 -0700329 if (exception == NULL) {
Brian Carlstromdd8af232012-05-13 23:56:07 -0700330 return "<no pending exception>";
Elliott Hughes87f62a82011-04-22 19:22:54 -0700331 }
Jeff Browne2b11e72012-04-10 20:34:39 -0700332 }
Elliott Hughes87f62a82011-04-22 19:22:54 -0700333
Jeff Browne2b11e72012-04-10 20:34:39 -0700334 if (currentException.get() != NULL) {
Elliott Hughes87f62a82011-04-22 19:22:54 -0700335 (*env)->ExceptionClear(e);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700336 }
337
Brian Carlstromdd8af232012-05-13 23:56:07 -0700338 std::string trace;
339 if (!getStackTrace(env, exception, trace)) {
Elliott Hughes87f62a82011-04-22 19:22:54 -0700340 (*env)->ExceptionClear(e);
Brian Carlstromdd8af232012-05-13 23:56:07 -0700341 getExceptionSummary(env, exception, trace);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700342 }
343
Elliott Hughes87f62a82011-04-22 19:22:54 -0700344 if (currentException.get() != NULL) {
Jeff Browne2b11e72012-04-10 20:34:39 -0700345 (*env)->Throw(e, currentException.get()); // rethrow
Elliott Hughes87f62a82011-04-22 19:22:54 -0700346 }
Brian Carlstromdd8af232012-05-13 23:56:07 -0700347
348 return trace;
Elliott Hughes87f62a82011-04-22 19:22:54 -0700349}
350
Elliott Hughesa4e4e742013-09-03 17:47:18 -0700351void jniLogException(C_JNIEnv* env, int priority, const char* tag, jthrowable exception) {
352 std::string trace(jniGetStackTrace(env, exception));
353 __android_log_write(priority, tag, trace.c_str());
354}
355
Alex Light48694f72018-10-31 14:50:54 -0700356// Note: glibc has a nonstandard strerror_r that returns char* rather than POSIX's int.
357// char *strerror_r(int errnum, char *buf, size_t n);
358//
359// Some versions of bionic support the glibc style call. Since the set of defines that determine
360// which version is used is byzantine in its complexity we will just use this C++ template hack to
361// select the correct jniStrError implementation based on the libc being used.
362namespace impl {
363
Alex Light48694f72018-10-31 14:50:54 -0700364using GNUStrError = char* (*)(int,char*,size_t);
365using POSIXStrError = int (*)(int,char*,size_t);
366
Alex Light48694f72018-10-31 14:50:54 -0700367inline const char* realJniStrError(GNUStrError func, int errnum, char* buf, size_t buflen) {
368 return func(errnum, buf, buflen);
369}
370
Alex Light48694f72018-10-31 14:50:54 -0700371inline const char* realJniStrError(POSIXStrError func, int errnum, char* buf, size_t buflen) {
372 int rc = func(errnum, buf, buflen);
Elliott Hughesd60512c2013-10-08 14:15:18 -0700373 if (rc != 0) {
374 // (POSIX only guarantees a value other than 0. The safest
Elliott Hughes87f62a82011-04-22 19:22:54 -0700375 // way to implement this function is to use C++ and overload on the
Elliott Hughesd60512c2013-10-08 14:15:18 -0700376 // type of strerror_r to accurately distinguish GNU from POSIX.)
Elliott Hughes87f62a82011-04-22 19:22:54 -0700377 snprintf(buf, buflen, "errno %d", errnum);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700378 }
Elliott Hughesd60512c2013-10-08 14:15:18 -0700379 return buf;
Alex Light48694f72018-10-31 14:50:54 -0700380}
Elliott Hughes71cb8412018-11-09 11:10:40 -0800381
Alex Light48694f72018-10-31 14:50:54 -0700382} // namespace impl
383
384const char* jniStrError(int errnum, char* buf, size_t buflen) {
Elliott Hughes71cb8412018-11-09 11:10:40 -0800385 // The magic of C++ overloading selects the correct implementation based on the declared type of
Alex Light48694f72018-10-31 14:50:54 -0700386 // strerror_r. The inline will ensure that we don't have any indirect calls.
387 return impl::realJniStrError(strerror_r, errnum, buf, buflen);
Elliott Hughes87f62a82011-04-22 19:22:54 -0700388}
389
Elliott Hughes87f62a82011-04-22 19:22:54 -0700390jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd) {
391 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
Logan Chien63e49172016-06-08 11:33:36 +0800392 if (fileDescriptorInitMethod == nullptr) {
393 InitFieldsAndMethods(e);
394 }
395 jobject fileDescriptor = (*env)->NewObject(e, JniConstants::fileDescriptorClass,
396 fileDescriptorInitMethod);
Narayan Kamathe29dbf52013-10-31 17:17:10 +0000397 // NOTE: NewObject ensures that an OutOfMemoryError will be seen by the Java
398 // caller if the alloc fails, so we just return NULL when that happens.
399 if (fileDescriptor != NULL) {
400 jniSetFileDescriptorOfFD(env, fileDescriptor, fd);
401 }
Elliott Hughes87f62a82011-04-22 19:22:54 -0700402 return fileDescriptor;
403}
404
405int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor) {
406 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
Logan Chien63e49172016-06-08 11:33:36 +0800407 if (fileDescriptorDescriptorField == nullptr) {
408 InitFieldsAndMethods(e);
409 }
Narayan Kamathe29dbf52013-10-31 17:17:10 +0000410 if (fileDescriptor != NULL) {
Logan Chien63e49172016-06-08 11:33:36 +0800411 return (*env)->GetIntField(e, fileDescriptor,
412 fileDescriptorDescriptorField);
Narayan Kamathe29dbf52013-10-31 17:17:10 +0000413 } else {
414 return -1;
415 }
Elliott Hughes87f62a82011-04-22 19:22:54 -0700416}
417
418void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor, int value) {
419 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
Logan Chien63e49172016-06-08 11:33:36 +0800420 if (fileDescriptorDescriptorField == nullptr) {
421 InitFieldsAndMethods(e);
422 }
Pete Bentley0505b222018-07-20 18:18:44 +0100423
424 if (fileDescriptor == nullptr) {
425 jniThrowNullPointerException(e, "null FileDescriptor");
426 } else {
427 e->SetIntField(fileDescriptor, fileDescriptorDescriptorField, value);
428 }
Elliott Hughes87f62a82011-04-22 19:22:54 -0700429}
430
Josh Gao669bc9e2018-06-25 16:22:11 -0700431jlong jniGetOwnerIdFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor) {
432 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
433 if (fileDescriptorOwnerIdField == nullptr) {
434 InitFieldsAndMethods(e);
435 }
436 return (*env)->GetLongField(e, fileDescriptor, fileDescriptorOwnerIdField);
437}
438
Jeff Browndc176c52013-04-02 18:09:29 -0700439jobject jniGetReferent(C_JNIEnv* env, jobject ref) {
440 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
Logan Chien63e49172016-06-08 11:33:36 +0800441 if (referenceGetMethod == nullptr) {
442 InitFieldsAndMethods(e);
443 }
444 return (*env)->CallObjectMethod(e, ref, referenceGetMethod);
Jeff Browndc176c52013-04-02 18:09:29 -0700445}
446
Fredrik Roubert2e312802017-07-04 21:53:08 +0200447jstring jniCreateString(C_JNIEnv* env, const jchar* unicodeChars, jsize len) {
448 JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
449 return (*env)->NewString(e, unicodeChars, len);
450}