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 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 |
121 const jobject GetApplicationContext() { | 143 const jobject GetApplicationContext() { |
122 DCHECK(!g_application_context.Get().is_null()); | 144 DCHECK(!g_application_context.Get().is_null()); |
123 return g_application_context.Get().obj(); | 145 return g_application_context.Get().obj(); |
124 } | 146 } |
125 | 147 |
126 ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) { | 148 ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) { |
127 jclass clazz = env->FindClass(class_name); | 149 jclass clazz; |
| 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 } |
128 CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name; | 158 CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name; |
129 return ScopedJavaLocalRef<jclass>(env, clazz); | 159 return ScopedJavaLocalRef<jclass>(env, clazz); |
130 } | 160 } |
131 | 161 |
| 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 |
132 template<MethodID::Type type> | 187 template<MethodID::Type type> |
133 jmethodID MethodID::Get(JNIEnv* env, | 188 jmethodID MethodID::Get(JNIEnv* env, |
134 jclass clazz, | 189 jclass clazz, |
135 const char* method_name, | 190 const char* method_name, |
136 const char* jni_signature) { | 191 const char* jni_signature) { |
137 jmethodID id = type == TYPE_STATIC ? | 192 jmethodID id = type == TYPE_STATIC ? |
138 env->GetStaticMethodID(clazz, method_name, jni_signature) : | 193 env->GetStaticMethodID(clazz, method_name, jni_signature) : |
139 env->GetMethodID(clazz, method_name, jni_signature); | 194 env->GetMethodID(clazz, method_name, jni_signature); |
140 CHECK(base::android::ClearException(env) || id) << | 195 CHECK(base::android::ClearException(env) || id) << |
141 "Failed to find " << | 196 "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( | 264 base::android::BuildInfo::GetInstance()->set_java_exception_info( |
210 GetJavaExceptionInfo(env, java_throwable)); | 265 GetJavaExceptionInfo(env, java_throwable)); |
211 } | 266 } |
212 | 267 |
213 // Now, feel good about it and die. | 268 // Now, feel good about it and die. |
214 CHECK(false) << "Please include Java exception stack in crash report"; | 269 CHECK(false) << "Please include Java exception stack in crash report"; |
215 } | 270 } |
216 | 271 |
217 } // namespace android | 272 } // namespace android |
218 } // namespace base | 273 } // namespace base |
OLD | NEW |