xref: /aosp_15_r20/external/libchrome/base/android/jni_android.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/android/jni_android.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <stddef.h>
8*635a8641SAndroid Build Coastguard Worker #include <sys/prctl.h>
9*635a8641SAndroid Build Coastguard Worker 
10*635a8641SAndroid Build Coastguard Worker #include <map>
11*635a8641SAndroid Build Coastguard Worker 
12*635a8641SAndroid Build Coastguard Worker #include "base/android/java_exception_reporter.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/android/jni_string.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/debug/debugging_buildflags.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/lazy_instance.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_local.h"
18*635a8641SAndroid Build Coastguard Worker 
19*635a8641SAndroid Build Coastguard Worker namespace {
20*635a8641SAndroid Build Coastguard Worker using base::android::GetClass;
21*635a8641SAndroid Build Coastguard Worker using base::android::MethodID;
22*635a8641SAndroid Build Coastguard Worker using base::android::ScopedJavaLocalRef;
23*635a8641SAndroid Build Coastguard Worker 
24*635a8641SAndroid Build Coastguard Worker JavaVM* g_jvm = NULL;
25*635a8641SAndroid Build Coastguard Worker base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject>>::Leaky
26*635a8641SAndroid Build Coastguard Worker     g_class_loader = LAZY_INSTANCE_INITIALIZER;
27*635a8641SAndroid Build Coastguard Worker jmethodID g_class_loader_load_class_method_id = 0;
28*635a8641SAndroid Build Coastguard Worker 
29*635a8641SAndroid Build Coastguard Worker #if BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
30*635a8641SAndroid Build Coastguard Worker base::LazyInstance<base::ThreadLocalPointer<void>>::Leaky
31*635a8641SAndroid Build Coastguard Worker     g_stack_frame_pointer = LAZY_INSTANCE_INITIALIZER;
32*635a8641SAndroid Build Coastguard Worker #endif
33*635a8641SAndroid Build Coastguard Worker 
34*635a8641SAndroid Build Coastguard Worker bool g_fatal_exception_occurred = false;
35*635a8641SAndroid Build Coastguard Worker 
36*635a8641SAndroid Build Coastguard Worker }  // namespace
37*635a8641SAndroid Build Coastguard Worker 
38*635a8641SAndroid Build Coastguard Worker namespace base {
39*635a8641SAndroid Build Coastguard Worker namespace android {
40*635a8641SAndroid Build Coastguard Worker 
AttachCurrentThread()41*635a8641SAndroid Build Coastguard Worker JNIEnv* AttachCurrentThread() {
42*635a8641SAndroid Build Coastguard Worker   DCHECK(g_jvm);
43*635a8641SAndroid Build Coastguard Worker   JNIEnv* env = nullptr;
44*635a8641SAndroid Build Coastguard Worker   jint ret = g_jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_2);
45*635a8641SAndroid Build Coastguard Worker   if (ret == JNI_EDETACHED || !env) {
46*635a8641SAndroid Build Coastguard Worker     JavaVMAttachArgs args;
47*635a8641SAndroid Build Coastguard Worker     args.version = JNI_VERSION_1_2;
48*635a8641SAndroid Build Coastguard Worker     args.group = nullptr;
49*635a8641SAndroid Build Coastguard Worker 
50*635a8641SAndroid Build Coastguard Worker     // 16 is the maximum size for thread names on Android.
51*635a8641SAndroid Build Coastguard Worker     char thread_name[16];
52*635a8641SAndroid Build Coastguard Worker     int err = prctl(PR_GET_NAME, thread_name);
53*635a8641SAndroid Build Coastguard Worker     if (err < 0) {
54*635a8641SAndroid Build Coastguard Worker       DPLOG(ERROR) << "prctl(PR_GET_NAME)";
55*635a8641SAndroid Build Coastguard Worker       args.name = nullptr;
56*635a8641SAndroid Build Coastguard Worker     } else {
57*635a8641SAndroid Build Coastguard Worker       args.name = thread_name;
58*635a8641SAndroid Build Coastguard Worker     }
59*635a8641SAndroid Build Coastguard Worker 
60*635a8641SAndroid Build Coastguard Worker     ret = g_jvm->AttachCurrentThread(&env, &args);
61*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(JNI_OK, ret);
62*635a8641SAndroid Build Coastguard Worker   }
63*635a8641SAndroid Build Coastguard Worker   return env;
64*635a8641SAndroid Build Coastguard Worker }
65*635a8641SAndroid Build Coastguard Worker 
AttachCurrentThreadWithName(const std::string & thread_name)66*635a8641SAndroid Build Coastguard Worker JNIEnv* AttachCurrentThreadWithName(const std::string& thread_name) {
67*635a8641SAndroid Build Coastguard Worker   DCHECK(g_jvm);
68*635a8641SAndroid Build Coastguard Worker   JavaVMAttachArgs args;
69*635a8641SAndroid Build Coastguard Worker   args.version = JNI_VERSION_1_2;
70*635a8641SAndroid Build Coastguard Worker   args.name = thread_name.c_str();
71*635a8641SAndroid Build Coastguard Worker   args.group = NULL;
72*635a8641SAndroid Build Coastguard Worker   JNIEnv* env = NULL;
73*635a8641SAndroid Build Coastguard Worker   jint ret = g_jvm->AttachCurrentThread(&env, &args);
74*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ(JNI_OK, ret);
75*635a8641SAndroid Build Coastguard Worker   return env;
76*635a8641SAndroid Build Coastguard Worker }
77*635a8641SAndroid Build Coastguard Worker 
DetachFromVM()78*635a8641SAndroid Build Coastguard Worker void DetachFromVM() {
79*635a8641SAndroid Build Coastguard Worker   // Ignore the return value, if the thread is not attached, DetachCurrentThread
80*635a8641SAndroid Build Coastguard Worker   // will fail. But it is ok as the native thread may never be attached.
81*635a8641SAndroid Build Coastguard Worker   if (g_jvm)
82*635a8641SAndroid Build Coastguard Worker     g_jvm->DetachCurrentThread();
83*635a8641SAndroid Build Coastguard Worker }
84*635a8641SAndroid Build Coastguard Worker 
InitVM(JavaVM * vm)85*635a8641SAndroid Build Coastguard Worker void InitVM(JavaVM* vm) {
86*635a8641SAndroid Build Coastguard Worker   DCHECK(!g_jvm || g_jvm == vm);
87*635a8641SAndroid Build Coastguard Worker   g_jvm = vm;
88*635a8641SAndroid Build Coastguard Worker }
89*635a8641SAndroid Build Coastguard Worker 
IsVMInitialized()90*635a8641SAndroid Build Coastguard Worker bool IsVMInitialized() {
91*635a8641SAndroid Build Coastguard Worker   return g_jvm != NULL;
92*635a8641SAndroid Build Coastguard Worker }
93*635a8641SAndroid Build Coastguard Worker 
InitReplacementClassLoader(JNIEnv * env,const JavaRef<jobject> & class_loader)94*635a8641SAndroid Build Coastguard Worker void InitReplacementClassLoader(JNIEnv* env,
95*635a8641SAndroid Build Coastguard Worker                                 const JavaRef<jobject>& class_loader) {
96*635a8641SAndroid Build Coastguard Worker   DCHECK(g_class_loader.Get().is_null());
97*635a8641SAndroid Build Coastguard Worker   DCHECK(!class_loader.is_null());
98*635a8641SAndroid Build Coastguard Worker 
99*635a8641SAndroid Build Coastguard Worker   ScopedJavaLocalRef<jclass> class_loader_clazz =
100*635a8641SAndroid Build Coastguard Worker       GetClass(env, "java/lang/ClassLoader");
101*635a8641SAndroid Build Coastguard Worker   CHECK(!ClearException(env));
102*635a8641SAndroid Build Coastguard Worker   g_class_loader_load_class_method_id =
103*635a8641SAndroid Build Coastguard Worker       env->GetMethodID(class_loader_clazz.obj(),
104*635a8641SAndroid Build Coastguard Worker                        "loadClass",
105*635a8641SAndroid Build Coastguard Worker                        "(Ljava/lang/String;)Ljava/lang/Class;");
106*635a8641SAndroid Build Coastguard Worker   CHECK(!ClearException(env));
107*635a8641SAndroid Build Coastguard Worker 
108*635a8641SAndroid Build Coastguard Worker   DCHECK(env->IsInstanceOf(class_loader.obj(), class_loader_clazz.obj()));
109*635a8641SAndroid Build Coastguard Worker   g_class_loader.Get().Reset(class_loader);
110*635a8641SAndroid Build Coastguard Worker }
111*635a8641SAndroid Build Coastguard Worker 
GetClass(JNIEnv * env,const char * class_name)112*635a8641SAndroid Build Coastguard Worker ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) {
113*635a8641SAndroid Build Coastguard Worker   jclass clazz;
114*635a8641SAndroid Build Coastguard Worker   if (!g_class_loader.Get().is_null()) {
115*635a8641SAndroid Build Coastguard Worker     // ClassLoader.loadClass expects a classname with components separated by
116*635a8641SAndroid Build Coastguard Worker     // dots instead of the slashes that JNIEnv::FindClass expects. The JNI
117*635a8641SAndroid Build Coastguard Worker     // generator generates names with slashes, so we have to replace them here.
118*635a8641SAndroid Build Coastguard Worker     // TODO(torne): move to an approach where we always use ClassLoader except
119*635a8641SAndroid Build Coastguard Worker     // for the special case of base::android::GetClassLoader(), and change the
120*635a8641SAndroid Build Coastguard Worker     // JNI generator to generate dot-separated names. http://crbug.com/461773
121*635a8641SAndroid Build Coastguard Worker     size_t bufsize = strlen(class_name) + 1;
122*635a8641SAndroid Build Coastguard Worker     char dotted_name[bufsize];
123*635a8641SAndroid Build Coastguard Worker     memmove(dotted_name, class_name, bufsize);
124*635a8641SAndroid Build Coastguard Worker     for (size_t i = 0; i < bufsize; ++i) {
125*635a8641SAndroid Build Coastguard Worker       if (dotted_name[i] == '/') {
126*635a8641SAndroid Build Coastguard Worker         dotted_name[i] = '.';
127*635a8641SAndroid Build Coastguard Worker       }
128*635a8641SAndroid Build Coastguard Worker     }
129*635a8641SAndroid Build Coastguard Worker 
130*635a8641SAndroid Build Coastguard Worker     clazz = static_cast<jclass>(
131*635a8641SAndroid Build Coastguard Worker         env->CallObjectMethod(g_class_loader.Get().obj(),
132*635a8641SAndroid Build Coastguard Worker                               g_class_loader_load_class_method_id,
133*635a8641SAndroid Build Coastguard Worker                               ConvertUTF8ToJavaString(env, dotted_name).obj()));
134*635a8641SAndroid Build Coastguard Worker   } else {
135*635a8641SAndroid Build Coastguard Worker     clazz = env->FindClass(class_name);
136*635a8641SAndroid Build Coastguard Worker   }
137*635a8641SAndroid Build Coastguard Worker   if (ClearException(env) || !clazz) {
138*635a8641SAndroid Build Coastguard Worker     LOG(FATAL) << "Failed to find class " << class_name;
139*635a8641SAndroid Build Coastguard Worker   }
140*635a8641SAndroid Build Coastguard Worker   return ScopedJavaLocalRef<jclass>(env, clazz);
141*635a8641SAndroid Build Coastguard Worker }
142*635a8641SAndroid Build Coastguard Worker 
LazyGetClass(JNIEnv * env,const char * class_name,base::subtle::AtomicWord * atomic_class_id)143*635a8641SAndroid Build Coastguard Worker jclass LazyGetClass(
144*635a8641SAndroid Build Coastguard Worker     JNIEnv* env,
145*635a8641SAndroid Build Coastguard Worker     const char* class_name,
146*635a8641SAndroid Build Coastguard Worker     base::subtle::AtomicWord* atomic_class_id) {
147*635a8641SAndroid Build Coastguard Worker   static_assert(sizeof(subtle::AtomicWord) >= sizeof(jclass),
148*635a8641SAndroid Build Coastguard Worker                 "AtomicWord can't be smaller than jclass");
149*635a8641SAndroid Build Coastguard Worker   subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_class_id);
150*635a8641SAndroid Build Coastguard Worker   if (value)
151*635a8641SAndroid Build Coastguard Worker     return reinterpret_cast<jclass>(value);
152*635a8641SAndroid Build Coastguard Worker   ScopedJavaGlobalRef<jclass> clazz;
153*635a8641SAndroid Build Coastguard Worker   clazz.Reset(GetClass(env, class_name));
154*635a8641SAndroid Build Coastguard Worker   subtle::AtomicWord null_aw = reinterpret_cast<subtle::AtomicWord>(NULL);
155*635a8641SAndroid Build Coastguard Worker   subtle::AtomicWord cas_result = base::subtle::Release_CompareAndSwap(
156*635a8641SAndroid Build Coastguard Worker       atomic_class_id,
157*635a8641SAndroid Build Coastguard Worker       null_aw,
158*635a8641SAndroid Build Coastguard Worker       reinterpret_cast<subtle::AtomicWord>(clazz.obj()));
159*635a8641SAndroid Build Coastguard Worker   if (cas_result == null_aw) {
160*635a8641SAndroid Build Coastguard Worker     // We intentionally leak the global ref since we now storing it as a raw
161*635a8641SAndroid Build Coastguard Worker     // pointer in |atomic_class_id|.
162*635a8641SAndroid Build Coastguard Worker     return clazz.Release();
163*635a8641SAndroid Build Coastguard Worker   } else {
164*635a8641SAndroid Build Coastguard Worker     return reinterpret_cast<jclass>(cas_result);
165*635a8641SAndroid Build Coastguard Worker   }
166*635a8641SAndroid Build Coastguard Worker }
167*635a8641SAndroid Build Coastguard Worker 
168*635a8641SAndroid Build Coastguard Worker template<MethodID::Type type>
Get(JNIEnv * env,jclass clazz,const char * method_name,const char * jni_signature)169*635a8641SAndroid Build Coastguard Worker jmethodID MethodID::Get(JNIEnv* env,
170*635a8641SAndroid Build Coastguard Worker                         jclass clazz,
171*635a8641SAndroid Build Coastguard Worker                         const char* method_name,
172*635a8641SAndroid Build Coastguard Worker                         const char* jni_signature) {
173*635a8641SAndroid Build Coastguard Worker   jmethodID id = type == TYPE_STATIC ?
174*635a8641SAndroid Build Coastguard Worker       env->GetStaticMethodID(clazz, method_name, jni_signature) :
175*635a8641SAndroid Build Coastguard Worker       env->GetMethodID(clazz, method_name, jni_signature);
176*635a8641SAndroid Build Coastguard Worker   if (base::android::ClearException(env) || !id) {
177*635a8641SAndroid Build Coastguard Worker     LOG(FATAL) << "Failed to find " <<
178*635a8641SAndroid Build Coastguard Worker         (type == TYPE_STATIC ? "static " : "") <<
179*635a8641SAndroid Build Coastguard Worker         "method " << method_name << " " << jni_signature;
180*635a8641SAndroid Build Coastguard Worker   }
181*635a8641SAndroid Build Coastguard Worker   return id;
182*635a8641SAndroid Build Coastguard Worker }
183*635a8641SAndroid Build Coastguard Worker 
184*635a8641SAndroid Build Coastguard Worker // If |atomic_method_id| set, it'll return immediately. Otherwise, it'll call
185*635a8641SAndroid Build Coastguard Worker // into ::Get() above. If there's a race, it's ok since the values are the same
186*635a8641SAndroid Build Coastguard Worker // (and the duplicated effort will happen only once).
187*635a8641SAndroid Build Coastguard Worker template<MethodID::Type type>
LazyGet(JNIEnv * env,jclass clazz,const char * method_name,const char * jni_signature,base::subtle::AtomicWord * atomic_method_id)188*635a8641SAndroid Build Coastguard Worker jmethodID MethodID::LazyGet(JNIEnv* env,
189*635a8641SAndroid Build Coastguard Worker                             jclass clazz,
190*635a8641SAndroid Build Coastguard Worker                             const char* method_name,
191*635a8641SAndroid Build Coastguard Worker                             const char* jni_signature,
192*635a8641SAndroid Build Coastguard Worker                             base::subtle::AtomicWord* atomic_method_id) {
193*635a8641SAndroid Build Coastguard Worker   static_assert(sizeof(subtle::AtomicWord) >= sizeof(jmethodID),
194*635a8641SAndroid Build Coastguard Worker                 "AtomicWord can't be smaller than jMethodID");
195*635a8641SAndroid Build Coastguard Worker   subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_method_id);
196*635a8641SAndroid Build Coastguard Worker   if (value)
197*635a8641SAndroid Build Coastguard Worker     return reinterpret_cast<jmethodID>(value);
198*635a8641SAndroid Build Coastguard Worker   jmethodID id = MethodID::Get<type>(env, clazz, method_name, jni_signature);
199*635a8641SAndroid Build Coastguard Worker   base::subtle::Release_Store(
200*635a8641SAndroid Build Coastguard Worker       atomic_method_id, reinterpret_cast<subtle::AtomicWord>(id));
201*635a8641SAndroid Build Coastguard Worker   return id;
202*635a8641SAndroid Build Coastguard Worker }
203*635a8641SAndroid Build Coastguard Worker 
204*635a8641SAndroid Build Coastguard Worker // Various template instantiations.
205*635a8641SAndroid Build Coastguard Worker template jmethodID MethodID::Get<MethodID::TYPE_STATIC>(
206*635a8641SAndroid Build Coastguard Worker     JNIEnv* env, jclass clazz, const char* method_name,
207*635a8641SAndroid Build Coastguard Worker     const char* jni_signature);
208*635a8641SAndroid Build Coastguard Worker 
209*635a8641SAndroid Build Coastguard Worker template jmethodID MethodID::Get<MethodID::TYPE_INSTANCE>(
210*635a8641SAndroid Build Coastguard Worker     JNIEnv* env, jclass clazz, const char* method_name,
211*635a8641SAndroid Build Coastguard Worker     const char* jni_signature);
212*635a8641SAndroid Build Coastguard Worker 
213*635a8641SAndroid Build Coastguard Worker template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>(
214*635a8641SAndroid Build Coastguard Worker     JNIEnv* env, jclass clazz, const char* method_name,
215*635a8641SAndroid Build Coastguard Worker     const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
216*635a8641SAndroid Build Coastguard Worker 
217*635a8641SAndroid Build Coastguard Worker template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>(
218*635a8641SAndroid Build Coastguard Worker     JNIEnv* env, jclass clazz, const char* method_name,
219*635a8641SAndroid Build Coastguard Worker     const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
220*635a8641SAndroid Build Coastguard Worker 
HasException(JNIEnv * env)221*635a8641SAndroid Build Coastguard Worker bool HasException(JNIEnv* env) {
222*635a8641SAndroid Build Coastguard Worker   return env->ExceptionCheck() != JNI_FALSE;
223*635a8641SAndroid Build Coastguard Worker }
224*635a8641SAndroid Build Coastguard Worker 
ClearException(JNIEnv * env)225*635a8641SAndroid Build Coastguard Worker bool ClearException(JNIEnv* env) {
226*635a8641SAndroid Build Coastguard Worker   if (!HasException(env))
227*635a8641SAndroid Build Coastguard Worker     return false;
228*635a8641SAndroid Build Coastguard Worker   env->ExceptionDescribe();
229*635a8641SAndroid Build Coastguard Worker   env->ExceptionClear();
230*635a8641SAndroid Build Coastguard Worker   return true;
231*635a8641SAndroid Build Coastguard Worker }
232*635a8641SAndroid Build Coastguard Worker 
CheckException(JNIEnv * env)233*635a8641SAndroid Build Coastguard Worker void CheckException(JNIEnv* env) {
234*635a8641SAndroid Build Coastguard Worker   if (!HasException(env))
235*635a8641SAndroid Build Coastguard Worker     return;
236*635a8641SAndroid Build Coastguard Worker 
237*635a8641SAndroid Build Coastguard Worker   jthrowable java_throwable = env->ExceptionOccurred();
238*635a8641SAndroid Build Coastguard Worker   if (java_throwable) {
239*635a8641SAndroid Build Coastguard Worker     // Clear the pending exception, since a local reference is now held.
240*635a8641SAndroid Build Coastguard Worker     env->ExceptionDescribe();
241*635a8641SAndroid Build Coastguard Worker     env->ExceptionClear();
242*635a8641SAndroid Build Coastguard Worker 
243*635a8641SAndroid Build Coastguard Worker     if (g_fatal_exception_occurred) {
244*635a8641SAndroid Build Coastguard Worker       // Another exception (probably OOM) occurred during GetJavaExceptionInfo.
245*635a8641SAndroid Build Coastguard Worker       base::android::SetJavaException(
246*635a8641SAndroid Build Coastguard Worker           "Java OOM'ed in exception handling, check logcat");
247*635a8641SAndroid Build Coastguard Worker     } else {
248*635a8641SAndroid Build Coastguard Worker       g_fatal_exception_occurred = true;
249*635a8641SAndroid Build Coastguard Worker       // RVO should avoid any extra copies of the exception string.
250*635a8641SAndroid Build Coastguard Worker       base::android::SetJavaException(
251*635a8641SAndroid Build Coastguard Worker           GetJavaExceptionInfo(env, java_throwable).c_str());
252*635a8641SAndroid Build Coastguard Worker     }
253*635a8641SAndroid Build Coastguard Worker   }
254*635a8641SAndroid Build Coastguard Worker 
255*635a8641SAndroid Build Coastguard Worker   // Now, feel good about it and die.
256*635a8641SAndroid Build Coastguard Worker   // TODO(lhchavez): Remove this hack. See b/28814913 for details.
257*635a8641SAndroid Build Coastguard Worker   if (java_throwable)
258*635a8641SAndroid Build Coastguard Worker     LOG(FATAL) << GetJavaExceptionInfo(env, java_throwable);
259*635a8641SAndroid Build Coastguard Worker   else
260*635a8641SAndroid Build Coastguard Worker     LOG(FATAL) << "Unhandled exception";
261*635a8641SAndroid Build Coastguard Worker }
262*635a8641SAndroid Build Coastguard Worker 
GetJavaExceptionInfo(JNIEnv * env,jthrowable java_throwable)263*635a8641SAndroid Build Coastguard Worker std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
264*635a8641SAndroid Build Coastguard Worker   ScopedJavaLocalRef<jclass> throwable_clazz =
265*635a8641SAndroid Build Coastguard Worker       GetClass(env, "java/lang/Throwable");
266*635a8641SAndroid Build Coastguard Worker   jmethodID throwable_printstacktrace =
267*635a8641SAndroid Build Coastguard Worker       MethodID::Get<MethodID::TYPE_INSTANCE>(
268*635a8641SAndroid Build Coastguard Worker           env, throwable_clazz.obj(), "printStackTrace",
269*635a8641SAndroid Build Coastguard Worker           "(Ljava/io/PrintStream;)V");
270*635a8641SAndroid Build Coastguard Worker 
271*635a8641SAndroid Build Coastguard Worker   // Create an instance of ByteArrayOutputStream.
272*635a8641SAndroid Build Coastguard Worker   ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz =
273*635a8641SAndroid Build Coastguard Worker       GetClass(env, "java/io/ByteArrayOutputStream");
274*635a8641SAndroid Build Coastguard Worker   jmethodID bytearray_output_stream_constructor =
275*635a8641SAndroid Build Coastguard Worker       MethodID::Get<MethodID::TYPE_INSTANCE>(
276*635a8641SAndroid Build Coastguard Worker           env, bytearray_output_stream_clazz.obj(), "<init>", "()V");
277*635a8641SAndroid Build Coastguard Worker   jmethodID bytearray_output_stream_tostring =
278*635a8641SAndroid Build Coastguard Worker       MethodID::Get<MethodID::TYPE_INSTANCE>(
279*635a8641SAndroid Build Coastguard Worker           env, bytearray_output_stream_clazz.obj(), "toString",
280*635a8641SAndroid Build Coastguard Worker           "()Ljava/lang/String;");
281*635a8641SAndroid Build Coastguard Worker   ScopedJavaLocalRef<jobject> bytearray_output_stream(env,
282*635a8641SAndroid Build Coastguard Worker       env->NewObject(bytearray_output_stream_clazz.obj(),
283*635a8641SAndroid Build Coastguard Worker                      bytearray_output_stream_constructor));
284*635a8641SAndroid Build Coastguard Worker   CheckException(env);
285*635a8641SAndroid Build Coastguard Worker 
286*635a8641SAndroid Build Coastguard Worker   // Create an instance of PrintStream.
287*635a8641SAndroid Build Coastguard Worker   ScopedJavaLocalRef<jclass> printstream_clazz =
288*635a8641SAndroid Build Coastguard Worker       GetClass(env, "java/io/PrintStream");
289*635a8641SAndroid Build Coastguard Worker   jmethodID printstream_constructor =
290*635a8641SAndroid Build Coastguard Worker       MethodID::Get<MethodID::TYPE_INSTANCE>(
291*635a8641SAndroid Build Coastguard Worker           env, printstream_clazz.obj(), "<init>",
292*635a8641SAndroid Build Coastguard Worker           "(Ljava/io/OutputStream;)V");
293*635a8641SAndroid Build Coastguard Worker   ScopedJavaLocalRef<jobject> printstream(env,
294*635a8641SAndroid Build Coastguard Worker       env->NewObject(printstream_clazz.obj(), printstream_constructor,
295*635a8641SAndroid Build Coastguard Worker                      bytearray_output_stream.obj()));
296*635a8641SAndroid Build Coastguard Worker   CheckException(env);
297*635a8641SAndroid Build Coastguard Worker 
298*635a8641SAndroid Build Coastguard Worker   // Call Throwable.printStackTrace(PrintStream)
299*635a8641SAndroid Build Coastguard Worker   env->CallVoidMethod(java_throwable, throwable_printstacktrace,
300*635a8641SAndroid Build Coastguard Worker       printstream.obj());
301*635a8641SAndroid Build Coastguard Worker   CheckException(env);
302*635a8641SAndroid Build Coastguard Worker 
303*635a8641SAndroid Build Coastguard Worker   // Call ByteArrayOutputStream.toString()
304*635a8641SAndroid Build Coastguard Worker   ScopedJavaLocalRef<jstring> exception_string(
305*635a8641SAndroid Build Coastguard Worker       env, static_cast<jstring>(
306*635a8641SAndroid Build Coastguard Worker           env->CallObjectMethod(bytearray_output_stream.obj(),
307*635a8641SAndroid Build Coastguard Worker                                 bytearray_output_stream_tostring)));
308*635a8641SAndroid Build Coastguard Worker   CheckException(env);
309*635a8641SAndroid Build Coastguard Worker 
310*635a8641SAndroid Build Coastguard Worker   return ConvertJavaStringToUTF8(exception_string);
311*635a8641SAndroid Build Coastguard Worker }
312*635a8641SAndroid Build Coastguard Worker 
313*635a8641SAndroid Build Coastguard Worker #if BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
314*635a8641SAndroid Build Coastguard Worker 
JNIStackFrameSaver(void * current_fp)315*635a8641SAndroid Build Coastguard Worker JNIStackFrameSaver::JNIStackFrameSaver(void* current_fp) {
316*635a8641SAndroid Build Coastguard Worker   previous_fp_ = g_stack_frame_pointer.Pointer()->Get();
317*635a8641SAndroid Build Coastguard Worker   g_stack_frame_pointer.Pointer()->Set(current_fp);
318*635a8641SAndroid Build Coastguard Worker }
319*635a8641SAndroid Build Coastguard Worker 
~JNIStackFrameSaver()320*635a8641SAndroid Build Coastguard Worker JNIStackFrameSaver::~JNIStackFrameSaver() {
321*635a8641SAndroid Build Coastguard Worker   g_stack_frame_pointer.Pointer()->Set(previous_fp_);
322*635a8641SAndroid Build Coastguard Worker }
323*635a8641SAndroid Build Coastguard Worker 
SavedFrame()324*635a8641SAndroid Build Coastguard Worker void* JNIStackFrameSaver::SavedFrame() {
325*635a8641SAndroid Build Coastguard Worker   return g_stack_frame_pointer.Pointer()->Get();
326*635a8641SAndroid Build Coastguard Worker }
327*635a8641SAndroid Build Coastguard Worker 
328*635a8641SAndroid Build Coastguard Worker #endif  // BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
329*635a8641SAndroid Build Coastguard Worker 
330*635a8641SAndroid Build Coastguard Worker }  // namespace android
331*635a8641SAndroid Build Coastguard Worker }  // namespace base
332