| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/plugin/plugin_channel.h" | 5 #include "content/plugin/plugin_channel.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/process_util.h" | 9 #include "base/process_util.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 const int kPluginReleaseTimeMinutes = 5; | 34 const int kPluginReleaseTimeMinutes = 5; |
| 35 | 35 |
| 36 } // namespace | 36 } // namespace |
| 37 | 37 |
| 38 // If a sync call to the renderer results in a modal dialog, we need to have a | 38 // If a sync call to the renderer results in a modal dialog, we need to have a |
| 39 // way to know so that we can run a nested message loop to simulate what would | 39 // way to know so that we can run a nested message loop to simulate what would |
| 40 // happen in a single process browser and avoid deadlock. | 40 // happen in a single process browser and avoid deadlock. |
| 41 class PluginChannel::MessageFilter : public IPC::ChannelProxy::MessageFilter { | 41 class PluginChannel::MessageFilter : public IPC::ChannelProxy::MessageFilter { |
| 42 public: | 42 public: |
| 43 MessageFilter() : channel_(NULL) { } | 43 MessageFilter() : channel_(NULL) { } |
| 44 ~MessageFilter() { | |
| 45 // Clean up in case of renderer crash. | |
| 46 for (ModalDialogEventMap::iterator i = modal_dialog_event_map_.begin(); | |
| 47 i != modal_dialog_event_map_.end(); ++i) { | |
| 48 delete i->second.event; | |
| 49 } | |
| 50 } | |
| 51 | 44 |
| 52 base::WaitableEvent* GetModalDialogEvent( | 45 base::WaitableEvent* GetModalDialogEvent( |
| 53 gfx::NativeViewId containing_window) { | 46 gfx::NativeViewId containing_window) { |
| 54 base::AutoLock auto_lock(modal_dialog_event_map_lock_); | 47 base::AutoLock auto_lock(modal_dialog_event_map_lock_); |
| 55 if (!modal_dialog_event_map_.count(containing_window)) { | 48 if (!modal_dialog_event_map_.count(containing_window)) { |
| 56 NOTREACHED(); | 49 NOTREACHED(); |
| 57 return NULL; | 50 return NULL; |
| 58 } | 51 } |
| 59 | 52 |
| 60 return modal_dialog_event_map_[containing_window].event; | 53 return modal_dialog_event_map_[containing_window].event; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 76 MessageLoop::current()->DeleteSoon( | 69 MessageLoop::current()->DeleteSoon( |
| 77 FROM_HERE, modal_dialog_event_map_[containing_window].event); | 70 FROM_HERE, modal_dialog_event_map_[containing_window].event); |
| 78 modal_dialog_event_map_.erase(containing_window); | 71 modal_dialog_event_map_.erase(containing_window); |
| 79 } | 72 } |
| 80 | 73 |
| 81 bool Send(IPC::Message* message) { | 74 bool Send(IPC::Message* message) { |
| 82 // Need this function for the IPC_MESSAGE_HANDLER_DELAY_REPLY macro. | 75 // Need this function for the IPC_MESSAGE_HANDLER_DELAY_REPLY macro. |
| 83 return channel_->Send(message); | 76 return channel_->Send(message); |
| 84 } | 77 } |
| 85 | 78 |
| 86 private: | 79 // IPC::ChannelProxy::MessageFilter: |
| 87 void OnFilterAdded(IPC::Channel* channel) { channel_ = channel; } | 80 void OnFilterAdded(IPC::Channel* channel) { channel_ = channel; } |
| 88 | 81 |
| 89 bool OnMessageReceived(const IPC::Message& message) { | 82 bool OnMessageReceived(const IPC::Message& message) { |
| 90 IPC_BEGIN_MESSAGE_MAP(PluginChannel::MessageFilter, message) | 83 IPC_BEGIN_MESSAGE_MAP(PluginChannel::MessageFilter, message) |
| 91 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_Init, OnInit) | 84 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_Init, OnInit) |
| 92 IPC_MESSAGE_HANDLER(PluginMsg_SignalModalDialogEvent, | 85 IPC_MESSAGE_HANDLER(PluginMsg_SignalModalDialogEvent, |
| 93 OnSignalModalDialogEvent) | 86 OnSignalModalDialogEvent) |
| 94 IPC_MESSAGE_HANDLER(PluginMsg_ResetModalDialogEvent, | 87 IPC_MESSAGE_HANDLER(PluginMsg_ResetModalDialogEvent, |
| 95 OnResetModalDialogEvent) | 88 OnResetModalDialogEvent) |
| 96 IPC_END_MESSAGE_MAP() | 89 IPC_END_MESSAGE_MAP() |
| 97 return message.type() == PluginMsg_SignalModalDialogEvent::ID || | 90 return message.type() == PluginMsg_SignalModalDialogEvent::ID || |
| 98 message.type() == PluginMsg_ResetModalDialogEvent::ID; | 91 message.type() == PluginMsg_ResetModalDialogEvent::ID; |
| 99 } | 92 } |
| 100 | 93 |
| 94 |
| 95 |
| 96 protected: |
| 97 virtual ~MessageFilter() { |
| 98 // 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: |
| 101 void OnInit(const PluginMsg_Init_Params& params, IPC::Message* reply_msg) { | 106 void OnInit(const PluginMsg_Init_Params& params, IPC::Message* reply_msg) { |
| 102 base::AutoLock auto_lock(modal_dialog_event_map_lock_); | 107 base::AutoLock auto_lock(modal_dialog_event_map_lock_); |
| 103 if (modal_dialog_event_map_.count(params.containing_window)) { | 108 if (modal_dialog_event_map_.count(params.containing_window)) { |
| 104 modal_dialog_event_map_[params.containing_window].refcount++; | 109 modal_dialog_event_map_[params.containing_window].refcount++; |
| 105 return; | 110 return; |
| 106 } | 111 } |
| 107 | 112 |
| 108 WaitableEventWrapper wrapper; | 113 WaitableEventWrapper wrapper; |
| 109 wrapper.event = new base::WaitableEvent(true, false); | 114 wrapper.event = new base::WaitableEvent(true, false); |
| 110 wrapper.refcount = 1; | 115 wrapper.refcount = 1; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 channel->renderer_id_ = renderer_id; | 158 channel->renderer_id_ = renderer_id; |
| 154 | 159 |
| 155 return channel; | 160 return channel; |
| 156 } | 161 } |
| 157 | 162 |
| 158 // static | 163 // static |
| 159 void PluginChannel::NotifyRenderersOfPendingShutdown() { | 164 void PluginChannel::NotifyRenderersOfPendingShutdown() { |
| 160 Broadcast(new PluginHostMsg_PluginShuttingDown()); | 165 Broadcast(new PluginHostMsg_PluginShuttingDown()); |
| 161 } | 166 } |
| 162 | 167 |
| 163 PluginChannel::PluginChannel() | |
| 164 : renderer_id_(-1), | |
| 165 in_send_(0), | |
| 166 incognito_(false), | |
| 167 filter_(new MessageFilter()) { | |
| 168 set_send_unblocking_only_during_unblock_dispatch(); | |
| 169 ChildProcess::current()->AddRefProcess(); | |
| 170 const CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
| 171 log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages); | |
| 172 } | |
| 173 | |
| 174 PluginChannel::~PluginChannel() { | |
| 175 MessageLoop::current()->PostDelayedTask( | |
| 176 FROM_HERE, | |
| 177 base::Bind(&PluginReleaseCallback), | |
| 178 base::TimeDelta::FromMinutes(kPluginReleaseTimeMinutes)); | |
| 179 } | |
| 180 | |
| 181 bool PluginChannel::Send(IPC::Message* msg) { | 168 bool PluginChannel::Send(IPC::Message* msg) { |
| 182 in_send_++; | 169 in_send_++; |
| 183 if (log_messages_) { | 170 if (log_messages_) { |
| 184 VLOG(1) << "sending message @" << msg << " on channel @" << this | 171 VLOG(1) << "sending message @" << msg << " on channel @" << this |
| 185 << " with type " << msg->type(); | 172 << " with type " << msg->type(); |
| 186 } | 173 } |
| 187 bool result = NPChannelBase::Send(msg); | 174 bool result = NPChannelBase::Send(msg); |
| 188 in_send_--; | 175 in_send_--; |
| 189 return result; | 176 return result; |
| 190 } | 177 } |
| 191 | 178 |
| 192 bool PluginChannel::OnMessageReceived(const IPC::Message& msg) { | 179 bool PluginChannel::OnMessageReceived(const IPC::Message& msg) { |
| 193 if (log_messages_) { | 180 if (log_messages_) { |
| 194 VLOG(1) << "received message @" << &msg << " on channel @" << this | 181 VLOG(1) << "received message @" << &msg << " on channel @" << this |
| 195 << " with type " << msg.type(); | 182 << " with type " << msg.type(); |
| 196 } | 183 } |
| 197 return NPChannelBase::OnMessageReceived(msg); | 184 return NPChannelBase::OnMessageReceived(msg); |
| 198 } | 185 } |
| 199 | 186 |
| 187 void PluginChannel::OnChannelError() { |
| 188 NPChannelBase::OnChannelError(); |
| 189 CleanUp(); |
| 190 } |
| 191 |
| 192 int PluginChannel::GenerateRouteID() { |
| 193 static int last_id = 0; |
| 194 return ++last_id; |
| 195 } |
| 196 |
| 197 base::WaitableEvent* PluginChannel::GetModalDialogEvent( |
| 198 gfx::NativeViewId containing_window) { |
| 199 return filter_->GetModalDialogEvent(containing_window); |
| 200 } |
| 201 |
| 202 PluginChannel::~PluginChannel() { |
| 203 MessageLoop::current()->PostDelayedTask( |
| 204 FROM_HERE, |
| 205 base::Bind(&PluginReleaseCallback), |
| 206 base::TimeDelta::FromMinutes(kPluginReleaseTimeMinutes)); |
| 207 } |
| 208 |
| 209 void PluginChannel::CleanUp() { |
| 210 // We need to clean up the stubs so that they call NPPDestroy. This will |
| 211 // also lead to them releasing their reference on this object so that it can |
| 212 // be deleted. |
| 213 for (size_t i = 0; i < plugin_stubs_.size(); ++i) |
| 214 RemoveRoute(plugin_stubs_[i]->instance_id()); |
| 215 |
| 216 // Need to addref this object temporarily because otherwise removing the last |
| 217 // stub will cause the destructor of this object to be called, however at |
| 218 // that point plugin_stubs_ will have one element and its destructor will be |
| 219 // called twice. |
| 220 scoped_refptr<PluginChannel> me(this); |
| 221 |
| 222 plugin_stubs_.clear(); |
| 223 } |
| 224 |
| 225 bool PluginChannel::Init(base::MessageLoopProxy* ipc_message_loop, |
| 226 bool create_pipe_now, |
| 227 base::WaitableEvent* shutdown_event) { |
| 228 if (!NPChannelBase::Init(ipc_message_loop, 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 ChildProcess::current()->AddRefProcess(); |
| 242 const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 243 log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages); |
| 244 } |
| 245 |
| 200 bool PluginChannel::OnControlMessageReceived(const IPC::Message& msg) { | 246 bool PluginChannel::OnControlMessageReceived(const IPC::Message& msg) { |
| 201 bool handled = true; | 247 bool handled = true; |
| 202 IPC_BEGIN_MESSAGE_MAP(PluginChannel, msg) | 248 IPC_BEGIN_MESSAGE_MAP(PluginChannel, msg) |
| 203 IPC_MESSAGE_HANDLER(PluginMsg_CreateInstance, OnCreateInstance) | 249 IPC_MESSAGE_HANDLER(PluginMsg_CreateInstance, OnCreateInstance) |
| 204 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_DestroyInstance, | 250 IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_DestroyInstance, |
| 205 OnDestroyInstance) | 251 OnDestroyInstance) |
| 206 IPC_MESSAGE_HANDLER(PluginMsg_GenerateRouteID, OnGenerateRouteID) | 252 IPC_MESSAGE_HANDLER(PluginMsg_GenerateRouteID, OnGenerateRouteID) |
| 207 IPC_MESSAGE_HANDLER(PluginMsg_ClearSiteData, OnClearSiteData) | 253 IPC_MESSAGE_HANDLER(PluginMsg_ClearSiteData, OnClearSiteData) |
| 208 IPC_MESSAGE_UNHANDLED(handled = false) | 254 IPC_MESSAGE_UNHANDLED(handled = false) |
| 209 IPC_END_MESSAGE_MAP() | 255 IPC_END_MESSAGE_MAP() |
| (...skipping 30 matching lines...) Expand all Loading... |
| 240 } | 286 } |
| 241 } | 287 } |
| 242 | 288 |
| 243 NOTREACHED() << "Couldn't find WebPluginDelegateStub to destroy"; | 289 NOTREACHED() << "Couldn't find WebPluginDelegateStub to destroy"; |
| 244 } | 290 } |
| 245 | 291 |
| 246 void PluginChannel::OnGenerateRouteID(int* route_id) { | 292 void PluginChannel::OnGenerateRouteID(int* route_id) { |
| 247 *route_id = GenerateRouteID(); | 293 *route_id = GenerateRouteID(); |
| 248 } | 294 } |
| 249 | 295 |
| 250 int PluginChannel::GenerateRouteID() { | |
| 251 static int last_id = 0; | |
| 252 return ++last_id; | |
| 253 } | |
| 254 | |
| 255 void PluginChannel::OnClearSiteData(const std::string& site, | 296 void PluginChannel::OnClearSiteData(const std::string& site, |
| 256 uint64 flags, | 297 uint64 flags, |
| 257 uint64 max_age) { | 298 uint64 max_age) { |
| 258 bool success = false; | 299 bool success = false; |
| 259 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 300 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 260 FilePath path = command_line->GetSwitchValuePath(switches::kPluginPath); | 301 FilePath path = command_line->GetSwitchValuePath(switches::kPluginPath); |
| 261 scoped_refptr<webkit::npapi::PluginLib> plugin_lib( | 302 scoped_refptr<webkit::npapi::PluginLib> plugin_lib( |
| 262 webkit::npapi::PluginLib::CreatePluginLib(path)); | 303 webkit::npapi::PluginLib::CreatePluginLib(path)); |
| 263 if (plugin_lib.get()) { | 304 if (plugin_lib.get()) { |
| 264 NPError err = plugin_lib->NP_Initialize(); | 305 NPError err = plugin_lib->NP_Initialize(); |
| 265 if (err == NPERR_NO_ERROR) { | 306 if (err == NPERR_NO_ERROR) { |
| 266 const char* site_str = site.empty() ? NULL : site.c_str(); | 307 const char* site_str = site.empty() ? NULL : site.c_str(); |
| 267 err = plugin_lib->NP_ClearSiteData(site_str, flags, max_age); | 308 err = plugin_lib->NP_ClearSiteData(site_str, flags, max_age); |
| 268 std::string site_name = | 309 std::string site_name = |
| 269 site.empty() ? "NULL" | 310 site.empty() ? "NULL" |
| 270 : base::StringPrintf("\"%s\"", site_str); | 311 : base::StringPrintf("\"%s\"", site_str); |
| 271 VLOG(1) << "NPP_ClearSiteData(" << site_name << ", " << flags << ", " | 312 VLOG(1) << "NPP_ClearSiteData(" << site_name << ", " << flags << ", " |
| 272 << max_age << ") returned " << err; | 313 << max_age << ") returned " << err; |
| 273 success = (err == NPERR_NO_ERROR); | 314 success = (err == NPERR_NO_ERROR); |
| 274 } | 315 } |
| 275 } | 316 } |
| 276 Send(new PluginHostMsg_ClearSiteDataResult(success)); | 317 Send(new PluginHostMsg_ClearSiteDataResult(success)); |
| 277 } | 318 } |
| 278 | |
| 279 base::WaitableEvent* PluginChannel::GetModalDialogEvent( | |
| 280 gfx::NativeViewId containing_window) { | |
| 281 return filter_->GetModalDialogEvent(containing_window); | |
| 282 } | |
| 283 | |
| 284 void PluginChannel::OnChannelError() { | |
| 285 NPChannelBase::OnChannelError(); | |
| 286 CleanUp(); | |
| 287 } | |
| 288 | |
| 289 void PluginChannel::CleanUp() { | |
| 290 // We need to clean up the stubs so that they call NPPDestroy. This will | |
| 291 // also lead to them releasing their reference on this object so that it can | |
| 292 // be deleted. | |
| 293 for (size_t i = 0; i < plugin_stubs_.size(); ++i) | |
| 294 RemoveRoute(plugin_stubs_[i]->instance_id()); | |
| 295 | |
| 296 // Need to addref this object temporarily because otherwise removing the last | |
| 297 // stub will cause the destructor of this object to be called, however at | |
| 298 // that point plugin_stubs_ will have one element and its destructor will be | |
| 299 // called twice. | |
| 300 scoped_refptr<PluginChannel> me(this); | |
| 301 | |
| 302 plugin_stubs_.clear(); | |
| 303 } | |
| 304 | |
| 305 bool PluginChannel::Init(base::MessageLoopProxy* ipc_message_loop, | |
| 306 bool create_pipe_now, | |
| 307 base::WaitableEvent* shutdown_event) { | |
| 308 if (!NPChannelBase::Init(ipc_message_loop, create_pipe_now, shutdown_event)) | |
| 309 return false; | |
| 310 | |
| 311 channel_->AddFilter(filter_.get()); | |
| 312 return true; | |
| 313 } | |
| 314 | |
| OLD | NEW |