summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/chrome.gyp2
-rw-r--r--chrome/plugin/plugin_channel.cc8
-rw-r--r--chrome/ppapi_plugin/plugin_process_dispatcher.cc38
-rw-r--r--chrome/ppapi_plugin/plugin_process_dispatcher.h24
-rw-r--r--chrome/ppapi_plugin/ppapi_thread.cc4
-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
-rw-r--r--webkit/glue/webkit_glue.gypi2
-rw-r--r--webkit/plugins/ppapi/plugin_module.cc11
-rw-r--r--webkit/plugins/ppapi/plugin_module.h4
-rw-r--r--webkit/plugins/ppapi/ppapi_plugin_instance.cc12
-rw-r--r--webkit/plugins/ppapi/ppapi_plugin_instance.h3
-rw-r--r--webkit/plugins/ppapi/ppb_proxy_impl.cc34
-rw-r--r--webkit/plugins/ppapi/ppb_proxy_impl.h22
-rw-r--r--webkit/plugins/ppapi/resource_tracker.cc114
-rw-r--r--webkit/plugins/ppapi/resource_tracker.h10
22 files changed, 318 insertions, 81 deletions
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 49e6e81d..80caf95 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -780,6 +780,8 @@
'../ppapi/ppapi.gyp:ppapi_proxy',
],
'sources': [
+ 'ppapi_plugin/plugin_process_dispatcher.cc',
+ 'ppapi_plugin/plugin_process_dispatcher.h',
'ppapi_plugin/ppapi_plugin_main.cc',
'ppapi_plugin/ppapi_process.cc',
'ppapi_plugin/ppapi_process.h',
diff --git a/chrome/plugin/plugin_channel.cc b/chrome/plugin/plugin_channel.cc
index 205b3fa..ff817a7 100644
--- a/chrome/plugin/plugin_channel.cc
+++ b/chrome/plugin/plugin_channel.cc
@@ -23,6 +23,8 @@
#include "ipc/ipc_channel_posix.h"
#endif
+namespace {
+
class PluginReleaseTask : public Task {
public:
void Run() {
@@ -31,8 +33,9 @@ class PluginReleaseTask : public Task {
};
// How long we wait before releasing the plugin process.
-static const int kPluginReleaseTimeMS = 5 * 60 * 1000; // 5 minutes
+const int kPluginReleaseTimeMs = 5 * 60 * 1000; // 5 minutes
+} // namespace
// If a sync call to the renderer results in a modal dialog, we need to have a
// way to know so that we can run a nested message loop to simulate what would
@@ -133,7 +136,6 @@ class PluginChannel::MessageFilter : public IPC::ChannelProxy::MessageFilter {
IPC::Channel* channel_;
};
-
PluginChannel* PluginChannel::GetPluginChannel(int renderer_id,
MessageLoop* ipc_message_loop) {
// Map renderer ID to a (single) channel to that process.
@@ -176,7 +178,7 @@ PluginChannel::~PluginChannel() {
base::CloseProcessHandle(renderer_handle_);
MessageLoop::current()->PostDelayedTask(FROM_HERE, new PluginReleaseTask(),
- kPluginReleaseTimeMS);
+ kPluginReleaseTimeMs);
}
bool PluginChannel::Send(IPC::Message* msg) {
diff --git a/chrome/ppapi_plugin/plugin_process_dispatcher.cc b/chrome/ppapi_plugin/plugin_process_dispatcher.cc
new file mode 100644
index 0000000..833a20e
--- /dev/null
+++ b/chrome/ppapi_plugin/plugin_process_dispatcher.cc
@@ -0,0 +1,38 @@
+// 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.
+
+#include "chrome/ppapi_plugin/plugin_process_dispatcher.h"
+
+#include "chrome/common/child_process.h"
+
+namespace {
+
+class PluginReleaseTask : public Task {
+ public:
+ void Run() {
+ ChildProcess::current()->ReleaseProcess();
+ }
+};
+
+// How long we wait before releasing the plugin process.
+const int kPluginReleaseTimeMs = 30 * 1000; // 30 seconds.
+
+} // namespace
+
+PluginProcessDispatcher::PluginProcessDispatcher(
+ base::ProcessHandle remote_process_handle,
+ GetInterfaceFunc get_interface)
+ : pp::proxy::PluginDispatcher(remote_process_handle, get_interface) {
+ ChildProcess::current()->AddRefProcess();
+}
+
+PluginProcessDispatcher::~PluginProcessDispatcher() {
+ // Don't free the process right away. This timer allows the child process
+ // to be re-used if the user rapidly goes to a new page that requires this
+ // plugin. This is the case for common plugins where they may be used on a
+ // source and destination page of a navigation. We don't want to tear down
+ // and re-start processes each time in these cases.
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, new PluginReleaseTask(),
+ kPluginReleaseTimeMs);
+}
diff --git a/chrome/ppapi_plugin/plugin_process_dispatcher.h b/chrome/ppapi_plugin/plugin_process_dispatcher.h
new file mode 100644
index 0000000..b382528
--- /dev/null
+++ b/chrome/ppapi_plugin/plugin_process_dispatcher.h
@@ -0,0 +1,24 @@
+// 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 CHROME_PPAPI_PLUGIN_PLUGIN_PROCESS_DISPATCHER_H_
+#define CHROME_PPAPI_PLUGIN_PLUGIN_PROCESS_DISPATCHER_H_
+
+#include "base/basictypes.h"
+#include "ppapi/proxy/plugin_dispatcher.h"
+
+// Wrapper around a PluginDispatcher that provides the necessary integration
+// for plugin process management. This class is to avoid direct dependencies
+// from the PPAPI proxy on the Chrome multiprocess infrastructure.
+class PluginProcessDispatcher : public pp::proxy::PluginDispatcher {
+ public:
+ PluginProcessDispatcher(base::ProcessHandle remote_process_handle,
+ GetInterfaceFunc get_interface);
+ virtual ~PluginProcessDispatcher();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PluginProcessDispatcher);
+};
+
+#endif // CHROME_PPAPI_PLUGIN_PLUGIN_PROCESS_DISPATCHER_H_
diff --git a/chrome/ppapi_plugin/ppapi_thread.cc b/chrome/ppapi_plugin/ppapi_thread.cc
index 483863c..0e1a030 100644
--- a/chrome/ppapi_plugin/ppapi_thread.cc
+++ b/chrome/ppapi_plugin/ppapi_thread.cc
@@ -9,11 +9,11 @@
#include "base/process_util.h"
#include "base/rand_util.h"
#include "chrome/common/child_process.h"
+#include "chrome/ppapi_plugin/plugin_process_dispatcher.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_sync_channel.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/ppp.h"
-#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/ppapi_messages.h"
PpapiThread::PpapiThread()
@@ -97,7 +97,7 @@ void PpapiThread::OnMsgCreateChannel(base::ProcessHandle host_process_handle,
bool PpapiThread::SetupRendererChannel(base::ProcessHandle host_process_handle,
int renderer_id,
IPC::ChannelHandle* handle) {
- pp::proxy::PluginDispatcher* dispatcher = new pp::proxy::PluginDispatcher(
+ PluginProcessDispatcher* dispatcher = new PluginProcessDispatcher(
host_process_handle, get_plugin_interface_);
IPC::ChannelHandle plugin_handle;
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
diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi
index 4a3d03f..2db2299 100644
--- a/webkit/glue/webkit_glue.gypi
+++ b/webkit/glue/webkit_glue.gypi
@@ -314,6 +314,8 @@
'../plugins/ppapi/ppb_opengles_impl.h',
'../plugins/ppapi/ppb_pdf_impl.cc',
'../plugins/ppapi/ppb_pdf_impl.h',
+ '../plugins/ppapi/ppb_proxy_impl.cc',
+ '../plugins/ppapi/ppb_proxy_impl.h',
'../plugins/ppapi/ppb_scrollbar_impl.cc',
'../plugins/ppapi/ppb_scrollbar_impl.h',
'../plugins/ppapi/ppb_surface_3d_impl.cc',
diff --git a/webkit/plugins/ppapi/plugin_module.cc b/webkit/plugins/ppapi/plugin_module.cc
index a8d804a..a99a29c 100644
--- a/webkit/plugins/ppapi/plugin_module.cc
+++ b/webkit/plugins/ppapi/plugin_module.cc
@@ -52,6 +52,7 @@
#include "ppapi/c/private/ppb_flash.h"
#include "ppapi/c/private/ppb_flash_menu.h"
#include "ppapi/c/private/ppb_pdf.h"
+#include "ppapi/c/private/ppb_proxy_private.h"
#include "ppapi/c/private/ppb_nacl_private.h"
#include "ppapi/c/trusted/ppb_image_data_trusted.h"
#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
@@ -74,6 +75,7 @@
#include "webkit/plugins/ppapi/ppb_image_data_impl.h"
#include "webkit/plugins/ppapi/ppb_nacl_private_impl.h"
#include "webkit/plugins/ppapi/ppb_pdf_impl.h"
+#include "webkit/plugins/ppapi/ppb_proxy_impl.h"
#include "webkit/plugins/ppapi/ppb_scrollbar_impl.h"
#include "webkit/plugins/ppapi/ppb_transport_impl.h"
#include "webkit/plugins/ppapi/ppb_url_loader_impl.h"
@@ -260,6 +262,8 @@ const void* GetInterface(const char* name) {
return PluginInstance::GetInterface();
if (strcmp(name, PPB_PDF_INTERFACE) == 0)
return PPB_PDF_Impl::GetInterface();
+ if (strcmp(name, PPB_PROXY_PRIVATE_INTERFACE) == 0)
+ return PPB_Proxy_Impl::GetInterface();
if (strcmp(name, PPB_SCROLLBAR_DEV_INTERFACE) == 0)
return PPB_Scrollbar_Impl::GetInterface();
if (strcmp(name, PPB_TRANSPORT_DEV_INTERFACE) == 0)
@@ -472,6 +476,13 @@ scoped_refptr<CallbackTracker> PluginModule::GetCallbackTracker() {
return callback_tracker_;
}
+void PluginModule::PluginCrashed() {
+ // Notify all instances that they crashed.
+ for (PluginInstanceSet::iterator i = instances_.begin();
+ i != instances_.end(); ++i)
+ (*i)->InstanceCrashed();
+}
+
bool PluginModule::InitializeModule() {
DCHECK(!out_of_process_proxy_.get()) << "Don't call for proxied modules.";
int retval = entry_points_.initialize_module(pp_module(), &GetInterface);
diff --git a/webkit/plugins/ppapi/plugin_module.h b/webkit/plugins/ppapi/plugin_module.h
index 4f3e9c3..f21dbde 100644
--- a/webkit/plugins/ppapi/plugin_module.h
+++ b/webkit/plugins/ppapi/plugin_module.h
@@ -122,6 +122,10 @@ class PluginModule : public base::RefCounted<PluginModule>,
scoped_refptr<CallbackTracker> GetCallbackTracker();
+ // Called when running out of process and the plugin crashed. This will
+ // release relevant resources and update all affected instances.
+ void PluginCrashed();
+
private:
// Calls the InitializeModule entrypoint. The entrypoint must have been
// set and the plugin must not be out of process (we don't maintain
diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc
index ee815f3..421d676 100644
--- a/webkit/plugins/ppapi/ppapi_plugin_instance.cc
+++ b/webkit/plugins/ppapi/ppapi_plugin_instance.cc
@@ -417,6 +417,18 @@ void PluginInstance::CommitBackingTexture() {
container_->commitBackingTexture();
}
+void PluginInstance::InstanceCrashed() {
+ // Force free all resources and vars.
+ ResourceTracker::Get()->InstanceCrashed(pp_instance());
+
+ // Free any associated graphics.
+ SetFullscreen(false);
+ bound_graphics_ = NULL;
+ InvalidateRect(gfx::Rect());
+
+ // TODO(brettw) show a crashed plugin screen.
+}
+
PP_Var PluginInstance::GetWindowObject() {
if (!container_)
return PP_MakeUndefined();
diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.h b/webkit/plugins/ppapi/ppapi_plugin_instance.h
index b876d1d..c6ba2ec 100644
--- a/webkit/plugins/ppapi/ppapi_plugin_instance.h
+++ b/webkit/plugins/ppapi/ppapi_plugin_instance.h
@@ -122,6 +122,9 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
// rendering up to an offscreen SwapBuffers are visible.
void CommitBackingTexture();
+ // Called when the out-of-process plugin implementing this instance crashed.
+ void InstanceCrashed();
+
// PPB_Instance implementation.
PP_Var GetWindowObject();
PP_Var GetOwnerElementObject();
diff --git a/webkit/plugins/ppapi/ppb_proxy_impl.cc b/webkit/plugins/ppapi/ppb_proxy_impl.cc
new file mode 100644
index 0000000..f5a5102
--- /dev/null
+++ b/webkit/plugins/ppapi/ppb_proxy_impl.cc
@@ -0,0 +1,34 @@
+// 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.
+
+#include "webkit/plugins/ppapi/ppb_proxy_impl.h"
+
+#include "ppapi/c/private/ppb_proxy_private.h"
+#include "webkit/plugins/ppapi/plugin_module.h"
+#include "webkit/plugins/ppapi/resource_tracker.h"
+
+namespace webkit {
+namespace ppapi {
+
+namespace {
+
+void PluginCrashed(PP_Module module) {
+ PluginModule* plugin_module = ResourceTracker::Get()->GetModule(module);
+ if (plugin_module)
+ plugin_module->PluginCrashed();
+}
+
+const PPB_Proxy_Private ppb_proxy = {
+ &PluginCrashed
+};
+
+} // namespace
+
+// static
+const PPB_Proxy_Private* PPB_Proxy_Impl::GetInterface() {
+ return &ppb_proxy;
+}
+
+} // namespace ppapi
+} // namespace webkit
diff --git a/webkit/plugins/ppapi/ppb_proxy_impl.h b/webkit/plugins/ppapi/ppb_proxy_impl.h
new file mode 100644
index 0000000..72a333a
--- /dev/null
+++ b/webkit/plugins/ppapi/ppb_proxy_impl.h
@@ -0,0 +1,22 @@
+// 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 WEBKIT_PLUGINS_PPAPI_PPB_PROXY_IMPL_H_
+#define WEBKIT_PLUGINS_PPAPI_PPB_PROXY_IMPL_H_
+
+struct PPB_Proxy_Private;
+
+namespace webkit {
+namespace ppapi {
+
+class PPB_Proxy_Impl {
+ public:
+ static const PPB_Proxy_Private* GetInterface();
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // WEBKIT_PLUGINS_PPAPI_PPB_PROXY_IMPL_H_
+
diff --git a/webkit/plugins/ppapi/resource_tracker.cc b/webkit/plugins/ppapi/resource_tracker.cc
index ed876d7..b17210c 100644
--- a/webkit/plugins/ppapi/resource_tracker.cc
+++ b/webkit/plugins/ppapi/resource_tracker.cc
@@ -159,6 +159,64 @@ bool ResourceTracker::UnrefResource(PP_Resource res) {
}
}
+void ResourceTracker::CleanupInstanceData(PP_Instance instance,
+ bool delete_instance) {
+ DLOG_IF(ERROR, !CheckIdType(instance, PP_ID_TYPE_INSTANCE))
+ << instance << " is not a PP_Instance.";
+ InstanceMap::iterator found = instance_map_.find(instance);
+ if (found == instance_map_.end()) {
+ NOTREACHED();
+ return;
+ }
+ InstanceData& data = found->second;
+
+ // Force release all plugin references to resources associated with the
+ // deleted instance.
+ ResourceSet::iterator cur_res = data.resources.begin();
+ while (cur_res != data.resources.end()) {
+ ResourceMap::iterator found_resource = live_resources_.find(*cur_res);
+ if (found_resource == live_resources_.end()) {
+ NOTREACHED();
+ } else {
+ Resource* resource = found_resource->second.first;
+
+ // Must delete from the resource set first since the resource's instance
+ // pointer will get zeroed out in LastPluginRefWasDeleted.
+ resource->LastPluginRefWasDeleted(true);
+ live_resources_.erase(*cur_res);
+ }
+
+ // Iterators to a set are stable so we can iterate the set while the items
+ // are being deleted as long as we're careful not to delete the item we're
+ // holding an iterator to.
+ ResourceSet::iterator current = cur_res++;
+ data.resources.erase(current);
+ }
+ DCHECK(data.resources.empty());
+
+ // Force delete all var references.
+ VarSet::iterator cur_var = data.object_vars.begin();
+ while (cur_var != data.object_vars.end()) {
+ VarSet::iterator current = cur_var++;
+
+ // Tell the corresponding ObjectVar that the instance is gone.
+ PP_Var object_pp_var;
+ object_pp_var.type = PP_VARTYPE_OBJECT;
+ object_pp_var.value.as_id = *current;
+ scoped_refptr<ObjectVar> object_var(ObjectVar::FromPPVar(object_pp_var));
+ if (object_var.get())
+ object_var->InstanceDeleted();
+
+ // Clear the object from the var mapping and the live instance object list.
+ live_vars_.erase(*current);
+ data.object_vars.erase(*current);
+ }
+ DCHECK(data.object_vars.empty());
+
+ if (delete_instance)
+ instance_map_.erase(found);
+}
+
uint32 ResourceTracker::GetLiveObjectsForInstance(
PP_Instance instance) const {
InstanceMap::const_iterator found = instance_map_.find(instance);
@@ -228,59 +286,11 @@ PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) {
}
void ResourceTracker::InstanceDeleted(PP_Instance instance) {
- DLOG_IF(ERROR, !CheckIdType(instance, PP_ID_TYPE_INSTANCE))
- << instance << " is not a PP_Instance.";
- InstanceMap::iterator found = instance_map_.find(instance);
- if (found == instance_map_.end()) {
- NOTREACHED();
- return;
- }
- InstanceData& data = found->second;
-
- // Force release all plugin references to resources associated with the
- // deleted instance.
- ResourceSet::iterator cur_res = data.resources.begin();
- while (cur_res != data.resources.end()) {
- ResourceMap::iterator found_resource = live_resources_.find(*cur_res);
- if (found_resource == live_resources_.end()) {
- NOTREACHED();
- } else {
- Resource* resource = found_resource->second.first;
-
- // Must delete from the resource set first since the resource's instance
- // pointer will get zeroed out in LastPluginRefWasDeleted.
- resource->LastPluginRefWasDeleted(true);
- live_resources_.erase(*cur_res);
- }
-
- // Iterators to a set are stable so we can iterate the set while the items
- // are being deleted as long as we're careful not to delete the item we're
- // holding an iterator to.
- ResourceSet::iterator current = cur_res++;
- data.resources.erase(current);
- }
- DCHECK(data.resources.empty());
-
- // Force delete all var references.
- VarSet::iterator cur_var = data.object_vars.begin();
- while (cur_var != data.object_vars.end()) {
- VarSet::iterator current = cur_var++;
-
- // Tell the corresponding ObjectVar that the instance is gone.
- PP_Var object_pp_var;
- object_pp_var.type = PP_VARTYPE_OBJECT;
- object_pp_var.value.as_id = *current;
- scoped_refptr<ObjectVar> object_var(ObjectVar::FromPPVar(object_pp_var));
- if (object_var.get())
- object_var->InstanceDeleted();
-
- // Clear the object from the var mapping and the live instance object list.
- live_vars_.erase(*current);
- data.object_vars.erase(*current);
- }
- DCHECK(data.object_vars.empty());
+ CleanupInstanceData(instance, true);
+}
- instance_map_.erase(found);
+void ResourceTracker::InstanceCrashed(PP_Instance instance) {
+ CleanupInstanceData(instance, false);
}
PluginInstance* ResourceTracker::GetInstance(PP_Instance instance) {
diff --git a/webkit/plugins/ppapi/resource_tracker.h b/webkit/plugins/ppapi/resource_tracker.h
index 1187dda..20f3a2e 100644
--- a/webkit/plugins/ppapi/resource_tracker.h
+++ b/webkit/plugins/ppapi/resource_tracker.h
@@ -87,8 +87,11 @@ class ResourceTracker {
// The given handle should be one generated by AddInstance.
void InstanceDeleted(PP_Instance instance);
+ void InstanceCrashed(PP_Instance instance);
+
// Returns a pointer to the plugin instance object associated with the given
- // instance handle. The return value will be NULL if the handle is invalid.
+ // instance handle. The return value will be NULL if the handle is invalid or
+ // if the instance has crashed.
PluginInstance* GetInstance(PP_Instance instance);
private:
@@ -117,6 +120,11 @@ class ResourceTracker {
// The same as AddResource but for Var, and returns the new Var ID.
int32 AddVar(Var* var);
+ // Force frees all vars and resources associated with the given instance.
+ // If delete_instance is true, the instance tracking information will also
+ // be deleted.
+ void CleanupInstanceData(PP_Instance instance, bool delete_instance);
+
// Overrides the singleton object. This is used for tests which want to
// specify their own tracker (otherwise, you can get cross-talk between
// tests since the data will live into the subsequent tests).