diff options
author | ddorwin@chromium.org <ddorwin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-16 22:12:45 +0000 |
---|---|---|
committer | ddorwin@chromium.org <ddorwin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-16 22:12:45 +0000 |
commit | e2614c60e3bab6cc1b949ecd8101189d285da17f (patch) | |
tree | f664f4e27974b7dee547aba035abef48e27c167c | |
parent | 64a2958841eb968837a90c9a738d9b68e33abb70 (diff) | |
download | chromium_src-e2614c60e3bab6cc1b949ecd8101189d285da17f.zip chromium_src-e2614c60e3bab6cc1b949ecd8101189d285da17f.tar.gz chromium_src-e2614c60e3bab6cc1b949ecd8101189d285da17f.tar.bz2 |
Refactored ppapi Dispatcher to share common code between the plugin and broker dispatchers.
Common code is in DispatcherBase. The base of the dispatcher for plugins remains Dispatcher. The base of the dispatcher for Brokers is BrokerDispatcher.
BUG=none
TEST=ppapi out-of-process plugins
Review URL: http://codereview.chromium.org/6859003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81883 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | content/content_ppapi_plugin.gypi | 2 | ||||
-rw-r--r-- | content/ppapi_plugin/broker_process_dispatcher.cc | 38 | ||||
-rw-r--r-- | content/ppapi_plugin/broker_process_dispatcher.h | 24 | ||||
-rw-r--r-- | content/ppapi_plugin/ppapi_thread.cc | 34 | ||||
-rw-r--r-- | content/ppapi_plugin/ppapi_thread.h | 6 | ||||
-rw-r--r-- | content/renderer/pepper_plugin_delegate_impl.cc | 4 | ||||
-rw-r--r-- | ppapi/ppapi_shared_proxy.gypi | 4 | ||||
-rw-r--r-- | ppapi/proxy/broker_dispatcher.cc | 45 | ||||
-rw-r--r-- | ppapi/proxy/broker_dispatcher.h | 45 | ||||
-rw-r--r-- | ppapi/proxy/dispatcher.cc | 71 | ||||
-rw-r--r-- | ppapi/proxy/dispatcher.h | 82 | ||||
-rw-r--r-- | ppapi/proxy/host_dispatcher.cc | 7 | ||||
-rw-r--r-- | ppapi/proxy/host_dispatcher.h | 9 | ||||
-rw-r--r-- | ppapi/proxy/plugin_dispatcher.cc | 11 | ||||
-rw-r--r-- | ppapi/proxy/plugin_dispatcher.h | 16 | ||||
-rw-r--r-- | ppapi/proxy/proxy_channel.cc | 88 | ||||
-rw-r--r-- | ppapi/proxy/proxy_channel.h | 111 |
17 files changed, 415 insertions, 182 deletions
diff --git a/content/content_ppapi_plugin.gypi b/content/content_ppapi_plugin.gypi index c586705..e62050b 100644 --- a/content/content_ppapi_plugin.gypi +++ b/content/content_ppapi_plugin.gypi @@ -12,6 +12,8 @@ '../ppapi/ppapi.gyp:ppapi_proxy', ], 'sources': [ + 'ppapi_plugin/broker_process_dispatcher.cc', + 'ppapi_plugin/broker_process_dispatcher.h', 'ppapi_plugin/plugin_process_dispatcher.cc', 'ppapi_plugin/plugin_process_dispatcher.h', 'ppapi_plugin/ppapi_broker_main.cc', diff --git a/content/ppapi_plugin/broker_process_dispatcher.cc b/content/ppapi_plugin/broker_process_dispatcher.cc new file mode 100644 index 0000000..68e56e7 --- /dev/null +++ b/content/ppapi_plugin/broker_process_dispatcher.cc @@ -0,0 +1,38 @@ +// 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 "content/ppapi_plugin/broker_process_dispatcher.h" + +#include "content/common/child_process.h" + +namespace { + +class PluginReleaseTask : public Task { + public: + void Run() { + ChildProcess::current()->ReleaseProcess(); + } +}; + +// How long we wait before releasing the plugin process. +const int kPluginReleaseTimeMs = 30 * 1000; // 30 seconds. + +} // namespace + +BrokerProcessDispatcher::BrokerProcessDispatcher( + base::ProcessHandle remote_process_handle, + PP_ConnectInstance_Func connect_instance) + : pp::proxy::BrokerDispatcher(remote_process_handle, connect_instance) { + ChildProcess::current()->AddRefProcess(); +} + +BrokerProcessDispatcher::~BrokerProcessDispatcher() { + // Don't free the process right away. This timer allows the child process + // to be re-used if the user rapidly goes to a new page that requires this + // plugin. This is the case for common plugins where they may be used on a + // source and destination page of a navigation. We don't want to tear down + // and re-start processes each time in these cases. + MessageLoop::current()->PostDelayedTask(FROM_HERE, new PluginReleaseTask(), + kPluginReleaseTimeMs); +} diff --git a/content/ppapi_plugin/broker_process_dispatcher.h b/content/ppapi_plugin/broker_process_dispatcher.h new file mode 100644 index 0000000..e5086fd --- /dev/null +++ b/content/ppapi_plugin/broker_process_dispatcher.h @@ -0,0 +1,24 @@ +// 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 CONTENT_PPAPI_PLUGIN_BROKER_PROCESS_DISPATCHER_H_ +#define CONTENT_PPAPI_PLUGIN_BROKER_PROCESS_DISPATCHER_H_ + +#include "base/basictypes.h" +#include "ppapi/proxy/broker_dispatcher.h" + +// Wrapper around a BrokerDispatcher that provides the necessary integration +// for plugin process management. This class is to avoid direct dependencies +// from the PPAPI proxy on the Chrome multiprocess infrastructure. +class BrokerProcessDispatcher : public pp::proxy::BrokerDispatcher { + public: + BrokerProcessDispatcher(base::ProcessHandle remote_process_handle, + PP_ConnectInstance_Func connect_instance); + virtual ~BrokerProcessDispatcher(); + + private: + DISALLOW_COPY_AND_ASSIGN(BrokerProcessDispatcher); +}; + +#endif // CONTENT_PPAPI_PLUGIN_BROKER_PROCESS_DISPATCHER_H_ diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc index cab4d93..54215a2 100644 --- a/content/ppapi_plugin/ppapi_thread.cc +++ b/content/ppapi_plugin/ppapi_thread.cc @@ -9,6 +9,7 @@ #include "base/process_util.h" #include "base/rand_util.h" #include "content/common/child_process.h" +#include "content/ppapi_plugin/broker_process_dispatcher.h" #include "content/ppapi_plugin/plugin_process_dispatcher.h" #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_sync_channel.h" @@ -32,11 +33,11 @@ PpapiThread::~PpapiThread() { return; // The ShutdownModule/ShutdownBroker function is optional. - pp::proxy::Dispatcher::ShutdownModuleFunc shutdown_function = + pp::proxy::ProxyChannel::ShutdownModuleFunc shutdown_function = is_broker_ ? - reinterpret_cast<pp::proxy::Dispatcher::ShutdownModuleFunc>( + reinterpret_cast<pp::proxy::ProxyChannel::ShutdownModuleFunc>( library_.GetFunctionPointer("PPP_ShutdownBroker")) : - reinterpret_cast<pp::proxy::Dispatcher::ShutdownModuleFunc>( + reinterpret_cast<pp::proxy::ProxyChannel::ShutdownModuleFunc>( library_.GetFunctionPointer("PPP_ShutdownModule")); if (shutdown_function) shutdown_function(); @@ -139,18 +140,31 @@ void PpapiThread::OnMsgCreateChannel(base::ProcessHandle host_process_handle, bool PpapiThread::SetupRendererChannel(base::ProcessHandle host_process_handle, int renderer_id, IPC::ChannelHandle* handle) { - // TODO(ddorwin): PluginProcessDispatcher is overkill for the broker. TBD - // whether to create separate dispatcher classes for the broker. - // TODO(ddorwin): Provide connect_instance_func_ when is_broker_. DCHECK(is_broker_ == (connect_instance_func_ != NULL)); DCHECK(is_broker_ == (get_plugin_interface_ == NULL)); - PluginProcessDispatcher* dispatcher(new PluginProcessDispatcher( - host_process_handle, get_plugin_interface_)); - IPC::ChannelHandle plugin_handle; plugin_handle.name = StringPrintf("%d.r%d", base::GetCurrentProcId(), renderer_id); - if (!dispatcher->InitWithChannel(this, plugin_handle, false)) { + + pp::proxy::ProxyChannel* dispatcher = NULL; + bool init_result = false; + if (is_broker_) { + BrokerProcessDispatcher* broker_dispatcher = + new BrokerProcessDispatcher(host_process_handle, connect_instance_func_); + init_result = broker_dispatcher->InitBrokerWithChannel(this, + plugin_handle, + false); + dispatcher = broker_dispatcher; + } else { + PluginProcessDispatcher* plugin_dispatcher = + new PluginProcessDispatcher(host_process_handle, get_plugin_interface_); + init_result = plugin_dispatcher->InitPluginWithChannel(this, + plugin_handle, + false); + dispatcher = plugin_dispatcher; + } + + if (!init_result) { delete dispatcher; return false; } diff --git a/content/ppapi_plugin/ppapi_thread.h b/content/ppapi_plugin/ppapi_thread.h index 95cd7dc..ea8593c 100644 --- a/content/ppapi_plugin/ppapi_thread.h +++ b/content/ppapi_plugin/ppapi_thread.h @@ -22,12 +22,6 @@ namespace IPC { struct ChannelHandle; } -namespace pp { -namespace proxy { -class PluginDispatcher; -} -} - class PpapiThread : public ChildThread, public pp::proxy::Dispatcher::Delegate { public: diff --git a/content/renderer/pepper_plugin_delegate_impl.cc b/content/renderer/pepper_plugin_delegate_impl.cc index e63dd01..95d24db 100644 --- a/content/renderer/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper_plugin_delegate_impl.cc @@ -318,8 +318,8 @@ bool DispatcherWrapper::Init( dispatcher_.reset(new pp::proxy::HostDispatcher( plugin_process_handle, pp_module, local_get_interface)); - if (!dispatcher_->InitWithChannel(PepperPluginRegistry::GetInstance(), - channel_handle, true)) { + if (!dispatcher_->InitHostWithChannel(PepperPluginRegistry::GetInstance(), + channel_handle, true)) { dispatcher_.reset(); return false; } diff --git a/ppapi/ppapi_shared_proxy.gypi b/ppapi/ppapi_shared_proxy.gypi index bdc1d6b..1ddb78e 100644 --- a/ppapi/ppapi_shared_proxy.gypi +++ b/ppapi/ppapi_shared_proxy.gypi @@ -54,6 +54,8 @@ 'sources': [ 'proxy/callback_tracker.cc', 'proxy/callback_tracker.h', + 'proxy/broker_dispatcher.cc', + 'proxy/broker_dispatcher.h', 'proxy/dispatcher.cc', 'proxy/dispatcher.h', 'proxy/host_dispatcher.cc', @@ -147,6 +149,8 @@ 'proxy/ppp_graphics_3d_proxy.h', 'proxy/ppp_instance_proxy.cc', 'proxy/ppp_instance_proxy.h', + 'proxy/proxy_channel.cc', + 'proxy/proxy_channel.h', 'proxy/serialized_flash_menu.cc', 'proxy/serialized_flash_menu.h', 'proxy/serialized_structs.cc', diff --git a/ppapi/proxy/broker_dispatcher.cc b/ppapi/proxy/broker_dispatcher.cc new file mode 100644 index 0000000..f72f37a --- /dev/null +++ b/ppapi/proxy/broker_dispatcher.cc @@ -0,0 +1,45 @@ +// 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/broker_dispatcher.h" + +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +BrokerDispatcher::BrokerDispatcher(base::ProcessHandle remote_process_handle, + PP_ConnectInstance_Func connect_instance) + : ProxyChannel(remote_process_handle) { + // TODO(ddorwin): Do something with connect_instance. +} + +BrokerDispatcher::~BrokerDispatcher() { +} + +bool BrokerDispatcher::InitBrokerWithChannel( + ProxyChannel::Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client) { + return ProxyChannel::InitWithChannel(delegate, channel_handle, is_client); +} + +bool BrokerDispatcher::OnMessageReceived(const IPC::Message& msg) { + // Control messages. + if (msg.routing_id() == MSG_ROUTING_CONTROL) { + bool handled = true; + // TODO(ddorwin): Implement. Don't build empty block - fails on Windows. +#if 0 + IPC_BEGIN_MESSAGE_MAP(BrokerDispatcher, msg) + // IPC_MESSAGE_FORWARD(PpapiMsg_ConnectToInstance) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() +#endif + return handled; + } + return false; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/broker_dispatcher.h b/ppapi/proxy/broker_dispatcher.h new file mode 100644 index 0000000..6b0673b --- /dev/null +++ b/ppapi/proxy/broker_dispatcher.h @@ -0,0 +1,45 @@ +// 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_BROKER_DISPATCHER_H_ +#define PPAPI_PROXY_BROKER_DISPATCHER_H_ + +#include "ppapi/c/trusted/ppp_broker.h" +#include "ppapi/proxy/proxy_channel.h" + +namespace pp { +namespace proxy { + +class BrokerDispatcher : public ProxyChannel { + public: + virtual ~BrokerDispatcher(); + + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + virtual bool InitBrokerWithChannel(ProxyChannel::Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client); + + // Returns true if the dispatcher is on the broker side, or false if it's the + // browser side. + // TODO(ddorwin): Implement. + // virtual bool IsBroker() const = 0; + + // IPC::Channel::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + protected: + // You must call InitBrokerWithChannel after the constructor. + BrokerDispatcher(base::ProcessHandle remote_process_handle, + PP_ConnectInstance_Func connect_instance); + + private: + DISALLOW_COPY_AND_ASSIGN(BrokerDispatcher); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_BROKER_DISPATCHER_H_ diff --git a/ppapi/proxy/dispatcher.cc b/ppapi/proxy/dispatcher.cc index a4d9798..36f8f0a 100644 --- a/ppapi/proxy/dispatcher.cc +++ b/ppapi/proxy/dispatcher.cc @@ -11,9 +11,6 @@ #include "base/compiler_specific.h" #include "base/logging.h" #include "base/memory/singleton.h" -#include "ipc/ipc_message.h" -#include "ipc/ipc_sync_channel.h" -#include "ipc/ipc_test_sink.h" #include "ppapi/c/dev/ppb_buffer_dev.h" #include "ppapi/c/dev/ppb_char_set_dev.h" #include "ppapi/c/dev/ppb_context_3d_dev.h" @@ -178,9 +175,7 @@ InterfaceList* InterfaceList::GetInstance() { Dispatcher::Dispatcher(base::ProcessHandle remote_process_handle, GetInterfaceFunc local_get_interface) - : delegate_(NULL), - remote_process_handle_(remote_process_handle), - test_sink_(NULL), + : ProxyChannel(remote_process_handle), disallow_trusted_interfaces_(false), // TODO(brettw) make this settable. local_get_interface_(local_get_interface), callback_tracker_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { @@ -189,23 +184,6 @@ Dispatcher::Dispatcher(base::ProcessHandle remote_process_handle, Dispatcher::~Dispatcher() { } -bool Dispatcher::InitWithChannel(Delegate* delegate, - const IPC::ChannelHandle& channel_handle, - bool is_client) { - delegate_ = delegate; - IPC::Channel::Mode mode = is_client ? IPC::Channel::MODE_CLIENT - : IPC::Channel::MODE_SERVER; - channel_.reset(new IPC::SyncChannel(channel_handle, mode, this, - delegate->GetIPCMessageLoop(), false, - delegate->GetShutdownEvent())); - return true; -} - -void Dispatcher::InitWithTestSink(IPC::TestSink* test_sink) { - DCHECK(!test_sink_); - test_sink_ = test_sink; -} - bool Dispatcher::OnMessageReceived(const IPC::Message& msg) { // Control messages. if (msg.routing_id() == MSG_ROUTING_CONTROL) { @@ -220,10 +198,6 @@ bool Dispatcher::OnMessageReceived(const IPC::Message& msg) { return false; } -void Dispatcher::OnChannelError() { - channel_.reset(); -} - // static const InterfaceProxy::Info* Dispatcher::GetPPBInterfaceInfo( const std::string& name) { @@ -271,53 +245,14 @@ const void* Dispatcher::GetLocalInterface(const char* interface_name) { return local_get_interface_(interface_name); } -IPC::PlatformFileForTransit Dispatcher::ShareHandleWithRemote( - base::PlatformFile handle, - bool should_close_source) { - IPC::PlatformFileForTransit out_handle; -#if defined(OS_WIN) - DWORD options = DUPLICATE_SAME_ACCESS; - if (should_close_source) - options |= DUPLICATE_CLOSE_SOURCE; - if (!::DuplicateHandle(::GetCurrentProcess(), - handle, - remote_process_handle_, - &out_handle, - 0, - FALSE, - options)) - out_handle = IPC::InvalidPlatformFileForTransit(); -#elif defined(OS_POSIX) - // If asked to close the source, we can simply re-use the source fd instead of - // dup()ing and close()ing. - int fd = should_close_source ? handle : ::dup(handle); - out_handle = base::FileDescriptor(fd, true); -#else - #error Not implemented. -#endif - return out_handle; -} - MessageLoop* Dispatcher::GetIPCMessageLoop() { - return delegate_->GetIPCMessageLoop(); + return delegate()->GetIPCMessageLoop(); } void Dispatcher::AddIOThreadMessageFilter( IPC::ChannelProxy::MessageFilter* filter) { - channel_->AddFilter(filter); -} - -bool Dispatcher::Send(IPC::Message* msg) { - if (test_sink_) - return test_sink_->Send(msg); - if (channel_.get()) - return channel_->Send(msg); - - // Remote side crashed, drop this message. - delete msg; - return false; + channel()->AddFilter(filter); } } // namespace proxy } // namespace pp - diff --git a/ppapi/proxy/dispatcher.h b/ppapi/proxy/dispatcher.h index 5e6ea28..2d900b1 100644 --- a/ppapi/proxy/dispatcher.h +++ b/ppapi/proxy/dispatcher.h @@ -5,38 +5,19 @@ #ifndef PPAPI_PROXY_DISPATCHER_H_ #define PPAPI_PROXY_DISPATCHER_H_ -#include <map> #include <set> #include <string> #include <vector> -#include "base/memory/linked_ptr.h" -#include "base/memory/scoped_ptr.h" -#include "base/process.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_channel_handle.h" #include "ipc/ipc_channel_proxy.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/proxy_channel.h" #include "ppapi/proxy/interface_id.h" #include "ppapi/proxy/interface_proxy.h" #include "ppapi/proxy/plugin_var_tracker.h" -class MessageLoop; -struct PPB_Var_Deprecated; - -namespace base { -class WaitableEvent; -} - -namespace IPC { -class SyncChannel; -class TestSink; -} - namespace pp { namespace proxy { @@ -56,22 +37,13 @@ class VarSerializationRules; // "Target" | "Source" // InterfaceProxy <---------------------- InterfaceProxy // | -class Dispatcher : public IPC::Channel::Listener, - public IPC::Message::Sender { +class Dispatcher : public ProxyChannel { public: typedef const void* (*GetInterfaceFunc)(const char*); typedef int32_t (*InitModuleFunc)(PP_Module, GetInterfaceFunc); - typedef void (*ShutdownModuleFunc)(); - class Delegate { + class Delegate : public ProxyChannel::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. @@ -82,18 +54,6 @@ class Dispatcher : public IPC::Channel::Listener, virtual ~Dispatcher(); - // You must call this function before anything else. Returns true on success. - // 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 - // must outlive this class. - void InitWithTestSink(IPC::TestSink* test_sink); - // Returns true if the dispatcher is on the plugin side, or false if it's the // browser side. virtual bool IsPlugin() const = 0; @@ -105,16 +65,6 @@ class Dispatcher : public IPC::Channel::Listener, // Wrapper for calling the local GetInterface function. const void* GetLocalInterface(const char* interface_name); - // Shares a file handle (HANDLE / file descriptor) with the remote side. It - // returns a handle that should be sent in exactly one IPC message. Upon - // receipt, the remote side then owns that handle. Note: if sending the - // message fails, the returned handle is properly closed by the IPC system. If - // should_close_source is set to true, the original handle is closed by this - // operation and should not be used again. - IPC::PlatformFileForTransit ShareHandleWithRemote( - base::PlatformFile handle, - bool should_close_source); - // Returns the pointer to the IO thread for processing IPC messages. // TODO(brettw) remove this. It's a hack to support the Flash // ModuleLocalThreadAdapter. When the thread stuff is sorted out, this @@ -127,21 +77,13 @@ class Dispatcher : public IPC::Channel::Listener, // implementation detail should be hidden. void AddIOThreadMessageFilter(IPC::ChannelProxy::MessageFilter* filter); + // TODO(brettw): What is this comment referring to? // Called if the remote side is declaring to us which interfaces it supports // so we don't have to query for each one. We'll pre-create proxies for // each of the given interfaces. - // IPC::Message::Sender implementation. - virtual bool Send(IPC::Message* msg); - // IPC::Channel::Listener implementation. virtual bool OnMessageReceived(const IPC::Message& msg); - virtual void OnChannelError(); - - // Will be NULL in some unit tests and if the remote side has crashed. - IPC::SyncChannel* channel() const { - return channel_.get(); - } CallbackTracker& callback_tracker() { return callback_tracker_; @@ -170,23 +112,7 @@ 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 - // be deposited so they can be inspected by the test. When non-NULL, this - // indicates that the channel should not be used. - IPC::TestSink* test_sink_; - - // Will be null for some tests when there is a test_sink_, and if the - // remote side has crashed. - scoped_ptr<IPC::SyncChannel> channel_; - bool disallow_trusted_interfaces_; GetInterfaceFunc local_get_interface_; diff --git a/ppapi/proxy/host_dispatcher.cc b/ppapi/proxy/host_dispatcher.cc index 1347e78..25e06fb 100644 --- a/ppapi/proxy/host_dispatcher.cc +++ b/ppapi/proxy/host_dispatcher.cc @@ -86,6 +86,13 @@ HostDispatcher::~HostDispatcher() { g_module_to_dispatcher->erase(pp_module_); } +bool HostDispatcher::InitHostWithChannel( + ProxyChannel::Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client) { + return Dispatcher::InitWithChannel(delegate, channel_handle, is_client); +} + // static HostDispatcher* HostDispatcher::GetForInstance(PP_Instance instance) { if (!g_instance_to_dispatcher) diff --git a/ppapi/proxy/host_dispatcher.h b/ppapi/proxy/host_dispatcher.h index 1662ea7..ea676d1 100644 --- a/ppapi/proxy/host_dispatcher.h +++ b/ppapi/proxy/host_dispatcher.h @@ -36,12 +36,19 @@ class HostDispatcher : public Dispatcher { public: // Constructor for the renderer side. // - // You must call Dispatcher::InitWithChannel after the constructor. + // You must call InitHostWithChannel after the constructor. HostDispatcher(base::ProcessHandle host_process_handle, PP_Module module, GetInterfaceFunc local_get_interface); ~HostDispatcher(); + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + virtual bool InitHostWithChannel(ProxyChannel::Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client); + // The host side maintains a mapping from PP_Instance to Dispatcher so // that we can send the messages to the right channel. static HostDispatcher* GetForInstance(PP_Instance instance); diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc index 37a59c26..6fb29bf 100644 --- a/ppapi/proxy/plugin_dispatcher.cc +++ b/ppapi/proxy/plugin_dispatcher.cc @@ -66,8 +66,8 @@ const void* PluginDispatcher::GetInterfaceFromDispatcher( return info->interface_ptr; } -bool PluginDispatcher::InitWithChannel( - Delegate* delegate, +bool PluginDispatcher::InitPluginWithChannel( + PluginDispatcher::Delegate* delegate, const IPC::ChannelHandle& channel_handle, bool is_client) { if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client)) @@ -188,13 +188,6 @@ InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) { return (it == instance_map_.end()) ? NULL : &it->second; } -#if defined(OS_POSIX) -int PluginDispatcher::GetRendererFD() { - DCHECK(channel()); - return channel()->GetClientFileDescriptor(); -} -#endif - void PluginDispatcher::ForceFreeAllInstances() { if (!g_instance_to_dispatcher) return; diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h index dbc13d2..efa0d70 100644 --- a/ppapi/proxy/plugin_dispatcher.h +++ b/ppapi/proxy/plugin_dispatcher.h @@ -35,7 +35,7 @@ class PluginDispatcher : public Dispatcher { // will be automatically called when requested by the renderer side. The // module ID will be set upon receipt of the InitializeModule message. // - // You must call Dispatcher::InitWithChannel after the constructor. + // You must call InitPluginWithChannel after the constructor. PluginDispatcher(base::ProcessHandle remote_process_handle, GetInterfaceFunc get_interface); virtual ~PluginDispatcher(); @@ -48,10 +48,14 @@ class PluginDispatcher : public Dispatcher { static const void* GetInterfaceFromDispatcher(const char* interface); + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + virtual bool InitPluginWithChannel(Dispatcher::Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client); + // Dispatcher overrides. - virtual bool InitWithChannel(Delegate* delegate, - const IPC::ChannelHandle& channel_handle, - bool is_client); virtual bool IsPlugin() const; virtual bool Send(IPC::Message* msg); @@ -68,10 +72,6 @@ class PluginDispatcher : public Dispatcher { // correspond to a known instance. InstanceData* GetInstanceData(PP_Instance instance); -#if defined(OS_POSIX) - int GetRendererFD(); -#endif - private: friend class PluginDispatcherTest; diff --git a/ppapi/proxy/proxy_channel.cc b/ppapi/proxy/proxy_channel.cc new file mode 100644 index 0000000..0bce041 --- /dev/null +++ b/ppapi/proxy/proxy_channel.cc @@ -0,0 +1,88 @@ +// 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/proxy_channel.h" + +#include "ipc/ipc_test_sink.h" + +namespace pp { +namespace proxy { + +ProxyChannel::ProxyChannel(base::ProcessHandle remote_process_handle) + : delegate_(NULL), + remote_process_handle_(remote_process_handle), + test_sink_(NULL) { +} + +ProxyChannel::~ProxyChannel() { +} + +bool ProxyChannel::InitWithChannel(Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client) { + delegate_ = delegate; + IPC::Channel::Mode mode = is_client ? IPC::Channel::MODE_CLIENT + : IPC::Channel::MODE_SERVER; + channel_.reset(new IPC::SyncChannel(channel_handle, mode, this, + delegate->GetIPCMessageLoop(), false, + delegate->GetShutdownEvent())); + return true; +} + +void ProxyChannel::InitWithTestSink(IPC::TestSink* test_sink) { + DCHECK(!test_sink_); + test_sink_ = test_sink; +} + +void ProxyChannel::OnChannelError() { + channel_.reset(); +} + +#if defined(OS_POSIX) +int ProxyChannel::GetRendererFD() { + DCHECK(channel()); + return channel()->GetClientFileDescriptor(); +} +#endif + +IPC::PlatformFileForTransit ProxyChannel::ShareHandleWithRemote( + base::PlatformFile handle, + bool should_close_source) { + IPC::PlatformFileForTransit out_handle; +#if defined(OS_WIN) + DWORD options = DUPLICATE_SAME_ACCESS; + if (should_close_source) + options |= DUPLICATE_CLOSE_SOURCE; + if (!::DuplicateHandle(::GetCurrentProcess(), + handle, + remote_process_handle_, + &out_handle, + 0, + FALSE, + options)) + out_handle = IPC::InvalidPlatformFileForTransit(); +#elif defined(OS_POSIX) + // If asked to close the source, we can simply re-use the source fd instead of + // dup()ing and close()ing. + int fd = should_close_source ? handle : ::dup(handle); + out_handle = base::FileDescriptor(fd, true); +#else + #error Not implemented. +#endif + return out_handle; +} + +bool ProxyChannel::Send(IPC::Message* msg) { + if (test_sink_) + return test_sink_->Send(msg); + if (channel_.get()) + return channel_->Send(msg); + + // Remote side crashed, drop this message. + delete msg; + return false; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/proxy_channel.h b/ppapi/proxy/proxy_channel.h new file mode 100644 index 0000000..91e98ac --- /dev/null +++ b/ppapi/proxy/proxy_channel.h @@ -0,0 +1,111 @@ +// 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_PROXY_CHANNEL_H_ +#define PPAPI_PROXY_PROXY_CHANNEL_H_ + +#include "base/memory/scoped_ptr.h" +#include "base/process.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_platform_file.h" +#include "ipc/ipc_sync_channel.h" + +class MessageLoop; + +namespace base { +class WaitableEvent; +} + +namespace IPC { +class TestSink; +} + +namespace pp { +namespace proxy { + +class VarSerializationRules; + +class ProxyChannel : public IPC::Channel::Listener, + public IPC::Message::Sender { + public: + 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; + }; + + virtual ~ProxyChannel(); + + // Alternative to InitWithChannel() for unit tests that want to send all + // messages sent via this dispatcher to the given test sink. The test sink + // must outlive this class. + void InitWithTestSink(IPC::TestSink* test_sink); + + // Shares a file handle (HANDLE / file descriptor) with the remote side. It + // returns a handle that should be sent in exactly one IPC message. Upon + // receipt, the remote side then owns that handle. Note: if sending the + // message fails, the returned handle is properly closed by the IPC system. If + // should_close_source is set to true, the original handle is closed by this + // operation and should not be used again. + IPC::PlatformFileForTransit ShareHandleWithRemote( + base::PlatformFile handle, + bool should_close_source); + + // IPC::Message::Sender implementation. + virtual bool Send(IPC::Message* msg); + + // IPC::Channel::Listener implementation. + virtual void OnChannelError(); + + // Will be NULL in some unit tests and if the remote side has crashed. + IPC::SyncChannel* channel() const { + return channel_.get(); + } + +#if defined(OS_POSIX) + int GetRendererFD(); +#endif + + protected: + ProxyChannel(base::ProcessHandle remote_process_handle); + + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + virtual bool InitWithChannel(Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client); + + ProxyChannel::Delegate* delegate() const { + return delegate_; + } + + private: + // Non-owning pointer. Guaranteed non-NULL after init is called. + ProxyChannel::Delegate* delegate_; + + base::ProcessHandle remote_process_handle_; // See getter above. + + // When we're unit testing, this will indicate the sink for the messages to + // be deposited so they can be inspected by the test. When non-NULL, this + // indicates that the channel should not be used. + IPC::TestSink* test_sink_; + + // Will be null for some tests when there is a test_sink_, and if the + // remote side has crashed. + scoped_ptr<IPC::SyncChannel> channel_; + + DISALLOW_COPY_AND_ASSIGN(ProxyChannel); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PROXY_CHANNEL_H_ |