OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/android/jni_android.h" | 5 #include "base/android/jni_android.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/android/build_info.h" | 9 #include "base/android/build_info.h" |
10 #include "base/android/jni_string.h" | 10 #include "base/android/jni_string.h" |
11 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/threading/platform_thread.h" | |
14 | 13 |
15 namespace { | 14 namespace { |
16 using base::android::GetClass; | 15 using base::android::GetClass; |
17 using base::android::MethodID; | 16 using base::android::MethodID; |
18 using base::android::ScopedJavaLocalRef; | 17 using base::android::ScopedJavaLocalRef; |
19 | 18 |
20 struct MethodIdentifier { | |
21 const char* class_name; | |
22 const char* method; | |
23 const char* jni_signature; | |
24 | |
25 bool operator<(const MethodIdentifier& other) const { | |
26 int r = strcmp(class_name, other.class_name); | |
27 if (r < 0) { | |
28 return true; | |
29 } else if (r > 0) { | |
30 return false; | |
31 } | |
32 | |
33 r = strcmp(method, other.method); | |
34 if (r < 0) { | |
35 return true; | |
36 } else if (r > 0) { | |
37 return false; | |
38 } | |
39 | |
40 return strcmp(jni_signature, other.jni_signature) < 0; | |
41 } | |
42 }; | |
43 | |
44 typedef std::map<MethodIdentifier, jmethodID> MethodIDMap; | |
45 | |
46 const base::subtle::AtomicWord kUnlocked = 0; | |
47 const base::subtle::AtomicWord kLocked = 1; | |
48 base::subtle::AtomicWord g_method_id_map_lock = kUnlocked; | |
49 JavaVM* g_jvm = NULL; | 19 JavaVM* g_jvm = NULL; |
50 // Leak the global app context, as it is used from a non-joinable worker thread | 20 // Leak the global app context, as it is used from a non-joinable worker thread |
51 // that may still be running at shutdown. There is no harm in doing this. | 21 // that may still be running at shutdown. There is no harm in doing this. |
52 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky | 22 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky |
53 g_application_context = LAZY_INSTANCE_INITIALIZER; | 23 g_application_context = LAZY_INSTANCE_INITIALIZER; |
54 base::LazyInstance<MethodIDMap> g_method_id_map = LAZY_INSTANCE_INITIALIZER; | |
55 | 24 |
56 std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) { | 25 std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) { |
57 ScopedJavaLocalRef<jclass> throwable_clazz = | 26 ScopedJavaLocalRef<jclass> throwable_clazz = |
58 GetClass(env, "java/lang/Throwable"); | 27 GetClass(env, "java/lang/Throwable"); |
59 jmethodID throwable_printstacktrace = | 28 jmethodID throwable_printstacktrace = |
60 MethodID::Get<MethodID::TYPE_INSTANCE>( | 29 MethodID::Get<MethodID::TYPE_INSTANCE>( |
61 env, throwable_clazz.obj(), "printStackTrace", | 30 env, throwable_clazz.obj(), "printStackTrace", |
62 "(Ljava/io/PrintStream;)V"); | 31 "(Ljava/io/PrintStream;)V"); |
63 | 32 |
64 // Create an instance of ByteArrayOutputStream. | 33 // Create an instance of ByteArrayOutputStream. |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 DCHECK(!g_application_context.Get().is_null()); | 106 DCHECK(!g_application_context.Get().is_null()); |
138 return g_application_context.Get().obj(); | 107 return g_application_context.Get().obj(); |
139 } | 108 } |
140 | 109 |
141 ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) { | 110 ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) { |
142 jclass clazz = env->FindClass(class_name); | 111 jclass clazz = env->FindClass(class_name); |
143 CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name; | 112 CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name; |
144 return ScopedJavaLocalRef<jclass>(env, clazz); | 113 return ScopedJavaLocalRef<jclass>(env, clazz); |
145 } | 114 } |
146 | 115 |
147 bool HasClass(JNIEnv* env, const char* class_name) { | |
148 ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name)); | |
149 if (!clazz.obj()) { | |
150 ClearException(env); | |
151 return false; | |
152 } | |
153 bool error = ClearException(env); | |
154 DCHECK(!error); | |
155 return true; | |
156 } | |
157 | |
158 template<MethodID::Type type> | 116 template<MethodID::Type type> |
159 jmethodID MethodID::Get(JNIEnv* env, | 117 jmethodID MethodID::Get(JNIEnv* env, |
160 jclass clazz, | 118 jclass clazz, |
161 const char* method_name, | 119 const char* method_name, |
162 const char* jni_signature) { | 120 const char* jni_signature) { |
163 jmethodID id = type == TYPE_STATIC ? | 121 jmethodID id = type == TYPE_STATIC ? |
164 env->GetStaticMethodID(clazz, method_name, jni_signature) : | 122 env->GetStaticMethodID(clazz, method_name, jni_signature) : |
165 env->GetMethodID(clazz, method_name, jni_signature); | 123 env->GetMethodID(clazz, method_name, jni_signature); |
166 CHECK(base::android::ClearException(env) || id) << | 124 CHECK(base::android::ClearException(env) || id) << |
167 "Failed to find " << | 125 "Failed to find " << |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 const char* jni_signature); | 158 const char* jni_signature); |
201 | 159 |
202 template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>( | 160 template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>( |
203 JNIEnv* env, jclass clazz, const char* method_name, | 161 JNIEnv* env, jclass clazz, const char* method_name, |
204 const char* jni_signature, base::subtle::AtomicWord* atomic_method_id); | 162 const char* jni_signature, base::subtle::AtomicWord* atomic_method_id); |
205 | 163 |
206 template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>( | 164 template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>( |
207 JNIEnv* env, jclass clazz, const char* method_name, | 165 JNIEnv* env, jclass clazz, const char* method_name, |
208 const char* jni_signature, base::subtle::AtomicWord* atomic_method_id); | 166 const char* jni_signature, base::subtle::AtomicWord* atomic_method_id); |
209 | 167 |
210 jfieldID GetFieldID(JNIEnv* env, | |
211 const JavaRef<jclass>& clazz, | |
212 const char* field_name, | |
213 const char* jni_signature) { | |
214 jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature); | |
215 CHECK(!ClearException(env) && field_id) << "Failed to find field " << | |
216 field_name << " " << jni_signature; | |
217 return field_id; | |
218 } | |
219 | |
220 bool HasField(JNIEnv* env, | |
221 const JavaRef<jclass>& clazz, | |
222 const char* field_name, | |
223 const char* jni_signature) { | |
224 jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature); | |
225 if (!field_id) { | |
226 ClearException(env); | |
227 return false; | |
228 } | |
229 bool error = ClearException(env); | |
230 DCHECK(!error); | |
231 return true; | |
232 } | |
233 | |
234 jfieldID GetStaticFieldID(JNIEnv* env, | |
235 const JavaRef<jclass>& clazz, | |
236 const char* field_name, | |
237 const char* jni_signature) { | |
238 jfieldID field_id = | |
239 env->GetStaticFieldID(clazz.obj(), field_name, jni_signature); | |
240 CHECK(!ClearException(env) && field_id) << "Failed to find static field " << | |
241 field_name << " " << jni_signature; | |
242 return field_id; | |
243 } | |
244 | |
245 jmethodID GetMethodIDFromClassName(JNIEnv* env, | |
246 const char* class_name, | |
247 const char* method, | |
248 const char* jni_signature) { | |
249 MethodIdentifier key; | |
250 key.class_name = class_name; | |
251 key.method = method; | |
252 key.jni_signature = jni_signature; | |
253 | |
254 MethodIDMap* map = g_method_id_map.Pointer(); | |
255 bool found = false; | |
256 | |
257 while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, | |
258 kUnlocked, | |
259 kLocked) != kUnlocked) { | |
260 base::PlatformThread::YieldCurrentThread(); | |
261 } | |
262 MethodIDMap::const_iterator iter = map->find(key); | |
263 if (iter != map->end()) { | |
264 found = true; | |
265 } | |
266 base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); | |
267 | |
268 // Addition to the map does not invalidate this iterator. | |
269 if (found) { | |
270 return iter->second; | |
271 } | |
272 | |
273 ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name)); | |
274 jmethodID id = MethodID::Get<MethodID::TYPE_INSTANCE>( | |
275 env, clazz.obj(), method, jni_signature); | |
276 | |
277 while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, | |
278 kUnlocked, | |
279 kLocked) != kUnlocked) { | |
280 base::PlatformThread::YieldCurrentThread(); | |
281 } | |
282 // Another thread may have populated the map already. | |
283 std::pair<MethodIDMap::const_iterator, bool> result = | |
284 map->insert(std::make_pair(key, id)); | |
285 DCHECK_EQ(id, result.first->second); | |
286 base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); | |
287 | |
288 return id; | |
289 } | |
290 | |
291 bool HasException(JNIEnv* env) { | 168 bool HasException(JNIEnv* env) { |
292 return env->ExceptionCheck() != JNI_FALSE; | 169 return env->ExceptionCheck() != JNI_FALSE; |
293 } | 170 } |
294 | 171 |
295 bool ClearException(JNIEnv* env) { | 172 bool ClearException(JNIEnv* env) { |
296 if (!HasException(env)) | 173 if (!HasException(env)) |
297 return false; | 174 return false; |
298 env->ExceptionDescribe(); | 175 env->ExceptionDescribe(); |
299 env->ExceptionClear(); | 176 env->ExceptionClear(); |
300 return true; | 177 return true; |
(...skipping 17 matching lines...) Expand all Loading... |
318 // RVO should avoid any extra copies of the exception string. | 195 // RVO should avoid any extra copies of the exception string. |
319 base::android::BuildInfo::GetInstance()->set_java_exception_info( | 196 base::android::BuildInfo::GetInstance()->set_java_exception_info( |
320 GetJavaExceptionInfo(env, java_throwable)); | 197 GetJavaExceptionInfo(env, java_throwable)); |
321 | 198 |
322 // Now, feel good about it and die. | 199 // Now, feel good about it and die. |
323 CHECK(false); | 200 CHECK(false); |
324 } | 201 } |
325 | 202 |
326 } // namespace android | 203 } // namespace android |
327 } // namespace base | 204 } // namespace base |
OLD | NEW |