summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/common/DEPS1
-rw-r--r--chrome/common/pepper_plugin_registry.cc17
-rw-r--r--chrome/common/pepper_plugin_registry.h9
-rw-r--r--chrome/ppapi_plugin/ppapi_thread.cc17
-rw-r--r--chrome/ppapi_plugin/ppapi_thread.h11
-rw-r--r--chrome/renderer/pepper_plugin_delegate_impl.cc5
-rw-r--r--content/common/child_process.h6
-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
-rw-r--r--webkit/plugins/ppapi/plugin_module.cc15
-rw-r--r--webkit/plugins/ppapi/plugin_module.h16
-rw-r--r--webkit/plugins/ppapi/ppb_proxy_impl.cc10
-rw-r--r--webkit/plugins/ppapi/resource_tracker.cc4
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;