blob: bc5e61ee425ee03c1e2da99f823639378d38c181 [file] [log] [blame]
[email protected]3cd32022010-10-21 20:40:571// Copyright (c) 2010 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
initial.commit09911bf2008-07-26 23:55:295#include "chrome/plugin/plugin_channel.h"
6
[email protected]bf24d2c2009-02-24 23:07:457#include "base/command_line.h"
[email protected]8beff0762009-09-29 02:18:308#include "base/lock.h"
[email protected]4566f132009-03-12 01:55:139#include "base/process_util.h"
initial.commit09911bf2008-07-26 23:55:2910#include "base/string_util.h"
[email protected]8beff0762009-09-29 02:18:3011#include "base/waitable_event.h"
[email protected]d2e884d2009-06-22 20:37:5212#include "build/build_config.h"
[email protected]51d70e02009-03-27 20:45:5913#include "chrome/common/child_process.h"
14#include "chrome/common/plugin_messages.h"
[email protected]bf24d2c2009-02-24 23:07:4515#include "chrome/common/chrome_switches.h"
[email protected]8930d472009-02-21 08:05:2816#include "chrome/plugin/plugin_thread.h"
[email protected]8beff0762009-09-29 02:18:3017#include "chrome/plugin/webplugin_delegate_stub.h"
18#include "chrome/plugin/webplugin_proxy.h"
[email protected]191eb3f72010-12-21 06:27:5019#include "webkit/plugins/npapi/plugin_instance.h"
initial.commit09911bf2008-07-26 23:55:2920
[email protected]d2e884d2009-06-22 20:37:5221#if defined(OS_POSIX)
[email protected]4a8278472010-03-18 16:14:4922#include "base/eintr_wrapper.h"
[email protected]946d1b22009-07-22 23:57:2123#include "ipc/ipc_channel_posix.h"
[email protected]d2e884d2009-06-22 20:37:5224#endif
25
[email protected]f137d13a2009-08-07 22:57:0626class PluginReleaseTask : public Task {
27 public:
28 void Run() {
29 ChildProcess::current()->ReleaseProcess();
30 }
31};
32
33// How long we wait before releasing the plugin process.
[email protected]2913e84f32010-05-13 18:36:1534static const int kPluginReleaseTimeMS = 5 * 60 * 1000; // 5 minutes
[email protected]f137d13a2009-08-07 22:57:0635
[email protected]8beff0762009-09-29 02:18:3036
37// If a sync call to the renderer results in a modal dialog, we need to have a
38// way to know so that we can run a nested message loop to simulate what would
39// happen in a single process browser and avoid deadlock.
40class PluginChannel::MessageFilter : public IPC::ChannelProxy::MessageFilter {
41 public:
42 MessageFilter() : channel_(NULL) { }
43 ~MessageFilter() {
44 // Clean up in case of renderer crash.
45 for (ModalDialogEventMap::iterator i = modal_dialog_event_map_.begin();
46 i != modal_dialog_event_map_.end(); ++i) {
47 delete i->second.event;
48 }
49 }
50
51 base::WaitableEvent* GetModalDialogEvent(
52 gfx::NativeViewId containing_window) {
53 AutoLock auto_lock(modal_dialog_event_map_lock_);
54 if (!modal_dialog_event_map_.count(containing_window)) {
55 NOTREACHED();
56 return NULL;
57 }
58
59 return modal_dialog_event_map_[containing_window].event;
60 }
61
62 // Decrement the ref count associated with the modal dialog event for the
63 // given tab.
64 void ReleaseModalDialogEvent(gfx::NativeViewId containing_window) {
65 AutoLock auto_lock(modal_dialog_event_map_lock_);
66 if (!modal_dialog_event_map_.count(containing_window)) {
67 NOTREACHED();
68 return;
69 }
70
71 if (--(modal_dialog_event_map_[containing_window].refcount))
72 return;
73
74 // Delete the event when the stack unwinds as it could be in use now.
75 MessageLoop::current()->DeleteSoon(
76 FROM_HERE, modal_dialog_event_map_[containing_window].event);
77 modal_dialog_event_map_.erase(containing_window);
78 }
79
80 bool Send(IPC::Message* message) {
81 // Need this function for the IPC_MESSAGE_HANDLER_DELAY_REPLY macro.
82 return channel_->Send(message);
83 }
84
85 private:
86 void OnFilterAdded(IPC::Channel* channel) { channel_ = channel; }
87
88 bool OnMessageReceived(const IPC::Message& message) {
89 IPC_BEGIN_MESSAGE_MAP(PluginChannel::MessageFilter, message)
90 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_Init, OnInit)
91 IPC_MESSAGE_HANDLER(PluginMsg_SignalModalDialogEvent,
92 OnSignalModalDialogEvent)
93 IPC_MESSAGE_HANDLER(PluginMsg_ResetModalDialogEvent,
94 OnResetModalDialogEvent)
95 IPC_END_MESSAGE_MAP()
96 return message.type() == PluginMsg_SignalModalDialogEvent::ID ||
97 message.type() == PluginMsg_ResetModalDialogEvent::ID;
98 }
99
100 void OnInit(const PluginMsg_Init_Params& params, IPC::Message* reply_msg) {
101 AutoLock auto_lock(modal_dialog_event_map_lock_);
102 if (modal_dialog_event_map_.count(params.containing_window)) {
103 modal_dialog_event_map_[params.containing_window].refcount++;
104 return;
105 }
106
107 WaitableEventWrapper wrapper;
108 wrapper.event = new base::WaitableEvent(true, false);
109 wrapper.refcount = 1;
110 modal_dialog_event_map_[params.containing_window] = wrapper;
111 }
112
113 void OnSignalModalDialogEvent(gfx::NativeViewId containing_window) {
114 AutoLock auto_lock(modal_dialog_event_map_lock_);
115 if (modal_dialog_event_map_.count(containing_window))
116 modal_dialog_event_map_[containing_window].event->Signal();
117 }
118
119 void OnResetModalDialogEvent(gfx::NativeViewId containing_window) {
120 AutoLock auto_lock(modal_dialog_event_map_lock_);
121 if (modal_dialog_event_map_.count(containing_window))
122 modal_dialog_event_map_[containing_window].event->Reset();
123 }
124
125 struct WaitableEventWrapper {
126 base::WaitableEvent* event;
127 int refcount; // There could be multiple plugin instances per tab.
128 };
129 typedef std::map<gfx::NativeViewId, WaitableEventWrapper> ModalDialogEventMap;
130 ModalDialogEventMap modal_dialog_event_map_;
131 Lock modal_dialog_event_map_lock_;
132
133 IPC::Channel* channel_;
134};
135
136
[email protected]76543b92009-08-31 17:27:45137PluginChannel* PluginChannel::GetPluginChannel(int renderer_id,
138 MessageLoop* ipc_message_loop) {
139 // Map renderer ID to a (single) channel to that process.
[email protected]8ad72d592010-08-25 20:14:17140 std::string channel_key = StringPrintf(
[email protected]76543b92009-08-31 17:27:45141 "%d.r%d", base::GetCurrentProcId(), renderer_id);
initial.commit09911bf2008-07-26 23:55:29142
[email protected]c84a7852009-09-16 21:36:44143 PluginChannel* channel =
144 static_cast<PluginChannel*>(PluginChannelBase::GetChannel(
[email protected]8ad72d592010-08-25 20:14:17145 channel_key,
[email protected]c84a7852009-09-16 21:36:44146 IPC::Channel::MODE_SERVER,
147 ClassFactory,
148 ipc_message_loop,
149 false));
150
151 if (channel)
152 channel->renderer_id_ = renderer_id;
153
154 return channel;
initial.commit09911bf2008-07-26 23:55:29155}
156
[email protected]4e59e812010-04-06 20:51:16157// static
158void PluginChannel::NotifyRenderersOfPendingShutdown() {
159 Broadcast(new PluginHostMsg_PluginShuttingDown());
160}
161
[email protected]3dfc7a42009-06-27 01:43:51162PluginChannel::PluginChannel()
163 : renderer_handle_(0),
[email protected]c84a7852009-09-16 21:36:44164 renderer_id_(-1),
[email protected]3dfc7a42009-06-27 01:43:51165 in_send_(0),
[email protected]8beff0762009-09-29 02:18:30166 off_the_record_(false),
167 filter_(new MessageFilter()) {
[email protected]390c7812010-05-12 20:32:52168 set_send_unblocking_only_during_unblock_dispatch();
[email protected]51d70e02009-03-27 20:45:59169 ChildProcess::current()->AddRefProcess();
[email protected]bf24d2c2009-02-24 23:07:45170 const CommandLine* command_line = CommandLine::ForCurrentProcess();
171 log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
initial.commit09911bf2008-07-26 23:55:29172}
173
174PluginChannel::~PluginChannel() {
[email protected]157e5d22009-04-23 18:43:35175 if (renderer_handle_)
176 base::CloseProcessHandle(renderer_handle_);
[email protected]4a8278472010-03-18 16:14:49177
[email protected]f137d13a2009-08-07 22:57:06178 MessageLoop::current()->PostDelayedTask(FROM_HERE, new PluginReleaseTask(),
179 kPluginReleaseTimeMS);
initial.commit09911bf2008-07-26 23:55:29180}
181
182bool PluginChannel::Send(IPC::Message* msg) {
183 in_send_++;
[email protected]bf24d2c2009-02-24 23:07:45184 if (log_messages_) {
[email protected]3cd32022010-10-21 20:40:57185 VLOG(1) << "sending message @" << msg << " on channel @" << this
186 << " with type " << msg->type();
[email protected]bf24d2c2009-02-24 23:07:45187 }
initial.commit09911bf2008-07-26 23:55:29188 bool result = PluginChannelBase::Send(msg);
189 in_send_--;
190 return result;
191}
192
[email protected]bf24d2c2009-02-24 23:07:45193void PluginChannel::OnMessageReceived(const IPC::Message& msg) {
194 if (log_messages_) {
[email protected]3cd32022010-10-21 20:40:57195 VLOG(1) << "received message @" << &msg << " on channel @" << this
196 << " with type " << msg.type();
[email protected]bf24d2c2009-02-24 23:07:45197 }
198 PluginChannelBase::OnMessageReceived(msg);
199}
200
initial.commit09911bf2008-07-26 23:55:29201void PluginChannel::OnControlMessageReceived(const IPC::Message& msg) {
202 IPC_BEGIN_MESSAGE_MAP(PluginChannel, msg)
203 IPC_MESSAGE_HANDLER(PluginMsg_CreateInstance, OnCreateInstance)
[email protected]f09c7182009-03-10 12:54:04204 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_DestroyInstance,
205 OnDestroyInstance)
initial.commit09911bf2008-07-26 23:55:29206 IPC_MESSAGE_HANDLER(PluginMsg_GenerateRouteID, OnGenerateRouteID)
[email protected]8b8a554d2010-11-18 13:26:40207 IPC_MESSAGE_HANDLER(PluginMsg_ClearSiteData, OnClearSiteData)
initial.commit09911bf2008-07-26 23:55:29208 IPC_MESSAGE_UNHANDLED_ERROR()
209 IPC_END_MESSAGE_MAP()
210}
211
212void PluginChannel::OnCreateInstance(const std::string& mime_type,
213 int* instance_id) {
214 *instance_id = GenerateRouteID();
[email protected]ad8e04a2010-11-01 04:16:27215 scoped_refptr<WebPluginDelegateStub> stub(new WebPluginDelegateStub(
216 mime_type, *instance_id, this));
[email protected]6a329462010-05-06 19:22:23217 AddRoute(*instance_id, stub, NULL);
initial.commit09911bf2008-07-26 23:55:29218 plugin_stubs_.push_back(stub);
219}
220
221void PluginChannel::OnDestroyInstance(int instance_id,
222 IPC::Message* reply_msg) {
223 for (size_t i = 0; i < plugin_stubs_.size(); ++i) {
224 if (plugin_stubs_[i]->instance_id() == instance_id) {
[email protected]49f69ae2009-10-06 19:11:22225 scoped_refptr<MessageFilter> filter(filter_);
226 gfx::NativeViewId window =
227 plugin_stubs_[i]->webplugin()->containing_window();
initial.commit09911bf2008-07-26 23:55:29228 plugin_stubs_.erase(plugin_stubs_.begin() + i);
initial.commit09911bf2008-07-26 23:55:29229 Send(reply_msg);
[email protected]49f69ae2009-10-06 19:11:22230 RemoveRoute(instance_id);
231 // NOTE: *this* might be deleted as a result of calling RemoveRoute.
232 // Don't release the modal dialog event right away, but do it after the
233 // stack unwinds since the plugin can be destroyed later if it's in use
234 // right now.
235 MessageLoop::current()->PostNonNestableTask(FROM_HERE, NewRunnableMethod(
236 filter.get(), &MessageFilter::ReleaseModalDialogEvent, window));
initial.commit09911bf2008-07-26 23:55:29237 return;
238 }
239 }
240
241 NOTREACHED() << "Couldn't find WebPluginDelegateStub to destroy";
242}
243
244void PluginChannel::OnGenerateRouteID(int* route_id) {
245 *route_id = GenerateRouteID();
246}
247
248int PluginChannel::GenerateRouteID() {
[email protected]157e5d22009-04-23 18:43:35249 static int last_id = 0;
250 return ++last_id;
initial.commit09911bf2008-07-26 23:55:29251}
252
[email protected]8b8a554d2010-11-18 13:26:40253void PluginChannel::OnClearSiteData(uint64 flags,
254 const std::string& domain,
255 base::Time begin_time) {
256 bool success = false;
257 CommandLine* command_line = CommandLine::ForCurrentProcess();
258 FilePath path = command_line->GetSwitchValuePath(switches::kPluginPath);
[email protected]191eb3f72010-12-21 06:27:50259 scoped_refptr<webkit::npapi::PluginLib> plugin_lib(
260 webkit::npapi::PluginLib::CreatePluginLib(path));
[email protected]8b8a554d2010-11-18 13:26:40261 if (plugin_lib.get()) {
262 NPError err = plugin_lib->NP_Initialize();
263 if (err == NPERR_NO_ERROR) {
[email protected]191eb3f72010-12-21 06:27:50264 scoped_refptr<webkit::npapi::PluginInstance> instance(
[email protected]8b8a554d2010-11-18 13:26:40265 plugin_lib->CreateInstance(std::string()));
266
267 const char* domain_str = domain.empty() ? NULL : domain.c_str();
268 uint64 max_age;
269 if (begin_time > base::Time()) {
270 base::TimeDelta delta = base::Time::Now() - begin_time;
271 max_age = delta.InSeconds();
272 } else {
273 max_age = kuint64max;
274 }
275 err = instance->NPP_ClearSiteData(flags, domain_str, max_age);
276 success = (err == NPERR_NO_ERROR);
277 }
278 }
279 Send(new PluginHostMsg_ClearSiteDataResult(success));
280}
281
[email protected]8beff0762009-09-29 02:18:30282base::WaitableEvent* PluginChannel::GetModalDialogEvent(
283 gfx::NativeViewId containing_window) {
284 return filter_->GetModalDialogEvent(containing_window);
285}
286
[email protected]4566f132009-03-12 01:55:13287void PluginChannel::OnChannelConnected(int32 peer_pid) {
[email protected]6c6cc802009-04-03 17:01:36288 base::ProcessHandle handle;
289 if (!base::OpenProcessHandle(peer_pid, &handle)) {
290 NOTREACHED();
291 }
[email protected]157e5d22009-04-23 18:43:35292 renderer_handle_ = handle;
[email protected]4566f132009-03-12 01:55:13293 PluginChannelBase::OnChannelConnected(peer_pid);
294}
295
initial.commit09911bf2008-07-26 23:55:29296void PluginChannel::OnChannelError() {
[email protected]157e5d22009-04-23 18:43:35297 base::CloseProcessHandle(renderer_handle_);
298 renderer_handle_ = 0;
initial.commit09911bf2008-07-26 23:55:29299 PluginChannelBase::OnChannelError();
300 CleanUp();
301}
302
303void PluginChannel::CleanUp() {
304 // We need to clean up the stubs so that they call NPPDestroy. This will
305 // also lead to them releasing their reference on this object so that it can
306 // be deleted.
307 for (size_t i = 0; i < plugin_stubs_.size(); ++i)
308 RemoveRoute(plugin_stubs_[i]->instance_id());
309
310 // Need to addref this object temporarily because otherwise removing the last
311 // stub will cause the destructor of this object to be called, however at
312 // that point plugin_stubs_ will have one element and its destructor will be
313 // called twice.
314 scoped_refptr<PluginChannel> me(this);
315
316 plugin_stubs_.clear();
license.botbf09a502008-08-24 00:55:55317}
[email protected]3dfc7a42009-06-27 01:43:51318
319bool PluginChannel::Init(MessageLoop* ipc_message_loop, bool create_pipe_now) {
[email protected]8beff0762009-09-29 02:18:30320 if (!PluginChannelBase::Init(ipc_message_loop, create_pipe_now))
321 return false;
322
323 channel_->AddFilter(filter_.get());
324 return true;
[email protected]3dfc7a42009-06-27 01:43:51325}
[email protected]4a8278472010-03-18 16:14:49326