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 |