blob: c37eb0c2f6dfd3557619cd2ca7c1535e28fec4a2 [file] [log] [blame]
[email protected]6189cd92012-01-28 02:16:201// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]3c5c6d82011-03-16 17:23:585#include "content/plugin/plugin_channel.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]a4888372011-11-19 02:13:337#include "base/bind.h"
[email protected]bf24d2c2009-02-24 23:07:458#include "base/command_line.h"
[email protected]54724e22013-07-25 13:02:159#include "base/process/process_handle.h"
[email protected]26dd01c2013-06-12 13:52:1310#include "base/strings/string_util.h"
[email protected]20305ec2011-01-21 04:55:5211#include "base/synchronization/lock.h"
[email protected]44f9c952011-01-02 06:05:3912#include "base/synchronization/waitable_event.h"
[email protected]d2e884d2009-06-22 20:37:5213#include "build/build_config.h"
[email protected]10208ea2013-06-06 20:08:0314#include "content/child/child_process.h"
[email protected]29e2fb42013-07-19 01:13:4715#include "content/child/npapi/plugin_instance.h"
[email protected]93cabae2013-10-01 16:11:3616#include "content/child/npapi/webplugin_delegate_impl.h"
[email protected]c7199a6e2013-06-04 12:56:0117#include "content/child/plugin_messages.h"
[email protected]872f3a92013-05-21 08:16:0818#include "content/common/plugin_process_messages.h"
[email protected]3c5c6d82011-03-16 17:23:5819#include "content/plugin/plugin_thread.h"
20#include "content/plugin/webplugin_delegate_stub.h"
21#include "content/plugin/webplugin_proxy.h"
[email protected]c7199a6e2013-06-04 12:56:0122#include "content/public/common/content_switches.h"
[email protected]74122042014-04-25 00:07:3023#include "ipc/message_filter.h"
[email protected]a84bb1462013-06-21 15:59:5024#include "third_party/WebKit/public/web/WebBindings.h"
initial.commit09911bf2008-07-26 23:55:2925
[email protected]d2e884d2009-06-22 20:37:5226#if defined(OS_POSIX)
[email protected]946d1b22009-07-22 23:57:2127#include "ipc/ipc_channel_posix.h"
[email protected]d2e884d2009-06-22 20:37:5228#endif
29
[email protected]180ef242013-11-07 06:50:4630using blink::WebBindings;
[email protected]a84bb1462013-06-21 15:59:5031
[email protected]91355a82012-10-21 19:52:4732namespace content {
33
[email protected]4f15d2842011-02-15 17:36:3334namespace {
35
[email protected]f137d13a2009-08-07 22:57:0636// How long we wait before releasing the plugin process.
[email protected]6189cd92012-01-28 02:16:2037const int kPluginReleaseTimeMinutes = 5;
[email protected]f137d13a2009-08-07 22:57:0638
[email protected]4f15d2842011-02-15 17:36:3339} // namespace
[email protected]8beff0762009-09-29 02:18:3040
41// If a sync call to the renderer results in a modal dialog, we need to have a
42// way to know so that we can run a nested message loop to simulate what would
43// happen in a single process browser and avoid deadlock.
[email protected]74122042014-04-25 00:07:3044class PluginChannel::MessageFilter : public IPC::MessageFilter {
[email protected]8beff0762009-09-29 02:18:3045 public:
[email protected]d1549b82014-06-13 06:07:1446 MessageFilter() : sender_(NULL) { }
[email protected]8beff0762009-09-29 02:18:3047
[email protected]c48de1a2012-11-02 19:06:5648 base::WaitableEvent* GetModalDialogEvent(int render_view_id) {
[email protected]20305ec2011-01-21 04:55:5249 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
[email protected]c48de1a2012-11-02 19:06:5650 if (!modal_dialog_event_map_.count(render_view_id)) {
[email protected]8beff0762009-09-29 02:18:3051 NOTREACHED();
52 return NULL;
53 }
54
[email protected]c48de1a2012-11-02 19:06:5655 return modal_dialog_event_map_[render_view_id].event;
[email protected]8beff0762009-09-29 02:18:3056 }
57
58 // Decrement the ref count associated with the modal dialog event for the
59 // given tab.
[email protected]c48de1a2012-11-02 19:06:5660 void ReleaseModalDialogEvent(int render_view_id) {
[email protected]20305ec2011-01-21 04:55:5261 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
[email protected]c48de1a2012-11-02 19:06:5662 if (!modal_dialog_event_map_.count(render_view_id)) {
[email protected]8beff0762009-09-29 02:18:3063 NOTREACHED();
64 return;
65 }
66
[email protected]c48de1a2012-11-02 19:06:5667 if (--(modal_dialog_event_map_[render_view_id].refcount))
[email protected]8beff0762009-09-29 02:18:3068 return;
69
70 // Delete the event when the stack unwinds as it could be in use now.
[email protected]dd32b1272013-05-04 14:17:1171 base::MessageLoop::current()->DeleteSoon(
[email protected]c48de1a2012-11-02 19:06:5672 FROM_HERE, modal_dialog_event_map_[render_view_id].event);
73 modal_dialog_event_map_.erase(render_view_id);
[email protected]8beff0762009-09-29 02:18:3074 }
75
76 bool Send(IPC::Message* message) {
77 // Need this function for the IPC_MESSAGE_HANDLER_DELAY_REPLY macro.
[email protected]d1549b82014-06-13 06:07:1478 return sender_->Send(message);
[email protected]8beff0762009-09-29 02:18:3079 }
80
[email protected]74122042014-04-25 00:07:3081 // IPC::MessageFilter:
dchenge933b3e2014-10-21 11:44:0982 void OnFilterAdded(IPC::Sender* sender) override { sender_ = sender; }
[email protected]8beff0762009-09-29 02:18:3083
dchenge933b3e2014-10-21 11:44:0984 bool OnMessageReceived(const IPC::Message& message) override {
[email protected]8beff0762009-09-29 02:18:3085 IPC_BEGIN_MESSAGE_MAP(PluginChannel::MessageFilter, message)
86 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_Init, OnInit)
87 IPC_MESSAGE_HANDLER(PluginMsg_SignalModalDialogEvent,
88 OnSignalModalDialogEvent)
89 IPC_MESSAGE_HANDLER(PluginMsg_ResetModalDialogEvent,
90 OnResetModalDialogEvent)
91 IPC_END_MESSAGE_MAP()
92 return message.type() == PluginMsg_SignalModalDialogEvent::ID ||
93 message.type() == PluginMsg_ResetModalDialogEvent::ID;
94 }
95
[email protected]871da302012-05-11 19:30:5596 protected:
dchenge933b3e2014-10-21 11:44:0997 ~MessageFilter() override {
[email protected]871da302012-05-11 19:30:5598 // Clean up in case of renderer crash.
99 for (ModalDialogEventMap::iterator i = modal_dialog_event_map_.begin();
100 i != modal_dialog_event_map_.end(); ++i) {
101 delete i->second.event;
102 }
103 }
104
105 private:
[email protected]8beff0762009-09-29 02:18:30106 void OnInit(const PluginMsg_Init_Params& params, IPC::Message* reply_msg) {
[email protected]20305ec2011-01-21 04:55:52107 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
[email protected]c48de1a2012-11-02 19:06:56108 if (modal_dialog_event_map_.count(params.host_render_view_routing_id)) {
109 modal_dialog_event_map_[params.host_render_view_routing_id].refcount++;
[email protected]8beff0762009-09-29 02:18:30110 return;
111 }
112
113 WaitableEventWrapper wrapper;
114 wrapper.event = new base::WaitableEvent(true, false);
115 wrapper.refcount = 1;
[email protected]c48de1a2012-11-02 19:06:56116 modal_dialog_event_map_[params.host_render_view_routing_id] = wrapper;
[email protected]8beff0762009-09-29 02:18:30117 }
118
[email protected]c48de1a2012-11-02 19:06:56119 void OnSignalModalDialogEvent(int render_view_id) {
[email protected]20305ec2011-01-21 04:55:52120 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
[email protected]c48de1a2012-11-02 19:06:56121 if (modal_dialog_event_map_.count(render_view_id))
122 modal_dialog_event_map_[render_view_id].event->Signal();
[email protected]8beff0762009-09-29 02:18:30123 }
124
[email protected]c48de1a2012-11-02 19:06:56125 void OnResetModalDialogEvent(int render_view_id) {
[email protected]20305ec2011-01-21 04:55:52126 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
[email protected]c48de1a2012-11-02 19:06:56127 if (modal_dialog_event_map_.count(render_view_id))
128 modal_dialog_event_map_[render_view_id].event->Reset();
[email protected]8beff0762009-09-29 02:18:30129 }
130
131 struct WaitableEventWrapper {
132 base::WaitableEvent* event;
133 int refcount; // There could be multiple plugin instances per tab.
134 };
[email protected]c48de1a2012-11-02 19:06:56135 typedef std::map<int, WaitableEventWrapper> ModalDialogEventMap;
[email protected]8beff0762009-09-29 02:18:30136 ModalDialogEventMap modal_dialog_event_map_;
[email protected]20305ec2011-01-21 04:55:52137 base::Lock modal_dialog_event_map_lock_;
[email protected]8beff0762009-09-29 02:18:30138
[email protected]d1549b82014-06-13 06:07:14139 IPC::Sender* sender_;
[email protected]8beff0762009-09-29 02:18:30140};
141
[email protected]92bf9062011-05-02 18:00:49142PluginChannel* PluginChannel::GetPluginChannel(
erikchenf7f988822015-06-17 23:27:07143 int renderer_id,
144 base::SingleThreadTaskRunner* ipc_task_runner,
145 IPC::AttachmentBroker* broker) {
[email protected]76543b92009-08-31 17:27:45146 // Map renderer ID to a (single) channel to that process.
[email protected]7d3cbc92013-03-18 22:33:04147 std::string channel_key = base::StringPrintf(
[email protected]76543b92009-08-31 17:27:45148 "%d.r%d", base::GetCurrentProcId(), renderer_id);
initial.commit09911bf2008-07-26 23:55:29149
[email protected]c84a7852009-09-16 21:36:44150 PluginChannel* channel =
[email protected]099587b72011-09-20 00:40:50151 static_cast<PluginChannel*>(NPChannelBase::GetChannel(
erikchenf7f988822015-06-17 23:27:07152 channel_key, IPC::Channel::MODE_SERVER, ClassFactory, ipc_task_runner,
153 false, ChildProcess::current()->GetShutDownEvent(), broker));
[email protected]c84a7852009-09-16 21:36:44154
155 if (channel)
156 channel->renderer_id_ = renderer_id;
157
158 return channel;
initial.commit09911bf2008-07-26 23:55:29159}
160
[email protected]4e59e812010-04-06 20:51:16161// static
162void PluginChannel::NotifyRenderersOfPendingShutdown() {
163 Broadcast(new PluginHostMsg_PluginShuttingDown());
164}
165
initial.commit09911bf2008-07-26 23:55:29166bool PluginChannel::Send(IPC::Message* msg) {
167 in_send_++;
[email protected]bf24d2c2009-02-24 23:07:45168 if (log_messages_) {
[email protected]3cd32022010-10-21 20:40:57169 VLOG(1) << "sending message @" << msg << " on channel @" << this
170 << " with type " << msg->type();
[email protected]bf24d2c2009-02-24 23:07:45171 }
[email protected]099587b72011-09-20 00:40:50172 bool result = NPChannelBase::Send(msg);
initial.commit09911bf2008-07-26 23:55:29173 in_send_--;
174 return result;
175}
176
[email protected]a95986a82010-12-24 06:19:28177bool PluginChannel::OnMessageReceived(const IPC::Message& msg) {
[email protected]bf24d2c2009-02-24 23:07:45178 if (log_messages_) {
[email protected]3cd32022010-10-21 20:40:57179 VLOG(1) << "received message @" << &msg << " on channel @" << this
180 << " with type " << msg.type();
[email protected]bf24d2c2009-02-24 23:07:45181 }
[email protected]099587b72011-09-20 00:40:50182 return NPChannelBase::OnMessageReceived(msg);
[email protected]bf24d2c2009-02-24 23:07:45183}
184
[email protected]871da302012-05-11 19:30:55185void PluginChannel::OnChannelError() {
186 NPChannelBase::OnChannelError();
187 CleanUp();
188}
189
190int PluginChannel::GenerateRouteID() {
191 static int last_id = 0;
192 return ++last_id;
193}
194
[email protected]c48de1a2012-11-02 19:06:56195base::WaitableEvent* PluginChannel::GetModalDialogEvent(int render_view_id) {
196 return filter_->GetModalDialogEvent(render_view_id);
[email protected]871da302012-05-11 19:30:55197}
198
199PluginChannel::~PluginChannel() {
[email protected]01cb19912013-09-11 19:13:03200 PluginThread::current()->Send(new PluginProcessHostMsg_ChannelDestroyed(
201 renderer_id_));
[email protected]1673caf2013-11-12 20:15:54202 process_ref_.ReleaseWithDelay(
[email protected]871da302012-05-11 19:30:55203 base::TimeDelta::FromMinutes(kPluginReleaseTimeMinutes));
204}
205
206void PluginChannel::CleanUp() {
207 // We need to clean up the stubs so that they call NPPDestroy. This will
208 // also lead to them releasing their reference on this object so that it can
209 // be deleted.
210 for (size_t i = 0; i < plugin_stubs_.size(); ++i)
211 RemoveRoute(plugin_stubs_[i]->instance_id());
212
213 // Need to addref this object temporarily because otherwise removing the last
214 // stub will cause the destructor of this object to be called, however at
215 // that point plugin_stubs_ will have one element and its destructor will be
216 // called twice.
217 scoped_refptr<PluginChannel> me(this);
218
[email protected]f0938f3a2014-01-04 01:40:52219 while (!plugin_stubs_.empty()) {
220 // Separate vector::erase and ~WebPluginDelegateStub.
221 // See https://code.google.com/p/chromium/issues/detail?id=314088
222 scoped_refptr<WebPluginDelegateStub> stub = plugin_stubs_[0];
223 plugin_stubs_.erase(plugin_stubs_.begin());
224 }
[email protected]871da302012-05-11 19:30:55225}
226
skyostil12262cf2015-05-21 14:49:31227bool PluginChannel::Init(base::SingleThreadTaskRunner* ipc_task_runner,
[email protected]871da302012-05-11 19:30:55228 bool create_pipe_now,
erikchenf7f988822015-06-17 23:27:07229 base::WaitableEvent* shutdown_event,
230 IPC::AttachmentBroker* broker) {
231 if (!NPChannelBase::Init(ipc_task_runner, create_pipe_now, shutdown_event,
232 broker)) {
[email protected]871da302012-05-11 19:30:55233 return false;
erikchenf7f988822015-06-17 23:27:07234 }
[email protected]871da302012-05-11 19:30:55235
236 channel_->AddFilter(filter_.get());
237 return true;
238}
239
240PluginChannel::PluginChannel()
241 : renderer_id_(-1),
242 in_send_(0),
243 incognito_(false),
[email protected]a84bb1462013-06-21 15:59:50244 filter_(new MessageFilter()),
245 npp_(new struct _NPP) {
[email protected]871da302012-05-11 19:30:55246 set_send_unblocking_only_during_unblock_dispatch();
avi83883c82014-12-23 00:08:49247 const base::CommandLine* command_line =
248 base::CommandLine::ForCurrentProcess();
[email protected]2fe8d1912014-05-05 20:48:33249 log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
[email protected]a84bb1462013-06-21 15:59:50250
251 // Register |npp_| as the default owner for any object we receive via IPC,
252 // and register it with WebBindings as a valid owner.
253 SetDefaultNPObjectOwner(npp_.get());
254 WebBindings::registerObjectOwner(npp_.get());
[email protected]871da302012-05-11 19:30:55255}
256
[email protected]a95986a82010-12-24 06:19:28257bool PluginChannel::OnControlMessageReceived(const IPC::Message& msg) {
258 bool handled = true;
initial.commit09911bf2008-07-26 23:55:29259 IPC_BEGIN_MESSAGE_MAP(PluginChannel, msg)
260 IPC_MESSAGE_HANDLER(PluginMsg_CreateInstance, OnCreateInstance)
[email protected]f09c7182009-03-10 12:54:04261 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_DestroyInstance,
262 OnDestroyInstance)
initial.commit09911bf2008-07-26 23:55:29263 IPC_MESSAGE_HANDLER(PluginMsg_GenerateRouteID, OnGenerateRouteID)
[email protected]872f3a92013-05-21 08:16:08264 IPC_MESSAGE_HANDLER(PluginProcessMsg_ClearSiteData, OnClearSiteData)
[email protected]93cabae2013-10-01 16:11:36265 IPC_MESSAGE_HANDLER(PluginHostMsg_DidAbortLoading, OnDidAbortLoading)
[email protected]a95986a82010-12-24 06:19:28266 IPC_MESSAGE_UNHANDLED(handled = false)
initial.commit09911bf2008-07-26 23:55:29267 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28268 DCHECK(handled);
269 return handled;
initial.commit09911bf2008-07-26 23:55:29270}
271
272void PluginChannel::OnCreateInstance(const std::string& mime_type,
273 int* instance_id) {
274 *instance_id = GenerateRouteID();
[email protected]ad8e04a2010-11-01 04:16:27275 scoped_refptr<WebPluginDelegateStub> stub(new WebPluginDelegateStub(
276 mime_type, *instance_id, this));
[email protected]fc72bb12013-06-02 21:13:46277 AddRoute(*instance_id, stub.get(), NULL);
initial.commit09911bf2008-07-26 23:55:29278 plugin_stubs_.push_back(stub);
279}
280
281void PluginChannel::OnDestroyInstance(int instance_id,
282 IPC::Message* reply_msg) {
283 for (size_t i = 0; i < plugin_stubs_.size(); ++i) {
284 if (plugin_stubs_[i]->instance_id() == instance_id) {
[email protected]49f69ae2009-10-06 19:11:22285 scoped_refptr<MessageFilter> filter(filter_);
[email protected]c48de1a2012-11-02 19:06:56286 int render_view_id =
287 plugin_stubs_[i]->webplugin()->host_render_view_routing_id();
[email protected]f0938f3a2014-01-04 01:40:52288 // Separate vector::erase and ~WebPluginDelegateStub.
289 // See https://code.google.com/p/chromium/issues/detail?id=314088
290 scoped_refptr<WebPluginDelegateStub> stub = plugin_stubs_[i];
initial.commit09911bf2008-07-26 23:55:29291 plugin_stubs_.erase(plugin_stubs_.begin() + i);
[email protected]f0938f3a2014-01-04 01:40:52292 stub = NULL;
293
initial.commit09911bf2008-07-26 23:55:29294 Send(reply_msg);
[email protected]49f69ae2009-10-06 19:11:22295 RemoveRoute(instance_id);
296 // NOTE: *this* might be deleted as a result of calling RemoveRoute.
297 // Don't release the modal dialog event right away, but do it after the
298 // stack unwinds since the plugin can be destroyed later if it's in use
299 // right now.
[email protected]dd32b1272013-05-04 14:17:11300 base::MessageLoop::current()->PostNonNestableTask(
301 FROM_HERE,
302 base::Bind(&MessageFilter::ReleaseModalDialogEvent,
303 filter.get(),
304 render_view_id));
initial.commit09911bf2008-07-26 23:55:29305 return;
306 }
307 }
308
309 NOTREACHED() << "Couldn't find WebPluginDelegateStub to destroy";
310}
311
312void PluginChannel::OnGenerateRouteID(int* route_id) {
313 *route_id = GenerateRouteID();
314}
315
[email protected]a4b146f2011-01-11 12:43:36316void PluginChannel::OnClearSiteData(const std::string& site,
317 uint64 flags,
[email protected]1bf0fb22012-04-12 21:44:16318 uint64 max_age) {
[email protected]8b8a554d2010-11-18 13:26:40319 bool success = false;
avi83883c82014-12-23 00:08:49320 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
[email protected]d30a36f2013-02-07 04:16:26321 base::FilePath path = command_line->GetSwitchValuePath(switches::kPluginPath);
[email protected]29e2fb42013-07-19 01:13:47322 scoped_refptr<PluginLib> plugin_lib(PluginLib::CreatePluginLib(path));
[email protected]fc72bb12013-06-02 21:13:46323 if (plugin_lib.get()) {
[email protected]8b8a554d2010-11-18 13:26:40324 NPError err = plugin_lib->NP_Initialize();
325 if (err == NPERR_NO_ERROR) {
[email protected]a4b146f2011-01-11 12:43:36326 const char* site_str = site.empty() ? NULL : site.c_str();
[email protected]a4b146f2011-01-11 12:43:36327 err = plugin_lib->NP_ClearSiteData(site_str, flags, max_age);
[email protected]b1f172a72011-04-11 17:26:07328 std::string site_name =
329 site.empty() ? "NULL"
330 : base::StringPrintf("\"%s\"", site_str);
331 VLOG(1) << "NPP_ClearSiteData(" << site_name << ", " << flags << ", "
332 << max_age << ") returned " << err;
[email protected]8b8a554d2010-11-18 13:26:40333 success = (err == NPERR_NO_ERROR);
334 }
335 }
[email protected]872f3a92013-05-21 08:16:08336 Send(new PluginProcessHostMsg_ClearSiteDataResult(success));
[email protected]8b8a554d2010-11-18 13:26:40337}
[email protected]91355a82012-10-21 19:52:47338
[email protected]93cabae2013-10-01 16:11:36339void PluginChannel::OnDidAbortLoading(int render_view_id) {
340 for (size_t i = 0; i < plugin_stubs_.size(); ++i) {
341 if (plugin_stubs_[i]->webplugin()->host_render_view_routing_id() ==
342 render_view_id) {
343 plugin_stubs_[i]->delegate()->instance()->CloseStreams();
344 }
345 }
346}
347
[email protected]91355a82012-10-21 19:52:47348} // namespace content