diff options
Diffstat (limited to 'ppapi')
-rw-r--r-- | ppapi/c/private/ppb_proxy_private.h | 16 | ||||
-rw-r--r-- | ppapi/ppapi_shared_proxy.gypi | 2 | ||||
-rw-r--r-- | ppapi/proxy/dispatcher.cc | 11 | ||||
-rw-r--r-- | ppapi/proxy/dispatcher.h | 33 | ||||
-rw-r--r-- | ppapi/proxy/host_dispatcher.cc | 42 | ||||
-rw-r--r-- | ppapi/proxy/host_dispatcher.h | 4 | ||||
-rw-r--r-- | ppapi/proxy/plugin_dispatcher.cc | 15 | ||||
-rw-r--r-- | ppapi/proxy/plugin_dispatcher.h | 3 | ||||
-rw-r--r-- | ppapi/proxy/plugin_message_filter.cc | 61 | ||||
-rw-r--r-- | ppapi/proxy/plugin_message_filter.h | 56 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_messages_internal.h | 18 | ||||
-rw-r--r-- | ppapi/proxy/ppb_file_ref_proxy.cc | 2 |
12 files changed, 241 insertions, 22 deletions
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 = |