diff options
24 files changed, 574 insertions, 42 deletions
diff --git a/chrome/browser/task_manager/task_manager_resource_providers.cc b/chrome/browser/task_manager/task_manager_resource_providers.cc index 19747c0..559e8d7 100644 --- a/chrome/browser/task_manager/task_manager_resource_providers.cc +++ b/chrome/browser/task_manager/task_manager_resource_providers.cc @@ -933,7 +933,8 @@ string16 TaskManagerChildProcessResource::GetLocalizedTitle() const { return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NACL_BROKER_PREFIX); case ChildProcessInfo::PLUGIN_PROCESS: - case ChildProcessInfo::PPAPI_PLUGIN_PROCESS: { + case ChildProcessInfo::PPAPI_PLUGIN_PROCESS: + case ChildProcessInfo::PPAPI_BROKER_PROCESS: { return l10n_util::GetStringFUTF16( IDS_TASK_MANAGER_PLUGIN_PREFIX, title, WideToUTF16Hack(child_process_.version())); diff --git a/content/browser/plugin_service.cc b/content/browser/plugin_service.cc index 409bd67..1a12a36 100644 --- a/content/browser/plugin_service.cc +++ b/content/browser/plugin_service.cc @@ -223,6 +223,22 @@ PpapiPluginProcessHost* PluginService::FindPpapiPluginProcess( return NULL; } +PpapiBrokerProcessHost* PluginService::FindPpapiBrokerProcess( + const FilePath& broker_path) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + for (BrowserChildProcessHost::Iterator iter( + ChildProcessInfo::PPAPI_BROKER_PROCESS); + !iter.Done(); ++iter) { + PpapiBrokerProcessHost* broker = + static_cast<PpapiBrokerProcessHost*>(*iter); + if (broker->broker_path() == broker_path) + return broker; + } + + return NULL; +} + PluginProcessHost* PluginService::FindOrStartNpapiPluginProcess( const FilePath& plugin_path) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); @@ -254,15 +270,8 @@ PpapiPluginProcessHost* PluginService::FindOrStartPpapiPluginProcess( if (plugin_host) return plugin_host; - // Validate that the plugin is actually registered. There should generally - // be very few plugins so a brute-force search is fine. - PepperPluginInfo* info = NULL; - for (size_t i = 0; i < ppapi_plugins_.size(); i++) { - if (ppapi_plugins_[i].path == plugin_path) { - info = &ppapi_plugins_[i]; - break; - } - } + // Validate that the plugin is actually registered. + PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path); if (!info) return NULL; @@ -275,6 +284,32 @@ PpapiPluginProcessHost* PluginService::FindOrStartPpapiPluginProcess( return new_host.release(); } +PpapiBrokerProcessHost* PluginService::FindOrStartPpapiBrokerProcess( + const FilePath& plugin_path) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + PpapiBrokerProcessHost* plugin_host = FindPpapiBrokerProcess(plugin_path); + if (plugin_host) + return plugin_host; + + // Validate that the plugin is actually registered. + PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path); + if (!info) + return NULL; + + // TODO(ddorwin): Uncomment once out of process is supported. + // DCHECK(info->is_out_of_process); + + // This broker isn't loaded by any broker process, so create a new process. + scoped_ptr<PpapiBrokerProcessHost> new_host( + new PpapiBrokerProcessHost); + if (!new_host->Init(*info)) { + NOTREACHED(); // Init is not expected to fail. + return NULL; + } + return new_host.release(); +} + void PluginService::OpenChannelToNpapiPlugin( int render_process_id, int render_view_id, @@ -300,6 +335,16 @@ void PluginService::OpenChannelToPpapiPlugin( client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle()); } +void PluginService::OpenChannelToPpapiBroker( + const FilePath& path, + PpapiBrokerProcessHost::Client* client) { + PpapiBrokerProcessHost* plugin_host = FindOrStartPpapiBrokerProcess(path); + if (plugin_host) + plugin_host->OpenChannelToPpapiBroker(client); + else // Send error. + client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle()); +} + void PluginService::GetAllowedPluginForOpenChannelToPlugin( int render_process_id, int render_view_id, @@ -503,6 +548,19 @@ void PluginService::RegisterPepperPlugins() { } } +// There should generally be very few plugins so a brute-force search is fine. +PepperPluginInfo* PluginService::GetRegisteredPpapiPluginInfo( + const FilePath& plugin_path) { + PepperPluginInfo* info = NULL; + for (size_t i = 0; i < ppapi_plugins_.size(); i++) { + if (ppapi_plugins_[i].path == plugin_path) { + info = &ppapi_plugins_[i]; + break; + } + } + return info; +} + #if defined(OS_LINUX) // static void PluginService::RegisterFilePathWatcher( diff --git a/content/browser/plugin_service.h b/content/browser/plugin_service.h index 4943d42..5c37c01 100644 --- a/content/browser/plugin_service.h +++ b/content/browser/plugin_service.h @@ -21,6 +21,7 @@ #include "build/build_config.h" #include "content/browser/plugin_process_host.h" #include "content/browser/ppapi_plugin_process_host.h" +#include "content/browser/ppapi_broker_process_host.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" #include "googleurl/src/gurl.h" @@ -84,6 +85,7 @@ class PluginService // started. PluginProcessHost* FindNpapiPluginProcess(const FilePath& plugin_path); PpapiPluginProcessHost* FindPpapiPluginProcess(const FilePath& plugin_path); + PpapiBrokerProcessHost* FindPpapiBrokerProcess(const FilePath& broker_path); // Returns the plugin process host corresponding to the plugin process that // has been started by this service. This will start a process to host the @@ -93,6 +95,8 @@ class PluginService const FilePath& plugin_path); PpapiPluginProcessHost* FindOrStartPpapiPluginProcess( const FilePath& plugin_path); + PpapiBrokerProcessHost* FindOrStartPpapiBrokerProcess( + const FilePath& plugin_path); // Opens a channel to a plugin process for the given mime type, starting // a new plugin process if necessary. This must be called on the IO thread @@ -104,6 +108,8 @@ class PluginService PluginProcessHost::Client* client); void OpenChannelToPpapiPlugin(const FilePath& path, PpapiPluginProcessHost::Client* client); + void OpenChannelToPpapiBroker(const FilePath& path, + PpapiBrokerProcessHost::Client* client); // Gets the first allowed plugin in the list of plugins that matches // the given url and mime type. Must be called on the FILE thread. @@ -152,6 +158,8 @@ class PluginService void RegisterPepperPlugins(); + PepperPluginInfo* GetRegisteredPpapiPluginInfo(const FilePath& plugin_path); + // Helper so we can do the plugin lookup on the FILE thread. void GetAllowedPluginForOpenChannelToPlugin( int render_process_id, diff --git a/content/browser/ppapi_broker_process_host.cc b/content/browser/ppapi_broker_process_host.cc new file mode 100644 index 0000000..78c8c9b --- /dev/null +++ b/content/browser/ppapi_broker_process_host.cc @@ -0,0 +1,179 @@ +// 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/browser/ppapi_broker_process_host.h" + +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/process_util.h" +#include "base/utf_string_conversions.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pepper_plugin_registry.h" +#include "chrome/common/render_messages.h" +#include "content/browser/plugin_service.h" +#include "content/browser/renderer_host/render_message_filter.h" +#include "ipc/ipc_switches.h" +#include "ppapi/proxy/ppapi_messages.h" + +PpapiBrokerProcessHost::PpapiBrokerProcessHost() + : BrowserChildProcessHost( + ChildProcessInfo::PPAPI_BROKER_PROCESS, NULL) { +} + +PpapiBrokerProcessHost::~PpapiBrokerProcessHost() { + CancelRequests(); +} + +bool PpapiBrokerProcessHost::Init(const PepperPluginInfo& info) { + broker_path_ = info.path; + set_name(UTF8ToWide(info.name)); + set_version(UTF8ToWide(info.version)); + + if (!CreateChannel()) + return false; + + const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); + // Use the same launcher mechanism as ppapi plugins. + CommandLine::StringType plugin_launcher = + browser_command_line.GetSwitchValueNative(switches::kPpapiPluginLauncher); + + FilePath exe_path = ChildProcessHost::GetChildPath(plugin_launcher.empty()); + if (exe_path.empty()) + return false; + + CommandLine* cmd_line = new CommandLine(exe_path); + cmd_line->AppendSwitchASCII(switches::kProcessType, + switches::kPpapiBrokerProcess); + cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); + + if (!plugin_launcher.empty()) + cmd_line->PrependWrapper(plugin_launcher); + + // On posix, having a plugin launcher means we need to use another process + // instead of just forking the zygote. + Launch( +#if defined(OS_WIN) + FilePath(), +#elif defined(OS_POSIX) + false, // Never use the zygote for the broker. + base::environment_vector(), +#endif + cmd_line); + return true; +} + +void PpapiBrokerProcessHost::OpenChannelToPpapiBroker(Client* client) { + if (opening_channel()) { + // The channel is already in the process of being opened. Put + // this "open channel" request into a queue of requests that will + // be run once the channel is open. + pending_requests_.push_back(client); + return; + } + + // We already have an open channel, send a request right away to broker. + RequestPpapiBrokerChannel(client); +} + +void PpapiBrokerProcessHost::RequestPpapiBrokerChannel( + Client* client) { + base::ProcessHandle process_handle; + int renderer_id; + client->GetChannelInfo(&process_handle, &renderer_id); + + // We can't send any sync messages from the browser because it might lead to + // a hang. See the similar code in PluginProcessHost for more description. + PpapiMsg_CreateChannel* msg = new PpapiMsg_CreateChannel(process_handle, + renderer_id); + msg->set_unblock(true); + if (Send(msg)) + sent_requests_.push(client); + else + client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle()); +} + +bool PpapiBrokerProcessHost::CanShutdown() { + return true; +} + +void PpapiBrokerProcessHost::OnProcessLaunched() { +} + +bool PpapiBrokerProcessHost::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PpapiBrokerProcessHost, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_ChannelCreated, + OnRendererPpapiBrokerChannelCreated) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + DCHECK(handled); + return handled; +} + +// Called when the browser <--> ppapi broker channel has been established. +void PpapiBrokerProcessHost::OnChannelConnected(int32 peer_pid) { + // This will actually load the ppapi broker. Errors will actually not be + // reported back at this point. Instead, the broker will fail to establish the + // connections when we request them on behalf of the renderer(s). + Send(new PpapiMsg_LoadPlugin(broker_path_)); + + // Process all pending channel requests from the renderers. + for (size_t i = 0; i < pending_requests_.size(); i++) + RequestPpapiBrokerChannel(pending_requests_[i]); + pending_requests_.clear(); +} + +// Called when the browser <--> broker channel has an error. This normally +// means the broker has crashed. +void PpapiBrokerProcessHost::OnChannelError() { + // We don't need to notify the renderers that were communicating with the + // broker since they have their own channels which will go into the error + // state at the same time. Instead, we just need to notify any renderers + // that have requested a connection but have not yet received one. + CancelRequests(); +} + +void PpapiBrokerProcessHost::CancelRequests() { + for (size_t i = 0; i < pending_requests_.size(); i++) { + pending_requests_[i]->OnChannelOpened(base::kNullProcessHandle, + IPC::ChannelHandle()); + } + pending_requests_.clear(); + + while (!sent_requests_.empty()) { + sent_requests_.front()->OnChannelOpened(base::kNullProcessHandle, + IPC::ChannelHandle()); + sent_requests_.pop(); + } +} + +// Called when a new broker <--> renderer channel has been created. +void PpapiBrokerProcessHost::OnRendererPpapiBrokerChannelCreated( + const IPC::ChannelHandle& channel_handle) { + if (sent_requests_.empty()) + return; + + // All requests should be processed FIFO, so the next item in the + // sent_requests_ queue should be the one that the plugin just created. + Client* client = sent_requests_.front(); + sent_requests_.pop(); + + // Prepare the handle to send to the renderer. + base::ProcessHandle broker_process = GetChildProcessHandle(); +#if defined(OS_WIN) + base::ProcessHandle renderer_process; + int renderer_id; + client->GetChannelInfo(&renderer_process, &renderer_id); + + base::ProcessHandle renderers_broker_handle = NULL; + ::DuplicateHandle(::GetCurrentProcess(), broker_process, + renderer_process, &renderers_broker_handle, + 0, FALSE, DUPLICATE_SAME_ACCESS); +#elif defined(OS_POSIX) + // Don't need to duplicate anything on POSIX since it's just a PID. + base::ProcessHandle renderers_broker_handle = broker_process; +#endif + + client->OnChannelOpened(renderers_broker_handle, channel_handle); +} diff --git a/content/browser/ppapi_broker_process_host.h b/content/browser/ppapi_broker_process_host.h new file mode 100644 index 0000000..38a0314 --- /dev/null +++ b/content/browser/ppapi_broker_process_host.h @@ -0,0 +1,81 @@ +// 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_BROWSER_PPAPI_BROKER_PROCESS_HOST_H_ +#define CONTENT_BROWSER_PPAPI_BROKER_PROCESS_HOST_H_ +#pragma once + +#include <queue> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "content/browser/browser_child_process_host.h" + +struct PepperPluginInfo; + +// TODO(ddorwin): Consider merging this with PpapiPluginProcessHost after +// finishing broker implementation. +class PpapiBrokerProcessHost : public BrowserChildProcessHost { + public: + class Client { + public: + // Gets the information about the renderer that's requesting the channel. + virtual void GetChannelInfo(base::ProcessHandle* renderer_handle, + int* renderer_id) = 0; + + // Called when the channel is asynchronously opened to the broker or on + // error. On error, the parameters should be: + // base::kNullProcessHandle + // IPC::ChannelHandle() + virtual void OnChannelOpened(base::ProcessHandle broker_process_handle, + const IPC::ChannelHandle& channel_handle) = 0; + }; + + // You must call Init before doing anything else. + PpapiBrokerProcessHost(); + virtual ~PpapiBrokerProcessHost(); + + // Actually launches the process with the given plugin info. Returns true + // on success (the process was spawned). + bool Init(const PepperPluginInfo& info); + + // Opens a new channel to the plugin. The client will be notified when the + // channel is ready or if there's an error. + void OpenChannelToPpapiBroker(Client* client); + + const FilePath& broker_path() const { return broker_path_; } + + // The client pointer must remain valid until its callback is issued. + + private: + + void RequestPpapiBrokerChannel(Client* client); + + virtual bool CanShutdown(); + virtual void OnProcessLaunched(); + + virtual bool OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelConnected(int32 peer_pid); + virtual void OnChannelError(); + + void CancelRequests(); + + // IPC message handlers. + void OnRendererPpapiBrokerChannelCreated(const IPC::ChannelHandle& handle); + + // Channel requests that we are waiting to send to the plugin process once + // the channel is opened. + std::vector<Client*> pending_requests_; + + // Channel requests that we have already sent to the plugin process, but + // haven't heard back about yet. + std::queue<Client*> sent_requests_; + + // Path to the plugin library. + FilePath broker_path_; + + DISALLOW_COPY_AND_ASSIGN(PpapiBrokerProcessHost); +}; + +#endif // CONTENT_BROWSER_PPAPI_BROKER_PROCESS_HOST_H_ diff --git a/content/browser/ppapi_plugin_process_host.h b/content/browser/ppapi_plugin_process_host.h index aa6bc47..0412c25 100644 --- a/content/browser/ppapi_plugin_process_host.h +++ b/content/browser/ppapi_plugin_process_host.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -30,8 +30,8 @@ class PpapiPluginProcessHost : public BrowserChildProcessHost { const IPC::ChannelHandle& channel_handle) = 0; }; - // You must call init before doing anything else. - explicit PpapiPluginProcessHost(); + // You must call Init before doing anything else. + PpapiPluginProcessHost(); virtual ~PpapiPluginProcessHost(); // Actually launches the process with the given plugin info. Returns true diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc index 42a6e2e..699e266 100644 --- a/content/browser/renderer_host/render_message_filter.cc +++ b/content/browser/renderer_host/render_message_filter.cc @@ -34,6 +34,7 @@ #include "content/browser/plugin_process_host.h" #include "content/browser/plugin_service.h" #include "content/browser/ppapi_plugin_process_host.h" +#include "content/browser/ppapi_broker_process_host.h" #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_view_host_notification_task.h" #include "content/browser/renderer_host/render_widget_helper.h" @@ -182,6 +183,37 @@ class OpenChannelToPpapiPluginCallback : public RenderMessageCompletionCallback, } }; +class OpenChannelToPpapiBrokerCallback : public PpapiBrokerProcessHost::Client { + public: + OpenChannelToPpapiBrokerCallback(RenderMessageFilter* filter, + int routing_id, + int request_id) + : filter_(filter), + routing_id_(routing_id), + request_id_(request_id) { + } + + virtual void GetChannelInfo(base::ProcessHandle* renderer_handle, + int* renderer_id) { + *renderer_handle = filter_->peer_handle(); + *renderer_id = filter_->render_process_id(); + } + + virtual void OnChannelOpened(base::ProcessHandle plugin_process_handle, + const IPC::ChannelHandle& channel_handle) { + filter_->Send( + new ViewMsg_PpapiBrokerChannelCreated(routing_id_, + request_id_, + channel_handle)); + delete this; + } + + private: + scoped_refptr<RenderMessageFilter> filter_; + int routing_id_; + int request_id_; +}; + // Class to assist with clearing out the cache when we want to preserve // the sslhostinfo entries. It's not very efficient, but its just for debug. class DoomEntriesHelper { @@ -323,6 +355,8 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message, OnOpenChannelToPlugin) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenChannelToPepperPlugin, OnOpenChannelToPepperPlugin) + IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToPpapiBroker, + OnOpenChannelToPpapiBroker) IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_UpdateRect, render_widget_helper_->DidReceiveUpdateMsg(message)) IPC_MESSAGE_HANDLER(DesktopNotificationHostMsg_CheckPermission, @@ -605,6 +639,13 @@ void RenderMessageFilter::OnOpenChannelToPepperPlugin( path, new OpenChannelToPpapiPluginCallback(this, reply_msg)); } +void RenderMessageFilter::OnOpenChannelToPpapiBroker(int routing_id, + int request_id, + const FilePath& path) { + plugin_service_->OpenChannelToPpapiBroker( + path, new OpenChannelToPpapiBrokerCallback(this, routing_id, request_id)); +} + void RenderMessageFilter::OnGenerateRoutingID(int* route_id) { *route_id = render_widget_helper_->GetNextRoutingID(); } diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h index 2e9181b..266316d 100644 --- a/content/browser/renderer_host/render_message_filter.h +++ b/content/browser/renderer_host/render_message_filter.h @@ -157,6 +157,9 @@ class RenderMessageFilter : public BrowserMessageFilter { IPC::Message* reply_msg); void OnOpenChannelToPepperPlugin(const FilePath& path, IPC::Message* reply_msg); + void OnOpenChannelToPpapiBroker(int routing_id, + int request_id, + const FilePath& path); void OnGenerateRoutingID(int* route_id); void OnDownloadUrl(const IPC::Message& message, const GURL& url, diff --git a/content/common/child_process_info.cc b/content/common/child_process_info.cc index 4775d7b..5ffe92c 100644 --- a/content/common/child_process_info.cc +++ b/content/common/child_process_info.cc @@ -76,6 +76,8 @@ std::string ChildProcessInfo::GetTypeNameInEnglish( return "GPU"; case PPAPI_PLUGIN_PROCESS: return "Pepper Plugin"; + case PPAPI_BROKER_PROCESS: + return "Pepper Broker"; case UNKNOWN_PROCESS: default: DCHECK(false) << "Unknown child process type!"; diff --git a/content/common/child_process_info.h b/content/common/child_process_info.h index e36ee52..4b709bd 100644 --- a/content/common/child_process_info.h +++ b/content/common/child_process_info.h @@ -29,7 +29,8 @@ class ChildProcessInfo { SANDBOX_HELPER_PROCESS, NACL_BROKER_PROCESS, GPU_PROCESS, - PPAPI_PLUGIN_PROCESS + PPAPI_PLUGIN_PROCESS, + PPAPI_BROKER_PROCESS }; // NOTE: Do not remove or reorder the elements in this enum, and only add new diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 54435bc..06f3362 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -1146,6 +1146,11 @@ IPC_MESSAGE_ROUTED1(ViewMsg_AccessibilityDoDefaultAction, // message was processed and it can send addition notifications. IPC_MESSAGE_ROUTED0(ViewMsg_AccessibilityNotifications_ACK) +// Reply to ViewHostMsg_OpenChannelToPpapiBroker +// Tells the renderer that the channel to the broker has been created. +IPC_MESSAGE_ROUTED2(ViewMsg_PpapiBrokerChannelCreated, + int /* request_id */, + IPC::ChannelHandle /* handle */) // Messages sent from the renderer to the browser. @@ -1582,7 +1587,7 @@ IPC_MESSAGE_ROUTED3(ViewHostMsg_WebUISend, std::string /* args (as a JSON string) */) // A renderer sends this to the browser process when it wants to -// create a pepper plugin. The browser will create the plugin process if +// create a ppapi plugin. The browser will create the plugin process if // necessary, and will return a handle to the channel on success. // On error an empty string is returned. IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_OpenChannelToPepperPlugin, @@ -1590,6 +1595,16 @@ IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_OpenChannelToPepperPlugin, base::ProcessHandle /* plugin_process_handle */, IPC::ChannelHandle /* handle to channel */) +// A renderer sends this to the browser process when it wants to +// create a ppapi broker. The browser will create the broker process +// if necessary, and will return a handle to the channel on success. +// On error an empty string is returned. +// The browser will respond with ViewMsg_PpapiBrokerChannelCreated. +IPC_MESSAGE_CONTROL3(ViewHostMsg_OpenChannelToPpapiBroker, + int /* routing_id */, + int /* request_id */, + FilePath /* path */) + #if defined(USE_X11) // A renderer sends this when it needs a browser-side widget for // hosting a windowed plugin. id is the XID of the plugin window, for which diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 923362c..7cfa306 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -164,6 +164,8 @@ 'browser/mime_registry_message_filter.h', 'browser/ppapi_plugin_process_host.cc', 'browser/ppapi_plugin_process_host.h', + 'browser/ppapi_broker_process_host.cc', + 'browser/ppapi_broker_process_host.h', 'browser/plugin_process_host.cc', 'browser/plugin_process_host.h', 'browser/plugin_process_host_mac.cc', diff --git a/content/renderer/pepper_plugin_delegate_impl.cc b/content/renderer/pepper_plugin_delegate_impl.cc index 5a62f25..8ba9f4f 100644 --- a/content/renderer/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper_plugin_delegate_impl.cc @@ -35,7 +35,6 @@ #include "content/renderer/render_widget_fullscreen_pepper.h" #include "content/renderer/webgraphicscontext3d_command_buffer_impl.h" #include "content/renderer/webplugin_delegate_proxy.h" -#include "ipc/ipc_channel_handle.h" #include "ppapi/c/dev/pp_video_dev.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/private/ppb_flash.h" @@ -330,6 +329,45 @@ bool DispatcherWrapper::Init( } // namespace +PpapiBrokerImpl::PpapiBrokerImpl() { +} + +// If the channel is not ready, queue the connection. +void PpapiBrokerImpl::Connect(webkit::ppapi::PPB_Broker_Impl* client) { + if (channel_handle_.name.empty()) { + pending_connects_.push_back(client); + return; + } + DCHECK(pending_connects_.empty()); + + RequestPpapiBrokerPipe(client); +} + +void PpapiBrokerImpl::Disconnect(webkit::ppapi::PPB_Broker_Impl* client) { + // TODO(ddorwin): Send message using channel_handle_ and clean up any pending + // connects or pipes. +} + +void PpapiBrokerImpl::OnBrokerChannelConnected( + const IPC::ChannelHandle& channel_handle) { + channel_handle_ = channel_handle; + + // Process all pending channel requests from the renderers. + for (size_t i = 0; i < pending_connects_.size(); i++) + RequestPpapiBrokerPipe(pending_connects_[i]); + pending_connects_.clear(); +} + +void PpapiBrokerImpl::RequestPpapiBrokerPipe( + webkit::ppapi::PPB_Broker_Impl* client) { + // TOOD(ddorwin): Send an asynchronous message to the broker using + // channel_handle_, queue the client with an ID, then return. + // The broker will create the pipe, which will be provided in a message. + // That message handler will call then client->BrokerConnected(). + // Temporarily, just call back. + client->BrokerConnected(1); +} + PepperPluginDelegateImpl::PepperPluginDelegateImpl(RenderView* render_view) : render_view_(render_view), has_saved_context_menu_action_(false), @@ -391,6 +429,45 @@ PepperPluginDelegateImpl::CreatePepperPlugin( return module; } +scoped_refptr<webkit::ppapi::PluginDelegate::PpapiBroker> +PepperPluginDelegateImpl::CreatePpapiBroker( + webkit::ppapi::PluginModule* plugin_module) { + DCHECK(plugin_module); + DCHECK(!plugin_module->GetBroker()); + + // The broker path is the same as the plugin. + const FilePath& broker_path = plugin_module->path(); + + scoped_refptr<PpapiBrokerImpl> broker = new PpapiBrokerImpl; + plugin_module->SetBroker(broker); + + int request_id = + pending_connect_broker_.Add(new scoped_refptr<PpapiBrokerImpl>(broker)); + + // Have the browser start the broker process for us. + IPC::ChannelHandle channel_handle; + IPC::Message* msg = + new ViewHostMsg_OpenChannelToPpapiBroker(render_view_->routing_id(), + request_id, + broker_path); + if (!render_view_->Send(msg)) { + pending_connect_broker_.Remove(request_id); + return scoped_refptr<webkit::ppapi::PluginDelegate::PpapiBroker>(); + } + + return broker; +} + +void PepperPluginDelegateImpl::OnPpapiBrokerChannelCreated( + int request_id, + const IPC::ChannelHandle& handle) { + scoped_refptr<PpapiBrokerImpl> broker = + *pending_connect_broker_.Lookup(request_id); + pending_connect_broker_.Remove(request_id); + + broker->OnBrokerChannelConnected(handle); +} + void PepperPluginDelegateImpl::ViewInitiatedPaint() { // Notify all of our instances that we started painting. This is used for // internal bookkeeping only, so we know that the set can not change under @@ -560,22 +637,23 @@ PepperPluginDelegateImpl::CreateAudio( } } +// If a broker has not already been created for this plugin, creates one. webkit::ppapi::PluginDelegate::PpapiBroker* PepperPluginDelegateImpl::ConnectToPpapiBroker( - webkit::ppapi::PluginInstance* instance, webkit::ppapi::PPB_Broker_Impl* client) { - CHECK(instance); CHECK(client); - // TODO(ddorwin): Add IPC to broker process to do the following. - // 1) Check if there is an existing broker for instance->module(). - // 2) If not, create. - // 3) broker->Connect(client). - // * Asynchronously launches broker if necessary, establishes pipe, and - // calls BrokerConnected. - // 4) Return pointer to broker. + webkit::ppapi::PluginModule* plugin_module = client->instance()->module(); + scoped_refptr<webkit::ppapi::PluginDelegate::PpapiBroker> broker = + plugin_module->GetBroker(); + if (!broker) { + broker = CreatePpapiBroker(plugin_module); + if (!broker) + return NULL; + } - return NULL; + broker->Connect(client); + return broker; } bool PepperPluginDelegateImpl::RunFileChooser( diff --git a/content/renderer/pepper_plugin_delegate_impl.h b/content/renderer/pepper_plugin_delegate_impl.h index 4186b96..b2ee87e 100644 --- a/content/renderer/pepper_plugin_delegate_impl.h +++ b/content/renderer/pepper_plugin_delegate_impl.h @@ -8,12 +8,15 @@ #include <set> #include <string> +#include <vector> #include "base/basictypes.h" #include "base/id_map.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "ipc/ipc_channel_handle.h" #include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/ppb_broker_impl.h" #include "webkit/plugins/ppapi/ppb_flash_menu_impl.h" class FilePath; @@ -43,6 +46,30 @@ struct CustomContextMenuContext; class TransportDIB; +class PpapiBrokerImpl : public webkit::ppapi::PluginDelegate::PpapiBroker { + public: + PpapiBrokerImpl(); + + // PpapiBroker implementation. + virtual void Connect(webkit::ppapi::PPB_Broker_Impl* client); + virtual void Disconnect(webkit::ppapi::PPB_Broker_Impl* client); + + // Called when the channel to the broker has been established. + void OnBrokerChannelConnected(const IPC::ChannelHandle& channel_handle); + + // Asynchronously requests a pipe for this instance from the broker. + void RequestPpapiBrokerPipe(webkit::ppapi::PPB_Broker_Impl* client); + + protected: + IPC::ChannelHandle channel_handle_; + + std::vector<scoped_refptr<webkit::ppapi::PPB_Broker_Impl> > pending_connects_; + std::vector<scoped_refptr<webkit::ppapi::PPB_Broker_Impl> > pending_pipes_; + + DISALLOW_COPY_AND_ASSIGN(PpapiBrokerImpl); +}; + + class PepperPluginDelegateImpl : public webkit::ppapi::PluginDelegate, public base::SupportsWeakPtr<PepperPluginDelegateImpl> { @@ -81,6 +108,10 @@ class PepperPluginDelegateImpl base::PlatformFile file, int message_id); + // Called by RenderView when ViewMsg_PpapiBrokerChannelCreated. + void OnPpapiBrokerChannelCreated(int request_id, + const IPC::ChannelHandle& handle); + // Notification that the render view has been focused or defocused. This // notifies all of the plugins. void OnSetFocus(bool has_focus); @@ -101,7 +132,6 @@ class PepperPluginDelegateImpl virtual PlatformVideoDecoder* CreateVideoDecoder( PP_VideoDecoderConfig_Dev* decoder_config); virtual PpapiBroker* ConnectToPpapiBroker( - webkit::ppapi::PluginInstance* instance, webkit::ppapi::PPB_Broker_Impl* client); virtual void NumberOfFindResultsChanged(int identifier, int total, @@ -193,6 +223,10 @@ class PepperPluginDelegateImpl virtual webkit_glue::P2PTransport* CreateP2PTransport(); private: + // Asynchronously attempts to create a PPAPI broker for the given plugin. + scoped_refptr<webkit::ppapi::PluginDelegate::PpapiBroker> CreatePpapiBroker( + webkit::ppapi::PluginModule* plugin_module); + // Pointer to the RenderView that owns us. RenderView* render_view_; @@ -213,6 +247,9 @@ class PepperPluginDelegateImpl IDMap<scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl>, IDMapOwnPointer> pending_context_menus_; + IDMap<scoped_refptr<PpapiBrokerImpl>, IDMapOwnPointer> + pending_connect_broker_; + DISALLOW_COPY_AND_ASSIGN(PepperPluginDelegateImpl); }; diff --git a/content/renderer/render_view.cc b/content/renderer/render_view.cc index 1a41f03..4ea0bcc 100644 --- a/content/renderer/render_view.cc +++ b/content/renderer/render_view.cc @@ -932,6 +932,8 @@ bool RenderView::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ViewMsg_AccessibilityNotifications_ACK, OnAccessibilityNotificationsAck) IPC_MESSAGE_HANDLER(ViewMsg_AsyncOpenFile_ACK, OnAsyncFileOpened) + IPC_MESSAGE_HANDLER(ViewMsg_PpapiBrokerChannelCreated, + OnPpapiBrokerChannelCreated) #if defined(OS_MACOSX) IPC_MESSAGE_HANDLER(ViewMsg_SelectPopupMenuItem, OnSelectPopupMenuItem) #endif @@ -4801,6 +4803,11 @@ void RenderView::OnAsyncFileOpened(base::PlatformFileError error_code, message_id); } +void RenderView::OnPpapiBrokerChannelCreated(int request_id, + const IPC::ChannelHandle& handle) { + pepper_delegate_.OnPpapiBrokerChannelCreated(request_id, handle); +} + #if defined(OS_MACOSX) void RenderView::OnSelectPopupMenuItem(int selected_index) { if (external_popup_menu_ == NULL) { diff --git a/content/renderer/render_view.h b/content/renderer/render_view.h index 6fdc8f6..efe2323 100644 --- a/content/renderer/render_view.h +++ b/content/renderer/render_view.h @@ -746,6 +746,8 @@ class RenderView : public RenderWidget, void OnAsyncFileOpened(base::PlatformFileError error_code, IPC::PlatformFileForTransit file_for_transit, int message_id); + void OnPpapiBrokerChannelCreated(int request_id, + const IPC::ChannelHandle& handle); void OnCancelDownload(int32 download_id); void OnClearFocusedNode(); void OnClosePage(const ViewMsg_ClosePage_Params& params); diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index 057874e..270af84 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h @@ -29,7 +29,7 @@ #define IPC_MESSAGE_START PpapiMsgStart -// These are from the plugin to the renderer +// These are from the browser to the plugin. // Loads the given plugin. IPC_MESSAGE_CONTROL1(PpapiMsg_LoadPlugin, FilePath /* path */) diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.cc b/webkit/plugins/ppapi/mock_plugin_delegate.cc index a9da765..e896bcd 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.cc +++ b/webkit/plugins/ppapi/mock_plugin_delegate.cc @@ -53,7 +53,6 @@ MockPluginDelegate::PlatformAudio* MockPluginDelegate::CreateAudio( } MockPluginDelegate::PpapiBroker* MockPluginDelegate::ConnectToPpapiBroker( - PluginInstance* instance, PPB_Broker_Impl* client) { return NULL; } diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.h b/webkit/plugins/ppapi/mock_plugin_delegate.h index 78d59a2..101f788 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.h +++ b/webkit/plugins/ppapi/mock_plugin_delegate.h @@ -26,8 +26,7 @@ class MockPluginDelegate : public PluginDelegate { virtual PlatformAudio* CreateAudio(uint32_t sample_rate, uint32_t sample_count, PlatformAudio::Client* client); - virtual PpapiBroker* ConnectToPpapiBroker(PluginInstance* instance, - PPB_Broker_Impl* client); + virtual PpapiBroker* ConnectToPpapiBroker(PPB_Broker_Impl* client); virtual void NumberOfFindResultsChanged(int identifier, int total, bool final_result); diff --git a/webkit/plugins/ppapi/plugin_delegate.h b/webkit/plugins/ppapi/plugin_delegate.h index 786e924..d986e95 100644 --- a/webkit/plugins/ppapi/plugin_delegate.h +++ b/webkit/plugins/ppapi/plugin_delegate.h @@ -210,15 +210,18 @@ class PluginDelegate { }; // Provides access to the ppapi broker. - class PpapiBroker { + class PpapiBroker : public base::RefCountedThreadSafe<PpapiBroker> { public: - virtual ~PpapiBroker() {} + virtual void Connect(webkit::ppapi::PPB_Broker_Impl* client) = 0; - // Decrements the references to the broker for the instance. - // When the references reach 0 for all instances in this renderer, this - // object may be destroyed. When the references reach 0 for all instances - // using the same module, the broker may shut down. - virtual void Release(PluginInstance* instance) = 0; + // Decrements the references to the broker. + // When there are no more references, this renderer's dispatcher is + // destroyed, allowing the broker to shutdown if appropriate. + virtual void Disconnect(webkit::ppapi::PPB_Broker_Impl* client) = 0; + + protected: + friend class base::RefCountedThreadSafe<PpapiBroker>; + ~PpapiBroker() {} }; // Notification that the given plugin has crashed. When a plugin crashes, all @@ -259,7 +262,6 @@ class PluginDelegate { // The caller is responsible for calling Release() on the returned pointer // to clean up the corresponding resources allocated during this call. virtual PpapiBroker* ConnectToPpapiBroker( - PluginInstance* instance, webkit::ppapi::PPB_Broker_Impl* client) = 0; // Notifies that the number of find results has changed. diff --git a/webkit/plugins/ppapi/plugin_module.cc b/webkit/plugins/ppapi/plugin_module.cc index d469860..6fc7f7c 100644 --- a/webkit/plugins/ppapi/plugin_module.cc +++ b/webkit/plugins/ppapi/plugin_module.cc @@ -389,6 +389,7 @@ PluginModule::PluginModule(const std::string& name, : lifetime_delegate_(lifetime_delegate), callback_tracker_(new CallbackTracker), is_crashed_(false), + broker_(NULL), library_(NULL), name_(name), path_(path), @@ -527,6 +528,16 @@ bool PluginModule::ReserveInstanceID(PP_Instance instance) { return true; // Instance ID is usable. } +void PluginModule::SetBroker( + scoped_refptr<PluginDelegate::PpapiBroker> broker) { + DCHECK(!broker_.get()); + broker_ = broker; +} + +scoped_refptr<PluginDelegate::PpapiBroker> PluginModule::GetBroker(){ + return broker_; +} + 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 dabd032..e462f3a 100644 --- a/webkit/plugins/ppapi/plugin_module.h +++ b/webkit/plugins/ppapi/plugin_module.h @@ -145,6 +145,9 @@ class PluginModule : public base::RefCounted<PluginModule>, PP_Bool (*reserve)(PP_Module, PP_Instance)); bool ReserveInstanceID(PP_Instance instance); + void SetBroker(scoped_refptr<PluginDelegate::PpapiBroker> broker); + scoped_refptr<PluginDelegate::PpapiBroker> GetBroker(); + 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 +170,9 @@ class PluginModule : public base::RefCounted<PluginModule>, // entry_points_ aren't valid. scoped_ptr<PluginDelegate::OutOfProcessProxy> out_of_process_proxy_; + // Trusted broker for this plugin module. + scoped_refptr<PluginDelegate::PpapiBroker> broker_; + // Holds a reference to the base::NativeLibrary handle if this PluginModule // instance wraps functions loaded from a library. Can be NULL. If // |library_| is non-NULL, PluginModule will attempt to unload the library diff --git a/webkit/plugins/ppapi/ppb_broker_impl.cc b/webkit/plugins/ppapi/ppb_broker_impl.cc index 9e0cb5c..83912c5 100644 --- a/webkit/plugins/ppapi/ppb_broker_impl.cc +++ b/webkit/plugins/ppapi/ppb_broker_impl.cc @@ -72,7 +72,7 @@ PPB_Broker_Impl::PPB_Broker_Impl(PluginInstance* instance) PPB_Broker_Impl::~PPB_Broker_Impl() { if (broker_) { - broker_->Release(instance()); + broker_->Disconnect(this); broker_ = NULL; } @@ -94,7 +94,7 @@ int32_t PPB_Broker_Impl::Connect( return PP_ERROR_FAILED; } - broker_ = plugin_delegate->ConnectToPpapiBroker(instance(), this); + broker_ = plugin_delegate->ConnectToPpapiBroker(this); if (!broker_) return PP_ERROR_FAILED; diff --git a/webkit/plugins/ppapi/ppb_broker_impl.h b/webkit/plugins/ppapi/ppb_broker_impl.h index f83d280..66454b9 100644 --- a/webkit/plugins/ppapi/ppb_broker_impl.h +++ b/webkit/plugins/ppapi/ppb_broker_impl.h @@ -38,7 +38,7 @@ class PPB_Broker_Impl : public Resource { private: // PluginDelegate ppapi broker object. // We don't own this pointer but are responsible for calling Release on it. - PluginDelegate::PpapiBroker* broker_; + scoped_refptr<PluginDelegate::PpapiBroker> broker_; // Callback invoked from BrokerConnected. scoped_refptr<TrackedCompletionCallback> connect_callback_; |