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