| OLD | NEW |
| 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/android/jni_utils.h" | |
| 12 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
| 13 #include "base/logging.h" | 12 #include "base/logging.h" |
| 14 | 13 |
| 15 namespace { | 14 namespace { |
| 16 using base::android::GetClass; | 15 using base::android::GetClass; |
| 17 using base::android::MethodID; | 16 using base::android::MethodID; |
| 18 using base::android::ScopedJavaLocalRef; | 17 using base::android::ScopedJavaLocalRef; |
| 19 | 18 |
| 20 JavaVM* g_jvm = NULL; | 19 JavaVM* g_jvm = NULL; |
| 21 // Leak the global app context, as it is used from a non-joinable worker thread | 20 // Leak the global app context, as it is used from a non-joinable worker thread |
| 22 // that may still be running at shutdown. There is no harm in doing this. | 21 // that may still be running at shutdown. There is no harm in doing this. |
| 23 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky | 22 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky |
| 24 g_application_context = LAZY_INSTANCE_INITIALIZER; | 23 g_application_context = LAZY_INSTANCE_INITIALIZER; |
| 25 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky | |
| 26 g_class_loader = LAZY_INSTANCE_INITIALIZER; | |
| 27 jmethodID g_class_loader_load_class_method_id = 0; | |
| 28 | 24 |
| 29 std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) { | 25 std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) { |
| 30 ScopedJavaLocalRef<jclass> throwable_clazz = | 26 ScopedJavaLocalRef<jclass> throwable_clazz = |
| 31 GetClass(env, "java/lang/Throwable"); | 27 GetClass(env, "java/lang/Throwable"); |
| 32 jmethodID throwable_printstacktrace = | 28 jmethodID throwable_printstacktrace = |
| 33 MethodID::Get<MethodID::TYPE_INSTANCE>( | 29 MethodID::Get<MethodID::TYPE_INSTANCE>( |
| 34 env, throwable_clazz.obj(), "printStackTrace", | 30 env, throwable_clazz.obj(), "printStackTrace", |
| 35 "(Ljava/io/PrintStream;)V"); | 31 "(Ljava/io/PrintStream;)V"); |
| 36 | 32 |
| 37 // Create an instance of ByteArrayOutputStream. | 33 // Create an instance of ByteArrayOutputStream. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 | 111 |
| 116 void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) { | 112 void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) { |
| 117 if (env->IsSameObject(g_application_context.Get().obj(), context.obj())) { | 113 if (env->IsSameObject(g_application_context.Get().obj(), context.obj())) { |
| 118 // It's safe to set the context more than once if it's the same context. | 114 // It's safe to set the context more than once if it's the same context. |
| 119 return; | 115 return; |
| 120 } | 116 } |
| 121 DCHECK(g_application_context.Get().is_null()); | 117 DCHECK(g_application_context.Get().is_null()); |
| 122 g_application_context.Get().Reset(context); | 118 g_application_context.Get().Reset(context); |
| 123 } | 119 } |
| 124 | 120 |
| 125 void InitReplacementClassLoader(JNIEnv* env, | |
| 126 const JavaRef<jobject>& class_loader) { | |
| 127 DCHECK(g_class_loader.Get().is_null()); | |
| 128 DCHECK(!class_loader.is_null()); | |
| 129 | |
| 130 ScopedJavaLocalRef<jclass> class_loader_clazz = | |
| 131 GetClass(env, "java/lang/ClassLoader"); | |
| 132 CHECK(!ClearException(env)); | |
| 133 g_class_loader_load_class_method_id = | |
| 134 env->GetMethodID(class_loader_clazz.obj(), | |
| 135 "loadClass", | |
| 136 "(Ljava/lang/String;)Ljava/lang/Class;"); | |
| 137 CHECK(!ClearException(env)); | |
| 138 | |
| 139 DCHECK(env->IsInstanceOf(class_loader.obj(), class_loader_clazz.obj())); | |
| 140 g_class_loader.Get().Reset(class_loader); | |
| 141 } | |
| 142 | |
| 143 const jobject GetApplicationContext() { | 121 const jobject GetApplicationContext() { |
| 144 DCHECK(!g_application_context.Get().is_null()); | 122 DCHECK(!g_application_context.Get().is_null()); |
| 145 return g_application_context.Get().obj(); | 123 return g_application_context.Get().obj(); |
| 146 } | 124 } |
| 147 | 125 |
| 148 ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) { | 126 ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) { |
| 149 jclass clazz; | 127 jclass clazz = env->FindClass(class_name); |
| 150 if (!g_class_loader.Get().is_null()) { | |
| 151 clazz = static_cast<jclass>( | |
| 152 env->CallObjectMethod(g_class_loader.Get().obj(), | |
| 153 g_class_loader_load_class_method_id, | |
| 154 ConvertUTF8ToJavaString(env, class_name).obj())); | |
| 155 } else { | |
| 156 clazz = env->FindClass(class_name); | |
| 157 } | |
| 158 CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name; | 128 CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name; |
| 159 return ScopedJavaLocalRef<jclass>(env, clazz); | 129 return ScopedJavaLocalRef<jclass>(env, clazz); |
| 160 } | 130 } |
| 161 | 131 |
| 162 jclass LazyGetClass( | |
| 163 JNIEnv* env, | |
| 164 const char* class_name, | |
| 165 base::subtle::AtomicWord* atomic_class_id) { | |
| 166 COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jclass), | |
| 167 AtomicWord_SmallerThan_jMethodID); | |
| 168 subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_class_id); | |
| 169 if (value) | |
| 170 return reinterpret_cast<jclass>(value); | |
| 171 ScopedJavaGlobalRef<jclass> clazz; | |
| 172 clazz.Reset(GetClass(env, class_name)); | |
| 173 subtle::AtomicWord null_aw = reinterpret_cast<subtle::AtomicWord>(NULL); | |
| 174 subtle::AtomicWord cas_result = base::subtle::Release_CompareAndSwap( | |
| 175 atomic_class_id, | |
| 176 null_aw, | |
| 177 reinterpret_cast<subtle::AtomicWord>(clazz.obj())); | |
| 178 if (cas_result == null_aw) { | |
| 179 // We intentionally leak the global ref since we now storing it as a raw | |
| 180 // pointer in |atomic_class_id|. | |
| 181 return clazz.Release(); | |
| 182 } else { | |
| 183 return reinterpret_cast<jclass>(cas_result); | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 template<MethodID::Type type> | 132 template<MethodID::Type type> |
| 188 jmethodID MethodID::Get(JNIEnv* env, | 133 jmethodID MethodID::Get(JNIEnv* env, |
| 189 jclass clazz, | 134 jclass clazz, |
| 190 const char* method_name, | 135 const char* method_name, |
| 191 const char* jni_signature) { | 136 const char* jni_signature) { |
| 192 jmethodID id = type == TYPE_STATIC ? | 137 jmethodID id = type == TYPE_STATIC ? |
| 193 env->GetStaticMethodID(clazz, method_name, jni_signature) : | 138 env->GetStaticMethodID(clazz, method_name, jni_signature) : |
| 194 env->GetMethodID(clazz, method_name, jni_signature); | 139 env->GetMethodID(clazz, method_name, jni_signature); |
| 195 CHECK(base::android::ClearException(env) || id) << | 140 CHECK(base::android::ClearException(env) || id) << |
| 196 "Failed to find " << | 141 "Failed to find " << |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 base::android::BuildInfo::GetInstance()->set_java_exception_info( | 209 base::android::BuildInfo::GetInstance()->set_java_exception_info( |
| 265 GetJavaExceptionInfo(env, java_throwable)); | 210 GetJavaExceptionInfo(env, java_throwable)); |
| 266 } | 211 } |
| 267 | 212 |
| 268 // Now, feel good about it and die. | 213 // Now, feel good about it and die. |
| 269 CHECK(false) << "Please include Java exception stack in crash report"; | 214 CHECK(false) << "Please include Java exception stack in crash report"; |
| 270 } | 215 } |
| 271 | 216 |
| 272 } // namespace android | 217 } // namespace android |
| 273 } // namespace base | 218 } // namespace base |
| OLD | NEW |