diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-15 17:36:33 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-15 17:36:33 +0000 |
commit | 4f15d284466def720aa90d4f745edfa9af378094 (patch) | |
tree | e30ce116b0c05d4adacf9fa5aae6188178b4a3a7 /ppapi | |
parent | 351856ef135301f705435a8feecbc66ecfafbf77 (diff) | |
download | chromium_src-4f15d284466def720aa90d4f745edfa9af378094.zip chromium_src-4f15d284466def720aa90d4f745edfa9af378094.tar.gz chromium_src-4f15d284466def720aa90d4f745edfa9af378094.tar.bz2 |
Implement basic crash detection and shutdown handling for out of process PPAPI
plugins.
Currently when a crash is detected we just delete as much stuff as is
convenient, clear the plugin's backing store, and continue running. It does not
hook up a sad plugin page yet.
This adds a "proxy" interface for the proxy to tell the PPAPI backend
implementation in the renderer about proxy-related stuff (like the plugin
crashing).
This also implements keeping the process alive for a period of time so we can
re-use the same process.
Review URL: http://codereview.chromium.org/6493004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@74965 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
-rw-r--r-- | ppapi/c/private/ppb_proxy_private.h | 19 | ||||
-rw-r--r-- | ppapi/ppapi_cpp.gypi | 1 | ||||
-rw-r--r-- | ppapi/proxy/dispatcher.cc | 14 | ||||
-rw-r--r-- | ppapi/proxy/dispatcher.h | 19 | ||||
-rw-r--r-- | ppapi/proxy/host_dispatcher.cc | 19 | ||||
-rw-r--r-- | ppapi/proxy/host_dispatcher.h | 17 | ||||
-rw-r--r-- | ppapi/proxy/plugin_dispatcher.cc | 20 | ||||
-rw-r--r-- | ppapi/proxy/plugin_dispatcher.h | 2 |
8 files changed, 88 insertions, 23 deletions
diff --git a/ppapi/c/private/ppb_proxy_private.h b/ppapi/c/private/ppb_proxy_private.h new file mode 100644 index 0000000..fc8341e --- /dev/null +++ b/ppapi/c/private/ppb_proxy_private.h @@ -0,0 +1,19 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_C_PRIVATE_PROXY_PRIVATE_H_ +#define PPAPI_C_PRIVATE_PROXY_PRIVATE_H_ + +#include "ppapi/c/pp_module.h" + +#define PPB_PROXY_PRIVATE_INTERFACE "PPB_Proxy_Private;1" + +// Exposes functions needed by the out-of-process proxy to call into the +// renderer PPAPI implementation. +struct PPB_Proxy_Private { + // Called when the given plugin process has crashed. + void (*PluginCrashed)(PP_Module module); +}; + +#endif // PPAPI_C_PRIVATE_PROXY_PRIVATE_H_ diff --git a/ppapi/ppapi_cpp.gypi b/ppapi/ppapi_cpp.gypi index 112edcd..05efe6b 100644 --- a/ppapi/ppapi_cpp.gypi +++ b/ppapi/ppapi_cpp.gypi @@ -85,6 +85,7 @@ 'c/private/ppb_flash_menu.h', 'c/private/ppb_nacl_private.h', 'c/private/ppb_pdf.h', + 'c/private/ppb_proxy_private.h', # Deprecated interfaces. 'c/dev/deprecated_bool.h', diff --git a/ppapi/proxy/dispatcher.cc b/ppapi/proxy/dispatcher.cc index eb9726b..f3fbc06 100644 --- a/ppapi/proxy/dispatcher.cc +++ b/ppapi/proxy/dispatcher.cc @@ -151,8 +151,7 @@ InterfaceList* InterfaceList::GetInstance() { Dispatcher::Dispatcher(base::ProcessHandle remote_process_handle, GetInterfaceFunc local_get_interface) - : pp_module_(0), - remote_process_handle_(remote_process_handle), + : remote_process_handle_(remote_process_handle), test_sink_(NULL), disallow_trusted_interfaces_(false), // TODO(brettw) make this settable. local_get_interface_(local_get_interface), @@ -192,6 +191,10 @@ bool Dispatcher::OnMessageReceived(const IPC::Message& msg) { return false; } +void Dispatcher::OnChannelError() { + channel_.reset(); +} + // static const InterfaceProxy::Info* Dispatcher::GetPPBInterfaceInfo( const std::string& name) { @@ -242,7 +245,12 @@ const void* Dispatcher::GetLocalInterface(const char* interface) { bool Dispatcher::Send(IPC::Message* msg) { if (test_sink_) return test_sink_->Send(msg); - return channel_->Send(msg); + if (channel_.get()) + return channel_->Send(msg); + + // Remote side crashed, drop this message. + delete msg; + return false; } } // namespace proxy diff --git a/ppapi/proxy/dispatcher.h b/ppapi/proxy/dispatcher.h index b3b520d..82c0f31 100644 --- a/ppapi/proxy/dispatcher.h +++ b/ppapi/proxy/dispatcher.h @@ -59,7 +59,7 @@ class Dispatcher : public IPC::Channel::Listener, typedef int32_t (*InitModuleFunc)(PP_Module, GetInterfaceFunc); typedef void (*ShutdownModuleFunc)(); - ~Dispatcher(); + virtual ~Dispatcher(); // You must call this function before anything else. Returns true on success. bool InitWithChannel(MessageLoop* ipc_message_loop, @@ -79,9 +79,6 @@ class Dispatcher : public IPC::Channel::Listener, VarSerializationRules* serialization_rules() const { return serialization_rules_.get(); } - PP_Module pp_module() const { - return pp_module_; - } // Wrapper for calling the local GetInterface function. const void* GetLocalInterface(const char* interface); @@ -103,8 +100,9 @@ class Dispatcher : public IPC::Channel::Listener, // IPC::Channel::Listener implementation. virtual bool OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelError(); - // Will be NULL in some unit tests. + // Will be NULL in some unit tests and if the remote side has crashed. IPC::SyncChannel* channel() const { return channel_.get(); } @@ -132,19 +130,11 @@ class Dispatcher : public IPC::Channel::Listener, // Takes ownership of the given pointer, which must be on the heap. void SetSerializationRules(VarSerializationRules* var_serialization_rules); - void set_pp_module(PP_Module module) { - pp_module_ = module; - } - bool disallow_trusted_interfaces() const { return disallow_trusted_interfaces_; } private: - // Set by the derived classed to indicate the module ID corresponding to - // this dispatcher. - PP_Module pp_module_; - base::ProcessHandle remote_process_handle_; // See getter above. // When we're unit testing, this will indicate the sink for the messages to @@ -152,7 +142,8 @@ class Dispatcher : public IPC::Channel::Listener, // indicates that the channel should not be used. IPC::TestSink* test_sink_; - // Will be null for some tests when there is a test_sink_. + // Will be null for some tests when there is a test_sink_, and if the + // remote side has crashed. scoped_ptr<IPC::SyncChannel> channel_; bool disallow_trusted_interfaces_; diff --git a/ppapi/proxy/host_dispatcher.cc b/ppapi/proxy/host_dispatcher.cc index fce2b13..5572e91 100644 --- a/ppapi/proxy/host_dispatcher.cc +++ b/ppapi/proxy/host_dispatcher.cc @@ -7,6 +7,7 @@ #include <map> #include "base/logging.h" +#include "ppapi/c/private/ppb_proxy_private.h" #include "ppapi/c/dev/ppb_var_deprecated.h" #include "ppapi/proxy/host_var_serialization_rules.h" #include "ppapi/proxy/ppapi_messages.h" @@ -24,8 +25,9 @@ InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; HostDispatcher::HostDispatcher(base::ProcessHandle remote_process_handle, PP_Module module, GetInterfaceFunc local_get_interface) - : Dispatcher(remote_process_handle, local_get_interface) { - set_pp_module(module); + : Dispatcher(remote_process_handle, local_get_interface), + pp_module_(module), + ppb_proxy_(NULL) { const PPB_Var_Deprecated* var_interface = static_cast<const PPB_Var_Deprecated*>( local_get_interface(PPB_VAR_DEPRECATED_INTERFACE)); @@ -109,7 +111,10 @@ bool HostDispatcher::OnMessageReceived(const IPC::Message& msg) { } void HostDispatcher::OnChannelError() { - // TODO(brettw) plugin has crashed, handle this. + Dispatcher::OnChannelError(); // Stop using the channel. + + // Tell the host about the crash so it can clean up. + GetPPBProxy()->PluginCrashed(pp_module()); } const void* HostDispatcher::GetProxiedInterface(const std::string& interface) { @@ -137,6 +142,14 @@ const void* HostDispatcher::GetProxiedInterface(const std::string& interface) { return NULL; } +const PPB_Proxy_Private* HostDispatcher::GetPPBProxy() { + if (!ppb_proxy_) { + ppb_proxy_ = reinterpret_cast<const PPB_Proxy_Private*>( + GetLocalInterface(PPB_PROXY_PRIVATE_INTERFACE)); + } + return ppb_proxy_; +} + } // namespace proxy } // namespace pp diff --git a/ppapi/proxy/host_dispatcher.h b/ppapi/proxy/host_dispatcher.h index e38fca6..5153f19 100644 --- a/ppapi/proxy/host_dispatcher.h +++ b/ppapi/proxy/host_dispatcher.h @@ -15,6 +15,7 @@ #include "ppapi/proxy/dispatcher.h" #include "ppapi/proxy/plugin_var_tracker.h" +struct PPB_Proxy_Private; struct PPB_Var_Deprecated; namespace base { @@ -48,6 +49,14 @@ class HostDispatcher : public Dispatcher { HostDispatcher* dispatcher); static void RemoveForInstance(PP_Instance instance); + // Returns the host's notion of our PP_Module. This will be different than + // the plugin's notion of its PP_Module because the plugin process may be + // used by multiple renderer processes. + // + // Use this value instead of a value from the plugin whenever talking to the + // host. + PP_Module pp_module() const { return pp_module_; } + // Dispatcher overrides. virtual bool IsPlugin() const; @@ -61,9 +70,14 @@ class HostDispatcher : public Dispatcher { // given interface isn't supported by the plugin or the proxy. const void* GetProxiedInterface(const std::string& interface); + // Returns the proxy interface for talking to the implementation. + const PPB_Proxy_Private* GetPPBProxy(); + private: friend class HostDispatcherTest; + PP_Module pp_module_; + enum PluginInterfaceSupport { INTERFACE_UNQUERIED = 0, // Must be 0 so memset(0) will clear the list. INTERFACE_SUPPORTED, @@ -75,6 +89,9 @@ class HostDispatcher : public Dispatcher { // messages. They are created on demand when we receive messages. scoped_ptr<InterfaceProxy> target_proxies_[INTERFACE_ID_COUNT]; + // Lazily initialized, may be NULL. Use GetPPBProxy(). + const PPB_Proxy_Private* ppb_proxy_; + DISALLOW_COPY_AND_ASSIGN(HostDispatcher); }; diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc index 1f4454c..645f92f 100644 --- a/ppapi/proxy/plugin_dispatcher.cc +++ b/ppapi/proxy/plugin_dispatcher.cc @@ -129,6 +129,8 @@ bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { } void PluginDispatcher::OnChannelError() { + Dispatcher::OnChannelError(); + // The renderer has crashed. This channel and all instances associated with // it are no longer valid. ForceFreeAllInstances(); @@ -168,7 +170,7 @@ InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) { #if defined(OS_POSIX) int PluginDispatcher::GetRendererFD() { - if (renderer_fd_ == -1) + if (renderer_fd_ == -1 && channel()) renderer_fd_ = channel()->GetClientFileDescriptor(); return renderer_fd_; } @@ -183,7 +185,21 @@ void PluginDispatcher::CloseRendererFD() { #endif void PluginDispatcher::ForceFreeAllInstances() { - // TODO(brettw) implement freeing instances on crash. + if (!g_instance_to_dispatcher) + return; + + // Iterating will remove each item from the map, so we need to make a copy + // to avoid things changing out from under is. + InstanceToDispatcherMap temp_map = *g_instance_to_dispatcher; + for (InstanceToDispatcherMap::iterator i = temp_map.begin(); + i != temp_map.end(); ++i) { + if (i->second == this) { + // Synthesize an "instance destroyed" message, this will notify the + // plugin and also remove it from our list of tracked plugins. + OnMessageReceived( + PpapiMsg_PPPInstance_DidDestroy(INTERFACE_ID_PPP_INSTANCE, i->first)); + } + } } void PluginDispatcher::OnMsgSupportsInterface( diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h index 0b219f4..994edc0 100644 --- a/ppapi/proxy/plugin_dispatcher.h +++ b/ppapi/proxy/plugin_dispatcher.h @@ -38,7 +38,7 @@ class PluginDispatcher : public Dispatcher { // You must call Dispatcher::InitWithChannel after the constructor. PluginDispatcher(base::ProcessHandle remote_process_handle, GetInterfaceFunc get_interface); - ~PluginDispatcher(); + virtual ~PluginDispatcher(); // The plugin side maintains a mapping from PP_Instance to Dispatcher so // that we can send the messages to the right channel if there are multiple |