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. 4 5 #include "content/browser/renderer_host/java/java_bridge_dispatcher_host.h" 6 7 #include "base/android/java_handler_thread.h" 8 #include "base/bind.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" 19 20 #if !defined(OS_ANDROID) 21 #error "JavaBridge currently only supports OS_ANDROID" 22 #endif 23 24 namespace content { 25 26 namespace { 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 { 30 public: 31 JavaBridgeThread() : base::android::JavaHandlerThread("JavaBridge") { 32 Start(); 33 } 34 virtual ~JavaBridgeThread() { 35 Stop(); 36 } 37 }; 38 39 void CleanUpStubs(const std::vector<base::WeakPtr<NPObjectStub> > & stubs) { 40 for (size_t i = 0; i < stubs.size(); ++i) { 41 if (stubs[i]) { 42 stubs[i]->DeleteSoon(); 43 } 44 } 45 } 46 47 base::LazyInstance<JavaBridgeThread> g_background_thread = 48 LAZY_INSTANCE_INITIALIZER; 49 } // namespace 50 51 JavaBridgeDispatcherHost::JavaBridgeDispatcherHost( 52 RenderViewHost* render_view_host) 53 : RenderViewHostObserver(render_view_host), 54 is_renderer_initialized_(false) { 55 } 56 57 JavaBridgeDispatcherHost::~JavaBridgeDispatcherHost() { 58 g_background_thread.Get().message_loop()->PostTask( 59 FROM_HERE, 60 base::Bind(&CleanUpStubs, stubs_)); 61 } 62 63 void JavaBridgeDispatcherHost::AddNamedObject(const string16& name, 64 NPObject* object) { 65 NPVariant_Param variant_param; 66 CreateNPVariantParam(object, &variant_param); 67 68 if (!is_renderer_initialized_) { 69 is_renderer_initialized_ = true; 70 Send(new JavaBridgeMsg_Init(routing_id())); 71 } 72 Send(new JavaBridgeMsg_AddNamedObject(routing_id(), name, variant_param)); 73 } 74 75 void JavaBridgeDispatcherHost::RemoveNamedObject(const string16& name) { 76 // On receipt of this message, the JavaBridgeDispatcher will drop its 77 // reference to the corresponding proxy object. When the last reference is 78 // removed, the proxy object will delete its NPObjectProxy, which will cause 79 // the NPObjectStub to be deleted, which will drop its reference to the 80 // original NPObject. 81 Send(new JavaBridgeMsg_RemoveNamedObject(routing_id(), name)); 82 } 83 84 bool JavaBridgeDispatcherHost::Send(IPC::Message* msg) { 85 return RenderViewHostObserver::Send(msg); 86 } 87 88 void JavaBridgeDispatcherHost::RenderViewHostDestroyed( 89 RenderViewHost* render_view_host) { 90 // Base implementation deletes the object. This class is ref counted, with 91 // refs held by the JavaBridgeDispatcherHostManager and base::Bind, so that 92 // behavior is unwanted. 93 } 94 95 bool JavaBridgeDispatcherHost::OnMessageReceived(const IPC::Message& msg) { 96 bool handled = true; 97 IPC_BEGIN_MESSAGE_MAP(JavaBridgeDispatcherHost, msg) 98 IPC_MESSAGE_HANDLER_DELAY_REPLY(JavaBridgeHostMsg_GetChannelHandle, 99 OnGetChannelHandle) 100 IPC_MESSAGE_UNHANDLED(handled = false) 101 IPC_END_MESSAGE_MAP() 102 return handled; 103 } 104 105 void JavaBridgeDispatcherHost::OnGetChannelHandle(IPC::Message* reply_msg) { 106 g_background_thread.Get().message_loop()->PostTask( 107 FROM_HERE, 108 base::Bind(&JavaBridgeDispatcherHost::GetChannelHandle, this, reply_msg)); 109 } 110 111 void JavaBridgeDispatcherHost::GetChannelHandle(IPC::Message* reply_msg) { 112 // The channel creates the channel handle based on the renderer ID we passed 113 // to GetJavaBridgeChannelHost() and, on POSIX, the file descriptor used by 114 // the underlying channel. 115 JavaBridgeHostMsg_GetChannelHandle::WriteReplyParams( 116 reply_msg, 117 channel_->channel_handle()); 118 Send(reply_msg); 119 } 120 121 void JavaBridgeDispatcherHost::CreateNPVariantParam(NPObject* object, 122 NPVariant_Param* param) { 123 // The JavaBridgeChannelHost needs to be created on the background thread, as 124 // that is where Java objects will live, and CreateNPVariantParam() needs the 125 // channel to create the NPObjectStub. To avoid blocking here until the 126 // channel is ready, create the NPVariant_Param by hand, then post a message 127 // to the background thread to set up the channel and create the corresponding 128 // NPObjectStub. Post that message before doing any IPC, to make sure that 129 // the channel and object proxies are ready before responses are received 130 // from the renderer. 131 132 // Create an NPVariantParam suitable for serialization over IPC from our 133 // NPVariant. See CreateNPVariantParam() in npobject_utils. 134 param->type = NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID; 135 int route_id = JavaBridgeChannelHost::ThreadsafeGenerateRouteID(); 136 param->npobject_routing_id = route_id; 137 138 WebKit::WebBindings::retainObject(object); 139 g_background_thread.Get().message_loop()->PostTask( 140 FROM_HERE, 141 base::Bind(&JavaBridgeDispatcherHost::CreateObjectStub, this, object, 142 route_id)); 143 } 144 145 void JavaBridgeDispatcherHost::CreateObjectStub(NPObject* object, 146 int route_id) { 147 DCHECK_EQ(g_background_thread.Get().message_loop(), 148 base::MessageLoop::current()); 149 if (!channel_.get()) { 150 channel_ = JavaBridgeChannelHost::GetJavaBridgeChannelHost( 151 render_view_host()->GetProcess()->GetID(), 152 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)); 153 } 154 155 // In a typical scenario, the lifetime of each NPObjectStub is governed by 156 // that of the NPObjectProxy in the renderer, via the channel. However, 157 // we cannot guaranteed that the renderer always terminates cleanly 158 // (crashes / sometimes just unavoidable). We keep a weak reference to 159 // it now and schedule a delete on it when this host is getting deleted. 160 161 // Pass 0 for the containing window, as it's only used by plugins to pump the 162 // window message queue when a method on a renderer-side object causes a 163 // dialog to be displayed, and the Java Bridge does not need this 164 // functionality. The page URL is also not required. 165 stubs_.push_back((new NPObjectStub( 166 object, channel_.get(), route_id, 0, GURL()))->AsWeakPtr()); 167 168 // The NPObjectStub takes a reference to the NPObject. Release the ref added 169 // in CreateNPVariantParam(). 170 WebKit::WebBindings::releaseObject(object); 171 } 172 173 } // namespace content 174