15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/android/jni_android.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/android/build_info.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/android/jni_string.h" 1103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "base/android/jni_utils.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::GetClass; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::MethodID; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::ScopedJavaLocalRef; 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JavaVM* g_jvm = NULL; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Leak the global app context, as it is used from a non-joinable worker thread 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that may still be running at shutdown. There is no harm in doing this. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_application_context = LAZY_INSTANCE_INITIALIZER; 2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky 2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) g_class_loader = LAZY_INSTANCE_INITIALIZER; 2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)jmethodID g_class_loader_load_class_method_id = 0; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jclass> throwable_clazz = 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetClass(env, "java/lang/Throwable"); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID throwable_printstacktrace = 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MethodID::Get<MethodID::TYPE_INSTANCE>( 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env, throwable_clazz.obj(), "printStackTrace", 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "(Ljava/io/PrintStream;)V"); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create an instance of ByteArrayOutputStream. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz = 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetClass(env, "java/io/ByteArrayOutputStream"); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID bytearray_output_stream_constructor = 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MethodID::Get<MethodID::TYPE_INSTANCE>( 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env, bytearray_output_stream_clazz.obj(), "<init>", "()V"); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID bytearray_output_stream_tostring = 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MethodID::Get<MethodID::TYPE_INSTANCE>( 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env, bytearray_output_stream_clazz.obj(), "toString", 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "()Ljava/lang/String;"); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jobject> bytearray_output_stream(env, 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->NewObject(bytearray_output_stream_clazz.obj(), 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytearray_output_stream_constructor)); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create an instance of PrintStream. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jclass> printstream_clazz = 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetClass(env, "java/io/PrintStream"); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID printstream_constructor = 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MethodID::Get<MethodID::TYPE_INSTANCE>( 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env, printstream_clazz.obj(), "<init>", 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "(Ljava/io/OutputStream;)V"); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jobject> printstream(env, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->NewObject(printstream_clazz.obj(), printstream_constructor, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytearray_output_stream.obj())); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Call Throwable.printStackTrace(PrintStream) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->CallVoidMethod(java_throwable, throwable_printstacktrace, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printstream.obj()); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Call ByteArrayOutputStream.toString() 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedJavaLocalRef<jstring> exception_string( 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env, static_cast<jstring>( 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->CallObjectMethod(bytearray_output_stream.obj(), 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytearray_output_stream_tostring))); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ConvertJavaStringToUTF8(exception_string); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace android { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JNIEnv* AttachCurrentThread() { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(g_jvm); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JNIEnv* env = NULL; 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) jint ret = g_jvm->AttachCurrentThread(&env, NULL); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(JNI_OK, ret); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return env; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)JNIEnv* AttachCurrentThreadWithName(const std::string& thread_name) { 896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK(g_jvm); 906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) JavaVMAttachArgs args; 916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) args.version = JNI_VERSION_1_2; 926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) args.name = thread_name.c_str(); 936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) args.group = NULL; 946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) JNIEnv* env = NULL; 956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) jint ret = g_jvm->AttachCurrentThread(&env, &args); 966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK_EQ(JNI_OK, ret); 976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return env; 986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DetachFromVM() { 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore the return value, if the thread is not attached, DetachCurrentThread 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will fail. But it is ok as the native thread may never be attached. 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (g_jvm) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_jvm->DetachCurrentThread(); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InitVM(JavaVM* vm) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!g_jvm); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_jvm = vm; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool IsVMInitialized() { 1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return g_jvm != NULL; 1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) { 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (env->IsSameObject(g_application_context.Get().obj(), context.obj())) { 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // It's safe to set the context more than once if it's the same context. 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(g_application_context.Get().is_null()); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_application_context.Get().Reset(context); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InitReplacementClassLoader(JNIEnv* env, 12603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const JavaRef<jobject>& class_loader) { 12703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DCHECK(g_class_loader.Get().is_null()); 12803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DCHECK(!class_loader.is_null()); 12903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 13003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ScopedJavaLocalRef<jclass> class_loader_clazz = 13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) GetClass(env, "java/lang/ClassLoader"); 13203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CHECK(!ClearException(env)); 13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) g_class_loader_load_class_method_id = 13403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) env->GetMethodID(class_loader_clazz.obj(), 13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) "loadClass", 13603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) "(Ljava/lang/String;)Ljava/lang/Class;"); 13703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) CHECK(!ClearException(env)); 13803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 13903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DCHECK(env->IsInstanceOf(class_loader.obj(), class_loader_clazz.obj())); 14003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) g_class_loader.Get().Reset(class_loader); 14103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const jobject GetApplicationContext() { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!g_application_context.Get().is_null()); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return g_application_context.Get().obj(); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) { 14903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) jclass clazz; 15003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!g_class_loader.Get().is_null()) { 15103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) clazz = static_cast<jclass>( 15203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) env->CallObjectMethod(g_class_loader.Get().obj(), 15303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) g_class_loader_load_class_method_id, 15403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ConvertUTF8ToJavaString(env, class_name).obj())); 15503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } else { 15603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) clazz = env->FindClass(class_name); 15703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name; 159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return ScopedJavaLocalRef<jclass>(env, clazz); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)jclass LazyGetClass( 16303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) JNIEnv* env, 16403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const char* class_name, 16503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::subtle::AtomicWord* atomic_class_id) { 16603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jclass), 16703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) AtomicWord_SmallerThan_jMethodID); 16803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_class_id); 16903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (value) 17003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return reinterpret_cast<jclass>(value); 17103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ScopedJavaGlobalRef<jclass> clazz; 17203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) clazz.Reset(GetClass(env, class_name)); 17303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) subtle::AtomicWord null_aw = reinterpret_cast<subtle::AtomicWord>(NULL); 17403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) subtle::AtomicWord cas_result = base::subtle::Release_CompareAndSwap( 17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) atomic_class_id, 17603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) null_aw, 17703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) reinterpret_cast<subtle::AtomicWord>(clazz.obj())); 17803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (cas_result == null_aw) { 17903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // We intentionally leak the global ref since we now storing it as a raw 18003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // pointer in |atomic_class_id|. 18103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return clazz.Release(); 18203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } else { 18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return reinterpret_cast<jclass>(cas_result); 18403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 18503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 18603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<MethodID::Type type> 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)jmethodID MethodID::Get(JNIEnv* env, 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jclass clazz, 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* method_name, 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature) { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID id = type == TYPE_STATIC ? 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->GetStaticMethodID(clazz, method_name, jni_signature) : 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->GetMethodID(clazz, method_name, jni_signature); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(base::android::ClearException(env) || id) << 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to find " << 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (type == TYPE_STATIC ? "static " : "") << 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "method " << method_name << " " << jni_signature; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return id; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If |atomic_method_id| set, it'll return immediately. Otherwise, it'll call 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// into ::Get() above. If there's a race, it's ok since the values are the same 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (and the duplicated effort will happen only once). 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<MethodID::Type type> 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)jmethodID MethodID::LazyGet(JNIEnv* env, 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jclass clazz, 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* method_name, 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature, 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::subtle::AtomicWord* atomic_method_id) { 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jmethodID), 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AtomicWord_SmallerThan_jMethodID); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_method_id); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return reinterpret_cast<jmethodID>(value); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmethodID id = MethodID::Get<type>(env, clazz, method_name, jni_signature); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::subtle::Release_Store( 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) atomic_method_id, reinterpret_cast<subtle::AtomicWord>(id)); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return id; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Various template instantiations. 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template jmethodID MethodID::Get<MethodID::TYPE_STATIC>( 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JNIEnv* env, jclass clazz, const char* method_name, 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template jmethodID MethodID::Get<MethodID::TYPE_INSTANCE>( 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JNIEnv* env, jclass clazz, const char* method_name, 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>( 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JNIEnv* env, jclass clazz, const char* method_name, 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature, base::subtle::AtomicWord* atomic_method_id); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>( 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JNIEnv* env, jclass clazz, const char* method_name, 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* jni_signature, base::subtle::AtomicWord* atomic_method_id); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HasException(JNIEnv* env) { 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return env->ExceptionCheck() != JNI_FALSE; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ClearException(JNIEnv* env) { 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!HasException(env)) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->ExceptionDescribe(); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env->ExceptionClear(); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CheckException(JNIEnv* env) { 252116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!HasException(env)) 253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Exception has been found, might as well tell breakpad about it. 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jthrowable java_throwable = env->ExceptionOccurred(); 257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (java_throwable) { 258116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Clear the pending exception, since a local reference is now held. 259116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch env->ExceptionDescribe(); 260116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch env->ExceptionClear(); 261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 262116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Set the exception_string in BuildInfo so that breakpad can read it. 263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // RVO should avoid any extra copies of the exception string. 264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::android::BuildInfo::GetInstance()->set_java_exception_info( 265116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch GetJavaExceptionInfo(env, java_throwable)); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now, feel good about it and die. 269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch CHECK(false) << "Please include Java exception stack in crash report"; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace android 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 274