| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 #include "webrtc/sdk/android/src/jni/jni_helpers.h" | 10 #include "webrtc/sdk/android/src/jni/jni_helpers.h" |
| 11 | 11 |
| 12 #include "webrtc/sdk/android/src/jni/classreferenceholder.h" | 12 #include "webrtc/sdk/android/src/jni/classreferenceholder.h" |
| 13 | 13 |
| 14 #include <asm/unistd.h> | 14 #include <asm/unistd.h> |
| 15 #include <sys/prctl.h> | 15 #include <sys/prctl.h> |
| 16 #include <sys/syscall.h> | 16 #include <sys/syscall.h> |
| 17 #include <unistd.h> | 17 #include <unistd.h> |
| 18 #include <vector> | 18 #include <vector> |
| 19 | 19 |
| 20 namespace webrtc_jni { | 20 namespace webrtc_jni { |
| 21 | 21 |
| 22 static JavaVM* g_jvm = nullptr; | 22 static JavaVM* g_jvm = nullptr; |
| 23 | 23 |
| 24 static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT; | 24 static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT; |
| 25 | 25 |
| 26 // Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by | 26 // Key for per-thread JNIEnv* data. Non-null in threads attached to |g_jvm| by |
| 27 // AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that | 27 // AttachCurrentThreadIfNeeded(), null in unattached threads and threads that |
| 28 // were attached by the JVM because of a Java->native call. | 28 // were attached by the JVM because of a Java->native call. |
| 29 static pthread_key_t g_jni_ptr; | 29 static pthread_key_t g_jni_ptr; |
| 30 | 30 |
| 31 JavaVM *GetJVM() { | 31 JavaVM *GetJVM() { |
| 32 RTC_CHECK(g_jvm) << "JNI_OnLoad failed to run?"; | 32 RTC_CHECK(g_jvm) << "JNI_OnLoad failed to run?"; |
| 33 return g_jvm; | 33 return g_jvm; |
| 34 } | 34 } |
| 35 | 35 |
| 36 // Return a |JNIEnv*| usable on this thread or NULL if this thread is detached. | 36 // Return a |JNIEnv*| usable on this thread or null if this thread is detached. |
| 37 JNIEnv* GetEnv() { | 37 JNIEnv* GetEnv() { |
| 38 void* env = nullptr; | 38 void* env = nullptr; |
| 39 jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6); | 39 jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6); |
| 40 RTC_CHECK(((env != nullptr) && (status == JNI_OK)) || | 40 RTC_CHECK(((env != nullptr) && (status == JNI_OK)) || |
| 41 ((env == nullptr) && (status == JNI_EDETACHED))) | 41 ((env == nullptr) && (status == JNI_EDETACHED))) |
| 42 << "Unexpected GetEnv return: " << status << ":" << env; | 42 << "Unexpected GetEnv return: " << status << ":" << env; |
| 43 return reinterpret_cast<JNIEnv*>(env); | 43 return reinterpret_cast<JNIEnv*>(env); |
| 44 } | 44 } |
| 45 | 45 |
| 46 static void ThreadDestructor(void* prev_jni_ptr) { | 46 static void ThreadDestructor(void* prev_jni_ptr) { |
| 47 // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning | 47 // This function only runs on threads where |g_jni_ptr| is non-null, meaning |
| 48 // we were responsible for originally attaching the thread, so are responsible | 48 // we were responsible for originally attaching the thread, so are responsible |
| 49 // for detaching it now. However, because some JVM implementations (notably | 49 // for detaching it now. However, because some JVM implementations (notably |
| 50 // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism, | 50 // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism, |
| 51 // the JVMs accounting info for this thread may already be wiped out by the | 51 // the JVMs accounting info for this thread may already be wiped out by the |
| 52 // time this is called. Thus it may appear we are already detached even though | 52 // time this is called. Thus it may appear we are already detached even though |
| 53 // it was our responsibility to detach! Oh well. | 53 // it was our responsibility to detach! Oh well. |
| 54 if (!GetEnv()) | 54 if (!GetEnv()) |
| 55 return; | 55 return; |
| 56 | 56 |
| 57 RTC_CHECK(GetEnv() == prev_jni_ptr) | 57 RTC_CHECK(GetEnv() == prev_jni_ptr) |
| 58 << "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv(); | 58 << "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv(); |
| 59 jint status = g_jvm->DetachCurrentThread(); | 59 jint status = g_jvm->DetachCurrentThread(); |
| 60 RTC_CHECK(status == JNI_OK) << "Failed to detach thread: " << status; | 60 RTC_CHECK(status == JNI_OK) << "Failed to detach thread: " << status; |
| 61 RTC_CHECK(!GetEnv()) << "Detaching was a successful no-op???"; | 61 RTC_CHECK(!GetEnv()) << "Detaching was a successful no-op???"; |
| 62 } | 62 } |
| 63 | 63 |
| 64 static void CreateJNIPtrKey() { | 64 static void CreateJNIPtrKey() { |
| 65 RTC_CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor)) | 65 RTC_CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor)) |
| 66 << "pthread_key_create"; | 66 << "pthread_key_create"; |
| 67 } | 67 } |
| 68 | 68 |
| 69 jint InitGlobalJniVariables(JavaVM *jvm) { | 69 jint InitGlobalJniVariables(JavaVM *jvm) { |
| 70 RTC_CHECK(!g_jvm) << "InitGlobalJniVariables!"; | 70 RTC_CHECK(!g_jvm) << "InitGlobalJniVariables!"; |
| 71 g_jvm = jvm; | 71 g_jvm = jvm; |
| 72 RTC_CHECK(g_jvm) << "InitGlobalJniVariables handed NULL?"; | 72 RTC_CHECK(g_jvm) << "InitGlobalJniVariables handed null?"; |
| 73 | 73 |
| 74 RTC_CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once"; | 74 RTC_CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once"; |
| 75 | 75 |
| 76 JNIEnv* jni = nullptr; | 76 JNIEnv* jni = nullptr; |
| 77 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK) | 77 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK) |
| 78 return -1; | 78 return -1; |
| 79 | 79 |
| 80 return JNI_VERSION_1_6; | 80 return JNI_VERSION_1_6; |
| 81 } | 81 } |
| 82 | 82 |
| 83 // Return thread ID as a string. | 83 // Return thread ID as a string. |
| 84 static std::string GetThreadId() { | 84 static std::string GetThreadId() { |
| 85 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL. | 85 char buf[21]; // Big enough to hold a kuint64max plus terminating nullptr. |
| 86 RTC_CHECK_LT(snprintf(buf, sizeof(buf), "%ld", | 86 RTC_CHECK_LT(snprintf(buf, sizeof(buf), "%ld", |
| 87 static_cast<long>(syscall(__NR_gettid))), | 87 static_cast<long>(syscall(__NR_gettid))), |
| 88 sizeof(buf)) | 88 sizeof(buf)) |
| 89 << "Thread id is bigger than uint64??"; | 89 << "Thread id is bigger than uint64??"; |
| 90 return std::string(buf); | 90 return std::string(buf); |
| 91 } | 91 } |
| 92 | 92 |
| 93 // Return the current thread's name. | 93 // Return the current thread's name. |
| 94 static std::string GetThreadName() { | 94 static std::string GetThreadName() { |
| 95 char name[17] = {0}; | 95 char name[17] = {0}; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 112 args.name = &name[0]; | 112 args.name = &name[0]; |
| 113 args.group = nullptr; | 113 args.group = nullptr; |
| 114 // Deal with difference in signatures between Oracle's jni.h and Android's. | 114 // Deal with difference in signatures between Oracle's jni.h and Android's. |
| 115 #ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec! | 115 #ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec! |
| 116 void* env = nullptr; | 116 void* env = nullptr; |
| 117 #else | 117 #else |
| 118 JNIEnv* env = nullptr; | 118 JNIEnv* env = nullptr; |
| 119 #endif | 119 #endif |
| 120 RTC_CHECK(!g_jvm->AttachCurrentThread(&env, &args)) | 120 RTC_CHECK(!g_jvm->AttachCurrentThread(&env, &args)) |
| 121 << "Failed to attach thread"; | 121 << "Failed to attach thread"; |
| 122 RTC_CHECK(env) << "AttachCurrentThread handed back NULL!"; | 122 RTC_CHECK(env) << "AttachCurrentThread handed back null!"; |
| 123 jni = reinterpret_cast<JNIEnv*>(env); | 123 jni = reinterpret_cast<JNIEnv*>(env); |
| 124 RTC_CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific"; | 124 RTC_CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific"; |
| 125 return jni; | 125 return jni; |
| 126 } | 126 } |
| 127 | 127 |
| 128 // Return a |jlong| that will correctly convert back to |ptr|. This is needed | 128 // Return a |jlong| that will correctly convert back to |ptr|. This is needed |
| 129 // because the alternative (of silently passing a 32-bit pointer to a vararg | 129 // because the alternative (of silently passing a 32-bit pointer to a vararg |
| 130 // function expecting a 64-bit param) picks up garbage in the high 32 bits. | 130 // function expecting a 64-bit param) picks up garbage in the high 32 bits. |
| 131 jlong jlongFromPointer(void* ptr) { | 131 jlong jlongFromPointer(void* ptr) { |
| 132 static_assert(sizeof(intptr_t) <= sizeof(jlong), | 132 static_assert(sizeof(intptr_t) <= sizeof(jlong), |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 const char* signature) { | 173 const char* signature) { |
| 174 jfieldID f = jni->GetStaticFieldID(c, name, signature); | 174 jfieldID f = jni->GetStaticFieldID(c, name, signature); |
| 175 CHECK_EXCEPTION(jni) << "error during GetStaticFieldID"; | 175 CHECK_EXCEPTION(jni) << "error during GetStaticFieldID"; |
| 176 RTC_CHECK(f) << name << ", " << signature; | 176 RTC_CHECK(f) << name << ", " << signature; |
| 177 return f; | 177 return f; |
| 178 } | 178 } |
| 179 | 179 |
| 180 jclass GetObjectClass(JNIEnv* jni, jobject object) { | 180 jclass GetObjectClass(JNIEnv* jni, jobject object) { |
| 181 jclass c = jni->GetObjectClass(object); | 181 jclass c = jni->GetObjectClass(object); |
| 182 CHECK_EXCEPTION(jni) << "error during GetObjectClass"; | 182 CHECK_EXCEPTION(jni) << "error during GetObjectClass"; |
| 183 RTC_CHECK(c) << "GetObjectClass returned NULL"; | 183 RTC_CHECK(c) << "GetObjectClass returned null"; |
| 184 return c; | 184 return c; |
| 185 } | 185 } |
| 186 | 186 |
| 187 jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) { | 187 jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) { |
| 188 jobject o = jni->GetObjectField(object, id); | 188 jobject o = jni->GetObjectField(object, id); |
| 189 CHECK_EXCEPTION(jni) << "error during GetObjectField"; | 189 CHECK_EXCEPTION(jni) << "error during GetObjectField"; |
| 190 RTC_CHECK(!IsNull(jni, o)) << "GetObjectField returned NULL"; | 190 RTC_CHECK(!IsNull(jni, o)) << "GetObjectField returned null"; |
| 191 return o; | 191 return o; |
| 192 } | 192 } |
| 193 | 193 |
| 194 jobject GetStaticObjectField(JNIEnv* jni, jclass c, jfieldID id) { | 194 jobject GetStaticObjectField(JNIEnv* jni, jclass c, jfieldID id) { |
| 195 jobject o = jni->GetStaticObjectField(c, id); | 195 jobject o = jni->GetStaticObjectField(c, id); |
| 196 CHECK_EXCEPTION(jni) << "error during GetStaticObjectField"; | 196 CHECK_EXCEPTION(jni) << "error during GetStaticObjectField"; |
| 197 RTC_CHECK(!IsNull(jni, o)) << "GetStaticObjectField returned NULL"; | 197 RTC_CHECK(!IsNull(jni, o)) << "GetStaticObjectField returned null"; |
| 198 return o; | 198 return o; |
| 199 } | 199 } |
| 200 | 200 |
| 201 jobject GetNullableObjectField(JNIEnv* jni, jobject object, jfieldID id) { | 201 jobject GetNullableObjectField(JNIEnv* jni, jobject object, jfieldID id) { |
| 202 jobject o = jni->GetObjectField(object, id); | 202 jobject o = jni->GetObjectField(object, id); |
| 203 CHECK_EXCEPTION(jni) << "error during GetObjectField"; | 203 CHECK_EXCEPTION(jni) << "error during GetObjectField"; |
| 204 return o; | 204 return o; |
| 205 } | 205 } |
| 206 | 206 |
| 207 jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) { | 207 jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) { |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 RTC_CHECK(!AtEnd()); | 371 RTC_CHECK(!AtEnd()); |
| 372 return value_; | 372 return value_; |
| 373 } | 373 } |
| 374 | 374 |
| 375 bool Iterable::Iterator::AtEnd() const { | 375 bool Iterable::Iterator::AtEnd() const { |
| 376 RTC_CHECK(thread_checker_.CalledOnValidThread()); | 376 RTC_CHECK(thread_checker_.CalledOnValidThread()); |
| 377 return jni_ == nullptr || IsNull(jni_, iterator_); | 377 return jni_ == nullptr || IsNull(jni_, iterator_); |
| 378 } | 378 } |
| 379 | 379 |
| 380 } // namespace webrtc_jni | 380 } // namespace webrtc_jni |
| OLD | NEW |