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 |