diff options
23 files changed, 339 insertions, 35 deletions
diff --git a/chrome/common/DEPS b/chrome/common/DEPS index cd9bd3f..e6f68bb 100644 --- a/chrome/common/DEPS +++ b/chrome/common/DEPS @@ -6,6 +6,7 @@ include_rules = [ "+media/audio", "+media/base", "+ppapi/c", # For various types. + "+ppapi/proxy", "+remoting/client/plugin", "+sandbox/src", "+skia", diff --git a/chrome/common/pepper_plugin_registry.cc b/chrome/common/pepper_plugin_registry.cc index 2b315fb..ff312a2 100644 --- a/chrome/common/pepper_plugin_registry.cc +++ b/chrome/common/pepper_plugin_registry.cc @@ -13,6 +13,7 @@ #include "base/utf_string_conversions.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" +#include "content/common/child_process.h" #include "content/common/content_switches.h" #include "remoting/client/plugin/pepper_entrypoints.h" @@ -326,3 +327,19 @@ PepperPluginRegistry::PepperPluginRegistry() { preloaded_modules_[current.path] = module; } } + +MessageLoop* PepperPluginRegistry::GetIPCMessageLoop() { + // This is called only in the renderer so we know we have a child process. + DCHECK(ChildProcess::current()) << "Must be in the renderer."; + return ChildProcess::current()->io_message_loop(); +} + +base::WaitableEvent* PepperPluginRegistry::GetShutdownEvent() { + DCHECK(ChildProcess::current()) << "Must be in the renderer."; + return ChildProcess::current()->GetShutDownEvent(); +} + +std::set<PP_Instance>* PepperPluginRegistry::GetGloballySeenInstanceIDSet() { + // This function is not needed on the host side of the proxy. + return NULL; +} diff --git a/chrome/common/pepper_plugin_registry.h b/chrome/common/pepper_plugin_registry.h index beb808c3..1852954 100644 --- a/chrome/common/pepper_plugin_registry.h +++ b/chrome/common/pepper_plugin_registry.h @@ -11,6 +11,7 @@ #include <vector> #include "base/file_path.h" +#include "ppapi/proxy/dispatcher.h" #include "webkit/plugins/npapi/webplugininfo.h" #include "webkit/plugins/ppapi/plugin_delegate.h" #include "webkit/plugins/ppapi/plugin_module.h" @@ -45,7 +46,8 @@ struct PepperPluginInfo { // is a list of all live modules (some of which may be out-of-process and hence // not preloaded). class PepperPluginRegistry - : public webkit::ppapi::PluginDelegate::ModuleLifetime { + : public webkit::ppapi::PluginDelegate::ModuleLifetime, + public pp::proxy::Dispatcher::Delegate { public: ~PepperPluginRegistry(); @@ -90,6 +92,11 @@ class PepperPluginRegistry private: PepperPluginRegistry(); + // Dispatcher::Delegate implementation. + virtual MessageLoop* GetIPCMessageLoop(); + virtual base::WaitableEvent* GetShutdownEvent(); + virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet(); + // All known pepper plugins. std::vector<PepperPluginInfo> plugin_list_; diff --git a/chrome/ppapi_plugin/ppapi_thread.cc b/chrome/ppapi_plugin/ppapi_thread.cc index 98d0014..4e998ea 100644 --- a/chrome/ppapi_plugin/ppapi_thread.cc +++ b/chrome/ppapi_plugin/ppapi_thread.cc @@ -48,6 +48,18 @@ bool PpapiThread::OnMessageReceived(const IPC::Message& msg) { return true; } +MessageLoop* PpapiThread::GetIPCMessageLoop() { + return ChildProcess::current()->io_message_loop(); +} + +base::WaitableEvent* PpapiThread::GetShutdownEvent() { + return ChildProcess::current()->GetShutDownEvent(); +} + +std::set<PP_Instance>* PpapiThread::GetGloballySeenInstanceIDSet() { + return &globally_seen_instance_ids_; +} + void PpapiThread::OnMsgLoadPlugin(const FilePath& path) { base::ScopedNativeLibrary library(base::LoadNativeLibrary(path)); if (!library.is_valid()) @@ -103,10 +115,7 @@ bool PpapiThread::SetupRendererChannel(base::ProcessHandle host_process_handle, IPC::ChannelHandle plugin_handle; plugin_handle.name = StringPrintf("%d.r%d", base::GetCurrentProcId(), renderer_id); - if (!dispatcher->InitWithChannel( - ChildProcess::current()->io_message_loop(), - plugin_handle, false, - ChildProcess::current()->GetShutDownEvent())) + if (!dispatcher->InitWithChannel(this, plugin_handle, false)) return false; handle->name = plugin_handle.name; diff --git a/chrome/ppapi_plugin/ppapi_thread.h b/chrome/ppapi_plugin/ppapi_thread.h index e4058ad..34f06eb 100644 --- a/chrome/ppapi_plugin/ppapi_thread.h +++ b/chrome/ppapi_plugin/ppapi_thread.h @@ -27,7 +27,8 @@ class PluginDispatcher; } } -class PpapiThread : public ChildThread { +class PpapiThread : public ChildThread, + public pp::proxy::Dispatcher::Delegate { public: PpapiThread(); ~PpapiThread(); @@ -36,6 +37,11 @@ class PpapiThread : public ChildThread { // ChildThread overrides. virtual bool OnMessageReceived(const IPC::Message& msg); + // Dispatcher::Delegate implementation. + virtual MessageLoop* GetIPCMessageLoop(); + virtual base::WaitableEvent* GetShutdownEvent(); + virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet(); + // Message handlers. void OnMsgLoadPlugin(const FilePath& path); void OnMsgCreateChannel(base::ProcessHandle host_process_handle, @@ -59,6 +65,9 @@ class PpapiThread : public ChildThread { // and pass it around as necessary. PP_Module local_pp_module_; + // See Dispatcher::Delegate::GetGloballySeenInstanceIDSet. + std::set<PP_Instance> globally_seen_instance_ids_; + DISALLOW_COPY_AND_ASSIGN(PpapiThread); }; diff --git a/chrome/renderer/pepper_plugin_delegate_impl.cc b/chrome/renderer/pepper_plugin_delegate_impl.cc index 2fa07c2..9ba59c8 100644 --- a/chrome/renderer/pepper_plugin_delegate_impl.cc +++ b/chrome/renderer/pepper_plugin_delegate_impl.cc @@ -362,9 +362,8 @@ bool DispatcherWrapper::Init( dispatcher_.reset(new pp::proxy::HostDispatcher( plugin_process_handle, pp_module, local_get_interface)); - if (!dispatcher_->InitWithChannel( - ChildProcess::current()->io_message_loop(), channel_handle, - true, ChildProcess::current()->GetShutDownEvent())) { + if (!dispatcher_->InitWithChannel(PepperPluginRegistry::GetInstance(), + channel_handle, true)) { dispatcher_.reset(); return false; } diff --git a/content/common/child_process.h b/content/common/child_process.h index 518314d..d7e9a00 100644 --- a/content/common/child_process.h +++ b/content/common/child_process.h @@ -18,11 +18,15 @@ class ChildThread; class ChildProcess { public: // Child processes should have an object that derives from this class. + // Normally you would immediately call set_main_thread after construction. ChildProcess(); virtual ~ChildProcess(); - // Getter for the child process' main thread. + // May be NULL if the main thread hasn't been set explicitly. ChildThread* main_thread(); + + // Sets the object associated with the main thread of this process. + // Takes ownership of the pointer. void set_main_thread(ChildThread* thread); MessageLoop* io_message_loop() { return io_thread_.message_loop(); } diff --git a/ppapi/c/private/ppb_proxy_private.h b/ppapi/c/private/ppb_proxy_private.h index d003281..ae6a39e 100644 --- a/ppapi/c/private/ppb_proxy_private.h +++ b/ppapi/c/private/ppb_proxy_private.h @@ -5,11 +5,12 @@ #ifndef PPAPI_C_PRIVATE_PROXY_PRIVATE_H_ #define PPAPI_C_PRIVATE_PROXY_PRIVATE_H_ +#include "ppapi/c/pp_bool.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_module.h" #include "ppapi/c/pp_resource.h" -#define PPB_PROXY_PRIVATE_INTERFACE "PPB_Proxy_Private;2" +#define PPB_PROXY_PRIVATE_INTERFACE "PPB_Proxy_Private;3" // Exposes functions needed by the out-of-process proxy to call into the // renderer PPAPI implementation. @@ -19,6 +20,19 @@ struct PPB_Proxy_Private { // Returns the instance for the given resource, or 0 on failure. PP_Instance (*GetInstanceForResource)(PP_Resource resource); + + // Sets a callback that will be used to make sure that PP_Instance IDs + // are unique in the plugin. + // + // Since the plugin may be shared between several browser processes, we need + // to do extra work to make sure that an instance ID is globally unqiue. The + // given function will be called and will return true if the given + // PP_Instance is OK to use in the plugin. It will then be marked as "in use" + // On failure (returns false), the host implementation will generate a new + // instance ID and try again. + void (*SetReserveInstanceIDCallback)( + PP_Module module, + PP_Bool (*is_seen)(PP_Module, PP_Instance)); }; #endif // PPAPI_C_PRIVATE_PROXY_PRIVATE_H_ diff --git a/ppapi/ppapi_shared_proxy.gypi b/ppapi/ppapi_shared_proxy.gypi index 0c8b1ce..8c8a047 100644 --- a/ppapi/ppapi_shared_proxy.gypi +++ b/ppapi/ppapi_shared_proxy.gypi @@ -58,6 +58,8 @@ 'proxy/interface_proxy.h', 'proxy/plugin_dispatcher.cc', 'proxy/plugin_dispatcher.h', + 'proxy/plugin_message_filter.cc', + 'proxy/plugin_message_filter.h', 'proxy/plugin_resource.cc', 'proxy/plugin_resource.h', 'proxy/plugin_resource_tracker.cc', diff --git a/ppapi/proxy/dispatcher.cc b/ppapi/proxy/dispatcher.cc index dd4167c..391a882 100644 --- a/ppapi/proxy/dispatcher.cc +++ b/ppapi/proxy/dispatcher.cc @@ -165,7 +165,8 @@ InterfaceList* InterfaceList::GetInstance() { Dispatcher::Dispatcher(base::ProcessHandle remote_process_handle, GetInterfaceFunc local_get_interface) - : remote_process_handle_(remote_process_handle), + : delegate_(NULL), + remote_process_handle_(remote_process_handle), test_sink_(NULL), disallow_trusted_interfaces_(false), // TODO(brettw) make this settable. local_get_interface_(local_get_interface), @@ -175,14 +176,14 @@ Dispatcher::Dispatcher(base::ProcessHandle remote_process_handle, Dispatcher::~Dispatcher() { } -bool Dispatcher::InitWithChannel(MessageLoop* ipc_message_loop, +bool Dispatcher::InitWithChannel(Delegate* delegate, const IPC::ChannelHandle& channel_handle, - bool is_client, - base::WaitableEvent* shutdown_event) { + bool is_client) { IPC::Channel::Mode mode = is_client ? IPC::Channel::MODE_CLIENT : IPC::Channel::MODE_SERVER; channel_.reset(new IPC::SyncChannel(channel_handle, mode, this, - ipc_message_loop, false, shutdown_event)); + delegate->GetIPCMessageLoop(), false, + delegate->GetShutdownEvent())); return true; } diff --git a/ppapi/proxy/dispatcher.h b/ppapi/proxy/dispatcher.h index 161aa54..edcb7e7 100644 --- a/ppapi/proxy/dispatcher.h +++ b/ppapi/proxy/dispatcher.h @@ -6,6 +6,7 @@ #define PPAPI_PROXY_DISPATCHER_H_ #include <map> +#include <set> #include <string> #include <vector> @@ -16,6 +17,7 @@ #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_message.h" #include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_module.h" #include "ppapi/proxy/callback_tracker.h" #include "ppapi/proxy/interface_id.h" @@ -60,13 +62,31 @@ class Dispatcher : public IPC::Channel::Listener, typedef int32_t (*InitModuleFunc)(PP_Module, GetInterfaceFunc); typedef void (*ShutdownModuleFunc)(); + class Delegate { + public: + // Returns the dedicated message loop for processing IPC requests. + virtual MessageLoop* GetIPCMessageLoop() = 0; + + // Returns the event object that becomes signalled when the main thread's + // message loop exits. + virtual base::WaitableEvent* GetShutdownEvent() = 0; + + // Returns the set used for globally uniquifying PP_Instances. This same + // set must be returned for all channels. This is required only for the + // plugin side, for the host side, the return value may be NULL. + // + // DEREFERENCE ONLY ON THE I/O THREAD. + virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet() = 0; + }; + virtual ~Dispatcher(); // You must call this function before anything else. Returns true on success. - bool InitWithChannel(MessageLoop* ipc_message_loop, - const IPC::ChannelHandle& channel_handle, - bool is_client, - base::WaitableEvent* shutdown_event); + // The delegate pointer must outlive this class, ownership is not + // transferred. + virtual bool InitWithChannel(Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client); // Alternative to InitWithChannel() for unit tests that want to send all // messages sent via this dispatcher to the given test sink. The test sink @@ -137,7 +157,12 @@ class Dispatcher : public IPC::Channel::Listener, return disallow_trusted_interfaces_; } + Delegate* delegate() { return delegate_; } + private: + // Non-owning pointer. Guaranteed non-NULL after init is called. + Delegate* delegate_; + base::ProcessHandle remote_process_handle_; // See getter above. // When we're unit testing, this will indicate the sink for the messages to diff --git a/ppapi/proxy/host_dispatcher.cc b/ppapi/proxy/host_dispatcher.cc index aa972b5..52305e0 100644 --- a/ppapi/proxy/host_dispatcher.cc +++ b/ppapi/proxy/host_dispatcher.cc @@ -20,6 +20,27 @@ namespace { typedef std::map<PP_Instance, HostDispatcher*> InstanceToDispatcherMap; InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; +typedef std::map<PP_Module, HostDispatcher*> ModuleToDispatcherMap; +ModuleToDispatcherMap* g_module_to_dispatcher = NULL; + +PP_Bool ReserveInstanceID(PP_Module module, PP_Instance instance) { + // Default to returning true (usable) failure. Otherwise, if there's some + // kind of communication error or the plugin just crashed, we'll get into an + // infinite loop generating new instnace IDs since we think they're all in + // use. + ModuleToDispatcherMap::const_iterator found = + g_module_to_dispatcher->find(module); + if (found == g_module_to_dispatcher->end()) { + NOTREACHED(); + return PP_TRUE; + } + + bool usable = true; + if (!found->second->Send(new PpapiMsg_ReserveInstanceId(instance, &usable))) + return PP_TRUE; + return BoolToPPBool(usable); +} + } // namespace HostDispatcher::HostDispatcher(base::ProcessHandle remote_process_handle, @@ -28,6 +49,10 @@ HostDispatcher::HostDispatcher(base::ProcessHandle remote_process_handle, : Dispatcher(remote_process_handle, local_get_interface), pp_module_(module), ppb_proxy_(NULL) { + if (!g_module_to_dispatcher) + g_module_to_dispatcher = new ModuleToDispatcherMap; + (*g_module_to_dispatcher)[pp_module_] = this; + const PPB_Var_Deprecated* var_interface = static_cast<const PPB_Var_Deprecated*>( local_get_interface(PPB_VAR_DEPRECATED_INTERFACE)); @@ -35,9 +60,16 @@ HostDispatcher::HostDispatcher(base::ProcessHandle remote_process_handle, memset(plugin_interface_support_, 0, sizeof(PluginInterfaceSupport) * INTERFACE_ID_COUNT); + + ppb_proxy_ = reinterpret_cast<const PPB_Proxy_Private*>( + GetLocalInterface(PPB_PROXY_PRIVATE_INTERFACE)); + DCHECK(ppb_proxy_) << "The proxy interface should always be supported."; + + ppb_proxy_->SetReserveInstanceIDCallback(pp_module_, &ReserveInstanceID); } HostDispatcher::~HostDispatcher() { + g_module_to_dispatcher->erase(pp_module_); } // static @@ -104,7 +136,7 @@ void HostDispatcher::OnChannelError() { Dispatcher::OnChannelError(); // Stop using the channel. // Tell the host about the crash so it can clean up. - GetPPBProxy()->PluginCrashed(pp_module()); + ppb_proxy_->PluginCrashed(pp_module()); } const void* HostDispatcher::GetProxiedInterface(const std::string& interface) { @@ -152,14 +184,6 @@ InterfaceProxy* HostDispatcher::GetOrCreatePPBInterfaceProxy( return proxy; } -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_; -} - InterfaceProxy* HostDispatcher::CreatePPBInterfaceProxy( const InterfaceProxy::Info* info) { const void* local_interface = GetLocalInterface(info->name); diff --git a/ppapi/proxy/host_dispatcher.h b/ppapi/proxy/host_dispatcher.h index 35cdece..0fed9bd 100644 --- a/ppapi/proxy/host_dispatcher.h +++ b/ppapi/proxy/host_dispatcher.h @@ -79,7 +79,7 @@ class HostDispatcher : public Dispatcher { InterfaceProxy* GetOrCreatePPBInterfaceProxy(InterfaceID id); // Returns the proxy interface for talking to the implementation. - const PPB_Proxy_Private* GetPPBProxy(); + const PPB_Proxy_Private* ppb_proxy() const { return ppb_proxy_; } private: friend class HostDispatcherTest; @@ -101,7 +101,7 @@ 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(). + // Guaranteed non-NULL. 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 645f92f..793ccb8 100644 --- a/ppapi/proxy/plugin_dispatcher.cc +++ b/ppapi/proxy/plugin_dispatcher.cc @@ -12,6 +12,7 @@ #include "ipc/ipc_sync_channel.h" #include "ppapi/c/pp_errors.h" #include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_message_filter.h" #include "ppapi/proxy/plugin_var_serialization_rules.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/ppp_class_proxy.h" @@ -72,6 +73,20 @@ const void* PluginDispatcher::GetInterfaceFromDispatcher( return info->interface; } +bool PluginDispatcher::InitWithChannel( + Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client) { + if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client)) + return false; + + // The message filter will intercept and process certain messages directly + // on the I/O thread. + channel()->AddFilter( + new PluginMessageFilter(delegate->GetGloballySeenInstanceIDSet())); + return true; +} + bool PluginDispatcher::IsPlugin() const { return true; } diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h index 994edc0..8469ed7 100644 --- a/ppapi/proxy/plugin_dispatcher.h +++ b/ppapi/proxy/plugin_dispatcher.h @@ -49,6 +49,9 @@ class PluginDispatcher : public Dispatcher { static const void* GetInterfaceFromDispatcher(const char* interface); // Dispatcher overrides. + virtual bool InitWithChannel(Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client); virtual bool IsPlugin() const; // IPC::Channel::Listener implementation. diff --git a/ppapi/proxy/plugin_message_filter.cc b/ppapi/proxy/plugin_message_filter.cc new file mode 100644 index 0000000..9df2208 --- /dev/null +++ b/ppapi/proxy/plugin_message_filter.cc @@ -0,0 +1,61 @@ +// 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 "ppapi/proxy/plugin_message_filter.h" + +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +PluginMessageFilter::PluginMessageFilter( + std::set<PP_Instance>* seen_instance_ids) + : seen_instance_ids_(seen_instance_ids), + channel_(NULL) { +} + +PluginMessageFilter::~PluginMessageFilter() { +} + +void PluginMessageFilter::OnFilterAdded(IPC::Channel* channel) { + channel_ = channel; +} + +void PluginMessageFilter::OnFilterRemoved() { + channel_ = NULL; +} + +bool PluginMessageFilter::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PluginMessageFilter, message) + IPC_MESSAGE_HANDLER(PpapiMsg_ReserveInstanceId, OnMsgReserveInstanceId) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +bool PluginMessageFilter::Send(IPC::Message* msg) { + if (channel_) + return channel_->Send(msg); + delete msg; + return false; +} + +void PluginMessageFilter::OnMsgReserveInstanceId(PP_Instance instance, + bool* usable) { + // See the message definition for how this works. + if (seen_instance_ids_->find(instance) != seen_instance_ids_->end()) { + // Instance ID already seen, reject it. + *usable = false; + return; + } + + // This instance ID is new so we can return that it's usable and mark it as + // used for future reference. + seen_instance_ids_->insert(instance); + *usable = true; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/plugin_message_filter.h b/ppapi/proxy/plugin_message_filter.h new file mode 100644 index 0000000..fa3b2f4 --- /dev/null +++ b/ppapi/proxy/plugin_message_filter.h @@ -0,0 +1,56 @@ +// 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_PROXY_PLUGIN_MESSAGE_FILTER_H_ +#define PPAPI_PROXY_PLUGIN_MESSAGE_FILTER_H_ + +#include <set> + +#include "ipc/ipc_channel_proxy.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_instance.h" + +namespace pp { +namespace proxy { + +// Listens for messages on the I/O thread of the plugin and handles some of +// them to avoid needing to block on the plugin. +// +// There is one instance of this class for each renderer channel (same as for +// the PluginDispatchers). +class PluginMessageFilter : public IPC::ChannelProxy::MessageFilter, + public IPC::Message::Sender { + public: + // The input is a pointer to a set that will be used to uniquify PP_Instances + // across all renderer channels. The same pointer should be passed to each + // MessageFilter to ensure uniqueness, and the value should outlive this + // class. + PluginMessageFilter(std::set<PP_Instance>* seen_instance_ids); + virtual ~PluginMessageFilter(); + + // MessageFilter implementation. + virtual void OnFilterAdded(IPC::Channel* channel); + virtual void OnFilterRemoved(); + virtual bool OnMessageReceived(const IPC::Message& message); + + // Message::Sender implementation. + virtual bool Send(IPC::Message* msg); + + private: + void OnMsgReserveInstanceId(PP_Instance instance, bool* usable); + + // All instance IDs every queried by any renderer on this plugin. This is + // used to make sure that new instance IDs are unique. This is a non-owning + // pointer, it will be managed by the later that creates this class. + std::set<PP_Instance>* seen_instance_ids_; + + // The IPC channel to the renderer. May be NULL if we're not currently + // attached as a filter. + IPC::Channel* channel_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PLUGIN_MESSAGE_FILTER_H_ diff --git a/ppapi/proxy/ppapi_messages_internal.h b/ppapi/proxy/ppapi_messages_internal.h index e37f65b..375e7d5 100644 --- a/ppapi/proxy/ppapi_messages_internal.h +++ b/ppapi/proxy/ppapi_messages_internal.h @@ -20,6 +20,24 @@ IPC_MESSAGE_CONTROL2(PpapiMsg_CreateChannel, base::ProcessHandle /* host_process_handle */, int /* renderer_id */); +// Each plugin may be referenced by multiple renderers. We need the instance +// IDs to be unique within a plugin, despite coming from different renderers, +// and unique within a renderer, despite going to different plugins. This means +// that neither the renderer nor the plugin can generate instance IDs without +// consulting the other. +// +// We resolve this by having the renderer generate a unique instance ID inside +// its process. It then asks the plugin to reserve that ID by sending this sync +// message. If the plugin has not yet seen this ID, it will remember it as used +// (to prevent a race condition if another renderer tries to then use the same +// instance), and set usable as true. +// +// If the plugin has already seen the instance ID, it will set usable as false +// and the renderer must retry a new instance ID. +IPC_SYNC_MESSAGE_CONTROL1_1(PpapiMsg_ReserveInstanceId, + PP_Instance /* instance */, + bool /* usable */) + // Sent in both directions to see if the other side supports the given // interface. IPC_SYNC_MESSAGE_CONTROL1_1(PpapiMsg_SupportsInterface, diff --git a/ppapi/proxy/ppb_file_ref_proxy.cc b/ppapi/proxy/ppb_file_ref_proxy.cc index 3777ee3..ddf29e4 100644 --- a/ppapi/proxy/ppb_file_ref_proxy.cc +++ b/ppapi/proxy/ppb_file_ref_proxy.cc @@ -259,7 +259,7 @@ void PPB_FileRef_Proxy::SerializeFileRef(PP_Resource file_ref, } HostDispatcher* host_dispatcher = static_cast<HostDispatcher*>(dispatcher()); PP_Instance instance = - host_dispatcher->GetPPBProxy()->GetInstanceForResource(file_ref); + host_dispatcher->ppb_proxy()->GetInstanceForResource(file_ref); result->resource.SetHostResource(instance, file_ref); result->file_system_type = diff --git a/webkit/plugins/ppapi/plugin_module.cc b/webkit/plugins/ppapi/plugin_module.cc index 6c670f9..0ea2859 100644 --- a/webkit/plugins/ppapi/plugin_module.cc +++ b/webkit/plugins/ppapi/plugin_module.cc @@ -382,7 +382,8 @@ PluginModule::PluginModule(const std::string& name, callback_tracker_(new CallbackTracker), is_crashed_(false), library_(NULL), - name_(name) { + name_(name), + reserve_instance_id_(NULL) { pp_module_ = ResourceTracker::Get()->AddModule(this); GetMainThreadMessageLoop(); // Initialize the main thread message loop. GetLivePluginSet()->insert(this); @@ -505,6 +506,18 @@ void PluginModule::PluginCrashed() { lifetime_delegate_->PluginModuleDead(this); } +void PluginModule::SetReserveInstanceIDCallback( + PP_Bool (*reserve)(PP_Module, PP_Instance)) { + DCHECK(!reserve_instance_id_) << "Only expect one set."; + reserve_instance_id_ = reserve; +} + +bool PluginModule::ReserveInstanceID(PP_Instance instance) { + if (reserve_instance_id_) + return PPBoolToBool(reserve_instance_id_(pp_module_, instance)); + return true; // Instance ID is usable. +} + 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 39aa878..45545c9 100644 --- a/webkit/plugins/ppapi/plugin_module.h +++ b/webkit/plugins/ppapi/plugin_module.h @@ -15,6 +15,8 @@ #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/weak_ptr.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_module.h" #include "ppapi/c/ppb.h" #include "webkit/plugins/ppapi/plugin_delegate.h" @@ -126,6 +128,18 @@ class PluginModule : public base::RefCounted<PluginModule>, // release relevant resources and update all affected instances. void PluginCrashed(); + // Reserves the given instance is unique within the plugin, checking for + // collisions. See PPB_Proxy_Private for more information. + // + // The setter will set the callback which is set up when the proxy + // initializes. The Reserve function will call the previously set callback if + // it exists to validate the ID. If the callback has not been set (such as + // for in-process plugins), the Reserve function will assume that the ID is + // usable and will return true. + void SetReserveInstanceIDCallback( + PP_Bool (*reserve)(PP_Module, PP_Instance)); + bool ReserveInstanceID(PP_Instance instance); + private: // Calls the InitializeModule entrypoint. The entrypoint must have been // set and the plugin must not be out of process (we don't maintain @@ -167,6 +181,8 @@ class PluginModule : public base::RefCounted<PluginModule>, typedef std::set<PluginInstance*> PluginInstanceSet; PluginInstanceSet instances_; + PP_Bool (*reserve_instance_id_)(PP_Module, PP_Instance); + DISALLOW_COPY_AND_ASSIGN(PluginModule); }; diff --git a/webkit/plugins/ppapi/ppb_proxy_impl.cc b/webkit/plugins/ppapi/ppb_proxy_impl.cc index 540835e..f82ec46 100644 --- a/webkit/plugins/ppapi/ppb_proxy_impl.cc +++ b/webkit/plugins/ppapi/ppb_proxy_impl.cc @@ -28,9 +28,17 @@ PP_Instance GetInstanceForResource(PP_Resource resource) { return obj->instance()->pp_instance(); } +void SetReserveInstanceIDCallback(PP_Module module, + PP_Bool (*reserve)(PP_Module, PP_Instance)) { + PluginModule* plugin_module = ResourceTracker::Get()->GetModule(module); + if (plugin_module) + plugin_module->SetReserveInstanceIDCallback(reserve); +} + const PPB_Proxy_Private ppb_proxy = { &PluginCrashed, - &GetInstanceForResource + &GetInstanceForResource, + &SetReserveInstanceIDCallback }; } // namespace diff --git a/webkit/plugins/ppapi/resource_tracker.cc b/webkit/plugins/ppapi/resource_tracker.cc index b17210c..79a0125 100644 --- a/webkit/plugins/ppapi/resource_tracker.cc +++ b/webkit/plugins/ppapi/resource_tracker.cc @@ -12,6 +12,7 @@ #include "base/rand_util.h" #include "ppapi/c/pp_resource.h" #include "ppapi/c/pp_var.h" +#include "webkit/plugins/ppapi/plugin_module.h" #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" #include "webkit/plugins/ppapi/resource.h" #include "webkit/plugins/ppapi/var.h" @@ -279,7 +280,8 @@ PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) { new_instance = MakeTypedId(static_cast<PP_Instance>(base::RandUint64()), PP_ID_TYPE_INSTANCE); } while (!new_instance || - instance_map_.find(new_instance) != instance_map_.end()); + instance_map_.find(new_instance) != instance_map_.end() || + !instance->module()->ReserveInstanceID(new_instance)); instance_map_[new_instance].instance = instance; return new_instance; |