Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(591)

Side by Side Diff: chrome/plugin/plugin_channel.cc

Issue 6672048: Move plugin code to content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/plugin/plugin_channel.h ('k') | chrome/plugin/plugin_channel_base.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 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 "chrome/plugin/plugin_channel.h"
6
7 #include "base/command_line.h"
8 #include "base/process_util.h"
9 #include "base/string_util.h"
10 #include "base/synchronization/lock.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "build/build_config.h"
13 #include "chrome/plugin/plugin_thread.h"
14 #include "chrome/plugin/webplugin_delegate_stub.h"
15 #include "chrome/plugin/webplugin_proxy.h"
16 #include "content/common/child_process.h"
17 #include "content/common/content_switches.h"
18 #include "content/common/plugin_messages.h"
19 #include "webkit/plugins/npapi/plugin_instance.h"
20
21 #if defined(OS_POSIX)
22 #include "base/eintr_wrapper.h"
23 #include "ipc/ipc_channel_posix.h"
24 #endif
25
26 namespace {
27
28 class PluginReleaseTask : public Task {
29 public:
30 void Run() {
31 ChildProcess::current()->ReleaseProcess();
32 }
33 };
34
35 // How long we wait before releasing the plugin process.
36 const int kPluginReleaseTimeMs = 5 * 60 * 1000; // 5 minutes
37
38 } // namespace
39
40 // If a sync call to the renderer results in a modal dialog, we need to have a
41 // way to know so that we can run a nested message loop to simulate what would
42 // happen in a single process browser and avoid deadlock.
43 class PluginChannel::MessageFilter : public IPC::ChannelProxy::MessageFilter {
44 public:
45 MessageFilter() : channel_(NULL) { }
46 ~MessageFilter() {
47 // Clean up in case of renderer crash.
48 for (ModalDialogEventMap::iterator i = modal_dialog_event_map_.begin();
49 i != modal_dialog_event_map_.end(); ++i) {
50 delete i->second.event;
51 }
52 }
53
54 base::WaitableEvent* GetModalDialogEvent(
55 gfx::NativeViewId containing_window) {
56 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
57 if (!modal_dialog_event_map_.count(containing_window)) {
58 NOTREACHED();
59 return NULL;
60 }
61
62 return modal_dialog_event_map_[containing_window].event;
63 }
64
65 // Decrement the ref count associated with the modal dialog event for the
66 // given tab.
67 void ReleaseModalDialogEvent(gfx::NativeViewId containing_window) {
68 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
69 if (!modal_dialog_event_map_.count(containing_window)) {
70 NOTREACHED();
71 return;
72 }
73
74 if (--(modal_dialog_event_map_[containing_window].refcount))
75 return;
76
77 // Delete the event when the stack unwinds as it could be in use now.
78 MessageLoop::current()->DeleteSoon(
79 FROM_HERE, modal_dialog_event_map_[containing_window].event);
80 modal_dialog_event_map_.erase(containing_window);
81 }
82
83 bool Send(IPC::Message* message) {
84 // Need this function for the IPC_MESSAGE_HANDLER_DELAY_REPLY macro.
85 return channel_->Send(message);
86 }
87
88 private:
89 void OnFilterAdded(IPC::Channel* channel) { channel_ = channel; }
90
91 bool OnMessageReceived(const IPC::Message& message) {
92 IPC_BEGIN_MESSAGE_MAP(PluginChannel::MessageFilter, message)
93 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_Init, OnInit)
94 IPC_MESSAGE_HANDLER(PluginMsg_SignalModalDialogEvent,
95 OnSignalModalDialogEvent)
96 IPC_MESSAGE_HANDLER(PluginMsg_ResetModalDialogEvent,
97 OnResetModalDialogEvent)
98 IPC_END_MESSAGE_MAP()
99 return message.type() == PluginMsg_SignalModalDialogEvent::ID ||
100 message.type() == PluginMsg_ResetModalDialogEvent::ID;
101 }
102
103 void OnInit(const PluginMsg_Init_Params& params, IPC::Message* reply_msg) {
104 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
105 if (modal_dialog_event_map_.count(params.containing_window)) {
106 modal_dialog_event_map_[params.containing_window].refcount++;
107 return;
108 }
109
110 WaitableEventWrapper wrapper;
111 wrapper.event = new base::WaitableEvent(true, false);
112 wrapper.refcount = 1;
113 modal_dialog_event_map_[params.containing_window] = wrapper;
114 }
115
116 void OnSignalModalDialogEvent(gfx::NativeViewId containing_window) {
117 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
118 if (modal_dialog_event_map_.count(containing_window))
119 modal_dialog_event_map_[containing_window].event->Signal();
120 }
121
122 void OnResetModalDialogEvent(gfx::NativeViewId containing_window) {
123 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
124 if (modal_dialog_event_map_.count(containing_window))
125 modal_dialog_event_map_[containing_window].event->Reset();
126 }
127
128 struct WaitableEventWrapper {
129 base::WaitableEvent* event;
130 int refcount; // There could be multiple plugin instances per tab.
131 };
132 typedef std::map<gfx::NativeViewId, WaitableEventWrapper> ModalDialogEventMap;
133 ModalDialogEventMap modal_dialog_event_map_;
134 base::Lock modal_dialog_event_map_lock_;
135
136 IPC::Channel* channel_;
137 };
138
139 PluginChannel* PluginChannel::GetPluginChannel(int renderer_id,
140 MessageLoop* ipc_message_loop) {
141 // Map renderer ID to a (single) channel to that process.
142 std::string channel_key = StringPrintf(
143 "%d.r%d", base::GetCurrentProcId(), renderer_id);
144
145 PluginChannel* channel =
146 static_cast<PluginChannel*>(PluginChannelBase::GetChannel(
147 channel_key,
148 IPC::Channel::MODE_SERVER,
149 ClassFactory,
150 ipc_message_loop,
151 false));
152
153 if (channel)
154 channel->renderer_id_ = renderer_id;
155
156 return channel;
157 }
158
159 // static
160 void PluginChannel::NotifyRenderersOfPendingShutdown() {
161 Broadcast(new PluginHostMsg_PluginShuttingDown());
162 }
163
164 PluginChannel::PluginChannel()
165 : renderer_handle_(0),
166 renderer_id_(-1),
167 in_send_(0),
168 incognito_(false),
169 filter_(new MessageFilter()) {
170 set_send_unblocking_only_during_unblock_dispatch();
171 ChildProcess::current()->AddRefProcess();
172 const CommandLine* command_line = CommandLine::ForCurrentProcess();
173 log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
174 }
175
176 PluginChannel::~PluginChannel() {
177 if (renderer_handle_)
178 base::CloseProcessHandle(renderer_handle_);
179
180 MessageLoop::current()->PostDelayedTask(FROM_HERE, new PluginReleaseTask(),
181 kPluginReleaseTimeMs);
182 }
183
184 bool PluginChannel::Send(IPC::Message* msg) {
185 in_send_++;
186 if (log_messages_) {
187 VLOG(1) << "sending message @" << msg << " on channel @" << this
188 << " with type " << msg->type();
189 }
190 bool result = PluginChannelBase::Send(msg);
191 in_send_--;
192 return result;
193 }
194
195 bool PluginChannel::OnMessageReceived(const IPC::Message& msg) {
196 if (log_messages_) {
197 VLOG(1) << "received message @" << &msg << " on channel @" << this
198 << " with type " << msg.type();
199 }
200 return PluginChannelBase::OnMessageReceived(msg);
201 }
202
203 bool PluginChannel::OnControlMessageReceived(const IPC::Message& msg) {
204 bool handled = true;
205 IPC_BEGIN_MESSAGE_MAP(PluginChannel, msg)
206 IPC_MESSAGE_HANDLER(PluginMsg_CreateInstance, OnCreateInstance)
207 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_DestroyInstance,
208 OnDestroyInstance)
209 IPC_MESSAGE_HANDLER(PluginMsg_GenerateRouteID, OnGenerateRouteID)
210 IPC_MESSAGE_HANDLER(PluginMsg_ClearSiteData, OnClearSiteData)
211 IPC_MESSAGE_UNHANDLED(handled = false)
212 IPC_END_MESSAGE_MAP()
213 DCHECK(handled);
214 return handled;
215 }
216
217 void PluginChannel::OnCreateInstance(const std::string& mime_type,
218 int* instance_id) {
219 *instance_id = GenerateRouteID();
220 scoped_refptr<WebPluginDelegateStub> stub(new WebPluginDelegateStub(
221 mime_type, *instance_id, this));
222 AddRoute(*instance_id, stub, NULL);
223 plugin_stubs_.push_back(stub);
224 }
225
226 void PluginChannel::OnDestroyInstance(int instance_id,
227 IPC::Message* reply_msg) {
228 for (size_t i = 0; i < plugin_stubs_.size(); ++i) {
229 if (plugin_stubs_[i]->instance_id() == instance_id) {
230 scoped_refptr<MessageFilter> filter(filter_);
231 gfx::NativeViewId window =
232 plugin_stubs_[i]->webplugin()->containing_window();
233 plugin_stubs_.erase(plugin_stubs_.begin() + i);
234 Send(reply_msg);
235 RemoveRoute(instance_id);
236 // NOTE: *this* might be deleted as a result of calling RemoveRoute.
237 // Don't release the modal dialog event right away, but do it after the
238 // stack unwinds since the plugin can be destroyed later if it's in use
239 // right now.
240 MessageLoop::current()->PostNonNestableTask(FROM_HERE, NewRunnableMethod(
241 filter.get(), &MessageFilter::ReleaseModalDialogEvent, window));
242 return;
243 }
244 }
245
246 NOTREACHED() << "Couldn't find WebPluginDelegateStub to destroy";
247 }
248
249 void PluginChannel::OnGenerateRouteID(int* route_id) {
250 *route_id = GenerateRouteID();
251 }
252
253 int PluginChannel::GenerateRouteID() {
254 static int last_id = 0;
255 return ++last_id;
256 }
257
258 void PluginChannel::OnClearSiteData(const std::string& site,
259 uint64 flags,
260 base::Time begin_time) {
261 bool success = false;
262 CommandLine* command_line = CommandLine::ForCurrentProcess();
263 FilePath path = command_line->GetSwitchValuePath(switches::kPluginPath);
264 scoped_refptr<webkit::npapi::PluginLib> plugin_lib(
265 webkit::npapi::PluginLib::CreatePluginLib(path));
266 if (plugin_lib.get()) {
267 NPError err = plugin_lib->NP_Initialize();
268 if (err == NPERR_NO_ERROR) {
269 const char* site_str = site.empty() ? NULL : site.c_str();
270 uint64 max_age;
271 if (begin_time > base::Time()) {
272 base::TimeDelta delta = base::Time::Now() - begin_time;
273 max_age = delta.InSeconds();
274 } else {
275 max_age = kuint64max;
276 }
277 err = plugin_lib->NP_ClearSiteData(site_str, flags, max_age);
278 success = (err == NPERR_NO_ERROR);
279 }
280 }
281 Send(new PluginHostMsg_ClearSiteDataResult(success));
282 }
283
284 base::WaitableEvent* PluginChannel::GetModalDialogEvent(
285 gfx::NativeViewId containing_window) {
286 return filter_->GetModalDialogEvent(containing_window);
287 }
288
289 void PluginChannel::OnChannelConnected(int32 peer_pid) {
290 base::ProcessHandle handle;
291 if (!base::OpenProcessHandle(peer_pid, &handle)) {
292 NOTREACHED();
293 }
294 renderer_handle_ = handle;
295 PluginChannelBase::OnChannelConnected(peer_pid);
296 }
297
298 void PluginChannel::OnChannelError() {
299 base::CloseProcessHandle(renderer_handle_);
300 renderer_handle_ = 0;
301 PluginChannelBase::OnChannelError();
302 CleanUp();
303 }
304
305 void PluginChannel::CleanUp() {
306 // We need to clean up the stubs so that they call NPPDestroy. This will
307 // also lead to them releasing their reference on this object so that it can
308 // be deleted.
309 for (size_t i = 0; i < plugin_stubs_.size(); ++i)
310 RemoveRoute(plugin_stubs_[i]->instance_id());
311
312 // Need to addref this object temporarily because otherwise removing the last
313 // stub will cause the destructor of this object to be called, however at
314 // that point plugin_stubs_ will have one element and its destructor will be
315 // called twice.
316 scoped_refptr<PluginChannel> me(this);
317
318 plugin_stubs_.clear();
319 }
320
321 bool PluginChannel::Init(MessageLoop* ipc_message_loop, bool create_pipe_now) {
322 if (!PluginChannelBase::Init(ipc_message_loop, create_pipe_now))
323 return false;
324
325 channel_->AddFilter(filter_.get());
326 return true;
327 }
328
OLDNEW
« no previous file with comments | « chrome/plugin/plugin_channel.h ('k') | chrome/plugin/plugin_channel_base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698