Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / base / android / jni_android.cc
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
3 // found in the LICENSE file.
4
5 #include "base/android/jni_android.h"
6
7 #include <map>
8
9 #include "base/android/build_info.h"
10 #include "base/android/jni_string.h"
11 #include "base/lazy_instance.h"
12 #include "base/logging.h"
13
14 namespace {
15 using base::android::GetClass;
16 using base::android::MethodID;
17 using base::android::ScopedJavaLocalRef;
18
19 JavaVM* g_jvm = NULL;
20 // Leak the global app context, as it is used from a non-joinable worker thread
21 // that may still be running at shutdown. There is no harm in doing this.
22 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
23     g_application_context = LAZY_INSTANCE_INITIALIZER;
24
25 std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
26   ScopedJavaLocalRef<jclass> throwable_clazz =
27       GetClass(env, "java/lang/Throwable");
28   jmethodID throwable_printstacktrace =
29       MethodID::Get<MethodID::TYPE_INSTANCE>(
30           env, throwable_clazz.obj(), "printStackTrace",
31           "(Ljava/io/PrintStream;)V");
32
33   // Create an instance of ByteArrayOutputStream.
34   ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz =
35       GetClass(env, "java/io/ByteArrayOutputStream");
36   jmethodID bytearray_output_stream_constructor =
37       MethodID::Get<MethodID::TYPE_INSTANCE>(
38           env, bytearray_output_stream_clazz.obj(), "<init>", "()V");
39   jmethodID bytearray_output_stream_tostring =
40       MethodID::Get<MethodID::TYPE_INSTANCE>(
41           env, bytearray_output_stream_clazz.obj(), "toString",
42           "()Ljava/lang/String;");
43   ScopedJavaLocalRef<jobject> bytearray_output_stream(env,
44       env->NewObject(bytearray_output_stream_clazz.obj(),
45                      bytearray_output_stream_constructor));
46
47   // Create an instance of PrintStream.
48   ScopedJavaLocalRef<jclass> printstream_clazz =
49       GetClass(env, "java/io/PrintStream");
50   jmethodID printstream_constructor =
51       MethodID::Get<MethodID::TYPE_INSTANCE>(
52           env, printstream_clazz.obj(), "<init>",
53           "(Ljava/io/OutputStream;)V");
54   ScopedJavaLocalRef<jobject> printstream(env,
55       env->NewObject(printstream_clazz.obj(), printstream_constructor,
56                      bytearray_output_stream.obj()));
57
58   // Call Throwable.printStackTrace(PrintStream)
59   env->CallVoidMethod(java_throwable, throwable_printstacktrace,
60       printstream.obj());
61
62   // Call ByteArrayOutputStream.toString()
63   ScopedJavaLocalRef<jstring> exception_string(
64       env, static_cast<jstring>(
65           env->CallObjectMethod(bytearray_output_stream.obj(),
66                                 bytearray_output_stream_tostring)));
67
68   return ConvertJavaStringToUTF8(exception_string);
69 }
70
71 }  // namespace
72
73 namespace base {
74 namespace android {
75
76 JNIEnv* AttachCurrentThread() {
77   DCHECK(g_jvm);
78   JNIEnv* env = NULL;
79   jint ret = g_jvm->AttachCurrentThread(&env, NULL);
80   DCHECK_EQ(JNI_OK, ret);
81   return env;
82 }
83
84 JNIEnv* AttachCurrentThreadWithName(const std::string& thread_name) {
85   DCHECK(g_jvm);
86   JavaVMAttachArgs args;
87   args.version = JNI_VERSION_1_2;
88   args.name = thread_name.c_str();
89   args.group = NULL;
90   JNIEnv* env = NULL;
91   jint ret = g_jvm->AttachCurrentThread(&env, &args);
92   DCHECK_EQ(JNI_OK, ret);
93   return env;
94 }
95
96 void DetachFromVM() {
97   // Ignore the return value, if the thread is not attached, DetachCurrentThread
98   // will fail. But it is ok as the native thread may never be attached.
99   if (g_jvm)
100     g_jvm->DetachCurrentThread();
101 }
102
103 void InitVM(JavaVM* vm) {
104   DCHECK(!g_jvm);
105   g_jvm = vm;
106 }
107
108 bool IsVMInitialized() {
109   return g_jvm != NULL;
110 }
111
112 void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) {
113   if (env->IsSameObject(g_application_context.Get().obj(), context.obj())) {
114     // It's safe to set the context more than once if it's the same context.
115     return;
116   }
117   DCHECK(g_application_context.Get().is_null());
118   g_application_context.Get().Reset(context);
119 }
120
121 const jobject GetApplicationContext() {
122   DCHECK(!g_application_context.Get().is_null());
123   return g_application_context.Get().obj();
124 }
125
126 ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) {
127   jclass clazz = env->FindClass(class_name);
128   CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name;
129   return ScopedJavaLocalRef<jclass>(env, clazz);
130 }
131
132 template<MethodID::Type type>
133 jmethodID MethodID::Get(JNIEnv* env,
134                         jclass clazz,
135                         const char* method_name,
136                         const char* jni_signature) {
137   jmethodID id = type == TYPE_STATIC ?
138       env->GetStaticMethodID(clazz, method_name, jni_signature) :
139       env->GetMethodID(clazz, method_name, jni_signature);
140   CHECK(base::android::ClearException(env) || id) <<
141       "Failed to find " <<
142       (type == TYPE_STATIC ? "static " : "") <<
143       "method " << method_name << " " << jni_signature;
144   return id;
145 }
146
147 // If |atomic_method_id| set, it'll return immediately. Otherwise, it'll call
148 // into ::Get() above. If there's a race, it's ok since the values are the same
149 // (and the duplicated effort will happen only once).
150 template<MethodID::Type type>
151 jmethodID MethodID::LazyGet(JNIEnv* env,
152                             jclass clazz,
153                             const char* method_name,
154                             const char* jni_signature,
155                             base::subtle::AtomicWord* atomic_method_id) {
156   COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jmethodID),
157                  AtomicWord_SmallerThan_jMethodID);
158   subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_method_id);
159   if (value)
160     return reinterpret_cast<jmethodID>(value);
161   jmethodID id = MethodID::Get<type>(env, clazz, method_name, jni_signature);
162   base::subtle::Release_Store(
163       atomic_method_id, reinterpret_cast<subtle::AtomicWord>(id));
164   return id;
165 }
166
167 // Various template instantiations.
168 template jmethodID MethodID::Get<MethodID::TYPE_STATIC>(
169     JNIEnv* env, jclass clazz, const char* method_name,
170     const char* jni_signature);
171
172 template jmethodID MethodID::Get<MethodID::TYPE_INSTANCE>(
173     JNIEnv* env, jclass clazz, const char* method_name,
174     const char* jni_signature);
175
176 template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>(
177     JNIEnv* env, jclass clazz, const char* method_name,
178     const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
179
180 template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>(
181     JNIEnv* env, jclass clazz, const char* method_name,
182     const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
183
184 bool HasException(JNIEnv* env) {
185   return env->ExceptionCheck() != JNI_FALSE;
186 }
187
188 bool ClearException(JNIEnv* env) {
189   if (!HasException(env))
190     return false;
191   env->ExceptionDescribe();
192   env->ExceptionClear();
193   return true;
194 }
195
196 void CheckException(JNIEnv* env) {
197   if (!HasException(env)) return;
198
199   // Exception has been found, might as well tell breakpad about it.
200   jthrowable java_throwable = env->ExceptionOccurred();
201   if (!java_throwable) {
202     // Do nothing but return false.
203     CHECK(false);
204   }
205
206   // Clear the pending exception, since a local reference is now held.
207   env->ExceptionDescribe();
208   env->ExceptionClear();
209
210   // Set the exception_string in BuildInfo so that breakpad can read it.
211   // RVO should avoid any extra copies of the exception string.
212   base::android::BuildInfo::GetInstance()->set_java_exception_info(
213       GetJavaExceptionInfo(env, java_throwable));
214
215   // Now, feel good about it and die.
216   CHECK(false);
217 }
218
219 }  // namespace android
220 }  // namespace base