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

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

Issue 1852593004: Remove content/plugin (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@remove_npapi_test_plugin
Patch Set: . Created 4 years, 8 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
« no previous file with comments | « content/plugin/plugin_channel.h ('k') | content/plugin/plugin_interpose_util_mac.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) 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/plugin/plugin_channel.h"
6
7 #include <stddef.h>
8
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/process/process_handle.h"
12 #include "base/strings/string_util.h"
13 #include "base/synchronization/lock.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "build/build_config.h"
16 #include "content/child/child_process.h"
17 #include "content/child/npapi/plugin_instance.h"
18 #include "content/child/npapi/webplugin_delegate_impl.h"
19 #include "content/child/plugin_messages.h"
20 #include "content/common/plugin_process_messages.h"
21 #include "content/plugin/plugin_thread.h"
22 #include "content/plugin/webplugin_delegate_stub.h"
23 #include "content/plugin/webplugin_proxy.h"
24 #include "content/public/common/content_switches.h"
25 #include "ipc/message_filter.h"
26
27 #if defined(OS_POSIX)
28 #include "ipc/ipc_channel_posix.h"
29 #endif
30
31 namespace content {
32
33 namespace {
34
35 // How long we wait before releasing the plugin process.
36 const int kPluginReleaseTimeMinutes = 5;
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::MessageFilter {
44 public:
45 MessageFilter() : sender_(NULL) { }
46
47 base::WaitableEvent* GetModalDialogEvent(int render_view_id) {
48 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
49 if (!modal_dialog_event_map_.count(render_view_id)) {
50 NOTREACHED();
51 return NULL;
52 }
53
54 return modal_dialog_event_map_[render_view_id].event;
55 }
56
57 // Decrement the ref count associated with the modal dialog event for the
58 // given tab.
59 void ReleaseModalDialogEvent(int render_view_id) {
60 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
61 if (!modal_dialog_event_map_.count(render_view_id)) {
62 NOTREACHED();
63 return;
64 }
65
66 if (--(modal_dialog_event_map_[render_view_id].refcount))
67 return;
68
69 // Delete the event when the stack unwinds as it could be in use now.
70 base::MessageLoop::current()->DeleteSoon(
71 FROM_HERE, modal_dialog_event_map_[render_view_id].event);
72 modal_dialog_event_map_.erase(render_view_id);
73 }
74
75 bool Send(IPC::Message* message) {
76 // Need this function for the IPC_MESSAGE_HANDLER_DELAY_REPLY macro.
77 return sender_->Send(message);
78 }
79
80 // IPC::MessageFilter:
81 void OnFilterAdded(IPC::Sender* sender) override { sender_ = sender; }
82
83 bool OnMessageReceived(const IPC::Message& message) override {
84 IPC_BEGIN_MESSAGE_MAP(PluginChannel::MessageFilter, message)
85 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_Init, OnInit)
86 IPC_MESSAGE_HANDLER(PluginMsg_SignalModalDialogEvent,
87 OnSignalModalDialogEvent)
88 IPC_MESSAGE_HANDLER(PluginMsg_ResetModalDialogEvent,
89 OnResetModalDialogEvent)
90 IPC_END_MESSAGE_MAP()
91 return message.type() == PluginMsg_SignalModalDialogEvent::ID ||
92 message.type() == PluginMsg_ResetModalDialogEvent::ID;
93 }
94
95 protected:
96 ~MessageFilter() override {
97 // Clean up in case of renderer crash.
98 for (ModalDialogEventMap::iterator i = modal_dialog_event_map_.begin();
99 i != modal_dialog_event_map_.end(); ++i) {
100 delete i->second.event;
101 }
102 }
103
104 private:
105 void OnInit(const PluginMsg_Init_Params& params, IPC::Message* reply_msg) {
106 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
107 if (modal_dialog_event_map_.count(params.host_render_view_routing_id)) {
108 modal_dialog_event_map_[params.host_render_view_routing_id].refcount++;
109 return;
110 }
111
112 WaitableEventWrapper wrapper;
113 wrapper.event = new base::WaitableEvent(true, false);
114 wrapper.refcount = 1;
115 modal_dialog_event_map_[params.host_render_view_routing_id] = wrapper;
116 }
117
118 void OnSignalModalDialogEvent(int render_view_id) {
119 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
120 if (modal_dialog_event_map_.count(render_view_id))
121 modal_dialog_event_map_[render_view_id].event->Signal();
122 }
123
124 void OnResetModalDialogEvent(int render_view_id) {
125 base::AutoLock auto_lock(modal_dialog_event_map_lock_);
126 if (modal_dialog_event_map_.count(render_view_id))
127 modal_dialog_event_map_[render_view_id].event->Reset();
128 }
129
130 struct WaitableEventWrapper {
131 base::WaitableEvent* event;
132 int refcount; // There could be multiple plugin instances per tab.
133 };
134 typedef std::map<int, WaitableEventWrapper> ModalDialogEventMap;
135 ModalDialogEventMap modal_dialog_event_map_;
136 base::Lock modal_dialog_event_map_lock_;
137
138 IPC::Sender* sender_;
139 };
140
141 PluginChannel* PluginChannel::GetPluginChannel(
142 int renderer_id,
143 base::SingleThreadTaskRunner* ipc_task_runner) {
144 // Map renderer ID to a (single) channel to that process.
145 std::string channel_key = base::StringPrintf(
146 "%d.r%d", base::GetCurrentProcId(), renderer_id);
147
148 PluginChannel* channel =
149 static_cast<PluginChannel*>(NPChannelBase::GetChannel(
150 channel_key, IPC::Channel::MODE_SERVER, ClassFactory, ipc_task_runner,
151 false, ChildProcess::current()->GetShutDownEvent()));
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 bool PluginChannel::Send(IPC::Message* msg) {
165 in_send_++;
166 if (log_messages_) {
167 VLOG(1) << "sending message @" << msg << " on channel @" << this
168 << " with type " << msg->type();
169 }
170 bool result = NPChannelBase::Send(msg);
171 in_send_--;
172 return result;
173 }
174
175 bool PluginChannel::OnMessageReceived(const IPC::Message& msg) {
176 if (log_messages_) {
177 VLOG(1) << "received message @" << &msg << " on channel @" << this
178 << " with type " << msg.type();
179 }
180 return NPChannelBase::OnMessageReceived(msg);
181 }
182
183 void PluginChannel::OnChannelError() {
184 NPChannelBase::OnChannelError();
185 CleanUp();
186 }
187
188 int PluginChannel::GenerateRouteID() {
189 static int last_id = 0;
190 return ++last_id;
191 }
192
193 base::WaitableEvent* PluginChannel::GetModalDialogEvent(int render_view_id) {
194 return filter_->GetModalDialogEvent(render_view_id);
195 }
196
197 PluginChannel::~PluginChannel() {
198 PluginThread::current()->Send(new PluginProcessHostMsg_ChannelDestroyed(
199 renderer_id_));
200 process_ref_.ReleaseWithDelay(
201 base::TimeDelta::FromMinutes(kPluginReleaseTimeMinutes));
202 }
203
204 void PluginChannel::CleanUp() {
205 // We need to clean up the stubs so that they call NPPDestroy. This will
206 // also lead to them releasing their reference on this object so that it can
207 // be deleted.
208 for (size_t i = 0; i < plugin_stubs_.size(); ++i)
209 RemoveRoute(plugin_stubs_[i]->instance_id());
210
211 // Need to addref this object temporarily because otherwise removing the last
212 // stub will cause the destructor of this object to be called, however at
213 // that point plugin_stubs_ will have one element and its destructor will be
214 // called twice.
215 scoped_refptr<PluginChannel> me(this);
216
217 while (!plugin_stubs_.empty()) {
218 // Separate vector::erase and ~WebPluginDelegateStub.
219 // See https://code.google.com/p/chromium/issues/detail?id=314088
220 scoped_refptr<WebPluginDelegateStub> stub = plugin_stubs_[0];
221 plugin_stubs_.erase(plugin_stubs_.begin());
222 }
223 }
224
225 bool PluginChannel::Init(base::SingleThreadTaskRunner* ipc_task_runner,
226 bool create_pipe_now,
227 base::WaitableEvent* shutdown_event) {
228 if (!NPChannelBase::Init(ipc_task_runner, create_pipe_now, shutdown_event))
229 return false;
230
231 channel_->AddFilter(filter_.get());
232 return true;
233 }
234
235 PluginChannel::PluginChannel()
236 : renderer_id_(-1),
237 in_send_(0),
238 incognito_(false),
239 filter_(new MessageFilter()) {
240 set_send_unblocking_only_during_unblock_dispatch();
241 const base::CommandLine* command_line =
242 base::CommandLine::ForCurrentProcess();
243 log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
244 }
245
246 bool PluginChannel::OnControlMessageReceived(const IPC::Message& msg) {
247 bool handled = true;
248 IPC_BEGIN_MESSAGE_MAP(PluginChannel, msg)
249 IPC_MESSAGE_HANDLER(PluginMsg_CreateInstance, OnCreateInstance)
250 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_DestroyInstance,
251 OnDestroyInstance)
252 IPC_MESSAGE_HANDLER(PluginMsg_GenerateRouteID, OnGenerateRouteID)
253 IPC_MESSAGE_HANDLER(PluginProcessMsg_ClearSiteData, OnClearSiteData)
254 IPC_MESSAGE_UNHANDLED(handled = false)
255 IPC_END_MESSAGE_MAP()
256 DCHECK(handled);
257 return handled;
258 }
259
260 void PluginChannel::OnCreateInstance(const std::string& mime_type,
261 int* instance_id) {
262 *instance_id = GenerateRouteID();
263 scoped_refptr<WebPluginDelegateStub> stub(new WebPluginDelegateStub(
264 mime_type, *instance_id, this));
265 AddRoute(*instance_id, stub.get());
266 plugin_stubs_.push_back(stub);
267 }
268
269 void PluginChannel::OnDestroyInstance(int instance_id,
270 IPC::Message* reply_msg) {
271 for (size_t i = 0; i < plugin_stubs_.size(); ++i) {
272 if (plugin_stubs_[i]->instance_id() == instance_id) {
273 scoped_refptr<MessageFilter> filter(filter_);
274 int render_view_id =
275 plugin_stubs_[i]->webplugin()->host_render_view_routing_id();
276 // Separate vector::erase and ~WebPluginDelegateStub.
277 // See https://code.google.com/p/chromium/issues/detail?id=314088
278 scoped_refptr<WebPluginDelegateStub> stub = plugin_stubs_[i];
279 plugin_stubs_.erase(plugin_stubs_.begin() + i);
280 stub = NULL;
281
282 Send(reply_msg);
283 RemoveRoute(instance_id);
284 // NOTE: *this* might be deleted as a result of calling RemoveRoute.
285 // Don't release the modal dialog event right away, but do it after the
286 // stack unwinds since the plugin can be destroyed later if it's in use
287 // right now.
288 base::MessageLoop::current()->PostNonNestableTask(
289 FROM_HERE,
290 base::Bind(&MessageFilter::ReleaseModalDialogEvent,
291 filter.get(),
292 render_view_id));
293 return;
294 }
295 }
296
297 NOTREACHED() << "Couldn't find WebPluginDelegateStub to destroy";
298 }
299
300 void PluginChannel::OnGenerateRouteID(int* route_id) {
301 *route_id = GenerateRouteID();
302 }
303
304 void PluginChannel::OnClearSiteData(const std::string& site,
305 uint64_t flags,
306 uint64_t max_age) {
307 bool success = false;
308 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
309 base::FilePath path = command_line->GetSwitchValuePath(switches::kPluginPath);
310 scoped_refptr<PluginLib> plugin_lib(PluginLib::CreatePluginLib(path));
311 if (plugin_lib.get()) {
312 NPError err = plugin_lib->NP_Initialize();
313 if (err == NPERR_NO_ERROR) {
314 const char* site_str = site.empty() ? NULL : site.c_str();
315 err = plugin_lib->NP_ClearSiteData(site_str, flags, max_age);
316 std::string site_name =
317 site.empty() ? "NULL"
318 : base::StringPrintf("\"%s\"", site_str);
319 VLOG(1) << "NPP_ClearSiteData(" << site_name << ", " << flags << ", "
320 << max_age << ") returned " << err;
321 success = (err == NPERR_NO_ERROR);
322 }
323 }
324 Send(new PluginProcessHostMsg_ClearSiteDataResult(success));
325 }
326
327 } // namespace content
OLDNEW
« no previous file with comments | « content/plugin/plugin_channel.h ('k') | content/plugin/plugin_interpose_util_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698