OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "content/browser/renderer_host/java/gin_java_method_invocation_helper.h
" | 5 #include "content/browser/renderer_host/java/gin_java_method_invocation_helper.h
" |
6 | 6 |
7 #include <unistd.h> | 7 #include <unistd.h> |
8 | 8 |
9 #include "base/android/event_log.h" | 9 #include "base/android/event_log.h" |
10 #include "base/android/jni_android.h" | 10 #include "base/android/jni_android.h" |
11 #include "base/android/jni_string.h" | 11 #include "base/android/jni_string.h" |
12 #include "base/float_util.h" | 12 #include "base/float_util.h" |
13 #include "content/browser/renderer_host/java/gin_java_script_to_java_types_coerc
ion.h" | 13 #include "content/browser/renderer_host/java/gin_java_script_to_java_types_coerc
ion.h" |
14 #include "content/browser/renderer_host/java/java_method.h" | 14 #include "content/browser/renderer_host/java/java_method.h" |
15 #include "content/browser/renderer_host/java/jni_helper.h" | 15 #include "content/browser/renderer_host/java/jni_helper.h" |
16 #include "content/common/android/gin_java_bridge_value.h" | 16 #include "content/common/android/gin_java_bridge_value.h" |
17 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
18 | 18 |
19 using base::android::AttachCurrentThread; | 19 using base::android::AttachCurrentThread; |
20 using base::android::ScopedJavaLocalRef; | 20 using base::android::ScopedJavaLocalRef; |
21 | 21 |
22 namespace content { | 22 namespace content { |
23 | 23 |
24 namespace { | 24 namespace { |
25 | 25 |
26 const char kObjectIsGone[] = "Java object is gone"; | |
27 const char kMethodNotFound[] = "Method not found"; | |
28 const char kAccessToObjectGetClassIsBlocked[] = | |
29 "Access to java.lang.Object.getClass is blocked"; | |
30 const char kJavaExceptionRaised[] = | |
31 "Java exception has been raised during method invocation"; | |
32 | |
33 // See frameworks/base/core/java/android/webkit/EventLogTags.logtags | 26 // See frameworks/base/core/java/android/webkit/EventLogTags.logtags |
34 const int kObjectGetClassInvocationAttemptLogTag = 70151; | 27 const int kObjectGetClassInvocationAttemptLogTag = 70151; |
35 | 28 |
36 } // namespace | 29 } // namespace |
37 | 30 |
38 GinJavaMethodInvocationHelper::GinJavaMethodInvocationHelper( | 31 GinJavaMethodInvocationHelper::GinJavaMethodInvocationHelper( |
39 scoped_ptr<ObjectDelegate> object, | 32 scoped_ptr<ObjectDelegate> object, |
40 const std::string& method_name, | 33 const std::string& method_name, |
41 const base::ListValue& arguments) | 34 const base::ListValue& arguments) |
42 : object_(object.Pass()), | 35 : object_(object.Pass()), |
43 method_name_(method_name), | 36 method_name_(method_name), |
44 arguments_(arguments.DeepCopy()) { | 37 arguments_(arguments.DeepCopy()), |
| 38 invocation_error_(kGinJavaBridgeNoError) { |
45 } | 39 } |
46 | 40 |
47 GinJavaMethodInvocationHelper::~GinJavaMethodInvocationHelper() {} | 41 GinJavaMethodInvocationHelper::~GinJavaMethodInvocationHelper() {} |
48 | 42 |
49 void GinJavaMethodInvocationHelper::Init(DispatcherDelegate* dispatcher) { | 43 void GinJavaMethodInvocationHelper::Init(DispatcherDelegate* dispatcher) { |
50 // Build on the UI thread a map of object_id -> WeakRef for Java objects from | 44 // Build on the UI thread a map of object_id -> WeakRef for Java objects from |
51 // |arguments_|. Then we can use this map on the background thread without | 45 // |arguments_|. Then we can use this map on the background thread without |
52 // accessing |dispatcher|. | 46 // accessing |dispatcher|. |
53 BuildObjectRefsFromListValue(dispatcher, arguments_.get()); | 47 BuildObjectRefsFromListValue(dispatcher, arguments_.get()); |
54 } | 48 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 } | 108 } |
115 } | 109 } |
116 return true; | 110 return true; |
117 } | 111 } |
118 | 112 |
119 void GinJavaMethodInvocationHelper::Invoke() { | 113 void GinJavaMethodInvocationHelper::Invoke() { |
120 JNIEnv* env = AttachCurrentThread(); | 114 JNIEnv* env = AttachCurrentThread(); |
121 const JavaMethod* method = | 115 const JavaMethod* method = |
122 object_->FindMethod(method_name_, arguments_->GetSize()); | 116 object_->FindMethod(method_name_, arguments_->GetSize()); |
123 if (!method) { | 117 if (!method) { |
124 SetInvocationFailure(kMethodNotFound); | 118 SetInvocationError(kGinJavaBridgeMethodNotFound); |
125 return; | 119 return; |
126 } | 120 } |
127 | 121 |
128 if (object_->IsObjectGetClassMethod(method)) { | 122 if (object_->IsObjectGetClassMethod(method)) { |
129 base::android::EventLogWriteInt(kObjectGetClassInvocationAttemptLogTag, | 123 base::android::EventLogWriteInt(kObjectGetClassInvocationAttemptLogTag, |
130 getuid()); | 124 getuid()); |
131 SetInvocationFailure(kAccessToObjectGetClassIsBlocked); | 125 SetInvocationError(kGinJavaBridgeAccessToObjectGetClassIsBlocked); |
132 return; | 126 return; |
133 } | 127 } |
134 | 128 |
135 ScopedJavaLocalRef<jobject> obj; | 129 ScopedJavaLocalRef<jobject> obj; |
136 ScopedJavaLocalRef<jclass> cls; | 130 ScopedJavaLocalRef<jclass> cls; |
137 if (method->is_static()) { | 131 if (method->is_static()) { |
138 cls = object_->GetLocalClassRef(env); | 132 cls = object_->GetLocalClassRef(env); |
139 } else { | 133 } else { |
140 obj = object_->GetLocalRef(env); | 134 obj = object_->GetLocalRef(env); |
141 } | 135 } |
142 if (obj.is_null() && cls.is_null()) { | 136 if (obj.is_null() && cls.is_null()) { |
143 SetInvocationFailure(kObjectIsGone); | 137 SetInvocationError(kGinJavaBridgeObjectIsGone); |
144 return; | 138 return; |
145 } | 139 } |
146 | 140 |
147 std::vector<jvalue> parameters(method->num_parameters()); | 141 std::vector<jvalue> parameters(method->num_parameters()); |
148 for (size_t i = 0; i < method->num_parameters(); ++i) { | 142 for (size_t i = 0; i < method->num_parameters(); ++i) { |
149 const base::Value* argument; | 143 const base::Value* argument; |
150 arguments_->Get(i, &argument); | 144 arguments_->Get(i, &argument); |
151 parameters[i] = CoerceJavaScriptValueToJavaValue( | 145 parameters[i] = CoerceJavaScriptValueToJavaValue( |
152 env, argument, method->parameter_type(i), true, object_refs_); | 146 env, argument, method->parameter_type(i), true, object_refs_); |
153 } | 147 } |
154 if (method->is_static()) { | 148 if (method->is_static()) { |
155 InvokeMethod( | 149 InvokeMethod( |
156 NULL, cls.obj(), method->return_type(), method->id(), ¶meters[0]); | 150 NULL, cls.obj(), method->return_type(), method->id(), ¶meters[0]); |
157 } else { | 151 } else { |
158 InvokeMethod( | 152 InvokeMethod( |
159 obj.obj(), NULL, method->return_type(), method->id(), ¶meters[0]); | 153 obj.obj(), NULL, method->return_type(), method->id(), ¶meters[0]); |
160 } | 154 } |
161 | 155 |
162 // Now that we're done with the jvalue, release any local references created | 156 // Now that we're done with the jvalue, release any local references created |
163 // by CoerceJavaScriptValueToJavaValue(). | 157 // by CoerceJavaScriptValueToJavaValue(). |
164 for (size_t i = 0; i < method->num_parameters(); ++i) { | 158 for (size_t i = 0; i < method->num_parameters(); ++i) { |
165 ReleaseJavaValueIfRequired(env, ¶meters[i], method->parameter_type(i)); | 159 ReleaseJavaValueIfRequired(env, ¶meters[i], method->parameter_type(i)); |
166 } | 160 } |
167 } | 161 } |
168 | 162 |
169 void GinJavaMethodInvocationHelper::SetInvocationFailure( | 163 void GinJavaMethodInvocationHelper::SetInvocationError( |
170 const char* error_message) { | 164 GinJavaBridgeError error) { |
171 holds_primitive_result_ = true; | 165 holds_primitive_result_ = true; |
172 primitive_result_.reset(new base::ListValue()); | 166 primitive_result_.reset(new base::ListValue()); |
173 error_message_ = error_message; | 167 invocation_error_ = error; |
174 } | 168 } |
175 | 169 |
176 void GinJavaMethodInvocationHelper::SetPrimitiveResult( | 170 void GinJavaMethodInvocationHelper::SetPrimitiveResult( |
177 const base::ListValue& result_wrapper) { | 171 const base::ListValue& result_wrapper) { |
178 holds_primitive_result_ = true; | 172 holds_primitive_result_ = true; |
179 primitive_result_.reset(result_wrapper.DeepCopy()); | 173 primitive_result_.reset(result_wrapper.DeepCopy()); |
180 } | 174 } |
181 | 175 |
182 void GinJavaMethodInvocationHelper::SetObjectResult( | 176 void GinJavaMethodInvocationHelper::SetObjectResult( |
183 const base::android::JavaRef<jobject>& object, | 177 const base::android::JavaRef<jobject>& object, |
(...skipping 14 matching lines...) Expand all Loading... |
198 const base::android::JavaRef<jobject>& | 192 const base::android::JavaRef<jobject>& |
199 GinJavaMethodInvocationHelper::GetObjectResult() { | 193 GinJavaMethodInvocationHelper::GetObjectResult() { |
200 return object_result_; | 194 return object_result_; |
201 } | 195 } |
202 | 196 |
203 const base::android::JavaRef<jclass>& | 197 const base::android::JavaRef<jclass>& |
204 GinJavaMethodInvocationHelper::GetSafeAnnotationClass() { | 198 GinJavaMethodInvocationHelper::GetSafeAnnotationClass() { |
205 return safe_annotation_clazz_; | 199 return safe_annotation_clazz_; |
206 } | 200 } |
207 | 201 |
208 const std::string& GinJavaMethodInvocationHelper::GetErrorMessage() { | 202 const GinJavaBridgeError GinJavaMethodInvocationHelper::GetInvocationError() { |
209 return error_message_; | 203 return invocation_error_; |
210 } | 204 } |
211 | 205 |
212 void GinJavaMethodInvocationHelper::InvokeMethod(jobject object, | 206 void GinJavaMethodInvocationHelper::InvokeMethod(jobject object, |
213 jclass clazz, | 207 jclass clazz, |
214 const JavaType& return_type, | 208 const JavaType& return_type, |
215 jmethodID id, | 209 jmethodID id, |
216 jvalue* parameters) { | 210 jvalue* parameters) { |
217 DCHECK(object || clazz); | 211 DCHECK(object || clazz); |
218 JNIEnv* env = AttachCurrentThread(); | 212 JNIEnv* env = AttachCurrentThread(); |
219 base::ListValue result_wrapper; | 213 base::ListValue result_wrapper; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 GinJavaBridgeValue::CreateUndefinedValue().release()); | 282 GinJavaBridgeValue::CreateUndefinedValue().release()); |
289 break; | 283 break; |
290 case JavaType::TypeString: { | 284 case JavaType::TypeString: { |
291 jstring java_string = static_cast<jstring>( | 285 jstring java_string = static_cast<jstring>( |
292 object ? env->CallObjectMethodA(object, id, parameters) | 286 object ? env->CallObjectMethodA(object, id, parameters) |
293 : env->CallStaticObjectMethodA(clazz, id, parameters)); | 287 : env->CallStaticObjectMethodA(clazz, id, parameters)); |
294 // If an exception was raised, we must clear it before calling most JNI | 288 // If an exception was raised, we must clear it before calling most JNI |
295 // methods. ScopedJavaLocalRef is liable to make such calls, so we test | 289 // methods. ScopedJavaLocalRef is liable to make such calls, so we test |
296 // first. | 290 // first. |
297 if (base::android::ClearException(env)) { | 291 if (base::android::ClearException(env)) { |
298 SetInvocationFailure(kJavaExceptionRaised); | 292 SetInvocationError(kGinJavaBridgeJavaExceptionRaised); |
299 return; | 293 return; |
300 } | 294 } |
301 ScopedJavaLocalRef<jstring> scoped_java_string(env, java_string); | 295 ScopedJavaLocalRef<jstring> scoped_java_string(env, java_string); |
302 if (!scoped_java_string.obj()) { | 296 if (!scoped_java_string.obj()) { |
303 // LIVECONNECT_COMPLIANCE: Existing behavior is to return undefined. | 297 // LIVECONNECT_COMPLIANCE: Existing behavior is to return undefined. |
304 // Spec requires returning a null string. | 298 // Spec requires returning a null string. |
305 result_wrapper.Append( | 299 result_wrapper.Append( |
306 GinJavaBridgeValue::CreateUndefinedValue().release()); | 300 GinJavaBridgeValue::CreateUndefinedValue().release()); |
307 break; | 301 break; |
308 } | 302 } |
309 result_wrapper.AppendString( | 303 result_wrapper.AppendString( |
310 base::android::ConvertJavaStringToUTF8(scoped_java_string)); | 304 base::android::ConvertJavaStringToUTF8(scoped_java_string)); |
311 break; | 305 break; |
312 } | 306 } |
313 case JavaType::TypeObject: { | 307 case JavaType::TypeObject: { |
314 // If an exception was raised, we must clear it before calling most JNI | 308 // If an exception was raised, we must clear it before calling most JNI |
315 // methods. ScopedJavaLocalRef is liable to make such calls, so we test | 309 // methods. ScopedJavaLocalRef is liable to make such calls, so we test |
316 // first. | 310 // first. |
317 jobject java_object = | 311 jobject java_object = |
318 object ? env->CallObjectMethodA(object, id, parameters) | 312 object ? env->CallObjectMethodA(object, id, parameters) |
319 : env->CallStaticObjectMethodA(clazz, id, parameters); | 313 : env->CallStaticObjectMethodA(clazz, id, parameters); |
320 if (base::android::ClearException(env)) { | 314 if (base::android::ClearException(env)) { |
321 SetInvocationFailure(kJavaExceptionRaised); | 315 SetInvocationError(kGinJavaBridgeJavaExceptionRaised); |
322 return; | 316 return; |
323 } | 317 } |
324 ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object); | 318 ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object); |
325 if (!scoped_java_object.obj()) { | 319 if (!scoped_java_object.obj()) { |
326 result_wrapper.Append(base::Value::CreateNullValue()); | 320 result_wrapper.Append(base::Value::CreateNullValue()); |
327 break; | 321 break; |
328 } | 322 } |
329 SetObjectResult(scoped_java_object, object_->GetSafeAnnotationClass()); | 323 SetObjectResult(scoped_java_object, object_->GetSafeAnnotationClass()); |
330 return; | 324 return; |
331 } | 325 } |
332 } | 326 } |
333 // This is for all cases except JavaType::TypeObject. | 327 // This is for all cases except JavaType::TypeObject. |
334 if (!base::android::ClearException(env)) { | 328 if (!base::android::ClearException(env)) { |
335 SetPrimitiveResult(result_wrapper); | 329 SetPrimitiveResult(result_wrapper); |
336 } else { | 330 } else { |
337 SetInvocationFailure(kJavaExceptionRaised); | 331 SetInvocationError(kGinJavaBridgeJavaExceptionRaised); |
338 } | 332 } |
339 } | 333 } |
340 | 334 |
341 } // namespace content | 335 } // namespace content |
OLD | NEW |