Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Side by Side Diff: content/browser/renderer_host/java/gin_java_method_invocation_helper.cc

Issue 336313018: [Android] Move content/browser/{renderer_host => android}/java/* (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Updated paths for unit tests, rebased Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/renderer_host/java/gin_java_method_invocation_helper.h "
6
7 #include <unistd.h>
8
9 #include "base/android/event_log.h"
10 #include "base/android/jni_android.h"
11 #include "base/android/jni_string.h"
12 #include "base/float_util.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"
15 #include "content/browser/renderer_host/java/jni_helper.h"
16 #include "content/common/android/gin_java_bridge_value.h"
17 #include "content/public/browser/browser_thread.h"
18
19 using base::android::AttachCurrentThread;
20 using base::android::ScopedJavaLocalRef;
21
22 namespace content {
23
24 namespace {
25
26 // See frameworks/base/core/java/android/webkit/EventLogTags.logtags
27 const int kObjectGetClassInvocationAttemptLogTag = 70151;
28
29 } // namespace
30
31 GinJavaMethodInvocationHelper::GinJavaMethodInvocationHelper(
32 scoped_ptr<ObjectDelegate> object,
33 const std::string& method_name,
34 const base::ListValue& arguments)
35 : object_(object.Pass()),
36 method_name_(method_name),
37 arguments_(arguments.DeepCopy()),
38 invocation_error_(kGinJavaBridgeNoError) {
39 }
40
41 GinJavaMethodInvocationHelper::~GinJavaMethodInvocationHelper() {}
42
43 void GinJavaMethodInvocationHelper::Init(DispatcherDelegate* dispatcher) {
44 // Build on the UI thread a map of object_id -> WeakRef for Java objects from
45 // |arguments_|. Then we can use this map on the background thread without
46 // accessing |dispatcher|.
47 BuildObjectRefsFromListValue(dispatcher, arguments_.get());
48 }
49
50 // As V8ValueConverter has finite recursion depth when serializing
51 // JavaScript values, we don't bother about having a recursion threshold here.
52 void GinJavaMethodInvocationHelper::BuildObjectRefsFromListValue(
53 DispatcherDelegate* dispatcher,
54 const base::Value* list_value) {
55 DCHECK(list_value->IsType(base::Value::TYPE_LIST));
56 const base::ListValue* list;
57 list_value->GetAsList(&list);
58 for (base::ListValue::const_iterator iter = list->begin();
59 iter != list->end();
60 ++iter) {
61 if (AppendObjectRef(dispatcher, *iter))
62 continue;
63 if ((*iter)->IsType(base::Value::TYPE_LIST)) {
64 BuildObjectRefsFromListValue(dispatcher, *iter);
65 } else if ((*iter)->IsType(base::Value::TYPE_DICTIONARY)) {
66 BuildObjectRefsFromDictionaryValue(dispatcher, *iter);
67 }
68 }
69 }
70
71 void GinJavaMethodInvocationHelper::BuildObjectRefsFromDictionaryValue(
72 DispatcherDelegate* dispatcher,
73 const base::Value* dict_value) {
74 DCHECK(dict_value->IsType(base::Value::TYPE_DICTIONARY));
75 const base::DictionaryValue* dict;
76 dict_value->GetAsDictionary(&dict);
77 for (base::DictionaryValue::Iterator iter(*dict);
78 !iter.IsAtEnd();
79 iter.Advance()) {
80 if (AppendObjectRef(dispatcher, &iter.value()))
81 continue;
82 if (iter.value().IsType(base::Value::TYPE_LIST)) {
83 BuildObjectRefsFromListValue(dispatcher, &iter.value());
84 } else if (iter.value().IsType(base::Value::TYPE_DICTIONARY)) {
85 BuildObjectRefsFromDictionaryValue(dispatcher, &iter.value());
86 }
87 }
88 }
89
90 bool GinJavaMethodInvocationHelper::AppendObjectRef(
91 DispatcherDelegate* dispatcher,
92 const base::Value* raw_value) {
93 if (!GinJavaBridgeValue::ContainsGinJavaBridgeValue(raw_value))
94 return false;
95 scoped_ptr<const GinJavaBridgeValue> value(
96 GinJavaBridgeValue::FromValue(raw_value));
97 if (!value->IsType(GinJavaBridgeValue::TYPE_OBJECT_ID))
98 return false;
99 GinJavaBoundObject::ObjectID object_id;
100 if (value->GetAsObjectID(&object_id)) {
101 ObjectRefs::iterator iter = object_refs_.find(object_id);
102 if (iter == object_refs_.end()) {
103 JavaObjectWeakGlobalRef object_ref(
104 dispatcher->GetObjectWeakRef(object_id));
105 if (!object_ref.is_empty()) {
106 object_refs_.insert(std::make_pair(object_id, object_ref));
107 }
108 }
109 }
110 return true;
111 }
112
113 void GinJavaMethodInvocationHelper::Invoke() {
114 JNIEnv* env = AttachCurrentThread();
115 const JavaMethod* method =
116 object_->FindMethod(method_name_, arguments_->GetSize());
117 if (!method) {
118 SetInvocationError(kGinJavaBridgeMethodNotFound);
119 return;
120 }
121
122 if (object_->IsObjectGetClassMethod(method)) {
123 base::android::EventLogWriteInt(kObjectGetClassInvocationAttemptLogTag,
124 getuid());
125 SetInvocationError(kGinJavaBridgeAccessToObjectGetClassIsBlocked);
126 return;
127 }
128
129 ScopedJavaLocalRef<jobject> obj;
130 ScopedJavaLocalRef<jclass> cls;
131 if (method->is_static()) {
132 cls = object_->GetLocalClassRef(env);
133 } else {
134 obj = object_->GetLocalRef(env);
135 }
136 if (obj.is_null() && cls.is_null()) {
137 SetInvocationError(kGinJavaBridgeObjectIsGone);
138 return;
139 }
140
141 std::vector<jvalue> parameters(method->num_parameters());
142 for (size_t i = 0; i < method->num_parameters(); ++i) {
143 const base::Value* argument;
144 arguments_->Get(i, &argument);
145 parameters[i] = CoerceJavaScriptValueToJavaValue(
146 env, argument, method->parameter_type(i), true, object_refs_);
147 }
148 if (method->is_static()) {
149 InvokeMethod(
150 NULL, cls.obj(), method->return_type(), method->id(), &parameters[0]);
151 } else {
152 InvokeMethod(
153 obj.obj(), NULL, method->return_type(), method->id(), &parameters[0]);
154 }
155
156 // Now that we're done with the jvalue, release any local references created
157 // by CoerceJavaScriptValueToJavaValue().
158 for (size_t i = 0; i < method->num_parameters(); ++i) {
159 ReleaseJavaValueIfRequired(env, &parameters[i], method->parameter_type(i));
160 }
161 }
162
163 void GinJavaMethodInvocationHelper::SetInvocationError(
164 GinJavaBridgeError error) {
165 holds_primitive_result_ = true;
166 primitive_result_.reset(new base::ListValue());
167 invocation_error_ = error;
168 }
169
170 void GinJavaMethodInvocationHelper::SetPrimitiveResult(
171 const base::ListValue& result_wrapper) {
172 holds_primitive_result_ = true;
173 primitive_result_.reset(result_wrapper.DeepCopy());
174 }
175
176 void GinJavaMethodInvocationHelper::SetObjectResult(
177 const base::android::JavaRef<jobject>& object,
178 const base::android::JavaRef<jclass>& safe_annotation_clazz) {
179 holds_primitive_result_ = false;
180 object_result_.Reset(object);
181 safe_annotation_clazz_.Reset(safe_annotation_clazz);
182 }
183
184 bool GinJavaMethodInvocationHelper::HoldsPrimitiveResult() {
185 return holds_primitive_result_;
186 }
187
188 const base::ListValue& GinJavaMethodInvocationHelper::GetPrimitiveResult() {
189 return *primitive_result_.get();
190 }
191
192 const base::android::JavaRef<jobject>&
193 GinJavaMethodInvocationHelper::GetObjectResult() {
194 return object_result_;
195 }
196
197 const base::android::JavaRef<jclass>&
198 GinJavaMethodInvocationHelper::GetSafeAnnotationClass() {
199 return safe_annotation_clazz_;
200 }
201
202 const GinJavaBridgeError GinJavaMethodInvocationHelper::GetInvocationError() {
203 return invocation_error_;
204 }
205
206 void GinJavaMethodInvocationHelper::InvokeMethod(jobject object,
207 jclass clazz,
208 const JavaType& return_type,
209 jmethodID id,
210 jvalue* parameters) {
211 DCHECK(object || clazz);
212 JNIEnv* env = AttachCurrentThread();
213 base::ListValue result_wrapper;
214 switch (return_type.type) {
215 case JavaType::TypeBoolean:
216 result_wrapper.AppendBoolean(
217 object ? env->CallBooleanMethodA(object, id, parameters)
218 : env->CallStaticBooleanMethodA(clazz, id, parameters));
219 break;
220 case JavaType::TypeByte:
221 result_wrapper.AppendInteger(
222 object ? env->CallByteMethodA(object, id, parameters)
223 : env->CallStaticByteMethodA(clazz, id, parameters));
224 break;
225 case JavaType::TypeChar:
226 result_wrapper.AppendInteger(
227 object ? env->CallCharMethodA(object, id, parameters)
228 : env->CallStaticCharMethodA(clazz, id, parameters));
229 break;
230 case JavaType::TypeShort:
231 result_wrapper.AppendInteger(
232 object ? env->CallShortMethodA(object, id, parameters)
233 : env->CallStaticShortMethodA(clazz, id, parameters));
234 break;
235 case JavaType::TypeInt:
236 result_wrapper.AppendInteger(
237 object ? env->CallIntMethodA(object, id, parameters)
238 : env->CallStaticIntMethodA(clazz, id, parameters));
239 break;
240 case JavaType::TypeLong:
241 result_wrapper.AppendDouble(
242 object ? env->CallLongMethodA(object, id, parameters)
243 : env->CallStaticLongMethodA(clazz, id, parameters));
244 break;
245 case JavaType::TypeFloat: {
246 float result = object
247 ? env->CallFloatMethodA(object, id, parameters)
248 : env->CallStaticFloatMethodA(clazz, id, parameters);
249 if (base::IsFinite(result)) {
250 result_wrapper.AppendDouble(result);
251 } else {
252 result_wrapper.Append(
253 GinJavaBridgeValue::CreateNonFiniteValue(result).release());
254 }
255 break;
256 }
257 case JavaType::TypeDouble: {
258 double result = object
259 ? env->CallDoubleMethodA(object, id, parameters)
260 : env->CallStaticDoubleMethodA(clazz, id, parameters);
261 if (base::IsFinite(result)) {
262 result_wrapper.AppendDouble(result);
263 } else {
264 result_wrapper.Append(
265 GinJavaBridgeValue::CreateNonFiniteValue(result).release());
266 }
267 break;
268 }
269 case JavaType::TypeVoid:
270 if (object)
271 env->CallVoidMethodA(object, id, parameters);
272 else
273 env->CallStaticVoidMethodA(clazz, id, parameters);
274 result_wrapper.Append(
275 GinJavaBridgeValue::CreateUndefinedValue().release());
276 break;
277 case JavaType::TypeArray:
278 // LIVECONNECT_COMPLIANCE: Existing behavior is to not call methods that
279 // return arrays. Spec requires calling the method and converting the
280 // result to a JavaScript array.
281 result_wrapper.Append(
282 GinJavaBridgeValue::CreateUndefinedValue().release());
283 break;
284 case JavaType::TypeString: {
285 jstring java_string = static_cast<jstring>(
286 object ? env->CallObjectMethodA(object, id, parameters)
287 : env->CallStaticObjectMethodA(clazz, id, parameters));
288 // If an exception was raised, we must clear it before calling most JNI
289 // methods. ScopedJavaLocalRef is liable to make such calls, so we test
290 // first.
291 if (base::android::ClearException(env)) {
292 SetInvocationError(kGinJavaBridgeJavaExceptionRaised);
293 return;
294 }
295 ScopedJavaLocalRef<jstring> scoped_java_string(env, java_string);
296 if (!scoped_java_string.obj()) {
297 // LIVECONNECT_COMPLIANCE: Existing behavior is to return undefined.
298 // Spec requires returning a null string.
299 result_wrapper.Append(
300 GinJavaBridgeValue::CreateUndefinedValue().release());
301 break;
302 }
303 result_wrapper.AppendString(
304 base::android::ConvertJavaStringToUTF8(scoped_java_string));
305 break;
306 }
307 case JavaType::TypeObject: {
308 // If an exception was raised, we must clear it before calling most JNI
309 // methods. ScopedJavaLocalRef is liable to make such calls, so we test
310 // first.
311 jobject java_object =
312 object ? env->CallObjectMethodA(object, id, parameters)
313 : env->CallStaticObjectMethodA(clazz, id, parameters);
314 if (base::android::ClearException(env)) {
315 SetInvocationError(kGinJavaBridgeJavaExceptionRaised);
316 return;
317 }
318 ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object);
319 if (!scoped_java_object.obj()) {
320 result_wrapper.Append(base::Value::CreateNullValue());
321 break;
322 }
323 SetObjectResult(scoped_java_object, object_->GetSafeAnnotationClass());
324 return;
325 }
326 }
327 // This is for all cases except JavaType::TypeObject.
328 if (!base::android::ClearException(env)) {
329 SetPrimitiveResult(result_wrapper);
330 } else {
331 SetInvocationError(kGinJavaBridgeJavaExceptionRaised);
332 }
333 }
334
335 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698