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/android/java/gin_java_bridge_dispatcher_host.h" | 5 #include "content/browser/android/java/gin_java_bridge_dispatcher_host.h" |
6 | 6 |
7 #include "base/android/java_handler_thread.h" | 7 #include "base/android/java_handler_thread.h" |
8 #include "base/android/jni_android.h" | 8 #include "base/android/jni_android.h" |
9 #include "base/android/scoped_java_ref.h" | 9 #include "base/android/scoped_java_ref.h" |
10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 WebContents* web_contents, | 49 WebContents* web_contents, |
50 jobject retained_object_set) | 50 jobject retained_object_set) |
51 : WebContentsObserver(web_contents), | 51 : WebContentsObserver(web_contents), |
52 retained_object_set_(base::android::AttachCurrentThread(), | 52 retained_object_set_(base::android::AttachCurrentThread(), |
53 retained_object_set), | 53 retained_object_set), |
54 allow_object_contents_inspection_(true) { | 54 allow_object_contents_inspection_(true) { |
55 DCHECK(retained_object_set); | 55 DCHECK(retained_object_set); |
56 } | 56 } |
57 | 57 |
58 GinJavaBridgeDispatcherHost::~GinJavaBridgeDispatcherHost() { | 58 GinJavaBridgeDispatcherHost::~GinJavaBridgeDispatcherHost() { |
| 59 DCHECK(pending_replies_.empty()); |
59 } | 60 } |
60 | 61 |
61 void GinJavaBridgeDispatcherHost::RenderFrameCreated( | 62 void GinJavaBridgeDispatcherHost::RenderFrameCreated( |
62 RenderFrameHost* render_frame_host) { | 63 RenderFrameHost* render_frame_host) { |
63 for (NamedObjectMap::const_iterator iter = named_objects_.begin(); | 64 for (NamedObjectMap::const_iterator iter = named_objects_.begin(); |
64 iter != named_objects_.end(); | 65 iter != named_objects_.end(); |
65 ++iter) { | 66 ++iter) { |
66 render_frame_host->Send(new GinJavaBridgeMsg_AddNamedObject( | 67 render_frame_host->Send(new GinJavaBridgeMsg_AddNamedObject( |
67 render_frame_host->GetRoutingID(), iter->first, iter->second)); | 68 render_frame_host->GetRoutingID(), iter->first, iter->second)); |
68 } | 69 } |
69 } | 70 } |
70 | 71 |
71 void GinJavaBridgeDispatcherHost::RenderFrameDeleted( | 72 void GinJavaBridgeDispatcherHost::RenderFrameDeleted( |
72 RenderFrameHost* render_frame_host) { | 73 RenderFrameHost* render_frame_host) { |
| 74 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 75 IPC::Message* reply_msg = TakePendingReply(render_frame_host); |
| 76 if (reply_msg != NULL) { |
| 77 base::ListValue result; |
| 78 result.Append(base::Value::CreateNullValue()); |
| 79 IPC::WriteParam(reply_msg, result); |
| 80 IPC::WriteParam(reply_msg, kGinJavaBridgeRenderFrameDeleted); |
| 81 render_frame_host->Send(reply_msg); |
| 82 } |
73 RemoveHolder(render_frame_host, | 83 RemoveHolder(render_frame_host, |
74 GinJavaBoundObject::ObjectMap::iterator(&objects_), | 84 GinJavaBoundObject::ObjectMap::iterator(&objects_), |
75 objects_.size()); | 85 objects_.size()); |
76 } | 86 } |
77 | 87 |
78 GinJavaBoundObject::ObjectID GinJavaBridgeDispatcherHost::AddObject( | 88 GinJavaBoundObject::ObjectID GinJavaBridgeDispatcherHost::AddObject( |
79 const base::android::JavaRef<jobject>& object, | 89 const base::android::JavaRef<jobject>& object, |
80 const base::android::JavaRef<jclass>& safe_annotation_clazz, | 90 const base::android::JavaRef<jclass>& safe_annotation_clazz, |
81 bool is_named, | 91 bool is_named, |
82 RenderFrameHost* holder) { | 92 RenderFrameHost* holder) { |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 | 355 |
346 bool GinJavaBridgeDispatcherHost::IsValidRenderFrameHost( | 356 bool GinJavaBridgeDispatcherHost::IsValidRenderFrameHost( |
347 RenderFrameHost* render_frame_host) { | 357 RenderFrameHost* render_frame_host) { |
348 scoped_refptr<IsValidRenderFrameHostHelper> helper = | 358 scoped_refptr<IsValidRenderFrameHostHelper> helper = |
349 new IsValidRenderFrameHostHelper(render_frame_host); | 359 new IsValidRenderFrameHostHelper(render_frame_host); |
350 web_contents()->ForEachFrame( | 360 web_contents()->ForEachFrame( |
351 base::Bind(&IsValidRenderFrameHostHelper::OnFrame, helper)); | 361 base::Bind(&IsValidRenderFrameHostHelper::OnFrame, helper)); |
352 return helper->rfh_found(); | 362 return helper->rfh_found(); |
353 } | 363 } |
354 | 364 |
355 void GinJavaBridgeDispatcherHost::SendReply( | |
356 RenderFrameHost* render_frame_host, | |
357 IPC::Message* reply_msg) { | |
358 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
359 if (IsValidRenderFrameHost(render_frame_host)) { | |
360 render_frame_host->Send(reply_msg); | |
361 } else { | |
362 delete reply_msg; | |
363 } | |
364 } | |
365 | |
366 void GinJavaBridgeDispatcherHost::OnGetMethods( | 365 void GinJavaBridgeDispatcherHost::OnGetMethods( |
367 RenderFrameHost* render_frame_host, | 366 RenderFrameHost* render_frame_host, |
368 GinJavaBoundObject::ObjectID object_id, | 367 GinJavaBoundObject::ObjectID object_id, |
369 IPC::Message* reply_msg) { | 368 IPC::Message* reply_msg) { |
370 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 369 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
371 DCHECK(render_frame_host); | 370 DCHECK(render_frame_host); |
372 if (!allow_object_contents_inspection_) { | 371 if (!allow_object_contents_inspection_) { |
373 IPC::WriteParam(reply_msg, std::set<std::string>()); | 372 IPC::WriteParam(reply_msg, std::set<std::string>()); |
374 render_frame_host->Send(reply_msg); | 373 render_frame_host->Send(reply_msg); |
375 return; | 374 return; |
376 } | 375 } |
377 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id)); | 376 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id)); |
378 if (!object) { | 377 if (!object) { |
379 LOG(ERROR) << "WebView: Unknown object: " << object_id; | 378 LOG(ERROR) << "WebView: Unknown object: " << object_id; |
380 IPC::WriteParam(reply_msg, std::set<std::string>()); | 379 IPC::WriteParam(reply_msg, std::set<std::string>()); |
381 render_frame_host->Send(reply_msg); | 380 render_frame_host->Send(reply_msg); |
382 return; | 381 return; |
383 } | 382 } |
| 383 DCHECK(!HasPendingReply(render_frame_host)); |
| 384 pending_replies_[render_frame_host] = reply_msg; |
384 base::PostTaskAndReplyWithResult( | 385 base::PostTaskAndReplyWithResult( |
385 g_background_thread.Get().message_loop()->message_loop_proxy(), | 386 g_background_thread.Get().message_loop()->message_loop_proxy(), |
386 FROM_HERE, | 387 FROM_HERE, |
387 base::Bind(&GinJavaBoundObject::GetMethodNames, object), | 388 base::Bind(&GinJavaBoundObject::GetMethodNames, object), |
388 base::Bind(&GinJavaBridgeDispatcherHost::SendMethods, | 389 base::Bind(&GinJavaBridgeDispatcherHost::SendMethods, |
389 AsWeakPtr(), | 390 AsWeakPtr(), |
390 render_frame_host, | 391 render_frame_host)); |
391 reply_msg)); | |
392 } | 392 } |
393 | 393 |
394 void GinJavaBridgeDispatcherHost::SendMethods( | 394 void GinJavaBridgeDispatcherHost::SendMethods( |
395 RenderFrameHost* render_frame_host, | 395 RenderFrameHost* render_frame_host, |
396 IPC::Message* reply_msg, | |
397 const std::set<std::string>& method_names) { | 396 const std::set<std::string>& method_names) { |
| 397 IPC::Message* reply_msg = TakePendingReply(render_frame_host); |
| 398 if (!reply_msg) { |
| 399 return; |
| 400 } |
398 IPC::WriteParam(reply_msg, method_names); | 401 IPC::WriteParam(reply_msg, method_names); |
399 SendReply(render_frame_host, reply_msg); | 402 render_frame_host->Send(reply_msg); |
400 } | 403 } |
401 | 404 |
402 void GinJavaBridgeDispatcherHost::OnHasMethod( | 405 void GinJavaBridgeDispatcherHost::OnHasMethod( |
403 RenderFrameHost* render_frame_host, | 406 RenderFrameHost* render_frame_host, |
404 GinJavaBoundObject::ObjectID object_id, | 407 GinJavaBoundObject::ObjectID object_id, |
405 const std::string& method_name, | 408 const std::string& method_name, |
406 IPC::Message* reply_msg) { | 409 IPC::Message* reply_msg) { |
407 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 410 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
408 DCHECK(render_frame_host); | 411 DCHECK(render_frame_host); |
409 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id)); | 412 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id)); |
410 if (!object) { | 413 if (!object) { |
411 LOG(ERROR) << "WebView: Unknown object: " << object_id; | 414 LOG(ERROR) << "WebView: Unknown object: " << object_id; |
412 IPC::WriteParam(reply_msg, false); | 415 IPC::WriteParam(reply_msg, false); |
413 render_frame_host->Send(reply_msg); | 416 render_frame_host->Send(reply_msg); |
414 return; | 417 return; |
415 } | 418 } |
| 419 DCHECK(!HasPendingReply(render_frame_host)); |
| 420 pending_replies_[render_frame_host] = reply_msg; |
416 base::PostTaskAndReplyWithResult( | 421 base::PostTaskAndReplyWithResult( |
417 g_background_thread.Get().message_loop()->message_loop_proxy(), | 422 g_background_thread.Get().message_loop()->message_loop_proxy(), |
418 FROM_HERE, | 423 FROM_HERE, |
419 base::Bind(&GinJavaBoundObject::HasMethod, object, method_name), | 424 base::Bind(&GinJavaBoundObject::HasMethod, object, method_name), |
420 base::Bind(&GinJavaBridgeDispatcherHost::SendHasMethodReply, | 425 base::Bind(&GinJavaBridgeDispatcherHost::SendHasMethodReply, |
421 AsWeakPtr(), | 426 AsWeakPtr(), |
422 render_frame_host, | 427 render_frame_host)); |
423 reply_msg)); | |
424 } | 428 } |
425 | 429 |
426 void GinJavaBridgeDispatcherHost::SendHasMethodReply( | 430 void GinJavaBridgeDispatcherHost::SendHasMethodReply( |
427 RenderFrameHost* render_frame_host, | 431 RenderFrameHost* render_frame_host, |
428 IPC::Message* reply_msg, | |
429 bool result) { | 432 bool result) { |
| 433 IPC::Message* reply_msg = TakePendingReply(render_frame_host); |
| 434 if (!reply_msg) { |
| 435 return; |
| 436 } |
430 IPC::WriteParam(reply_msg, result); | 437 IPC::WriteParam(reply_msg, result); |
431 SendReply(render_frame_host, reply_msg); | 438 render_frame_host->Send(reply_msg); |
432 } | 439 } |
433 | 440 |
434 void GinJavaBridgeDispatcherHost::OnInvokeMethod( | 441 void GinJavaBridgeDispatcherHost::OnInvokeMethod( |
435 RenderFrameHost* render_frame_host, | 442 RenderFrameHost* render_frame_host, |
436 GinJavaBoundObject::ObjectID object_id, | 443 GinJavaBoundObject::ObjectID object_id, |
437 const std::string& method_name, | 444 const std::string& method_name, |
438 const base::ListValue& arguments, | 445 const base::ListValue& arguments, |
439 IPC::Message* reply_msg) { | 446 IPC::Message* reply_msg) { |
440 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 447 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
441 DCHECK(render_frame_host); | 448 DCHECK(render_frame_host); |
442 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id)); | 449 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id)); |
443 if (!object) { | 450 if (!object) { |
444 LOG(ERROR) << "WebView: Unknown object: " << object_id; | 451 LOG(ERROR) << "WebView: Unknown object: " << object_id; |
445 base::ListValue result; | 452 base::ListValue result; |
446 result.Append(base::Value::CreateNullValue()); | 453 result.Append(base::Value::CreateNullValue()); |
447 IPC::WriteParam(reply_msg, result); | 454 IPC::WriteParam(reply_msg, result); |
448 IPC::WriteParam(reply_msg, kGinJavaBridgeUnknownObjectId); | 455 IPC::WriteParam(reply_msg, kGinJavaBridgeUnknownObjectId); |
449 render_frame_host->Send(reply_msg); | 456 render_frame_host->Send(reply_msg); |
450 return; | 457 return; |
451 } | 458 } |
| 459 DCHECK(!HasPendingReply(render_frame_host)); |
| 460 pending_replies_[render_frame_host] = reply_msg; |
452 scoped_refptr<GinJavaMethodInvocationHelper> result = | 461 scoped_refptr<GinJavaMethodInvocationHelper> result = |
453 new GinJavaMethodInvocationHelper( | 462 new GinJavaMethodInvocationHelper( |
454 make_scoped_ptr(new GinJavaBoundObjectDelegate(object)) | 463 make_scoped_ptr(new GinJavaBoundObjectDelegate(object)) |
455 .PassAs<GinJavaMethodInvocationHelper::ObjectDelegate>(), | 464 .PassAs<GinJavaMethodInvocationHelper::ObjectDelegate>(), |
456 method_name, | 465 method_name, |
457 arguments); | 466 arguments); |
458 result->Init(this); | 467 result->Init(this); |
459 g_background_thread.Get() | 468 g_background_thread.Get() |
460 .message_loop() | 469 .message_loop() |
461 ->message_loop_proxy() | 470 ->message_loop_proxy() |
462 ->PostTaskAndReply( | 471 ->PostTaskAndReply( |
463 FROM_HERE, | 472 FROM_HERE, |
464 base::Bind(&GinJavaMethodInvocationHelper::Invoke, result), | 473 base::Bind(&GinJavaMethodInvocationHelper::Invoke, result), |
465 base::Bind( | 474 base::Bind( |
466 &GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult, | 475 &GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult, |
467 AsWeakPtr(), | 476 AsWeakPtr(), |
468 render_frame_host, | 477 render_frame_host, |
469 reply_msg, | |
470 result)); | 478 result)); |
471 } | 479 } |
472 | 480 |
473 void GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult( | 481 void GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult( |
474 RenderFrameHost* render_frame_host, | 482 RenderFrameHost* render_frame_host, |
475 IPC::Message* reply_msg, | |
476 scoped_refptr<GinJavaMethodInvocationHelper> result) { | 483 scoped_refptr<GinJavaMethodInvocationHelper> result) { |
477 if (result->HoldsPrimitiveResult()) { | 484 if (result->HoldsPrimitiveResult()) { |
| 485 IPC::Message* reply_msg = TakePendingReply(render_frame_host); |
| 486 if (!reply_msg) { |
| 487 return; |
| 488 } |
478 IPC::WriteParam(reply_msg, result->GetPrimitiveResult()); | 489 IPC::WriteParam(reply_msg, result->GetPrimitiveResult()); |
479 IPC::WriteParam(reply_msg, result->GetInvocationError()); | 490 IPC::WriteParam(reply_msg, result->GetInvocationError()); |
480 SendReply(render_frame_host, reply_msg); | 491 render_frame_host->Send(reply_msg); |
481 } else { | 492 } else { |
482 ProcessMethodInvocationObjectResult(render_frame_host, reply_msg, result); | 493 ProcessMethodInvocationObjectResult(render_frame_host, result); |
483 } | 494 } |
484 } | 495 } |
485 | 496 |
486 void GinJavaBridgeDispatcherHost::ProcessMethodInvocationObjectResult( | 497 void GinJavaBridgeDispatcherHost::ProcessMethodInvocationObjectResult( |
487 RenderFrameHost* render_frame_host, | 498 RenderFrameHost* render_frame_host, |
488 IPC::Message* reply_msg, | |
489 scoped_refptr<GinJavaMethodInvocationHelper> result) { | 499 scoped_refptr<GinJavaMethodInvocationHelper> result) { |
490 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 500 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 501 |
491 if (!IsValidRenderFrameHost(render_frame_host)) { | 502 if (!IsValidRenderFrameHost(render_frame_host)) { |
492 delete reply_msg; | 503 // In this case, we must've already sent the reply when the render frame |
| 504 // was destroyed. |
| 505 DCHECK(!HasPendingReply(render_frame_host)); |
493 return; | 506 return; |
494 } | 507 } |
| 508 |
495 base::ListValue wrapped_result; | 509 base::ListValue wrapped_result; |
496 if (!result->GetObjectResult().is_null()) { | 510 if (!result->GetObjectResult().is_null()) { |
497 GinJavaBoundObject::ObjectID returned_object_id; | 511 GinJavaBoundObject::ObjectID returned_object_id; |
498 if (FindObjectId(result->GetObjectResult(), &returned_object_id)) { | 512 if (FindObjectId(result->GetObjectResult(), &returned_object_id)) { |
499 (*objects_.Lookup(returned_object_id))->AddHolder(render_frame_host); | 513 (*objects_.Lookup(returned_object_id))->AddHolder(render_frame_host); |
500 } else { | 514 } else { |
501 returned_object_id = AddObject(result->GetObjectResult(), | 515 returned_object_id = AddObject(result->GetObjectResult(), |
502 result->GetSafeAnnotationClass(), | 516 result->GetSafeAnnotationClass(), |
503 false, | 517 false, |
504 render_frame_host); | 518 render_frame_host); |
505 } | 519 } |
506 wrapped_result.Append( | 520 wrapped_result.Append( |
507 GinJavaBridgeValue::CreateObjectIDValue(returned_object_id).release()); | 521 GinJavaBridgeValue::CreateObjectIDValue( |
| 522 returned_object_id).release()); |
508 } else { | 523 } else { |
509 wrapped_result.Append(base::Value::CreateNullValue()); | 524 wrapped_result.Append(base::Value::CreateNullValue()); |
510 } | 525 } |
| 526 IPC::Message* reply_msg = TakePendingReply(render_frame_host); |
| 527 if (!reply_msg) { |
| 528 return; |
| 529 } |
511 IPC::WriteParam(reply_msg, wrapped_result); | 530 IPC::WriteParam(reply_msg, wrapped_result); |
512 IPC::WriteParam(reply_msg, result->GetInvocationError()); | 531 IPC::WriteParam(reply_msg, result->GetInvocationError()); |
513 render_frame_host->Send(reply_msg); | 532 render_frame_host->Send(reply_msg); |
514 } | 533 } |
515 | 534 |
516 void GinJavaBridgeDispatcherHost::OnObjectWrapperDeleted( | 535 void GinJavaBridgeDispatcherHost::OnObjectWrapperDeleted( |
517 RenderFrameHost* render_frame_host, | 536 RenderFrameHost* render_frame_host, |
518 GinJavaBoundObject::ObjectID object_id) { | 537 GinJavaBoundObject::ObjectID object_id) { |
519 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 538 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
520 DCHECK(render_frame_host); | 539 DCHECK(render_frame_host); |
521 if (objects_.Lookup(object_id)) { | 540 if (objects_.Lookup(object_id)) { |
522 GinJavaBoundObject::ObjectMap::iterator iter(&objects_); | 541 GinJavaBoundObject::ObjectMap::iterator iter(&objects_); |
523 while (!iter.IsAtEnd() && iter.GetCurrentKey() != object_id) | 542 while (!iter.IsAtEnd() && iter.GetCurrentKey() != object_id) |
524 iter.Advance(); | 543 iter.Advance(); |
525 DCHECK(!iter.IsAtEnd()); | 544 DCHECK(!iter.IsAtEnd()); |
526 RemoveHolder(render_frame_host, iter, 1); | 545 RemoveHolder(render_frame_host, iter, 1); |
527 } | 546 } |
528 } | 547 } |
529 | 548 |
| 549 IPC::Message* GinJavaBridgeDispatcherHost::TakePendingReply( |
| 550 RenderFrameHost* render_frame_host) { |
| 551 if (!IsValidRenderFrameHost(render_frame_host)) { |
| 552 DCHECK(!HasPendingReply(render_frame_host)); |
| 553 return NULL; |
| 554 } |
| 555 |
| 556 PendingReplyMap::iterator it = pending_replies_.find(render_frame_host); |
| 557 // There may be no pending reply if we're called from RenderFrameDeleted and |
| 558 // we already sent the reply through the regular route. |
| 559 if (it == pending_replies_.end()) { |
| 560 return NULL; |
| 561 } |
| 562 |
| 563 IPC::Message* reply_msg = it->second; |
| 564 pending_replies_.erase(it); |
| 565 return reply_msg; |
| 566 } |
| 567 |
| 568 bool GinJavaBridgeDispatcherHost::HasPendingReply( |
| 569 RenderFrameHost* render_frame_host) const { |
| 570 return pending_replies_.find(render_frame_host) != pending_replies_.end(); |
| 571 } |
| 572 |
530 } // namespace content | 573 } // namespace content |
OLD | NEW |