summaryrefslogtreecommitdiffstats
path: root/ppapi
diff options
context:
space:
mode:
Diffstat (limited to 'ppapi')
-rw-r--r--ppapi/c/private/ppb_proxy_private.h16
-rw-r--r--ppapi/ppapi_shared_proxy.gypi2
-rw-r--r--ppapi/proxy/dispatcher.cc11
-rw-r--r--ppapi/proxy/dispatcher.h33
-rw-r--r--ppapi/proxy/host_dispatcher.cc42
-rw-r--r--ppapi/proxy/host_dispatcher.h4
-rw-r--r--ppapi/proxy/plugin_dispatcher.cc15
-rw-r--r--ppapi/proxy/plugin_dispatcher.h3
-rw-r--r--ppapi/proxy/plugin_message_filter.cc61
-rw-r--r--ppapi/proxy/plugin_message_filter.h56
-rw-r--r--ppapi/proxy/ppapi_messages_internal.h18
-rw-r--r--ppapi/proxy/ppb_file_ref_proxy.cc2
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 =