Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(414)

Side by Side Diff: base/android/jni_android.cc

Issue 11038015: Android: lazy initialization for method id. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Moves to MethodID Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/atomicops.h"
12 #include "base/lazy_instance.h" 11 #include "base/lazy_instance.h"
13 #include "base/logging.h" 12 #include "base/logging.h"
14 #include "base/threading/platform_thread.h" 13 #include "base/threading/platform_thread.h"
15 14
16 namespace { 15 namespace {
17 using base::android::GetClass; 16 using base::android::GetClass;
18 using base::android::GetMethodID; 17 using base::android::MethodID;
19 using base::android::ScopedJavaLocalRef; 18 using base::android::ScopedJavaLocalRef;
20 19
21 struct MethodIdentifier { 20 struct MethodIdentifier {
22 const char* class_name; 21 const char* class_name;
23 const char* method; 22 const char* method;
24 const char* jni_signature; 23 const char* jni_signature;
25 24
26 bool operator<(const MethodIdentifier& other) const { 25 bool operator<(const MethodIdentifier& other) const {
27 int r = strcmp(class_name, other.class_name); 26 int r = strcmp(class_name, other.class_name);
28 if (r < 0) { 27 if (r < 0) {
(...skipping 23 matching lines...) Expand all
52 // that may still be running at shutdown. There is no harm in doing this. 51 // that may still be running at shutdown. There is no harm in doing this.
53 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky 52 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
54 g_application_context = LAZY_INSTANCE_INITIALIZER; 53 g_application_context = LAZY_INSTANCE_INITIALIZER;
55 base::LazyInstance<MethodIDMap>::Leaky 54 base::LazyInstance<MethodIDMap>::Leaky
56 g_method_id_map = LAZY_INSTANCE_INITIALIZER; 55 g_method_id_map = LAZY_INSTANCE_INITIALIZER;
57 56
58 std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) { 57 std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
59 ScopedJavaLocalRef<jclass> throwable_clazz = 58 ScopedJavaLocalRef<jclass> throwable_clazz =
60 GetClass(env, "java/lang/Throwable"); 59 GetClass(env, "java/lang/Throwable");
61 jmethodID throwable_printstacktrace = 60 jmethodID throwable_printstacktrace =
62 GetMethodID(env, throwable_clazz, "printStackTrace", 61 MethodID::Get<MethodID::METHODTYPE_NORMAL, MethodID::EXCEPTIONCHECK_YES>(
63 "(Ljava/io/PrintStream;)V"); 62 env, throwable_clazz.obj(), "printStackTrace",
63 "(Ljava/io/PrintStream;)V");
64 64
65 // Create an instance of ByteArrayOutputStream. 65 // Create an instance of ByteArrayOutputStream.
66 ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz = 66 ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz =
67 GetClass(env, "java/io/ByteArrayOutputStream"); 67 GetClass(env, "java/io/ByteArrayOutputStream");
68 jmethodID bytearray_output_stream_constructor = 68 jmethodID bytearray_output_stream_constructor =
69 GetMethodID(env, bytearray_output_stream_clazz, "<init>", "()V"); 69 MethodID::Get<MethodID::METHODTYPE_NORMAL, MethodID::EXCEPTIONCHECK_YES>(
70 env, bytearray_output_stream_clazz.obj(), "<init>", "()V");
70 jmethodID bytearray_output_stream_tostring = 71 jmethodID bytearray_output_stream_tostring =
71 GetMethodID(env, bytearray_output_stream_clazz, "toString", 72 MethodID::Get<MethodID::METHODTYPE_NORMAL, MethodID::EXCEPTIONCHECK_YES>(
72 "()Ljava/lang/String;"); 73 env, bytearray_output_stream_clazz.obj(), "toString",
74 "()Ljava/lang/String;");
73 ScopedJavaLocalRef<jobject> bytearray_output_stream(env, 75 ScopedJavaLocalRef<jobject> bytearray_output_stream(env,
74 env->NewObject(bytearray_output_stream_clazz.obj(), 76 env->NewObject(bytearray_output_stream_clazz.obj(),
75 bytearray_output_stream_constructor)); 77 bytearray_output_stream_constructor));
76 78
77 // Create an instance of PrintStream. 79 // Create an instance of PrintStream.
78 ScopedJavaLocalRef<jclass> printstream_clazz = 80 ScopedJavaLocalRef<jclass> printstream_clazz =
79 GetClass(env, "java/io/PrintStream"); 81 GetClass(env, "java/io/PrintStream");
80 jmethodID printstream_constructor = 82 jmethodID printstream_constructor =
81 GetMethodID(env, printstream_clazz, "<init>", 83 MethodID::Get<MethodID::METHODTYPE_NORMAL, MethodID::EXCEPTIONCHECK_YES>(
82 "(Ljava/io/OutputStream;)V"); 84 env, printstream_clazz.obj(), "<init>",
85 "(Ljava/io/OutputStream;)V");
83 ScopedJavaLocalRef<jobject> printstream(env, 86 ScopedJavaLocalRef<jobject> printstream(env,
84 env->NewObject(printstream_clazz.obj(), printstream_constructor, 87 env->NewObject(printstream_clazz.obj(), printstream_constructor,
85 bytearray_output_stream.obj())); 88 bytearray_output_stream.obj()));
86 89
87 // Call Throwable.printStackTrace(PrintStream) 90 // Call Throwable.printStackTrace(PrintStream)
88 env->CallVoidMethod(java_throwable, throwable_printstacktrace, 91 env->CallVoidMethod(java_throwable, throwable_printstacktrace,
89 printstream.obj()); 92 printstream.obj());
90 93
91 // Call ByteArrayOutputStream.toString() 94 // Call ByteArrayOutputStream.toString()
92 ScopedJavaLocalRef<jstring> exception_string( 95 ScopedJavaLocalRef<jstring> exception_string(
93 env, static_cast<jstring>( 96 env, static_cast<jstring>(
94 env->CallObjectMethod(bytearray_output_stream.obj(), 97 env->CallObjectMethod(bytearray_output_stream.obj(),
95 bytearray_output_stream_tostring))); 98 bytearray_output_stream_tostring)));
96 99
97 return ConvertJavaStringToUTF8(exception_string); 100 return ConvertJavaStringToUTF8(exception_string);
98 } 101 }
99 102
100 enum MethodType {
101 METHODTYPE_STATIC,
102 METHODTYPE_NORMAL,
103 };
104
105 enum ExceptionCheck {
106 EXCEPTIONCHECK_YES,
107 EXCEPTIONCHECK_NO,
108 };
109
110 template<MethodType method_type, ExceptionCheck exception_check>
111 jmethodID GetMethodIDInternal(JNIEnv* env,
112 jclass clazz,
113 const char* method_name,
114 const char* jni_signature) {
115 jmethodID method_id = method_type == METHODTYPE_STATIC ?
116 env->GetStaticMethodID(clazz, method_name, jni_signature) :
117 env->GetMethodID(clazz, method_name, jni_signature);
118 if (exception_check == EXCEPTIONCHECK_YES) {
119 CHECK(!base::android::ClearException(env) && method_id) <<
120 "Failed to find " <<
121 (method_type == METHODTYPE_STATIC ? "static " : "") <<
122 "method " << method_name << " " << jni_signature;
123 } else if (base::android::HasException(env)) {
124 env->ExceptionClear();
125 }
126 return method_id;
127 }
128
129 } // namespace 103 } // namespace
130 104
131 namespace base { 105 namespace base {
132 namespace android { 106 namespace android {
133 107
134 JNIEnv* AttachCurrentThread() { 108 JNIEnv* AttachCurrentThread() {
135 if (!g_jvm) 109 if (!g_jvm)
136 return NULL; 110 return NULL;
137 JNIEnv* env = NULL; 111 JNIEnv* env = NULL;
138 jint ret = g_jvm->AttachCurrentThread(&env, NULL); 112 jint ret = g_jvm->AttachCurrentThread(&env, NULL);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name)); 150 ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name));
177 if (!clazz.obj()) { 151 if (!clazz.obj()) {
178 ClearException(env); 152 ClearException(env);
179 return false; 153 return false;
180 } 154 }
181 bool error = ClearException(env); 155 bool error = ClearException(env);
182 DCHECK(!error); 156 DCHECK(!error);
183 return true; 157 return true;
184 } 158 }
185 159
186 jmethodID GetMethodID(JNIEnv* env, 160 template<MethodID::MethodType method_type,
187 const JavaRef<jclass>& clazz, 161 MethodID::ExceptionCheck exception_check>
188 const char* method_name, 162 jmethodID MethodID::Get(JNIEnv* env,
189 const char* jni_signature) { 163 jclass clazz,
190 // clazz.env() can not be used as that may be from a different thread. 164 const char* method_name,
191 return GetMethodID(env, clazz.obj(), method_name, jni_signature); 165 const char* jni_signature) {
166 jmethodID id = method_type == METHODTYPE_STATIC ?
167 env->GetStaticMethodID(clazz, method_name, jni_signature) :
168 env->GetMethodID(clazz, method_name, jni_signature);
169 if (exception_check == EXCEPTIONCHECK_YES) {
170 CHECK(base::android::ClearException(env) || id) <<
171 "Failed to find " <<
172 (method_type == METHODTYPE_STATIC ? "static " : "") <<
173 "method " << method_name << " " << jni_signature;
174 } else if (base::android::HasException(env)) {
175 env->ExceptionClear();
176 }
177 return id;
192 } 178 }
193 179
194 jmethodID GetMethodID(JNIEnv* env, 180 template<MethodID::MethodType method_type,
195 jclass clazz, 181 MethodID::ExceptionCheck exception_check>
196 const char* method_name, 182 jmethodID MethodID::LazyGet(JNIEnv* env,
197 const char* jni_signature) { 183 jclass clazz,
198 return GetMethodIDInternal<METHODTYPE_NORMAL, EXCEPTIONCHECK_YES>( 184 const char* method_name,
185 const char* jni_signature,
186 base::subtle::AtomicWord* atomic_method_id) {
187 COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jmethodID),
188 AtomicWord_SmallerThan_jMethodID);
189 subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_method_id);
190 if (value)
191 return reinterpret_cast<jmethodID>(value);
192 jmethodID id = MethodID::Get<method_type, exception_check>(
199 env, clazz, method_name, jni_signature); 193 env, clazz, method_name, jni_signature);
194 base::subtle::Release_Store(
195 atomic_method_id, reinterpret_cast<subtle::AtomicWord>(id));
196 return id;
200 } 197 }
201 198
202 jmethodID GetMethodIDOrNull(JNIEnv* env, 199 // Various template instantiations.
203 jclass clazz, 200 template jmethodID MethodID::Get<MethodID::METHODTYPE_STATIC,
204 const char* method_name, 201 MethodID::EXCEPTIONCHECK_YES>(
205 const char* jni_signature) { 202 JNIEnv* env, jclass clazz, const char* method_name,
206 return GetMethodIDInternal<METHODTYPE_NORMAL, EXCEPTIONCHECK_NO>( 203 const char* jni_signature);
207 env, clazz, method_name, jni_signature);
208 }
209 204
210 jmethodID GetStaticMethodID(JNIEnv* env, 205 template jmethodID MethodID::Get<MethodID::METHODTYPE_NORMAL,
211 const JavaRef<jclass>& clazz, 206 MethodID::EXCEPTIONCHECK_YES>(
212 const char* method_name, 207 JNIEnv* env, jclass clazz, const char* method_name,
213 const char* jni_signature) { 208 const char* jni_signature);
214 return GetStaticMethodID(env, clazz.obj(), method_name,
215 jni_signature);
216 }
217 209
218 jmethodID GetStaticMethodID(JNIEnv* env, 210 template jmethodID MethodID::Get<MethodID::METHODTYPE_STATIC,
219 jclass clazz, 211 MethodID::EXCEPTIONCHECK_NO>(
220 const char* method_name, 212 JNIEnv* env, jclass clazz, const char* method_name,
221 const char* jni_signature) { 213 const char* jni_signature);
222 return GetMethodIDInternal<METHODTYPE_STATIC, EXCEPTIONCHECK_YES>(
223 env, clazz, method_name, jni_signature);
224 }
225 214
226 jmethodID GetStaticMethodIDOrNull(JNIEnv* env, 215 template jmethodID MethodID::Get<MethodID::METHODTYPE_NORMAL,
227 jclass clazz, 216 MethodID::EXCEPTIONCHECK_NO>(
228 const char* method_name, 217 JNIEnv* env, jclass clazz, const char* method_name,
229 const char* jni_signature) { 218 const char* jni_signature);
joth 2012/10/04 17:59:59 fwiw the ::Get() instantiations are not strictly n
bulach 2012/10/04 18:58:17 I'd love to delete, but I think this makes it clea
230 return GetMethodIDInternal<METHODTYPE_STATIC, EXCEPTIONCHECK_NO>(
231 env, clazz, method_name, jni_signature);
232 }
233 219
234 bool HasMethod(JNIEnv* env, 220 template jmethodID MethodID::LazyGet<MethodID::METHODTYPE_STATIC,
235 const JavaRef<jclass>& clazz, 221 MethodID::EXCEPTIONCHECK_YES>(
236 const char* method_name, 222 JNIEnv* env, jclass clazz, const char* method_name,
237 const char* jni_signature) { 223 const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
238 jmethodID method_id = 224
239 env->GetMethodID(clazz.obj(), method_name, jni_signature); 225 template jmethodID MethodID::LazyGet<MethodID::METHODTYPE_NORMAL,
240 if (!method_id) { 226 MethodID::EXCEPTIONCHECK_YES>(
241 ClearException(env); 227 JNIEnv* env, jclass clazz, const char* method_name,
242 return false; 228 const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
243 } 229
244 bool error = ClearException(env); 230 template jmethodID MethodID::LazyGet<MethodID::METHODTYPE_STATIC,
245 DCHECK(!error); 231 MethodID::EXCEPTIONCHECK_NO>(
246 return true; 232 JNIEnv* env, jclass clazz, const char* method_name,
247 } 233 const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
234
235 template jmethodID MethodID::LazyGet<MethodID::METHODTYPE_NORMAL,
236 MethodID::EXCEPTIONCHECK_NO>(
237 JNIEnv* env, jclass clazz, const char* method_name,
238 const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
248 239
249 jfieldID GetFieldID(JNIEnv* env, 240 jfieldID GetFieldID(JNIEnv* env,
250 const JavaRef<jclass>& clazz, 241 const JavaRef<jclass>& clazz,
251 const char* field_name, 242 const char* field_name,
252 const char* jni_signature) { 243 const char* jni_signature) {
253 jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature); 244 jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature);
254 CHECK(!ClearException(env) && field_id) << "Failed to find field " << 245 CHECK(!ClearException(env) && field_id) << "Failed to find field " <<
255 field_name << " " << jni_signature; 246 field_name << " " << jni_signature;
256 return field_id; 247 return field_id;
257 } 248 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 found = true; 294 found = true;
304 } 295 }
305 base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); 296 base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked);
306 297
307 // Addition to the map does not invalidate this iterator. 298 // Addition to the map does not invalidate this iterator.
308 if (found) { 299 if (found) {
309 return iter->second; 300 return iter->second;
310 } 301 }
311 302
312 ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name)); 303 ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name));
313 jmethodID id = GetMethodID(env, clazz, method, jni_signature); 304 jmethodID id = MethodID::Get<
305 MethodID::METHODTYPE_NORMAL, MethodID::EXCEPTIONCHECK_YES>(
306 env, clazz.obj(), method, jni_signature);
314 307
315 while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, 308 while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock,
316 kUnlocked, 309 kUnlocked,
317 kLocked) != kUnlocked) { 310 kLocked) != kUnlocked) {
318 base::PlatformThread::YieldCurrentThread(); 311 base::PlatformThread::YieldCurrentThread();
319 } 312 }
320 // Another thread may have populated the map already. 313 // Another thread may have populated the map already.
321 std::pair<MethodIDMap::const_iterator, bool> result = 314 std::pair<MethodIDMap::const_iterator, bool> result =
322 map->insert(std::make_pair(key, id)); 315 map->insert(std::make_pair(key, id));
323 DCHECK_EQ(id, result.first->second); 316 DCHECK_EQ(id, result.first->second);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 // RVO should avoid any extra copies of the exception string. 348 // RVO should avoid any extra copies of the exception string.
356 base::android::BuildInfo::GetInstance()->set_java_exception_info( 349 base::android::BuildInfo::GetInstance()->set_java_exception_info(
357 GetJavaExceptionInfo(env, java_throwable)); 350 GetJavaExceptionInfo(env, java_throwable));
358 351
359 // Now, feel good about it and die. 352 // Now, feel good about it and die.
360 CHECK(false); 353 CHECK(false);
361 } 354 }
362 355
363 } // namespace android 356 } // namespace android
364 } // namespace base 357 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698