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 |