| 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" |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 if (!object_ref.is_empty()) { | 111 if (!object_ref.is_empty()) { |
| 112 object_refs_.insert(std::make_pair(object_id, object_ref)); | 112 object_refs_.insert(std::make_pair(object_id, object_ref)); |
| 113 } | 113 } |
| 114 } | 114 } |
| 115 } | 115 } |
| 116 return true; | 116 return true; |
| 117 } | 117 } |
| 118 | 118 |
| 119 void GinJavaMethodInvocationHelper::Invoke() { | 119 void GinJavaMethodInvocationHelper::Invoke() { |
| 120 JNIEnv* env = AttachCurrentThread(); | 120 JNIEnv* env = AttachCurrentThread(); |
| 121 ScopedJavaLocalRef<jobject> obj(object_->GetLocalRef(env)); | |
| 122 if (obj.is_null()) { | |
| 123 SetInvocationFailure(kObjectIsGone); | |
| 124 return; | |
| 125 } | |
| 126 const JavaMethod* method = | 121 const JavaMethod* method = |
| 127 object_->FindMethod(method_name_, arguments_->GetSize()); | 122 object_->FindMethod(method_name_, arguments_->GetSize()); |
| 128 if (!method) { | 123 if (!method) { |
| 129 SetInvocationFailure(kMethodNotFound); | 124 SetInvocationFailure(kMethodNotFound); |
| 130 return; | 125 return; |
| 131 } | 126 } |
| 132 | 127 |
| 133 if (object_->IsObjectGetClassMethod(method)) { | 128 if (object_->IsObjectGetClassMethod(method)) { |
| 134 base::android::EventLogWriteInt(kObjectGetClassInvocationAttemptLogTag, | 129 base::android::EventLogWriteInt(kObjectGetClassInvocationAttemptLogTag, |
| 135 getuid()); | 130 getuid()); |
| 136 SetInvocationFailure(kAccessToObjectGetClassIsBlocked); | 131 SetInvocationFailure(kAccessToObjectGetClassIsBlocked); |
| 137 return; | 132 return; |
| 138 } | 133 } |
| 139 | 134 |
| 135 ScopedJavaLocalRef<jobject> obj; |
| 136 ScopedJavaLocalRef<jclass> cls; |
| 137 if (method->is_static()) { |
| 138 cls = object_->GetLocalClassRef(env); |
| 139 } else { |
| 140 obj = object_->GetLocalRef(env); |
| 141 } |
| 142 if (obj.is_null() && cls.is_null()) { |
| 143 SetInvocationFailure(kObjectIsGone); |
| 144 return; |
| 145 } |
| 146 |
| 140 std::vector<jvalue> parameters(method->num_parameters()); | 147 std::vector<jvalue> parameters(method->num_parameters()); |
| 141 for (size_t i = 0; i < method->num_parameters(); ++i) { | 148 for (size_t i = 0; i < method->num_parameters(); ++i) { |
| 142 const base::Value* argument; | 149 const base::Value* argument; |
| 143 arguments_->Get(i, &argument); | 150 arguments_->Get(i, &argument); |
| 144 parameters[i] = CoerceJavaScriptValueToJavaValue( | 151 parameters[i] = CoerceJavaScriptValueToJavaValue( |
| 145 env, argument, method->parameter_type(i), true, object_refs_); | 152 env, argument, method->parameter_type(i), true, object_refs_); |
| 146 } | 153 } |
| 147 InvokeMethod(obj.obj(), method->return_type(), method->id(), ¶meters[0]); | 154 if (method->is_static()) { |
| 155 InvokeMethod( |
| 156 NULL, cls.obj(), method->return_type(), method->id(), ¶meters[0]); |
| 157 } else { |
| 158 InvokeMethod( |
| 159 obj.obj(), NULL, method->return_type(), method->id(), ¶meters[0]); |
| 160 } |
| 148 | 161 |
| 149 // Now that we're done with the jvalue, release any local references created | 162 // Now that we're done with the jvalue, release any local references created |
| 150 // by CoerceJavaScriptValueToJavaValue(). | 163 // by CoerceJavaScriptValueToJavaValue(). |
| 151 for (size_t i = 0; i < method->num_parameters(); ++i) { | 164 for (size_t i = 0; i < method->num_parameters(); ++i) { |
| 152 ReleaseJavaValueIfRequired(env, ¶meters[i], method->parameter_type(i)); | 165 ReleaseJavaValueIfRequired(env, ¶meters[i], method->parameter_type(i)); |
| 153 } | 166 } |
| 154 } | 167 } |
| 155 | 168 |
| 156 void GinJavaMethodInvocationHelper::SetInvocationFailure( | 169 void GinJavaMethodInvocationHelper::SetInvocationFailure( |
| 157 const char* error_message) { | 170 const char* error_message) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 const base::android::JavaRef<jclass>& | 203 const base::android::JavaRef<jclass>& |
| 191 GinJavaMethodInvocationHelper::GetSafeAnnotationClass() { | 204 GinJavaMethodInvocationHelper::GetSafeAnnotationClass() { |
| 192 return safe_annotation_clazz_; | 205 return safe_annotation_clazz_; |
| 193 } | 206 } |
| 194 | 207 |
| 195 const std::string& GinJavaMethodInvocationHelper::GetErrorMessage() { | 208 const std::string& GinJavaMethodInvocationHelper::GetErrorMessage() { |
| 196 return error_message_; | 209 return error_message_; |
| 197 } | 210 } |
| 198 | 211 |
| 199 void GinJavaMethodInvocationHelper::InvokeMethod(jobject object, | 212 void GinJavaMethodInvocationHelper::InvokeMethod(jobject object, |
| 213 jclass clazz, |
| 200 const JavaType& return_type, | 214 const JavaType& return_type, |
| 201 jmethodID id, | 215 jmethodID id, |
| 202 jvalue* parameters) { | 216 jvalue* parameters) { |
| 217 DCHECK(object || clazz); |
| 203 JNIEnv* env = AttachCurrentThread(); | 218 JNIEnv* env = AttachCurrentThread(); |
| 204 base::ListValue result_wrapper; | 219 base::ListValue result_wrapper; |
| 205 switch (return_type.type) { | 220 switch (return_type.type) { |
| 206 case JavaType::TypeBoolean: | 221 case JavaType::TypeBoolean: |
| 207 result_wrapper.AppendBoolean( | 222 result_wrapper.AppendBoolean( |
| 208 env->CallBooleanMethodA(object, id, parameters)); | 223 object ? env->CallBooleanMethodA(object, id, parameters) |
| 224 : env->CallStaticBooleanMethodA(clazz, id, parameters)); |
| 209 break; | 225 break; |
| 210 case JavaType::TypeByte: | 226 case JavaType::TypeByte: |
| 211 result_wrapper.AppendInteger( | 227 result_wrapper.AppendInteger( |
| 212 env->CallByteMethodA(object, id, parameters)); | 228 object ? env->CallByteMethodA(object, id, parameters) |
| 229 : env->CallStaticByteMethodA(clazz, id, parameters)); |
| 213 break; | 230 break; |
| 214 case JavaType::TypeChar: | 231 case JavaType::TypeChar: |
| 215 result_wrapper.AppendInteger( | 232 result_wrapper.AppendInteger( |
| 216 env->CallCharMethodA(object, id, parameters)); | 233 object ? env->CallCharMethodA(object, id, parameters) |
| 234 : env->CallStaticCharMethodA(clazz, id, parameters)); |
| 217 break; | 235 break; |
| 218 case JavaType::TypeShort: | 236 case JavaType::TypeShort: |
| 219 result_wrapper.AppendInteger( | 237 result_wrapper.AppendInteger( |
| 220 env->CallShortMethodA(object, id, parameters)); | 238 object ? env->CallShortMethodA(object, id, parameters) |
| 239 : env->CallStaticShortMethodA(clazz, id, parameters)); |
| 221 break; | 240 break; |
| 222 case JavaType::TypeInt: | 241 case JavaType::TypeInt: |
| 223 result_wrapper.AppendInteger( | 242 result_wrapper.AppendInteger( |
| 224 env->CallIntMethodA(object, id, parameters)); | 243 object ? env->CallIntMethodA(object, id, parameters) |
| 244 : env->CallStaticIntMethodA(clazz, id, parameters)); |
| 225 break; | 245 break; |
| 226 case JavaType::TypeLong: | 246 case JavaType::TypeLong: |
| 227 result_wrapper.AppendDouble( | 247 result_wrapper.AppendDouble( |
| 228 env->CallLongMethodA(object, id, parameters)); | 248 object ? env->CallLongMethodA(object, id, parameters) |
| 249 : env->CallStaticLongMethodA(clazz, id, parameters)); |
| 229 break; | 250 break; |
| 230 case JavaType::TypeFloat: { | 251 case JavaType::TypeFloat: { |
| 231 float result = env->CallFloatMethodA(object, id, parameters); | 252 float result = object |
| 253 ? env->CallFloatMethodA(object, id, parameters) |
| 254 : env->CallStaticFloatMethodA(clazz, id, parameters); |
| 232 if (base::IsFinite(result)) { | 255 if (base::IsFinite(result)) { |
| 233 result_wrapper.AppendDouble(result); | 256 result_wrapper.AppendDouble(result); |
| 234 } else { | 257 } else { |
| 235 result_wrapper.Append( | 258 result_wrapper.Append( |
| 236 GinJavaBridgeValue::CreateNonFiniteValue(result).release()); | 259 GinJavaBridgeValue::CreateNonFiniteValue(result).release()); |
| 237 } | 260 } |
| 238 break; | 261 break; |
| 239 } | 262 } |
| 240 case JavaType::TypeDouble: { | 263 case JavaType::TypeDouble: { |
| 241 double result = env->CallDoubleMethodA(object, id, parameters); | 264 double result = object |
| 265 ? env->CallDoubleMethodA(object, id, parameters) |
| 266 : env->CallStaticDoubleMethodA(clazz, id, parameters); |
| 242 if (base::IsFinite(result)) { | 267 if (base::IsFinite(result)) { |
| 243 result_wrapper.AppendDouble(result); | 268 result_wrapper.AppendDouble(result); |
| 244 } else { | 269 } else { |
| 245 result_wrapper.Append( | 270 result_wrapper.Append( |
| 246 GinJavaBridgeValue::CreateNonFiniteValue(result).release()); | 271 GinJavaBridgeValue::CreateNonFiniteValue(result).release()); |
| 247 } | 272 } |
| 248 break; | 273 break; |
| 249 } | 274 } |
| 250 case JavaType::TypeVoid: | 275 case JavaType::TypeVoid: |
| 251 env->CallVoidMethodA(object, id, parameters); | 276 if (object) |
| 277 env->CallVoidMethodA(object, id, parameters); |
| 278 else |
| 279 env->CallStaticVoidMethodA(clazz, id, parameters); |
| 252 result_wrapper.Append( | 280 result_wrapper.Append( |
| 253 GinJavaBridgeValue::CreateUndefinedValue().release()); | 281 GinJavaBridgeValue::CreateUndefinedValue().release()); |
| 254 break; | 282 break; |
| 255 case JavaType::TypeArray: | 283 case JavaType::TypeArray: |
| 256 // LIVECONNECT_COMPLIANCE: Existing behavior is to not call methods that | 284 // LIVECONNECT_COMPLIANCE: Existing behavior is to not call methods that |
| 257 // return arrays. Spec requires calling the method and converting the | 285 // return arrays. Spec requires calling the method and converting the |
| 258 // result to a JavaScript array. | 286 // result to a JavaScript array. |
| 259 result_wrapper.Append( | 287 result_wrapper.Append( |
| 260 GinJavaBridgeValue::CreateUndefinedValue().release()); | 288 GinJavaBridgeValue::CreateUndefinedValue().release()); |
| 261 break; | 289 break; |
| 262 case JavaType::TypeString: { | 290 case JavaType::TypeString: { |
| 263 jstring java_string = static_cast<jstring>( | 291 jstring java_string = static_cast<jstring>( |
| 264 env->CallObjectMethodA(object, id, parameters)); | 292 object ? env->CallObjectMethodA(object, id, parameters) |
| 293 : env->CallStaticObjectMethodA(clazz, id, parameters)); |
| 265 // If an exception was raised, we must clear it before calling most JNI | 294 // If an exception was raised, we must clear it before calling most JNI |
| 266 // methods. ScopedJavaLocalRef is liable to make such calls, so we test | 295 // methods. ScopedJavaLocalRef is liable to make such calls, so we test |
| 267 // first. | 296 // first. |
| 268 if (base::android::ClearException(env)) { | 297 if (base::android::ClearException(env)) { |
| 269 SetInvocationFailure(kJavaExceptionRaised); | 298 SetInvocationFailure(kJavaExceptionRaised); |
| 270 return; | 299 return; |
| 271 } | 300 } |
| 272 ScopedJavaLocalRef<jstring> scoped_java_string(env, java_string); | 301 ScopedJavaLocalRef<jstring> scoped_java_string(env, java_string); |
| 273 if (!scoped_java_string.obj()) { | 302 if (!scoped_java_string.obj()) { |
| 274 // LIVECONNECT_COMPLIANCE: Existing behavior is to return undefined. | 303 // LIVECONNECT_COMPLIANCE: Existing behavior is to return undefined. |
| 275 // Spec requires returning a null string. | 304 // Spec requires returning a null string. |
| 276 result_wrapper.Append( | 305 result_wrapper.Append( |
| 277 GinJavaBridgeValue::CreateUndefinedValue().release()); | 306 GinJavaBridgeValue::CreateUndefinedValue().release()); |
| 278 break; | 307 break; |
| 279 } | 308 } |
| 280 result_wrapper.AppendString( | 309 result_wrapper.AppendString( |
| 281 base::android::ConvertJavaStringToUTF8(scoped_java_string)); | 310 base::android::ConvertJavaStringToUTF8(scoped_java_string)); |
| 282 break; | 311 break; |
| 283 } | 312 } |
| 284 case JavaType::TypeObject: { | 313 case JavaType::TypeObject: { |
| 285 // If an exception was raised, we must clear it before calling most JNI | 314 // If an exception was raised, we must clear it before calling most JNI |
| 286 // methods. ScopedJavaLocalRef is liable to make such calls, so we test | 315 // methods. ScopedJavaLocalRef is liable to make such calls, so we test |
| 287 // first. | 316 // first. |
| 288 jobject java_object = env->CallObjectMethodA(object, id, parameters); | 317 jobject java_object = |
| 318 object ? env->CallObjectMethodA(object, id, parameters) |
| 319 : env->CallStaticObjectMethodA(clazz, id, parameters); |
| 289 if (base::android::ClearException(env)) { | 320 if (base::android::ClearException(env)) { |
| 290 SetInvocationFailure(kJavaExceptionRaised); | 321 SetInvocationFailure(kJavaExceptionRaised); |
| 291 return; | 322 return; |
| 292 } | 323 } |
| 293 ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object); | 324 ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object); |
| 294 if (!scoped_java_object.obj()) { | 325 if (!scoped_java_object.obj()) { |
| 295 result_wrapper.Append(base::Value::CreateNullValue()); | 326 result_wrapper.Append(base::Value::CreateNullValue()); |
| 296 break; | 327 break; |
| 297 } | 328 } |
| 298 SetObjectResult(scoped_java_object, object_->GetSafeAnnotationClass()); | 329 SetObjectResult(scoped_java_object, object_->GetSafeAnnotationClass()); |
| 299 return; | 330 return; |
| 300 } | 331 } |
| 301 } | 332 } |
| 302 // This is for all cases except JavaType::TypeObject. | 333 // This is for all cases except JavaType::TypeObject. |
| 303 if (!base::android::ClearException(env)) { | 334 if (!base::android::ClearException(env)) { |
| 304 SetPrimitiveResult(result_wrapper); | 335 SetPrimitiveResult(result_wrapper); |
| 305 } else { | 336 } else { |
| 306 SetInvocationFailure(kJavaExceptionRaised); | 337 SetInvocationFailure(kJavaExceptionRaised); |
| 307 } | 338 } |
| 308 } | 339 } |
| 309 | 340 |
| 310 } // namespace content | 341 } // namespace content |
| OLD | NEW |