| 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 |