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