1 // Copyright (c) 2012 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.
5 #include "content/browser/renderer_host/java/java_bridge_dispatcher_host.h"
7 #include "base/android/java_handler_thread.h"
9 #include "base/lazy_instance.h"
10 #include "content/browser/renderer_host/java/java_bridge_channel_host.h"
11 #include "content/browser/renderer_host/render_view_host_impl.h"
12 #include "content/child/child_process.h"
13 #include "content/child/npapi/npobject_stub.h"
14 #include "content/child/npapi/npobject_util.h" // For CreateNPVariantParam()
15 #include "content/common/java_bridge_messages.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "third_party/WebKit/public/web/WebBindings.h"
20 #if !defined(OS_ANDROID)
21 #error "JavaBridge only supports OS_ANDROID"
27 // The JavaBridge needs to use a Java thread so the callback
28 // will happen on a thread with a prepared Looper.
29 class JavaBridgeThread
: public base::android::JavaHandlerThread
{
31 JavaBridgeThread() : base::android::JavaHandlerThread("JavaBridge") {
34 virtual ~JavaBridgeThread() {
39 void CleanUpStubs(const std::vector
<base::WeakPtr
<NPObjectStub
> > & stubs
) {
40 for (size_t i
= 0; i
< stubs
.size(); ++i
) {
42 stubs
[i
]->DeleteSoon();
47 base::LazyInstance
<JavaBridgeThread
> g_background_thread
=
48 LAZY_INSTANCE_INITIALIZER
;
51 JavaBridgeDispatcherHost::JavaBridgeDispatcherHost(
52 RenderViewHost
* render_view_host
)
53 : render_view_host_(render_view_host
) {
56 JavaBridgeDispatcherHost::~JavaBridgeDispatcherHost() {
57 g_background_thread
.Get().message_loop()->PostTask(
59 base::Bind(&CleanUpStubs
, stubs_
));
62 void JavaBridgeDispatcherHost::AddNamedObject(const base::string16
& name
,
64 NPVariant_Param variant_param
;
65 CreateNPVariantParam(object
, &variant_param
);
67 Send(new JavaBridgeMsg_AddNamedObject(
68 render_view_host_
->GetRoutingID(), name
, variant_param
));
71 void JavaBridgeDispatcherHost::RemoveNamedObject(const base::string16
& name
) {
72 // On receipt of this message, the JavaBridgeDispatcher will drop its
73 // reference to the corresponding proxy object. When the last reference is
74 // removed, the proxy object will delete its NPObjectProxy, which will cause
75 // the NPObjectStub to be deleted, which will drop its reference to the
77 Send(new JavaBridgeMsg_RemoveNamedObject(
78 render_view_host_
->GetRoutingID(), name
));
81 void JavaBridgeDispatcherHost::RenderViewDeleted() {
82 render_view_host_
= NULL
;
85 void JavaBridgeDispatcherHost::OnGetChannelHandle(IPC::Message
* reply_msg
) {
86 g_background_thread
.Get().message_loop()->PostTask(
88 base::Bind(&JavaBridgeDispatcherHost::GetChannelHandle
, this, reply_msg
));
91 void JavaBridgeDispatcherHost::Send(IPC::Message
* msg
) {
92 if (render_view_host_
) {
93 render_view_host_
->Send(msg
);
100 void JavaBridgeDispatcherHost::GetChannelHandle(IPC::Message
* reply_msg
) {
101 // The channel creates the channel handle based on the renderer ID we passed
102 // to GetJavaBridgeChannelHost() and, on POSIX, the file descriptor used by
103 // the underlying channel.
104 JavaBridgeHostMsg_GetChannelHandle::WriteReplyParams(
106 channel_
->channel_handle());
108 BrowserThread::PostTask(
111 base::Bind(&JavaBridgeDispatcherHost::Send
, this, reply_msg
));
114 void JavaBridgeDispatcherHost::CreateNPVariantParam(NPObject
* object
,
115 NPVariant_Param
* param
) {
116 // The JavaBridgeChannelHost needs to be created on the background thread, as
117 // that is where Java objects will live, and CreateNPVariantParam() needs the
118 // channel to create the NPObjectStub. To avoid blocking here until the
119 // channel is ready, create the NPVariant_Param by hand, then post a message
120 // to the background thread to set up the channel and create the corresponding
121 // NPObjectStub. Post that message before doing any IPC, to make sure that
122 // the channel and object proxies are ready before responses are received
123 // from the renderer.
125 // Create an NPVariantParam suitable for serialization over IPC from our
126 // NPVariant. See CreateNPVariantParam() in npobject_utils.
127 param
->type
= NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID
;
128 int route_id
= JavaBridgeChannelHost::ThreadsafeGenerateRouteID();
129 param
->npobject_routing_id
= route_id
;
131 blink::WebBindings::retainObject(object
);
132 g_background_thread
.Get().message_loop()->PostTask(
134 base::Bind(&JavaBridgeDispatcherHost::CreateObjectStub
, this, object
,
135 render_view_host_
->GetProcess()->GetID(), route_id
));
138 void JavaBridgeDispatcherHost::CreateObjectStub(NPObject
* object
,
139 int render_process_id
,
141 DCHECK_EQ(g_background_thread
.Get().message_loop(),
142 base::MessageLoop::current());
143 if (!channel_
.get()) {
144 channel_
= JavaBridgeChannelHost::GetJavaBridgeChannelHost(
146 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
));
149 // In a typical scenario, the lifetime of each NPObjectStub is governed by
150 // that of the NPObjectProxy in the renderer, via the channel. However,
151 // we cannot guaranteed that the renderer always terminates cleanly
152 // (crashes / sometimes just unavoidable). We keep a weak reference to
153 // it now and schedule a delete on it when this host is getting deleted.
155 // Pass 0 for the containing window, as it's only used by plugins to pump the
156 // window message queue when a method on a renderer-side object causes a
157 // dialog to be displayed, and the Java Bridge does not need this
158 // functionality. The page URL is also not required.
159 stubs_
.push_back((new NPObjectStub(
160 object
, channel_
.get(), route_id
, 0, GURL()))->AsWeakPtr());
162 // The NPObjectStub takes a reference to the NPObject. Release the ref added
163 // in CreateNPVariantParam().
164 blink::WebBindings::releaseObject(object
);
167 } // namespace content