summaryrefslogtreecommitdiffstats
path: root/ppapi
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-15 17:36:33 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-15 17:36:33 +0000
commit4f15d284466def720aa90d4f745edfa9af378094 (patch)
treee30ce116b0c05d4adacf9fa5aae6188178b4a3a7 /ppapi
parent351856ef135301f705435a8feecbc66ecfafbf77 (diff)
downloadchromium_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.h19
-rw-r--r--ppapi/ppapi_cpp.gypi1
-rw-r--r--ppapi/proxy/dispatcher.cc14
-rw-r--r--ppapi/proxy/dispatcher.h19
-rw-r--r--ppapi/proxy/host_dispatcher.cc19
-rw-r--r--ppapi/proxy/host_dispatcher.h17
-rw-r--r--ppapi/proxy/plugin_dispatcher.cc20
-rw-r--r--ppapi/proxy/plugin_dispatcher.h2
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