| Index: base/android/jni_android.cc
|
| diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
|
| index 6f080fb6e3b112d6d12feedc2d5d03ca5edd4386..e09c2d5d150587aedfbb9d57fc294b57dcc931ad 100644
|
| --- a/base/android/jni_android.cc
|
| +++ b/base/android/jni_android.cc
|
| @@ -8,6 +8,7 @@
|
|
|
| #include "base/android/build_info.h"
|
| #include "base/android/jni_string.h"
|
| +#include "base/android/jni_utils.h"
|
| #include "base/lazy_instance.h"
|
| #include "base/logging.h"
|
|
|
| @@ -21,6 +22,9 @@ JavaVM* g_jvm = NULL;
|
| // that may still be running at shutdown. There is no harm in doing this.
|
| base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
|
| g_application_context = LAZY_INSTANCE_INITIALIZER;
|
| +base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
|
| + g_class_loader = LAZY_INSTANCE_INITIALIZER;
|
| +jmethodID g_class_loader_load_class_method_id = 0;
|
|
|
| std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
|
| ScopedJavaLocalRef<jclass> throwable_clazz =
|
| @@ -118,17 +122,68 @@ void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) {
|
| g_application_context.Get().Reset(context);
|
| }
|
|
|
| +void InitReplacementClassLoader(JNIEnv* env,
|
| + const JavaRef<jobject>& class_loader) {
|
| + DCHECK(g_class_loader.Get().is_null());
|
| + DCHECK(!class_loader.is_null());
|
| +
|
| + ScopedJavaLocalRef<jclass> class_loader_clazz =
|
| + GetClass(env, "java/lang/ClassLoader");
|
| + CHECK(!ClearException(env));
|
| + g_class_loader_load_class_method_id =
|
| + env->GetMethodID(class_loader_clazz.obj(),
|
| + "loadClass",
|
| + "(Ljava/lang/String;)Ljava/lang/Class;");
|
| + CHECK(!ClearException(env));
|
| +
|
| + DCHECK(env->IsInstanceOf(class_loader.obj(), class_loader_clazz.obj()));
|
| + g_class_loader.Get().Reset(class_loader);
|
| +}
|
| +
|
| const jobject GetApplicationContext() {
|
| DCHECK(!g_application_context.Get().is_null());
|
| return g_application_context.Get().obj();
|
| }
|
|
|
| ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) {
|
| - jclass clazz = env->FindClass(class_name);
|
| + jclass clazz;
|
| + if (!g_class_loader.Get().is_null()) {
|
| + clazz = static_cast<jclass>(
|
| + env->CallObjectMethod(g_class_loader.Get().obj(),
|
| + g_class_loader_load_class_method_id,
|
| + ConvertUTF8ToJavaString(env, class_name).obj()));
|
| + } else {
|
| + clazz = env->FindClass(class_name);
|
| + }
|
| CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name;
|
| return ScopedJavaLocalRef<jclass>(env, clazz);
|
| }
|
|
|
| +jclass LazyGetClass(
|
| + JNIEnv* env,
|
| + const char* class_name,
|
| + base::subtle::AtomicWord* atomic_class_id) {
|
| + COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jclass),
|
| + AtomicWord_SmallerThan_jMethodID);
|
| + subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_class_id);
|
| + if (value)
|
| + return reinterpret_cast<jclass>(value);
|
| + ScopedJavaGlobalRef<jclass> clazz;
|
| + clazz.Reset(GetClass(env, class_name));
|
| + subtle::AtomicWord null_aw = reinterpret_cast<subtle::AtomicWord>(NULL);
|
| + subtle::AtomicWord cas_result = base::subtle::Release_CompareAndSwap(
|
| + atomic_class_id,
|
| + null_aw,
|
| + reinterpret_cast<subtle::AtomicWord>(clazz.obj()));
|
| + if (cas_result == null_aw) {
|
| + // We intentionally leak the global ref since we now storing it as a raw
|
| + // pointer in |atomic_class_id|.
|
| + return clazz.Release();
|
| + } else {
|
| + return reinterpret_cast<jclass>(cas_result);
|
| + }
|
| +}
|
| +
|
| template<MethodID::Type type>
|
| jmethodID MethodID::Get(JNIEnv* env,
|
| jclass clazz,
|
|
|