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