OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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> | |
8 | |
7 #include "base/android/scoped_java_ref.h" | 9 #include "base/android/scoped_java_ref.h" |
10 #include "base/atomicops.h" | |
11 #include "base/lazy_instance.h" | |
8 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/threading/platform_thread.h" | |
9 | 14 |
10 namespace { | 15 namespace { |
11 JavaVM* g_jvm = 0; | 16 JavaVM* g_jvm = 0; |
12 jobject g_application_context = NULL; | 17 jobject g_application_context = NULL; |
18 | |
19 typedef std::map<std::string, jmethodID> MethodIDMap; | |
20 base::LazyInstance<MethodIDMap> g_method_id_map = LAZY_INSTANCE_INITIALIZER; | |
joth
2011/12/02 14:10:13
fwiw, I think we're happy to use LeakyLazyInstance
| |
21 const base::subtle::AtomicWord kUnlocked = 0; | |
22 const base::subtle::AtomicWord kLocked = 1; | |
23 base::subtle::AtomicWord g_method_id_map_lock = kUnlocked; | |
13 } | 24 } |
14 | 25 |
15 namespace base { | 26 namespace base { |
16 namespace android { | 27 namespace android { |
17 | 28 |
18 JNIEnv* AttachCurrentThread() { | 29 JNIEnv* AttachCurrentThread() { |
19 if (!g_jvm) | 30 if (!g_jvm) |
20 return NULL; | 31 return NULL; |
21 | 32 |
22 JNIEnv* env = NULL; | 33 JNIEnv* env = NULL; |
(...skipping 17 matching lines...) Expand all Loading... | |
40 void InitApplicationContext(jobject context) { | 51 void InitApplicationContext(jobject context) { |
41 DCHECK(!g_application_context); | 52 DCHECK(!g_application_context); |
42 g_application_context = context; | 53 g_application_context = context; |
43 } | 54 } |
44 | 55 |
45 jobject GetApplicationContext() { | 56 jobject GetApplicationContext() { |
46 DCHECK(g_application_context); | 57 DCHECK(g_application_context); |
47 return g_application_context; | 58 return g_application_context; |
48 } | 59 } |
49 | 60 |
50 MethodID::MethodID(JNIEnv* env, const char* class_name, const char* method, | 61 jmethodID GetMethodIDFromClassName(JNIEnv* env, |
51 const char* jni_signature) { | 62 const char* class_name, |
63 const char* method, | |
64 const char* jni_signature) { | |
65 DCHECK_EQ(std::string::npos, std::string(class_name).find('!')); | |
66 DCHECK_EQ(std::string::npos, std::string(method).find('!')); | |
67 DCHECK_EQ(std::string::npos, std::string(jni_signature).find('!')); | |
68 std::string key(class_name); | |
69 key += '!'; | |
70 key += method; | |
71 key += '!'; | |
72 key += jni_signature; | |
joth
2011/12/02 14:10:13
shame we have to do this everytime we lookup a sym
| |
73 | |
74 MethodIDMap* map = g_method_id_map.Pointer(); | |
75 bool found = false; | |
76 | |
77 while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, | |
78 kUnlocked, | |
79 kLocked) != kUnlocked) { | |
80 base::PlatformThread::YieldCurrentThread(); | |
81 } | |
joth
2011/12/02 14:10:13
looks sufficiently fun to benefit from having some
| |
82 MethodIDMap::const_iterator iter = map->find(key); | |
83 if (iter != map->end()) { | |
84 found = true; | |
85 } | |
86 base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); | |
87 | |
88 // Addition to the map does not invalidate this iterator. | |
89 if (found) { | |
90 return iter->second; | |
91 } | |
92 | |
52 ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name)); | 93 ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name)); |
53 id_ = GetMethodID(env, clazz.obj(), method, jni_signature); | 94 jmethodID id = GetMethodID(env, clazz.obj(), method, jni_signature); |
95 | |
96 while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, | |
97 kUnlocked, | |
98 kLocked) != kUnlocked) { | |
99 base::PlatformThread::YieldCurrentThread(); | |
100 } | |
101 // Another thread may have populated the map already. | |
102 iter = map->find(key); | |
103 if (iter == map->end()) { | |
joth
2011/12/02 14:10:13
nit: rather than walk the tree twice here, you can
| |
104 map->insert(std::make_pair(key, id)); | |
105 } else { | |
106 DCHECK_EQ(id, iter->second); | |
107 } | |
108 base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); | |
109 | |
110 return id; | |
54 } | 111 } |
55 | 112 |
56 jmethodID GetMethodID(JNIEnv* env, | 113 jmethodID GetMethodID(JNIEnv* env, |
57 jclass clazz, | 114 jclass clazz, |
58 const char* const method, | 115 const char* const method, |
59 const char* const jni_signature) { | 116 const char* const jni_signature) { |
60 jmethodID id = env->GetMethodID(clazz, method, jni_signature); | 117 jmethodID id = env->GetMethodID(clazz, method, jni_signature); |
61 DCHECK(id) << method; | 118 DCHECK(id) << method; |
62 CheckException(env); | 119 CheckException(env); |
63 return id; | 120 return id; |
(...skipping 22 matching lines...) Expand all Loading... | |
86 bool CheckException(JNIEnv* env) { | 143 bool CheckException(JNIEnv* env) { |
87 if (env->ExceptionCheck() == JNI_FALSE) | 144 if (env->ExceptionCheck() == JNI_FALSE) |
88 return false; | 145 return false; |
89 env->ExceptionDescribe(); | 146 env->ExceptionDescribe(); |
90 env->ExceptionClear(); | 147 env->ExceptionClear(); |
91 return true; | 148 return true; |
92 } | 149 } |
93 | 150 |
94 } // namespace android | 151 } // namespace android |
95 } // namespace base | 152 } // namespace base |
OLD | NEW |