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 /webkit/plugins/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 'webkit/plugins/ppapi')
-rw-r--r-- | webkit/plugins/ppapi/plugin_module.cc | 11 | ||||
-rw-r--r-- | webkit/plugins/ppapi/plugin_module.h | 4 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppapi_plugin_instance.cc | 12 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppapi_plugin_instance.h | 3 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppb_proxy_impl.cc | 34 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppb_proxy_impl.h | 22 | ||||
-rw-r--r-- | webkit/plugins/ppapi/resource_tracker.cc | 114 | ||||
-rw-r--r-- | webkit/plugins/ppapi/resource_tracker.h | 10 |
8 files changed, 157 insertions, 53 deletions
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). |