diff options
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). |