summaryrefslogtreecommitdiffstats
path: root/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc
blob: 562517a114076f61d68922385a4ba5d9f560fda3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/java/java_bridge_dispatcher_host.h"

#include "base/android/java_handler_thread.h"
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "content/browser/renderer_host/java/java_bridge_channel_host.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/child/child_process.h"
#include "content/child/npapi/npobject_stub.h"
#include "content/child/npapi/npobject_util.h"  // For CreateNPVariantParam()
#include "content/common/java_bridge_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "third_party/WebKit/public/web/WebBindings.h"

#if !defined(OS_ANDROID)
#error "JavaBridge only supports OS_ANDROID"
#endif

namespace content {

namespace {
// The JavaBridge needs to use a Java thread so the callback
// will happen on a thread with a prepared Looper.
class JavaBridgeThread : public base::android::JavaHandlerThread {
 public:
  JavaBridgeThread() : base::android::JavaHandlerThread("JavaBridge") {
    Start();
  }
  virtual ~JavaBridgeThread() {
    Stop();
  }
};

void CleanUpStubs(const std::vector<base::WeakPtr<NPObjectStub> > & stubs) {
  for (size_t i = 0; i < stubs.size(); ++i) {
    if (stubs[i]) {
      stubs[i]->DeleteSoon();
    }
  }
}

base::LazyInstance<JavaBridgeThread> g_background_thread =
    LAZY_INSTANCE_INITIALIZER;
}  // namespace

JavaBridgeDispatcherHost::JavaBridgeDispatcherHost(
    RenderViewHost* render_view_host)
    : render_view_host_(render_view_host) {
}

JavaBridgeDispatcherHost::~JavaBridgeDispatcherHost() {
  g_background_thread.Get().message_loop()->PostTask(
      FROM_HERE,
      base::Bind(&CleanUpStubs, stubs_));
}

void JavaBridgeDispatcherHost::AddNamedObject(const base::string16& name,
                                              NPObject* object) {
  NPVariant_Param variant_param;
  CreateNPVariantParam(object, &variant_param);

  Send(new JavaBridgeMsg_AddNamedObject(
      render_view_host_->GetRoutingID(), name, variant_param));
}

void JavaBridgeDispatcherHost::RemoveNamedObject(const base::string16& name) {
  // On receipt of this message, the JavaBridgeDispatcher will drop its
  // reference to the corresponding proxy object. When the last reference is
  // removed, the proxy object will delete its NPObjectProxy, which will cause
  // the NPObjectStub to be deleted, which will drop its reference to the
  // original NPObject.
  Send(new JavaBridgeMsg_RemoveNamedObject(
      render_view_host_->GetRoutingID(), name));
}

void JavaBridgeDispatcherHost::RenderViewDeleted() {
  render_view_host_ = NULL;
}

void JavaBridgeDispatcherHost::OnGetChannelHandle(IPC::Message* reply_msg) {
  g_background_thread.Get().message_loop()->PostTask(
      FROM_HERE,
      base::Bind(&JavaBridgeDispatcherHost::GetChannelHandle, this, reply_msg));
}

void JavaBridgeDispatcherHost::Send(IPC::Message* msg) {
  if (render_view_host_) {
    render_view_host_->Send(msg);
    return;
  }

  delete msg;
}

void JavaBridgeDispatcherHost::GetChannelHandle(IPC::Message* reply_msg) {
  // The channel creates the channel handle based on the renderer ID we passed
  // to GetJavaBridgeChannelHost() and, on POSIX, the file descriptor used by
  // the underlying channel.
  JavaBridgeHostMsg_GetChannelHandle::WriteReplyParams(
      reply_msg,
      channel_->channel_handle());

  BrowserThread::PostTask(
      BrowserThread::UI,
      FROM_HERE,
      base::Bind(&JavaBridgeDispatcherHost::Send, this, reply_msg));
}

void JavaBridgeDispatcherHost::CreateNPVariantParam(NPObject* object,
                                                    NPVariant_Param* param) {
  // The JavaBridgeChannelHost needs to be created on the background thread, as
  // that is where Java objects will live, and CreateNPVariantParam() needs the
  // channel to create the NPObjectStub. To avoid blocking here until the
  // channel is ready, create the NPVariant_Param by hand, then post a message
  // to the background thread to set up the channel and create the corresponding
  // NPObjectStub. Post that message before doing any IPC, to make sure that
  // the channel and object proxies are ready before responses are received
  // from the renderer.

  // Create an NPVariantParam suitable for serialization over IPC from our
  // NPVariant. See CreateNPVariantParam() in npobject_utils.
  param->type = NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID;
  int route_id = JavaBridgeChannelHost::ThreadsafeGenerateRouteID();
  param->npobject_routing_id = route_id;

  blink::WebBindings::retainObject(object);
  g_background_thread.Get().message_loop()->PostTask(
      FROM_HERE,
      base::Bind(&JavaBridgeDispatcherHost::CreateObjectStub, this, object,
                 render_view_host_->GetProcess()->GetID(), route_id));
}

void JavaBridgeDispatcherHost::CreateObjectStub(NPObject* object,
                                                int render_process_id,
                                                int route_id) {
  DCHECK_EQ(g_background_thread.Get().message_loop(),
            base::MessageLoop::current());
  if (!channel_.get()) {
    channel_ = JavaBridgeChannelHost::GetJavaBridgeChannelHost(
        render_process_id,
        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
  }

  // In a typical scenario, the lifetime of each NPObjectStub is governed by
  // that of the NPObjectProxy in the renderer, via the channel. However,
  // we cannot guaranteed that the renderer always terminates cleanly
  // (crashes / sometimes just unavoidable). We keep a weak reference to
  // it now and schedule a delete on it when this host is getting deleted.

  // Pass 0 for the containing window, as it's only used by plugins to pump the
  // window message queue when a method on a renderer-side object causes a
  // dialog to be displayed, and the Java Bridge does not need this
  // functionality. The page URL is also not required.
  stubs_.push_back((new NPObjectStub(
      object, channel_.get(), route_id, 0, GURL()))->AsWeakPtr());

  // The NPObjectStub takes a reference to the NPObject. Release the ref added
  // in CreateNPVariantParam().
  blink::WebBindings::releaseObject(object);
}

}  // namespace content