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" |
| 10 #include "base/android/jni_string.h" |
9 #include "base/atomicops.h" | 11 #include "base/atomicops.h" |
10 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
11 #include "base/logging.h" | 13 #include "base/logging.h" |
12 #include "base/threading/platform_thread.h" | 14 #include "base/threading/platform_thread.h" |
13 | 15 |
14 namespace { | 16 namespace { |
| 17 using base::android::GetClass; |
| 18 using base::android::GetMethodID; |
| 19 using base::android::ScopedJavaLocalRef; |
15 | 20 |
16 JavaVM* g_jvm = NULL; | 21 JavaVM* g_jvm = NULL; |
17 | 22 |
18 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> > | 23 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> > |
19 g_application_context = LAZY_INSTANCE_INITIALIZER; | 24 g_application_context = LAZY_INSTANCE_INITIALIZER; |
20 | 25 |
21 struct MethodIdentifier { | 26 struct MethodIdentifier { |
22 const char* class_name; | 27 const char* class_name; |
23 const char* method; | 28 const char* method; |
24 const char* jni_signature; | 29 const char* jni_signature; |
(...skipping 17 matching lines...) Expand all Loading... |
42 } | 47 } |
43 }; | 48 }; |
44 | 49 |
45 typedef std::map<MethodIdentifier, jmethodID> MethodIDMap; | 50 typedef std::map<MethodIdentifier, jmethodID> MethodIDMap; |
46 base::LazyInstance<MethodIDMap>::Leaky | 51 base::LazyInstance<MethodIDMap>::Leaky |
47 g_method_id_map = LAZY_INSTANCE_INITIALIZER; | 52 g_method_id_map = LAZY_INSTANCE_INITIALIZER; |
48 const base::subtle::AtomicWord kUnlocked = 0; | 53 const base::subtle::AtomicWord kUnlocked = 0; |
49 const base::subtle::AtomicWord kLocked = 1; | 54 const base::subtle::AtomicWord kLocked = 1; |
50 base::subtle::AtomicWord g_method_id_map_lock = kUnlocked; | 55 base::subtle::AtomicWord g_method_id_map_lock = kUnlocked; |
51 | 56 |
| 57 std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) { |
| 58 ScopedJavaLocalRef<jclass> throwable_clazz = |
| 59 GetClass(env, "java/lang/Throwable"); |
| 60 jmethodID throwable_printstacktrace = |
| 61 GetMethodID(env, throwable_clazz, "printStackTrace", |
| 62 "(Ljava/io/PrintStream;)V"); |
| 63 |
| 64 // Create an instance of ByteArrayOutputStream. |
| 65 ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz = |
| 66 GetClass(env, "java/io/ByteArrayOutputStream"); |
| 67 jmethodID bytearray_output_stream_constructor = |
| 68 GetMethodID(env, bytearray_output_stream_clazz, "<init>", "()V"); |
| 69 jmethodID bytearray_output_stream_tostring = |
| 70 GetMethodID(env, bytearray_output_stream_clazz, "toString", |
| 71 "()Ljava/lang/String;"); |
| 72 ScopedJavaLocalRef<jobject> bytearray_output_stream(env, |
| 73 env->NewObject(bytearray_output_stream_clazz.obj(), |
| 74 bytearray_output_stream_constructor)); |
| 75 |
| 76 // Create an instance of PrintStream. |
| 77 ScopedJavaLocalRef<jclass> printstream_clazz = |
| 78 GetClass(env, "java/io/PrintStream"); |
| 79 jmethodID printstream_constructor = |
| 80 GetMethodID(env, printstream_clazz, "<init>", |
| 81 "(Ljava/io/OutputStream;)V"); |
| 82 ScopedJavaLocalRef<jobject> printstream(env, |
| 83 env->NewObject(printstream_clazz.obj(), printstream_constructor, |
| 84 bytearray_output_stream.obj())); |
| 85 |
| 86 // Call Throwable.printStackTrace(PrintStream) |
| 87 env->CallVoidMethod(java_throwable, throwable_printstacktrace, |
| 88 printstream.obj()); |
| 89 |
| 90 // Call ByteArrayOutputStream.toString() |
| 91 ScopedJavaLocalRef<jstring> exception_string( |
| 92 env, static_cast<jstring>( |
| 93 env->CallObjectMethod(bytearray_output_stream.obj(), |
| 94 bytearray_output_stream_tostring))); |
| 95 |
| 96 return ConvertJavaStringToUTF8(exception_string); |
52 } | 97 } |
| 98 } // namespace |
53 | 99 |
54 namespace base { | 100 namespace base { |
55 namespace android { | 101 namespace android { |
56 | 102 |
57 JNIEnv* AttachCurrentThread() { | 103 JNIEnv* AttachCurrentThread() { |
58 if (!g_jvm) | 104 if (!g_jvm) |
59 return NULL; | 105 return NULL; |
60 JNIEnv* env = NULL; | 106 JNIEnv* env = NULL; |
61 jint ret = g_jvm->AttachCurrentThread(&env, NULL); | 107 jint ret = g_jvm->AttachCurrentThread(&env, NULL); |
62 DCHECK_EQ(ret, JNI_OK); | 108 DCHECK_EQ(ret, JNI_OK); |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 return id; | 289 return id; |
244 } | 290 } |
245 | 291 |
246 bool HasException(JNIEnv* env) { | 292 bool HasException(JNIEnv* env) { |
247 return env->ExceptionCheck() != JNI_FALSE; | 293 return env->ExceptionCheck() != JNI_FALSE; |
248 } | 294 } |
249 | 295 |
250 bool ClearException(JNIEnv* env) { | 296 bool ClearException(JNIEnv* env) { |
251 if (!HasException(env)) | 297 if (!HasException(env)) |
252 return false; | 298 return false; |
| 299 env->ExceptionDescribe(); |
253 env->ExceptionClear(); | 300 env->ExceptionClear(); |
254 return true; | 301 return true; |
255 } | 302 } |
256 | 303 |
257 void CheckException(JNIEnv* env) { | 304 void CheckException(JNIEnv* env) { |
258 if (HasException(env)) { | 305 if (!HasException(env)) return; |
259 env->ExceptionDescribe(); | 306 |
| 307 // Ugh, we are going to die, might as well tell breakpad about it. |
| 308 jthrowable java_throwable = env->ExceptionOccurred(); |
| 309 if (!java_throwable) { |
| 310 // Nothing we can do. |
260 CHECK(false); | 311 CHECK(false); |
261 } | 312 } |
| 313 |
| 314 // Clear the pending exception, we do have a reference to it. |
| 315 env->ExceptionClear(); |
| 316 |
| 317 // Set the exception_string in BuildInfo so that breakpad can read it. |
| 318 // RVO should avoid any extra copies of the exception string. |
| 319 base::android::BuildInfo::GetInstance()->set_java_exception_info( |
| 320 GetJavaExceptionInfo(env, java_throwable)); |
| 321 |
| 322 // Now, feel good about it and die. |
| 323 CHECK(false); |
262 } | 324 } |
263 | 325 |
264 } // namespace android | 326 } // namespace android |
265 } // namespace base | 327 } // namespace base |
OLD | NEW |