• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/fml/platform/android/jni_util.h"
6 
7 #include <codecvt>
8 #include <string>
9 
10 #include "flutter/fml/logging.h"
11 
12 namespace fml {
13 namespace jni {
14 
15 static JavaVM* g_jvm = nullptr;
16 
17 #define ASSERT_NO_EXCEPTION() FML_CHECK(env->ExceptionCheck() == JNI_FALSE);
18 
InitJavaVM(JavaVM * vm)19 void InitJavaVM(JavaVM* vm) {
20   FML_DCHECK(g_jvm == nullptr);
21   g_jvm = vm;
22 }
23 
AttachCurrentThread()24 JNIEnv* AttachCurrentThread() {
25   FML_DCHECK(g_jvm != nullptr)
26       << "Trying to attach to current thread without calling InitJavaVM first.";
27   JNIEnv* env = nullptr;
28   jint ret = g_jvm->AttachCurrentThread(&env, nullptr);
29   FML_DCHECK(JNI_OK == ret);
30   return env;
31 }
32 
DetachFromVM()33 void DetachFromVM() {
34   if (g_jvm) {
35     g_jvm->DetachCurrentThread();
36   }
37 }
38 
UTF16StringToUTF8String(const char16_t * chars,size_t len)39 static std::string UTF16StringToUTF8String(const char16_t* chars, size_t len) {
40   std::u16string u16_string(chars, len);
41   return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
42       .to_bytes(u16_string);
43 }
44 
JavaStringToString(JNIEnv * env,jstring str)45 std::string JavaStringToString(JNIEnv* env, jstring str) {
46   if (env == nullptr || str == nullptr) {
47     return "";
48   }
49   const jchar* chars = env->GetStringChars(str, NULL);
50   if (chars == nullptr) {
51     return "";
52   }
53   std::string u8_string = UTF16StringToUTF8String(
54       reinterpret_cast<const char16_t*>(chars), env->GetStringLength(str));
55   env->ReleaseStringChars(str, chars);
56   ASSERT_NO_EXCEPTION();
57   return u8_string;
58 }
59 
UTF8StringToUTF16String(const std::string & string)60 static std::u16string UTF8StringToUTF16String(const std::string& string) {
61   return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
62       .from_bytes(string);
63 }
64 
StringToJavaString(JNIEnv * env,const std::string & u8_string)65 ScopedJavaLocalRef<jstring> StringToJavaString(JNIEnv* env,
66                                                const std::string& u8_string) {
67   std::u16string u16_string = UTF8StringToUTF16String(u8_string);
68   auto result = ScopedJavaLocalRef<jstring>(
69       env, env->NewString(reinterpret_cast<const jchar*>(u16_string.data()),
70                           u16_string.length()));
71   ASSERT_NO_EXCEPTION();
72   return result;
73 }
74 
StringArrayToVector(JNIEnv * env,jobjectArray array)75 std::vector<std::string> StringArrayToVector(JNIEnv* env, jobjectArray array) {
76   std::vector<std::string> out;
77   if (env == nullptr || array == nullptr) {
78     return out;
79   }
80 
81   jsize length = env->GetArrayLength(array);
82 
83   if (length == -1) {
84     return out;
85   }
86 
87   out.resize(length);
88   for (jsize i = 0; i < length; ++i) {
89     ScopedJavaLocalRef<jstring> java_string(
90         env, static_cast<jstring>(env->GetObjectArrayElement(array, i)));
91     out[i] = JavaStringToString(env, java_string.obj());
92   }
93 
94   return out;
95 }
96 
VectorToStringArray(JNIEnv * env,const std::vector<std::string> & vector)97 ScopedJavaLocalRef<jobjectArray> VectorToStringArray(
98     JNIEnv* env,
99     const std::vector<std::string>& vector) {
100   FML_DCHECK(env);
101   ScopedJavaLocalRef<jclass> string_clazz(env,
102                                           env->FindClass("java/lang/String"));
103   FML_DCHECK(!string_clazz.is_null());
104   jobjectArray joa =
105       env->NewObjectArray(vector.size(), string_clazz.obj(), NULL);
106   ASSERT_NO_EXCEPTION();
107   for (size_t i = 0; i < vector.size(); ++i) {
108     ScopedJavaLocalRef<jstring> item = StringToJavaString(env, vector[i]);
109     env->SetObjectArrayElement(joa, i, item.obj());
110   }
111   return ScopedJavaLocalRef<jobjectArray>(env, joa);
112 }
113 
HasException(JNIEnv * env)114 bool HasException(JNIEnv* env) {
115   return env->ExceptionCheck() != JNI_FALSE;
116 }
117 
ClearException(JNIEnv * env)118 bool ClearException(JNIEnv* env) {
119   if (!HasException(env))
120     return false;
121   env->ExceptionDescribe();
122   env->ExceptionClear();
123   return true;
124 }
125 
GetJavaExceptionInfo(JNIEnv * env,jthrowable java_throwable)126 std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
127   ScopedJavaLocalRef<jclass> throwable_clazz(
128       env, env->FindClass("java/lang/Throwable"));
129   jmethodID throwable_printstacktrace = env->GetMethodID(
130       throwable_clazz.obj(), "printStackTrace", "(Ljava/io/PrintStream;)V");
131 
132   // Create an instance of ByteArrayOutputStream.
133   ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz(
134       env, env->FindClass("java/io/ByteArrayOutputStream"));
135   jmethodID bytearray_output_stream_constructor =
136       env->GetMethodID(bytearray_output_stream_clazz.obj(), "<init>", "()V");
137   jmethodID bytearray_output_stream_tostring = env->GetMethodID(
138       bytearray_output_stream_clazz.obj(), "toString", "()Ljava/lang/String;");
139   ScopedJavaLocalRef<jobject> bytearray_output_stream(
140       env, env->NewObject(bytearray_output_stream_clazz.obj(),
141                           bytearray_output_stream_constructor));
142 
143   // Create an instance of PrintStream.
144   ScopedJavaLocalRef<jclass> printstream_clazz(
145       env, env->FindClass("java/io/PrintStream"));
146   jmethodID printstream_constructor = env->GetMethodID(
147       printstream_clazz.obj(), "<init>", "(Ljava/io/OutputStream;)V");
148   ScopedJavaLocalRef<jobject> printstream(
149       env, env->NewObject(printstream_clazz.obj(), printstream_constructor,
150                           bytearray_output_stream.obj()));
151 
152   // Call Throwable.printStackTrace(PrintStream)
153   env->CallVoidMethod(java_throwable, throwable_printstacktrace,
154                       printstream.obj());
155 
156   // Call ByteArrayOutputStream.toString()
157   ScopedJavaLocalRef<jstring> exception_string(
158       env,
159       static_cast<jstring>(env->CallObjectMethod(
160           bytearray_output_stream.obj(), bytearray_output_stream_tostring)));
161   if (ClearException(env)) {
162     return "Java OOM'd in exception handling, check logcat";
163   }
164 
165   return JavaStringToString(env, exception_string.obj());
166 }
167 
168 }  // namespace jni
169 }  // namespace fml
170