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

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

Issue 345753003: [Android] Java Bridge with Gin: implement Java Bridge dispatcher (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 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_bridge_dispatcher_host.h"
6
7 #include "base/android/java_handler_thread.h"
8 #include "base/android/jni_android.h"
9 #include "base/android/scoped_java_ref.h"
10 #include "base/lazy_instance.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/task_runner_util.h"
14 #include "content/browser/renderer_host/java/gin_java_bound_object_delegate.h"
15 #include "content/browser/renderer_host/java/jni_helper.h"
16 #include "content/common/android/gin_java_bridge_value.h"
17 #include "content/common/android/hash_set.h"
18 #include "content/common/gin_java_bridge_messages.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/render_frame_host.h"
21 #include "ipc/ipc_message_utils.h"
22
23 #if !defined(OS_ANDROID)
24 #error "JavaBridge only supports OS_ANDROID"
25 #endif
26
27 namespace content {
28
29 namespace {
30 // The JavaBridge needs to use a Java thread so the callback
31 // will happen on a thread with a prepared Looper.
32 class JavaBridgeThread : public base::android::JavaHandlerThread {
33 public:
34 JavaBridgeThread() : base::android::JavaHandlerThread("JavaBridge") {
35 Start();
36 }
37 virtual ~JavaBridgeThread() {
38 Stop();
39 }
40 };
41
42 base::LazyInstance<JavaBridgeThread> g_background_thread =
43 LAZY_INSTANCE_INITIALIZER;
44
45 const char kUnknownObjectId[] = "Unknown Java object ID";
46
47 } // namespace
48
49 GinJavaBridgeDispatcherHost::GinJavaBridgeDispatcherHost(
50 WebContents* web_contents,
51 jobject retained_object_set)
52 : WebContentsObserver(web_contents),
53 retained_object_set_(base::android::AttachCurrentThread(),
54 retained_object_set),
55 allow_object_contents_inspection_(true) {
56 DCHECK(retained_object_set);
57 }
58
59 GinJavaBridgeDispatcherHost::~GinJavaBridgeDispatcherHost() {
60 }
61
62 void GinJavaBridgeDispatcherHost::RenderFrameCreated(
63 RenderFrameHost* render_frame_host) {
64 renderers_.insert(render_frame_host);
65 for (NamedObjectMap::const_iterator iter = named_objects_.begin();
66 iter != named_objects_.end();
67 ++iter) {
68 render_frame_host->Send(new GinJavaBridgeMsg_AddNamedObject(
69 render_frame_host->GetRoutingID(), iter->first, iter->second));
70 }
71 }
72
73 void GinJavaBridgeDispatcherHost::RenderFrameDeleted(
74 RenderFrameHost* render_frame_host) {
75 renderers_.erase(render_frame_host);
76 RemoveHolder(render_frame_host,
77 GinJavaBoundObject::ObjectMap::iterator(&objects_),
78 objects_.size());
79 }
80
81 GinJavaBoundObject::ObjectID GinJavaBridgeDispatcherHost::AddObject(
82 const base::android::JavaRef<jobject>& object,
83 const base::android::JavaRef<jclass>& safe_annotation_clazz,
84 bool is_named,
85 RenderFrameHost* holder) {
86 DCHECK(is_named || holder);
87 GinJavaBoundObject::ObjectID object_id;
88 JNIEnv* env = base::android::AttachCurrentThread();
89 JavaObjectWeakGlobalRef ref(env, object.obj());
90 if (is_named) {
91 object_id = objects_.Add(new scoped_refptr<GinJavaBoundObject>(
92 GinJavaBoundObject::CreateNamed(ref, safe_annotation_clazz)));
93 } else {
94 object_id = objects_.Add(new scoped_refptr<GinJavaBoundObject>(
95 GinJavaBoundObject::CreateTransient(
96 ref, safe_annotation_clazz, holder)));
97 }
98 #if DCHECK_IS_ON
99 {
100 GinJavaBoundObject::ObjectID added_object_id;
101 DCHECK(FindObjectId(object, &added_object_id));
102 DCHECK_EQ(object_id, added_object_id);
103 }
104 #endif // DCHECK_IS_ON
105 base::android::ScopedJavaLocalRef<jobject> retained_object_set =
106 retained_object_set_.get(env);
107 if (!retained_object_set.is_null()) {
108 JNI_Java_HashSet_add(env, retained_object_set, object);
109 }
110 return object_id;
111 }
112
113 bool GinJavaBridgeDispatcherHost::FindObjectId(
114 const base::android::JavaRef<jobject>& object,
115 GinJavaBoundObject::ObjectID* object_id) {
116 JNIEnv* env = base::android::AttachCurrentThread();
117 for (GinJavaBoundObject::ObjectMap::iterator it(&objects_); !it.IsAtEnd();
118 it.Advance()) {
119 if (env->IsSameObject(
120 object.obj(),
121 it.GetCurrentValue()->get()->GetLocalRef(env).obj())) {
122 *object_id = it.GetCurrentKey();
123 return true;
124 }
125 }
126 return false;
127 }
128
129 JavaObjectWeakGlobalRef GinJavaBridgeDispatcherHost::GetObjectWeakRef(
130 GinJavaBoundObject::ObjectID object_id) {
131 scoped_refptr<GinJavaBoundObject>* result = objects_.Lookup(object_id);
132 scoped_refptr<GinJavaBoundObject> object(result ? *result : NULL);
133 if (object.get())
134 return object->GetWeakRef();
135 else
136 return JavaObjectWeakGlobalRef();
137 }
138
139 void GinJavaBridgeDispatcherHost::RemoveHolder(
140 RenderFrameHost* holder,
141 const GinJavaBoundObject::ObjectMap::iterator& from,
142 size_t count) {
143 JNIEnv* env = base::android::AttachCurrentThread();
144 base::android::ScopedJavaLocalRef<jobject> retained_object_set =
145 retained_object_set_.get(env);
146 size_t i = 0;
147 for (GinJavaBoundObject::ObjectMap::iterator it(from);
148 !it.IsAtEnd() && i < count;
149 it.Advance(), ++i) {
150 scoped_refptr<GinJavaBoundObject> object(*it.GetCurrentValue());
151 if (object->IsNamed())
152 continue;
153 object->RemoveHolder(holder);
154 if (!object->HasHolders()) {
155 if (!retained_object_set.is_null()) {
156 JNI_Java_HashSet_remove(
157 env, retained_object_set, object->GetLocalRef(env));
158 }
159 objects_.Remove(it.GetCurrentKey());
160 }
161 }
162 }
163
164 void GinJavaBridgeDispatcherHost::AddNamedObject(
165 const std::string& name,
166 const base::android::JavaRef<jobject>& object,
167 const base::android::JavaRef<jclass>& safe_annotation_clazz) {
168 DCHECK_CURRENTLY_ON(BrowserThread::UI);
169 GinJavaBoundObject::ObjectID object_id;
170 NamedObjectMap::iterator iter = named_objects_.find(name);
171 bool existing_object = FindObjectId(object, &object_id);
172 if (existing_object && iter != named_objects_.end() &&
173 iter->second == object_id) {
174 // Nothing to do.
175 return;
176 }
177 if (iter != named_objects_.end()) {
178 RemoveNamedObject(iter->first);
179 }
180 if (existing_object) {
181 (*objects_.Lookup(object_id))->AddName();
182 } else {
183 object_id = AddObject(object, safe_annotation_clazz, true, NULL);
184 }
185 named_objects_[name] = object_id;
186
187 for (RendererSet::iterator iter = renderers_.begin();
188 iter != renderers_.end(); ++iter) {
189 (*iter)->Send(new GinJavaBridgeMsg_AddNamedObject(
190 (*iter)->GetRoutingID(), name, object_id));
191 }
192 }
193
194 void GinJavaBridgeDispatcherHost::RemoveNamedObject(
195 const std::string& name) {
196 DCHECK_CURRENTLY_ON(BrowserThread::UI);
197 NamedObjectMap::iterator iter = named_objects_.find(name);
198 if (iter == named_objects_.end())
199 return;
200
201 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(iter->second));
202 named_objects_.erase(iter);
203 object->RemoveName();
204
205 // Not erasing from the objects map, as we can still receive method
206 // invocation requests for this object, and they should work until the
207 // java object is alive.
Torne 2014/06/23 10:53:10 no longer alive?
mnaganov (inactive) 2014/06/23 12:13:06 Yeah, should be "is gone" actually. Fixed.
208 if (!object->IsNamed()) {
209 JNIEnv* env = base::android::AttachCurrentThread();
210 base::android::ScopedJavaLocalRef<jobject> retained_object_set =
211 retained_object_set_.get(env);
212 if (!retained_object_set.is_null()) {
213 JNI_Java_HashSet_remove(
214 env, retained_object_set, object->GetLocalRef(env));
215 }
216 }
217
218 for (RendererSet::iterator iter = renderers_.begin();
219 iter != renderers_.end(); ++iter) {
220 (*iter)->Send(new GinJavaBridgeMsg_RemoveNamedObject(
221 (*iter)->GetRoutingID(), name));
222 }
223 }
224
225 void GinJavaBridgeDispatcherHost::SetAllowObjectContentsInspection(bool allow) {
226 allow_object_contents_inspection_ = allow;
227 }
228
229 void GinJavaBridgeDispatcherHost::DocumentAvailableInMainFrame() {
230 DCHECK_CURRENTLY_ON(BrowserThread::UI);
231 // Called when the window object has been cleared in the main frame.
232 // That means, all sub-frames have also been cleared, so only named
233 // objects survived.
234 JNIEnv* env = base::android::AttachCurrentThread();
235 base::android::ScopedJavaLocalRef<jobject> retained_object_set =
236 retained_object_set_.get(env);
237 if (!retained_object_set.is_null()) {
238 JNI_Java_HashSet_clear(env, retained_object_set);
239 }
240
241 // We also need to add back the named objects we have so far as they
242 // should survive navigations.
243 for (GinJavaBoundObject::ObjectMap::iterator it(&objects_); !it.IsAtEnd();
244 it.Advance()) {
245 scoped_refptr<GinJavaBoundObject> object(*it.GetCurrentValue());
246 if (object->IsNamed()) {
247 if (!retained_object_set.is_null()) {
248 JNI_Java_HashSet_add(
249 env, retained_object_set, object->GetLocalRef(env));
250 }
251 } else {
252 objects_.Remove(it.GetCurrentKey());
253 }
254 }
255 }
256
257 namespace {
258
259 // TODO(mnaganov): Implement passing of a parameter into sync message handlers.
Torne 2014/06/23 10:53:10 Are we going to need this later, or is that just s
mnaganov (inactive) 2014/06/23 12:13:06 I would like to do this later. Here is the issue -
260 class MessageForwarder : public IPC::Sender {
261 public:
262 MessageForwarder(GinJavaBridgeDispatcherHost* gjbdh,
263 RenderFrameHost* render_frame_host)
264 : gjbdh_(gjbdh), render_frame_host_(render_frame_host) {}
265 void OnGetMethods(GinJavaBoundObject::ObjectID object_id,
266 IPC::Message* reply_msg) {
267 gjbdh_->OnGetMethods(render_frame_host_,
268 object_id,
269 reply_msg);
270 }
271 void OnHasMethod(GinJavaBoundObject::ObjectID object_id,
272 const std::string& method_name,
273 IPC::Message* reply_msg) {
274 gjbdh_->OnHasMethod(render_frame_host_,
275 object_id,
276 method_name,
277 reply_msg);
278 }
279 void OnInvokeMethod(GinJavaBoundObject::ObjectID object_id,
280 const std::string& method_name,
281 const base::ListValue& arguments,
282 IPC::Message* reply_msg) {
283 gjbdh_->OnInvokeMethod(render_frame_host_,
284 object_id,
285 method_name,
286 arguments,
287 reply_msg);
288 }
289 virtual bool Send(IPC::Message* msg) OVERRIDE {
290 NOTREACHED();
291 return false;
292 }
293 private:
294 GinJavaBridgeDispatcherHost* gjbdh_;
295 RenderFrameHost* render_frame_host_;
296 };
297
298 }
299
300 bool GinJavaBridgeDispatcherHost::OnMessageReceived(
301 const IPC::Message& message,
302 RenderFrameHost* render_frame_host) {
303 DCHECK(render_frame_host);
304 bool handled = true;
305 MessageForwarder forwarder(this, render_frame_host);
306 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(GinJavaBridgeDispatcherHost, message,
307 render_frame_host)
308 IPC_MESSAGE_FORWARD_DELAY_REPLY(GinJavaBridgeHostMsg_GetMethods,
309 &forwarder,
310 MessageForwarder::OnGetMethods)
311 IPC_MESSAGE_FORWARD_DELAY_REPLY(GinJavaBridgeHostMsg_HasMethod,
312 &forwarder,
313 MessageForwarder::OnHasMethod)
314 IPC_MESSAGE_FORWARD_DELAY_REPLY(GinJavaBridgeHostMsg_InvokeMethod,
315 &forwarder,
316 MessageForwarder::OnInvokeMethod)
317 IPC_MESSAGE_HANDLER(GinJavaBridgeHostMsg_ObjectWrapperDeleted,
318 OnObjectWrapperDeleted)
319 IPC_MESSAGE_UNHANDLED(handled = false)
320 IPC_END_MESSAGE_MAP()
321 return handled;
322 }
323
324 void GinJavaBridgeDispatcherHost::SendReply(
325 RenderFrameHost* render_frame_host,
326 IPC::Message* reply_msg) {
327 DCHECK_CURRENTLY_ON(BrowserThread::UI);
328 if (renderers_.find(render_frame_host) != renderers_.end()) {
329 render_frame_host->Send(reply_msg);
330 } else {
331 delete reply_msg;
332 }
333 }
334
335 void GinJavaBridgeDispatcherHost::OnGetMethods(
336 RenderFrameHost* render_frame_host,
337 GinJavaBoundObject::ObjectID object_id,
338 IPC::Message* reply_msg) {
339 DCHECK_CURRENTLY_ON(BrowserThread::UI);
340 DCHECK(render_frame_host);
341 if (!allow_object_contents_inspection_) {
342 IPC::WriteParam(reply_msg, std::set<std::string>());
343 render_frame_host->Send(reply_msg);
344 return;
345 }
346 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id));
347 if (!object) {
348 LOG(ERROR) << "WebView: Unknown object: " << object_id;
349 IPC::WriteParam(reply_msg, std::set<std::string>());
350 render_frame_host->Send(reply_msg);
351 return;
352 }
353 base::PostTaskAndReplyWithResult(
354 g_background_thread.Get().message_loop()->message_loop_proxy(),
355 FROM_HERE,
356 base::Bind(&GinJavaBoundObject::GetMethodNames, object),
357 base::Bind(&GinJavaBridgeDispatcherHost::SendMethods,
358 AsWeakPtr(),
359 render_frame_host,
360 reply_msg));
361 }
362
363 void GinJavaBridgeDispatcherHost::SendMethods(
364 RenderFrameHost* render_frame_host,
365 IPC::Message* reply_msg,
366 const std::set<std::string>& method_names) {
367 IPC::WriteParam(reply_msg, method_names);
368 SendReply(render_frame_host, reply_msg);
369 }
370
371 void GinJavaBridgeDispatcherHost::OnHasMethod(
372 RenderFrameHost* render_frame_host,
373 GinJavaBoundObject::ObjectID object_id,
374 const std::string& method_name,
375 IPC::Message* reply_msg) {
376 DCHECK_CURRENTLY_ON(BrowserThread::UI);
377 DCHECK(render_frame_host);
378 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id));
379 if (!object) {
380 LOG(ERROR) << "WebView: Unknown object: " << object_id;
381 IPC::WriteParam(reply_msg, false);
382 render_frame_host->Send(reply_msg);
383 return;
384 }
385 base::PostTaskAndReplyWithResult(
386 g_background_thread.Get().message_loop()->message_loop_proxy(),
387 FROM_HERE,
388 base::Bind(&GinJavaBoundObject::HasMethod, object, method_name),
389 base::Bind(&GinJavaBridgeDispatcherHost::SendHasMethodReply,
390 AsWeakPtr(),
391 render_frame_host,
392 reply_msg));
393 }
394
395 void GinJavaBridgeDispatcherHost::SendHasMethodReply(
396 RenderFrameHost* render_frame_host,
397 IPC::Message* reply_msg,
398 bool result) {
399 IPC::WriteParam(reply_msg, result);
400 SendReply(render_frame_host, reply_msg);
401 }
402
403 void GinJavaBridgeDispatcherHost::OnInvokeMethod(
404 RenderFrameHost* render_frame_host,
405 GinJavaBoundObject::ObjectID object_id,
406 const std::string& method_name,
407 const base::ListValue& arguments,
408 IPC::Message* reply_msg) {
409 DCHECK_CURRENTLY_ON(BrowserThread::UI);
410 DCHECK(render_frame_host);
411 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id));
412 if (!object) {
413 LOG(ERROR) << "WebView: Unknown object: " << object_id;
414 base::ListValue result;
415 result.Append(base::Value::CreateNullValue());
416 IPC::WriteParam(reply_msg, result);
417 IPC::WriteParam(reply_msg, std::string(kUnknownObjectId));
418 render_frame_host->Send(reply_msg);
419 return;
420 }
421 scoped_refptr<GinJavaMethodInvocationHelper> result =
422 new GinJavaMethodInvocationHelper(
423 make_scoped_ptr(new GinJavaBoundObjectDelegate(object))
424 .PassAs<GinJavaMethodInvocationHelper::ObjectDelegate>(),
425 method_name,
426 arguments);
427 result->Init(this);
428 g_background_thread.Get()
429 .message_loop()
430 ->message_loop_proxy()
431 ->PostTaskAndReply(
432 FROM_HERE,
433 base::Bind(&GinJavaMethodInvocationHelper::Invoke, result),
434 base::Bind(
435 &GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult,
436 AsWeakPtr(),
437 render_frame_host,
438 reply_msg,
439 result));
440 }
441
442 void GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult(
443 RenderFrameHost* render_frame_host,
444 IPC::Message* reply_msg,
445 scoped_refptr<GinJavaMethodInvocationHelper> result) {
446 if (result->HoldsPrimitiveResult()) {
447 IPC::WriteParam(reply_msg, result->GetPrimitiveResult());
448 IPC::WriteParam(reply_msg, result->GetErrorMessage());
449 SendReply(render_frame_host, reply_msg);
450 } else {
451 ProcessMethodInvocationObjectResult(render_frame_host, reply_msg, result);
452 }
453 }
454
455 void GinJavaBridgeDispatcherHost::ProcessMethodInvocationObjectResult(
456 RenderFrameHost* render_frame_host,
457 IPC::Message* reply_msg,
458 scoped_refptr<GinJavaMethodInvocationHelper> result) {
459 DCHECK_CURRENTLY_ON(BrowserThread::UI);
460 if (renderers_.find(render_frame_host) == renderers_.end()) {
461 delete reply_msg;
462 return;
463 }
464 base::ListValue wrapped_result;
465 if (!result->GetObjectResult().is_null()) {
466 GinJavaBoundObject::ObjectID returned_object_id;
467 if (FindObjectId(result->GetObjectResult(), &returned_object_id)) {
468 (*objects_.Lookup(returned_object_id))->AddHolder(render_frame_host);
469 } else {
470 returned_object_id = AddObject(result->GetObjectResult(),
471 result->GetSafeAnnotationClass(),
472 false,
473 render_frame_host);
474 }
475 wrapped_result.Append(
476 GinJavaBridgeValue::CreateObjectIDValue(returned_object_id).release());
477 } else {
478 wrapped_result.Append(base::Value::CreateNullValue());
479 }
480 IPC::WriteParam(reply_msg, wrapped_result);
481 IPC::WriteParam(reply_msg, result->GetErrorMessage());
482 render_frame_host->Send(reply_msg);
483 }
484
485 void GinJavaBridgeDispatcherHost::OnObjectWrapperDeleted(
486 RenderFrameHost* render_frame_host,
487 GinJavaBoundObject::ObjectID object_id) {
488 DCHECK_CURRENTLY_ON(BrowserThread::UI);
489 DCHECK(render_frame_host);
490 if (objects_.Lookup(object_id)) {
491 GinJavaBoundObject::ObjectMap::iterator iter(&objects_);
492 while (!iter.IsAtEnd() && iter.GetCurrentKey() != object_id)
493 iter.Advance();
494 DCHECK(!iter.IsAtEnd());
495 RemoveHolder(render_frame_host, iter, 1);
496 }
497 }
498
499 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/renderer_host/java/gin_java_bridge_dispatcher_host.h ('k') | content/common/gin_java_bridge_messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698