diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-13 17:50:20 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-13 17:50:20 +0000 |
commit | a08ebeaea39acfe007d9ee9b25b28efd04011e5a (patch) | |
tree | c878b32554af650294155ab21491dc086cff0939 | |
parent | 9d7557f78d893c56afcf65f2e6317feabb9af796 (diff) | |
download | chromium_src-a08ebeaea39acfe007d9ee9b25b28efd04011e5a.zip chromium_src-a08ebeaea39acfe007d9ee9b25b28efd04011e5a.tar.gz chromium_src-a08ebeaea39acfe007d9ee9b25b28efd04011e5a.tar.bz2 |
Share PPAPI out-of-process plugins between renderer processes.
This provides the hook-up for plugin sharing but not shutdown or cleanup from
errors. There is still a lot of work to do cleaning up in the plugin and the
browser when a renderer dies, or cleaning up in the renderer and browser when a
plugin dies. Currently, even the normal exit case crashes in the browser. But
fixing it in this patch would be too complicated to write or review, so I'm
going to do shutdown & error handling in a followup.
Review URL: http://codereview.chromium.org/6486034
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@74766 0039d316-1c4b-4281-b951-d872f2087c98
30 files changed, 488 insertions, 293 deletions
diff --git a/chrome/browser/chrome_plugin_host.cc b/chrome/browser/chrome_plugin_host.cc index ad4462e..2b020d4 100644 --- a/chrome/browser/chrome_plugin_host.cc +++ b/chrome/browser/chrome_plugin_host.cc @@ -702,7 +702,7 @@ CPBool STDCALL CPB_IsPluginProcessRunning(CPID id) { PluginService* service = PluginService::GetInstance(); if (!service) return false; - PluginProcessHost *host = service->FindPluginProcess(plugin->filename()); + PluginProcessHost *host = service->FindNpapiPluginProcess(plugin->filename()); return host ? true : false; } @@ -720,7 +720,7 @@ CPError STDCALL CPB_SendMessage(CPID id, const void *data, uint32 data_len) { if (!service) return CPERR_FAILURE; PluginProcessHost *host = - service->FindOrStartPluginProcess(plugin->filename()); + service->FindOrStartNpapiPluginProcess(plugin->filename()); if (!host) return CPERR_FAILURE; diff --git a/chrome/browser/plugin_data_remover.cc b/chrome/browser/plugin_data_remover.cc index 188140a..a32e12b 100644 --- a/chrome/browser/plugin_data_remover.cc +++ b/chrome/browser/plugin_data_remover.cc @@ -49,7 +49,7 @@ base::WaitableEvent* PluginDataRemover::StartRemoving( is_removing_ = true; AddRef(); - PluginService::GetInstance()->OpenChannelToPlugin( + PluginService::GetInstance()->OpenChannelToNpapiPlugin( 0, 0, GURL(), mime_type_, this); BrowserThread::PostDelayedTask( diff --git a/chrome/browser/plugin_service.cc b/chrome/browser/plugin_service.cc index 148f65e..a65bea6 100644 --- a/chrome/browser/plugin_service.cc +++ b/chrome/browser/plugin_service.cc @@ -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. @@ -18,6 +18,7 @@ #include "chrome/browser/chrome_plugin_host.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/plugin_updater.h" +#include "chrome/browser/ppapi_plugin_process_host.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host.h" @@ -240,7 +241,7 @@ const std::string& PluginService::GetUILocale() { return ui_locale_; } -PluginProcessHost* PluginService::FindPluginProcess( +PluginProcessHost* PluginService::FindNpapiPluginProcess( const FilePath& plugin_path) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); @@ -254,11 +255,27 @@ PluginProcessHost* PluginService::FindPluginProcess( return NULL; } -PluginProcessHost* PluginService::FindOrStartPluginProcess( +PpapiPluginProcessHost* PluginService::FindPpapiPluginProcess( const FilePath& plugin_path) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - PluginProcessHost* plugin_host = FindPluginProcess(plugin_path); + for (BrowserChildProcessHost::Iterator iter( + ChildProcessInfo::PPAPI_PLUGIN_PROCESS); + !iter.Done(); ++iter) { + PpapiPluginProcessHost* plugin = + static_cast<PpapiPluginProcessHost*>(*iter); + if (plugin->plugin_path() == plugin_path) + return plugin; + } + + return NULL; +} + +PluginProcessHost* PluginService::FindOrStartNpapiPluginProcess( + const FilePath& plugin_path) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path); if (plugin_host) return plugin_host; @@ -271,14 +288,42 @@ PluginProcessHost* PluginService::FindOrStartPluginProcess( // This plugin isn't loaded by any plugin process, so create a new process. scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost()); if (!new_host->Init(info, ui_locale_)) { - NOTREACHED(); // Init is not expected to fail + NOTREACHED(); // Init is not expected to fail. return NULL; } + return new_host.release(); +} +PpapiPluginProcessHost* PluginService::FindOrStartPpapiPluginProcess( + const FilePath& plugin_path) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + PpapiPluginProcessHost* plugin_host = FindPpapiPluginProcess(plugin_path); + 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; + } + } + if (!info) + return NULL; + + // This plugin isn't loaded by any plugin process, so create a new process. + scoped_ptr<PpapiPluginProcessHost> new_host(new PpapiPluginProcessHost); + if (!new_host->Init(plugin_path)) { + NOTREACHED(); // Init is not expected to fail. + return NULL; + } return new_host.release(); } -void PluginService::OpenChannelToPlugin( +void PluginService::OpenChannelToNpapiPlugin( int render_process_id, int render_view_id, const GURL& url, @@ -293,6 +338,16 @@ void PluginService::OpenChannelToPlugin( render_process_id, render_view_id, url, mime_type, client)); } +void PluginService::OpenChannelToPpapiPlugin( + const FilePath& path, + PpapiPluginProcessHost::Client* client) { + PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess(path); + if (plugin_host) + plugin_host->OpenChannelToPlugin(client); + else // Send error. + client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle()); +} + void PluginService::GetAllowedPluginForOpenChannelToPlugin( int render_process_id, int render_view_id, @@ -320,7 +375,7 @@ void PluginService::FinishOpenChannelToPlugin( PluginProcessHost::Client* client) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - PluginProcessHost* plugin_host = FindOrStartPluginProcess(plugin_path); + PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path); if (plugin_host) plugin_host->OpenChannelToPlugin(client); else @@ -392,7 +447,7 @@ void PluginService::OnWaitableEventSignaled( static void ForceShutdownPlugin(const FilePath& plugin_path) { PluginProcessHost* plugin = - PluginService::GetInstance()->FindPluginProcess(plugin_path); + PluginService::GetInstance()->FindNpapiPluginProcess(plugin_path); if (plugin) plugin->ForceShutdown(); } @@ -490,26 +545,25 @@ void PluginService::OverridePluginForTab(OverriddenPlugin plugin) { } void PluginService::RegisterPepperPlugins() { - std::vector<PepperPluginInfo> plugins; - PepperPluginRegistry::ComputeList(&plugins); - for (size_t i = 0; i < plugins.size(); ++i) { + PepperPluginRegistry::ComputeList(&ppapi_plugins_); + for (size_t i = 0; i < ppapi_plugins_.size(); ++i) { webkit::npapi::WebPluginInfo info; - info.path = plugins[i].path; - info.name = plugins[i].name.empty() ? - plugins[i].path.BaseName().LossyDisplayName() : - ASCIIToUTF16(plugins[i].name); - info.desc = ASCIIToUTF16(plugins[i].description); + info.path = ppapi_plugins_[i].path; + info.name = ppapi_plugins_[i].name.empty() ? + ppapi_plugins_[i].path.BaseName().LossyDisplayName() : + ASCIIToUTF16(ppapi_plugins_[i].name); + info.desc = ASCIIToUTF16(ppapi_plugins_[i].description); info.enabled = webkit::npapi::WebPluginInfo::USER_ENABLED_POLICY_UNMANAGED; // TODO(evan): Pepper shouldn't require us to parse strings to get // the list of mime types out. if (!webkit::npapi::PluginList::ParseMimeTypes( - JoinString(plugins[i].mime_types, '|'), - plugins[i].file_extensions, - ASCIIToUTF16(plugins[i].type_descriptions), + JoinString(ppapi_plugins_[i].mime_types, '|'), + ppapi_plugins_[i].file_extensions, + ASCIIToUTF16(ppapi_plugins_[i].type_descriptions), &info.mime_types)) { LOG(ERROR) << "Error parsing mime types for " - << plugins[i].path.LossyDisplayName(); + << ppapi_plugins_[i].path.LossyDisplayName(); return; } diff --git a/chrome/browser/plugin_service.h b/chrome/browser/plugin_service.h index f2732b2..1c0af96 100644 --- a/chrome/browser/plugin_service.h +++ b/chrome/browser/plugin_service.h @@ -20,6 +20,7 @@ #include "base/synchronization/waitable_event_watcher.h" #include "build/build_config.h" #include "chrome/browser/plugin_process_host.h" +#include "chrome/browser/ppapi_plugin_process_host.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" #include "googleurl/src/gurl.h" @@ -46,8 +47,9 @@ class Message; } class MessageLoop; -class Profile; +struct PepperPluginInfo; class PluginDirWatcherDelegate; +class Profile; class ResourceDispatcherHost; namespace net { @@ -89,22 +91,28 @@ class PluginService // Returns the plugin process host corresponding to the plugin process that // has been started by this service. Returns NULL if no process has been // started. - PluginProcessHost* FindPluginProcess(const FilePath& plugin_path); + PluginProcessHost* FindNpapiPluginProcess(const FilePath& plugin_path); + PpapiPluginProcessHost* FindPpapiPluginProcess(const FilePath& plugin_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 // 'plugin_path' if needed. If the process fails to start, the return value // is NULL. Must be called on the IO thread. - PluginProcessHost* FindOrStartPluginProcess(const FilePath& plugin_path); + PluginProcessHost* FindOrStartNpapiPluginProcess( + const FilePath& plugin_path); + PpapiPluginProcessHost* FindOrStartPpapiPluginProcess( + 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 // or else a deadlock can occur. - void OpenChannelToPlugin(int render_process_id, - int render_view_id, - const GURL& url, - const std::string& mime_type, - PluginProcessHost::Client* client); + void OpenChannelToNpapiPlugin(int render_process_id, + int render_view_id, + const GURL& url, + const std::string& mime_type, + PluginProcessHost::Client* client); + void OpenChannelToPpapiPlugin(const FilePath& path, + PpapiPluginProcessHost::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. @@ -170,10 +178,6 @@ class PluginService FilePathWatcher::Delegate* delegate); #endif - // mapping between plugin path and PluginProcessHost - typedef base::hash_map<FilePath, PluginProcessHost*> PluginMap; - PluginMap plugin_hosts_; - // The main thread's message loop. MessageLoop* main_message_loop_; @@ -212,6 +216,8 @@ class PluginService scoped_refptr<PluginDirWatcherDelegate> file_watcher_delegate_; #endif + std::vector<PepperPluginInfo> ppapi_plugins_; + // Set to true if chrome plugins are enabled. Defaults to true. static bool enable_chrome_plugins_; diff --git a/chrome/browser/plugin_service_browsertest.cc b/chrome/browser/plugin_service_browsertest.cc index 3f31159..ee1be0c 100644 --- a/chrome/browser/plugin_service_browsertest.cc +++ b/chrome/browser/plugin_service_browsertest.cc @@ -72,19 +72,19 @@ IN_PROC_BROWSER_TEST_F(PluginServiceTest, StartAndFindPluginProcess) { // Try to load the default plugin and if this is successful consecutive // calls to FindPluginProcess should return non-zero values. PluginProcessHost* default_plugin_process_host = - plugin_service_->FindOrStartPluginProcess( + plugin_service_->FindOrStartNpapiPluginProcess( FilePath(webkit::npapi::kDefaultPluginLibraryName)); - EXPECT_EQ(default_plugin_process_host, plugin_service_->FindPluginProcess( - FilePath(webkit::npapi::kDefaultPluginLibraryName))); + EXPECT_EQ(default_plugin_process_host, + plugin_service_->FindNpapiPluginProcess( + FilePath(webkit::npapi::kDefaultPluginLibraryName))); } IN_PROC_BROWSER_TEST_F(PluginServiceTest, OpenChannelToPlugin) { MockPluginProcessHostClient mock_client; EXPECT_CALL(mock_client, SetPluginInfo(testing::_)).Times(1); - plugin_service_->OpenChannelToPlugin(0, 0, GURL("http://google.com/"), - "audio/mp3", - &mock_client); + plugin_service_->OpenChannelToNpapiPlugin(0, 0, GURL("http://google.com/"), + "audio/mp3", &mock_client); message_loop_.RunAllPending(); } diff --git a/chrome/browser/ppapi_plugin_process_host.cc b/chrome/browser/ppapi_plugin_process_host.cc index 225cc80..c319dd0 100644 --- a/chrome/browser/ppapi_plugin_process_host.cc +++ b/chrome/browser/ppapi_plugin_process_host.cc @@ -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. @@ -7,40 +7,36 @@ #include "base/command_line.h" #include "base/file_path.h" #include "base/process_util.h" +#include "chrome/browser/plugin_service.h" #include "chrome/browser/renderer_host/render_message_filter.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/render_messages.h" #include "ipc/ipc_switches.h" #include "ppapi/proxy/ppapi_messages.h" -PpapiPluginProcessHost::PpapiPluginProcessHost(RenderMessageFilter* filter) - : BrowserChildProcessHost(ChildProcessInfo::PPAPI_PLUGIN_PROCESS, - filter->resource_dispatcher_host()), - filter_(filter) { +PpapiPluginProcessHost::PpapiPluginProcessHost() + : BrowserChildProcessHost( + ChildProcessInfo::PPAPI_PLUGIN_PROCESS, + PluginService::GetInstance()->resource_dispatcher_host()) { } PpapiPluginProcessHost::~PpapiPluginProcessHost() { + CancelRequests(); } -void PpapiPluginProcessHost::Init(const FilePath& path, - IPC::Message* reply_msg) { +bool PpapiPluginProcessHost::Init(const FilePath& path) { plugin_path_ = path; - reply_msg_.reset(reply_msg); - if (!CreateChannel()) { - ReplyToRenderer(base::kNullProcessHandle, IPC::ChannelHandle()); - return; - } + if (!CreateChannel()) + return false; const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); CommandLine::StringType plugin_launcher = browser_command_line.GetSwitchValueNative(switches::kPpapiPluginLauncher); FilePath exe_path = ChildProcessHost::GetChildPath(plugin_launcher.empty()); - if (exe_path.empty()) { - ReplyToRenderer(base::kNullProcessHandle, IPC::ChannelHandle()); - return; - } + if (exe_path.empty()) + return false; CommandLine* cmd_line = new CommandLine(exe_path); cmd_line->AppendSwitchASCII(switches::kProcessType, @@ -60,6 +56,36 @@ void PpapiPluginProcessHost::Init(const FilePath& path, base::environment_vector(), #endif cmd_line); + return true; +} + +void PpapiPluginProcessHost::OpenChannelToPlugin(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 plugin. + RequestPluginChannel(client); +} + +void PpapiPluginProcessHost::RequestPluginChannel(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 PpapiPluginProcessHost::CanShutdown() { @@ -72,56 +98,77 @@ void PpapiPluginProcessHost::OnProcessLaunched() { bool PpapiPluginProcessHost::OnMessageReceived(const IPC::Message& msg) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PpapiPluginProcessHost, msg) - IPC_MESSAGE_HANDLER(PpapiHostMsg_PluginLoaded, OnPluginLoaded) + IPC_MESSAGE_HANDLER(PpapiHostMsg_ChannelCreated, + OnRendererPluginChannelCreated) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() DCHECK(handled); return handled; } +// Called when the browser <--> plugin channel has been established. void PpapiPluginProcessHost::OnChannelConnected(int32 peer_pid) { -#if defined(OS_WIN) - base::ProcessHandle plugins_renderer_handle = NULL; - ::DuplicateHandle(::GetCurrentProcess(), filter_->peer_handle(), - GetChildProcessHandle(), &plugins_renderer_handle, - 0, FALSE, DUPLICATE_SAME_ACCESS); -#elif defined(OS_POSIX) - base::ProcessHandle plugins_renderer_handle = filter_->peer_handle(); -#endif - - PpapiMsg_LoadPlugin* msg = new PpapiMsg_LoadPlugin( - plugins_renderer_handle, plugin_path_, filter_->render_process_id()); - if (!Send(msg)) // Just send an empty handle on failure. - ReplyToRenderer(base::kNullProcessHandle, IPC::ChannelHandle()); - // This function will result in OnChannelCreated getting called to finish. + // This will actually load the plugin. Errors will actually not be reported + // back at this point. Instead, the plugin will fail to establish the + // connections when we request them on behalf of the renderer(s). + Send(new PpapiMsg_LoadPlugin(plugin_path_)); + + // Process all pending channel requests from the renderers. + for (size_t i = 0; i < pending_requests_.size(); i++) + RequestPluginChannel(pending_requests_[i]); + pending_requests_.clear(); } +// Called when the browser <--> plugin channel has an error. This normally +// means the plugin has crashed. void PpapiPluginProcessHost::OnChannelError() { - if (reply_msg_.get()) - ReplyToRenderer(base::kNullProcessHandle, IPC::ChannelHandle()); + // We don't need to notify the renderers that were communicating with the + // plugin 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 PpapiPluginProcessHost::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(); + } } -void PpapiPluginProcessHost::OnPluginLoaded( +// Called when a new plugin <--> renderer channel has been created. +void PpapiPluginProcessHost::OnRendererPluginChannelCreated( 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 plugin_process = GetChildProcessHandle(); #if defined(OS_WIN) + base::ProcessHandle renderer_process; + int renderer_id; + client->GetChannelInfo(&renderer_process, &renderer_id); + base::ProcessHandle renderers_plugin_handle = NULL; ::DuplicateHandle(::GetCurrentProcess(), plugin_process, - filter_->peer_handle(), &renderers_plugin_handle, + renderer_process, &renderers_plugin_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_plugin_handle = plugin_process; #endif - ReplyToRenderer(renderers_plugin_handle, channel_handle); -} -void PpapiPluginProcessHost::ReplyToRenderer( - base::ProcessHandle plugin_handle, - const IPC::ChannelHandle& channel_handle) { - DCHECK(reply_msg_.get()); - ViewHostMsg_OpenChannelToPepperPlugin::WriteReplyParams(reply_msg_.get(), - plugin_handle, - channel_handle); - filter_->Send(reply_msg_.release()); + client->OnChannelOpened(renderers_plugin_handle, channel_handle); } diff --git a/chrome/browser/ppapi_plugin_process_host.h b/chrome/browser/ppapi_plugin_process_host.h index 227cf31..945195d 100644 --- a/chrome/browser/ppapi_plugin_process_host.h +++ b/chrome/browser/ppapi_plugin_process_host.h @@ -6,20 +6,48 @@ #define CHROME_BROWSER_PPAPI_PLUGIN_PROCESS_HOST_H_ #pragma once +#include <queue> + #include "base/basictypes.h" #include "base/file_path.h" #include "chrome/browser/browser_child_process_host.h" -class RenderMessageFilter; - class PpapiPluginProcessHost : public BrowserChildProcessHost { public: - explicit PpapiPluginProcessHost(RenderMessageFilter* filter); + 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 plugin or on + // error. On error, the parameters should be: + // base::kNullProcessHandle + // IPC::ChannelHandle() + virtual void OnChannelOpened(base::ProcessHandle plugin_process_handle, + const IPC::ChannelHandle& channel_handle) = 0; + }; + + // You must call init before doing anything else. + explicit PpapiPluginProcessHost(); virtual ~PpapiPluginProcessHost(); - void Init(const FilePath& path, IPC::Message* reply_msg); + // Actually launches the process with the given plugin path. Returns true + // on success (the process was spawned). + bool Init(const FilePath& path); + + // Opens a new channel to the plugin. The client will be notified when the + // channel is ready or if there's an error. + void OpenChannelToPlugin(Client* client); + + const FilePath& plugin_path() const { return plugin_path_; } + + // The client pointer must remain valid until its callback is issued. private: + + void RequestPluginChannel(Client* client); + virtual bool CanShutdown(); virtual void OnProcessLaunched(); @@ -27,22 +55,22 @@ class PpapiPluginProcessHost : public BrowserChildProcessHost { virtual void OnChannelConnected(int32 peer_pid); virtual void OnChannelError(); + void CancelRequests(); + // IPC message handlers. - void OnPluginLoaded(const IPC::ChannelHandle& handle); + void OnRendererPluginChannelCreated(const IPC::ChannelHandle& handle); - // Sends the reply_msg_ to the renderer with the given channel info. - void ReplyToRenderer(base::ProcessHandle plugin_handle, - const IPC::ChannelHandle& channel_handle); + // Channel requests that we are waiting to send to the plugin process once + // the channel is opened. + std::vector<Client*> pending_requests_; - RenderMessageFilter* filter_; + // 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 plugin_path_; - // When we're waiting for initialization of the plugin, this contains the - // reply message for the renderer to tell it that it can continue. - scoped_ptr<IPC::Message> reply_msg_; - DISALLOW_COPY_AND_ASSIGN(PpapiPluginProcessHost); }; diff --git a/chrome/browser/renderer_host/render_message_filter.cc b/chrome/browser/renderer_host/render_message_filter.cc index d9d7a32..f4f8514 100644 --- a/chrome/browser/renderer_host/render_message_filter.cc +++ b/chrome/browser/renderer_host/render_message_filter.cc @@ -167,39 +167,62 @@ void RenderParamsFromPrintSettings(const printing::PrintSettings& settings, params->supports_alpha_blend = settings.supports_alpha_blend(); } -class ClearCacheCompletion : public net::CompletionCallback { +// Common functionality for converting a sync renderer message to a callback +// function in the browser. Derive from this, create it on the heap when +// issuing your callback. When done, write your reply parameters into +// reply_msg(), and then call SendReplyAndDeleteThis(). +class RenderMessageCompletionCallback { public: - ClearCacheCompletion(IPC::Message* reply_msg, - RenderMessageFilter* filter) - : reply_msg_(reply_msg), - filter_(filter) { + RenderMessageCompletionCallback(RenderMessageFilter* filter, + IPC::Message* reply_msg) + : filter_(filter), + reply_msg_(reply_msg) { } - virtual void RunWithParams(const Tuple1<int>& params) { - ViewHostMsg_ClearCache::WriteReplyParams(reply_msg_, params.a); + virtual ~RenderMessageCompletionCallback() { + } + + RenderMessageFilter* filter() { return filter_.get(); } + IPC::Message* reply_msg() { return reply_msg_; } + + void SendReplyAndDeleteThis() { filter_->Send(reply_msg_); delete this; } private: - IPC::Message* reply_msg_; scoped_refptr<RenderMessageFilter> filter_; + IPC::Message* reply_msg_; }; -class OpenChannelToPluginCallback : public PluginProcessHost::Client { +class ClearCacheCompletion : public RenderMessageCompletionCallback, + public net::CompletionCallback { public: - OpenChannelToPluginCallback(RenderMessageFilter* filter, - IPC::Message* reply_msg) - : filter_(filter), - reply_msg_(reply_msg) { + ClearCacheCompletion(RenderMessageFilter* filter, + IPC::Message* reply_msg) + : RenderMessageCompletionCallback(filter, reply_msg) { + } + + virtual void RunWithParams(const Tuple1<int>& params) { + ViewHostMsg_ClearCache::WriteReplyParams(reply_msg(), params.a); + SendReplyAndDeleteThis(); + } +}; + +class OpenChannelToNpapiPluginCallback : public RenderMessageCompletionCallback, + public PluginProcessHost::Client { + public: + OpenChannelToNpapiPluginCallback(RenderMessageFilter* filter, + IPC::Message* reply_msg) + : RenderMessageCompletionCallback(filter, reply_msg) { } virtual int ID() { - return filter_->render_process_id(); + return filter()->render_process_id(); } virtual bool OffTheRecord() { - return filter_->off_the_record(); + return filter()->off_the_record(); } virtual void SetPluginInfo(const webkit::npapi::WebPluginInfo& info) { @@ -207,27 +230,45 @@ class OpenChannelToPluginCallback : public PluginProcessHost::Client { } virtual void OnChannelOpened(const IPC::ChannelHandle& handle) { - WriteReply(handle); + WriteReplyAndDeleteThis(handle); } virtual void OnError() { - WriteReply(IPC::ChannelHandle()); + WriteReplyAndDeleteThis(IPC::ChannelHandle()); } private: - void WriteReply(const IPC::ChannelHandle& handle) { - ViewHostMsg_OpenChannelToPlugin::WriteReplyParams(reply_msg_, - handle, - info_); - filter_->Send(reply_msg_); - delete this; + void WriteReplyAndDeleteThis(const IPC::ChannelHandle& handle) { + ViewHostMsg_OpenChannelToPlugin::WriteReplyParams(reply_msg(), + handle, info_); + SendReplyAndDeleteThis(); } - scoped_refptr<RenderMessageFilter> filter_; - IPC::Message* reply_msg_; webkit::npapi::WebPluginInfo info_; }; +class OpenChannelToPpapiPluginCallback : public RenderMessageCompletionCallback, + public PpapiPluginProcessHost::Client { + public: + OpenChannelToPpapiPluginCallback(RenderMessageFilter* filter, + IPC::Message* reply_msg) + : RenderMessageCompletionCallback(filter, reply_msg) { + } + + 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) { + ViewHostMsg_OpenChannelToPepperPlugin::WriteReplyParams( + reply_msg(), plugin_process_handle, channel_handle); + SendReplyAndDeleteThis(); + } +}; + } // namespace RenderMessageFilter::RenderMessageFilter( @@ -719,17 +760,16 @@ void RenderMessageFilter::OnOpenChannelToPlugin(int routing_id, const GURL& url, const std::string& mime_type, IPC::Message* reply_msg) { - plugin_service_->OpenChannelToPlugin( + plugin_service_->OpenChannelToNpapiPlugin( render_process_id_, routing_id, url, mime_type, - new OpenChannelToPluginCallback(this, reply_msg)); + new OpenChannelToNpapiPluginCallback(this, reply_msg)); } void RenderMessageFilter::OnOpenChannelToPepperPlugin( const FilePath& path, IPC::Message* reply_msg) { - PpapiPluginProcessHost* host = new PpapiPluginProcessHost(this); - host->Init(path, reply_msg); - ppapi_plugin_hosts_.push_back(linked_ptr<PpapiPluginProcessHost>(host)); + plugin_service_->OpenChannelToPpapiPlugin( + path, new OpenChannelToPpapiPluginCallback(this, reply_msg)); } void RenderMessageFilter::OnLaunchNaCl( @@ -1293,7 +1333,7 @@ void RenderMessageFilter::OnClearCache(IPC::Message* reply_msg) { http_transaction_factory()->GetCache()->GetCurrentBackend(); if (backend) { ClearCacheCompletion* callback = - new ClearCacheCompletion(reply_msg, this); + new ClearCacheCompletion(this, reply_msg); rv = backend->DoomAllEntries(callback); if (rv == net::ERR_IO_PENDING) { // The callback will send the reply. diff --git a/chrome/browser/renderer_host/render_message_filter.h b/chrome/browser/renderer_host/render_message_filter.h index d2901715..a0339de 100644 --- a/chrome/browser/renderer_host/render_message_filter.h +++ b/chrome/browser/renderer_host/render_message_filter.h @@ -34,7 +34,6 @@ struct FontDescriptor; class HostContentSettingsMap; class HostZoomMap; class NotificationsPrefsCache; -class PpapiPluginProcessHost; class Profile; class RenderWidgetHelper; class URLRequestContextGetter; @@ -410,9 +409,6 @@ class RenderMessageFilter : public BrowserMessageFilter, base::TimeTicks last_plugin_refresh_time_; // Initialized to 0. - // A list of all Ppapi plugin processes for this renderer. - std::vector<linked_ptr<PpapiPluginProcessHost> > ppapi_plugin_hosts_; - scoped_refptr<WebKitContext> webkit_context_; int render_process_id_; diff --git a/chrome/ppapi_plugin/ppapi_thread.cc b/chrome/ppapi_plugin/ppapi_thread.cc index 4e8c0c9..483863c 100644 --- a/chrome/ppapi_plugin/ppapi_thread.cc +++ b/chrome/ppapi_plugin/ppapi_thread.cc @@ -4,27 +4,33 @@ #include "chrome/ppapi_plugin/ppapi_thread.h" +#include <limits> + #include "base/process_util.h" +#include "base/rand_util.h" #include "chrome/common/child_process.h" #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_sync_channel.h" +#include "ppapi/c/pp_errors.h" #include "ppapi/c/ppp.h" #include "ppapi/proxy/plugin_dispatcher.h" #include "ppapi/proxy/ppapi_messages.h" -#if defined(OS_POSIX) -#include "base/eintr_wrapper.h" -#include "ipc/ipc_channel_posix.h" -#endif - PpapiThread::PpapiThread() -#if defined(OS_POSIX) - : renderer_fd_(-1) -#endif - { + : get_plugin_interface_(NULL), + local_pp_module_( + base::RandInt(0, std::numeric_limits<PP_Module>::max())) { } PpapiThread::~PpapiThread() { + if (library_.is_valid()) { + // The ShutdownModule function is optional. + pp::proxy::Dispatcher::ShutdownModuleFunc shutdown_module = + reinterpret_cast<pp::proxy::Dispatcher::ShutdownModuleFunc>( + library_.GetFunctionPointer("PPP_ShutdownModule")); + if (shutdown_module) + shutdown_module(); + } } // The "regular" ChildThread implements this function and does some standard @@ -37,37 +43,23 @@ PpapiThread::~PpapiThread() { bool PpapiThread::OnMessageReceived(const IPC::Message& msg) { IPC_BEGIN_MESSAGE_MAP(PpapiThread, msg) IPC_MESSAGE_HANDLER(PpapiMsg_LoadPlugin, OnMsgLoadPlugin) + IPC_MESSAGE_HANDLER(PpapiMsg_CreateChannel, OnMsgCreateChannel) IPC_END_MESSAGE_MAP() return true; } -void PpapiThread::OnMsgLoadPlugin(base::ProcessHandle host_process_handle, - const FilePath& path, - int renderer_id) { - IPC::ChannelHandle channel_handle; - if (!LoadPluginLib(host_process_handle, path) || - !SetupRendererChannel(renderer_id, &channel_handle)) { - // An empty channel handle indicates error. - Send(new PpapiHostMsg_PluginLoaded(IPC::ChannelHandle())); - return; - } - - Send(new PpapiHostMsg_PluginLoaded(channel_handle)); -} - -bool PpapiThread::LoadPluginLib(base::ProcessHandle host_process_handle, - const FilePath& path) { +void PpapiThread::OnMsgLoadPlugin(const FilePath& path) { base::ScopedNativeLibrary library(base::LoadNativeLibrary(path)); if (!library.is_valid()) - return false; + return; // Get the GetInterface function (required). - pp::proxy::Dispatcher::GetInterfaceFunc get_interface = + get_plugin_interface_ = reinterpret_cast<pp::proxy::Dispatcher::GetInterfaceFunc>( library.GetFunctionPointer("PPP_GetInterface")); - if (!get_interface) { + if (!get_plugin_interface_) { LOG(WARNING) << "No PPP_GetInterface in plugin library"; - return false; + return; } // Get the InitializeModule function (required). @@ -76,26 +68,42 @@ bool PpapiThread::LoadPluginLib(base::ProcessHandle host_process_handle, library.GetFunctionPointer("PPP_InitializeModule")); if (!init_module) { LOG(WARNING) << "No PPP_InitializeModule in plugin library"; - return false; + return; + } + int32_t init_error = init_module( + local_pp_module_, + &pp::proxy::PluginDispatcher::GetInterfaceFromDispatcher); + if (init_error != PP_OK) { + LOG(WARNING) << "InitModule failed with error " << init_error; + return; } - - // Get the ShutdownModule function (optional). - pp::proxy::Dispatcher::ShutdownModuleFunc shutdown_module = - reinterpret_cast<pp::proxy::Dispatcher::ShutdownModuleFunc>( - library.GetFunctionPointer("PPP_ShutdownModule")); library_.Reset(library.Release()); - dispatcher_.reset(new pp::proxy::PluginDispatcher( - host_process_handle, get_interface, init_module, shutdown_module)); - return true; } -bool PpapiThread::SetupRendererChannel(int renderer_id, +void PpapiThread::OnMsgCreateChannel(base::ProcessHandle host_process_handle, + int renderer_id) { + IPC::ChannelHandle channel_handle; + if (!library_.is_valid() || // Plugin couldn't be loaded. + !SetupRendererChannel(host_process_handle, renderer_id, + &channel_handle)) { + Send(new PpapiHostMsg_ChannelCreated(IPC::ChannelHandle())); + return; + } + + Send(new PpapiHostMsg_ChannelCreated(channel_handle)); +} + +bool PpapiThread::SetupRendererChannel(base::ProcessHandle host_process_handle, + int renderer_id, IPC::ChannelHandle* handle) { + pp::proxy::PluginDispatcher* dispatcher = new pp::proxy::PluginDispatcher( + host_process_handle, get_plugin_interface_); + IPC::ChannelHandle plugin_handle; plugin_handle.name = StringPrintf("%d.r%d", base::GetCurrentProcId(), renderer_id); - if (!dispatcher_->InitWithChannel( + if (!dispatcher->InitWithChannel( ChildProcess::current()->io_message_loop(), plugin_handle, false, ChildProcess::current()->GetShutDownEvent())) @@ -104,18 +112,9 @@ bool PpapiThread::SetupRendererChannel(int renderer_id, handle->name = plugin_handle.name; #if defined(OS_POSIX) // On POSIX, pass the renderer-side FD. - renderer_fd_ = dispatcher_->channel()->GetClientFileDescriptor(); - handle->socket = base::FileDescriptor(renderer_fd_, false); + handle->socket = base::FileDescriptor(dispatcher->GetRendererFD(), false); #endif + return true; } -#if defined(OS_POSIX) -void PpapiThread::CloseRendererFD() { - if (renderer_fd_ != -1) { - if (HANDLE_EINTR(close(renderer_fd_)) < 0) - PLOG(ERROR) << "close"; - renderer_fd_ = -1; - } -} -#endif diff --git a/chrome/ppapi_plugin/ppapi_thread.h b/chrome/ppapi_plugin/ppapi_thread.h index 08e62fc..32e45f5 100644 --- a/chrome/ppapi_plugin/ppapi_thread.h +++ b/chrome/ppapi_plugin/ppapi_thread.h @@ -12,6 +12,8 @@ #include "base/scoped_ptr.h" #include "build/build_config.h" #include "chrome/common/child_thread.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/proxy/dispatcher.h" class FilePath; @@ -35,35 +37,27 @@ class PpapiThread : public ChildThread { virtual bool OnMessageReceived(const IPC::Message& msg); // Message handlers. - void OnMsgLoadPlugin(base::ProcessHandle renderer_handle, - const FilePath& path, - int renderer_id); - - bool LoadPluginLib(base::ProcessHandle host_process_handle, - const FilePath& path); + void OnMsgLoadPlugin(const FilePath& path); + void OnMsgCreateChannel(base::ProcessHandle host_process_handle, + int renderer_id); // Sets up the channel to the given renderer. On success, returns true and // fills the given ChannelHandle with the information from the new channel. - bool SetupRendererChannel(int renderer_id, + bool SetupRendererChannel(base::ProcessHandle host_process_handle, + int renderer_id, IPC::ChannelHandle* handle); -#if defined(OS_POSIX) - // Close the plugin process' copy of the renderer's side of the plugin - // channel. This can be called after the renderer is known to have its own - // copy of renderer_fd_. - void CloseRendererFD(); -#endif - base::ScopedNativeLibrary library_; - scoped_ptr<pp::proxy::PluginDispatcher> dispatcher_; + pp::proxy::Dispatcher::GetInterfaceFunc get_plugin_interface_; -#if defined(OS_POSIX) - // FD for the renderer end of the socket. It is closed when the IPC layer - // indicates that the channel is connected, proving that the renderer has - // access to its side of the socket. - int renderer_fd_; -#endif + // Local concept of the module ID. Some functions take this. It's necessary + // for the in-process PPAPI to handle this properly, but for proxied it's + // unnecessary. The proxy talking to multiple renderers means that each + // renderer has a different idea of what the module ID is for this plugin. + // To force people to "do the right thing" we generate a random module ID + // and pass it around as necessary. + PP_Module local_pp_module_; DISALLOW_COPY_AND_ASSIGN(PpapiThread); }; diff --git a/chrome/renderer/pepper_plugin_delegate_impl.cc b/chrome/renderer/pepper_plugin_delegate_impl.cc index 87c8625..fd4a2dd 100644 --- a/chrome/renderer/pepper_plugin_delegate_impl.cc +++ b/chrome/renderer/pepper_plugin_delegate_impl.cc @@ -365,12 +365,6 @@ bool DispatcherWrapper::Init( dispatcher_.reset(); return false; } - - if (!dispatcher_->InitializeModule()) { - // TODO(brettw) does the module get unloaded in this case? - dispatcher_.reset(); - return false; - } return true; } diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 88df2cb..415dea3 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -5399,16 +5399,21 @@ const PPB_OpenGLES2_Dev* PPB_OpenGLES_Impl::GetInterface() { func.MakeOriginalArgString(""))) file.Write("}\n\n") - file.Write("const struct PPB_OpenGLES2_Dev ppb_opengles2 = {\n") + file.Write("const struct PPB_OpenGLES2_Dev opengles2_interface = {\n") file.Write(" &") file.Write(",\n &".join( f.name for f in self.original_functions if f.IsCoreGLFunction())) file.Write("\n") file.Write("};\n\n") - file.Write("} // namespace\n") - file.Write(""" +InterfaceProxy* CreateOpenGLES2Proxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_OpenGLES2_Proxy(dispatcher, target_interface); +} + +} // namespace + PPB_OpenGLES2_Proxy::PPB_OpenGLES2_Proxy(Dispatcher* dispatcher, const void* target_interface) : InterfaceProxy(dispatcher, target_interface) { @@ -5417,12 +5422,16 @@ PPB_OpenGLES2_Proxy::PPB_OpenGLES2_Proxy(Dispatcher* dispatcher, PPB_OpenGLES2_Proxy::~PPB_OpenGLES2_Proxy() { } -const void* PPB_OpenGLES2_Proxy::GetSourceInterface() const { - return &ppb_opengles2; -} - -InterfaceID PPB_OpenGLES2_Proxy::GetInterfaceId() const { - return INTERFACE_ID_NONE; +// static +const InterfaceProxy::Info* PPB_OpenGLES2_Proxy::GetInfo() { + static const Info info = { + &opengles2_interface, + PPB_OPENGLES2_DEV_INTERFACE, + INTERFACE_ID_PPB_OPENGLES2, + false, + &CreateOpenGLES2Proxy, + }; + return &info; } bool PPB_OpenGLES2_Proxy::OnMessageReceived(const IPC::Message& msg) { diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index 13cf792..953b22d 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.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. diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h index e69b7ee..2dc0687 100644 --- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.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. diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 0b27f6c..a8fcfa0 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.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. diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h index 22fb23a..8a37edb 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.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. diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h index e62ca7c..fcada01 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.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. diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h index fafbada..f4e0e9e 100644 --- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.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. diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index 60bf9ed..78bf68d 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.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. diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h index cd4c33d..0607a02 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.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. diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h index 7549fa9e..50715df 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.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. diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h index c528c1b..46da61e 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.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. diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h index 6a81894..f4ef6d8 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.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. diff --git a/ppapi/proxy/host_dispatcher.cc b/ppapi/proxy/host_dispatcher.cc index 7978786..fce2b13 100644 --- a/ppapi/proxy/host_dispatcher.cc +++ b/ppapi/proxy/host_dispatcher.cc @@ -36,14 +36,6 @@ HostDispatcher::HostDispatcher(base::ProcessHandle remote_process_handle, } HostDispatcher::~HostDispatcher() { - // Notify the plugin that it should exit. - Send(new PpapiMsg_Shutdown()); -} - -bool HostDispatcher::InitializeModule() { - bool init_result = false; - Send(new PpapiMsg_InitializeModule(pp_module(), &init_result)); - return init_result; } // static @@ -116,6 +108,10 @@ bool HostDispatcher::OnMessageReceived(const IPC::Message& msg) { return proxy->OnMessageReceived(msg); } +void HostDispatcher::OnChannelError() { + // TODO(brettw) plugin has crashed, handle this. +} + const void* HostDispatcher::GetProxiedInterface(const std::string& interface) { // First see if we even have a proxy for this interface. const InterfaceProxy::Info* info = GetPPPInterfaceInfo(interface); diff --git a/ppapi/proxy/host_dispatcher.h b/ppapi/proxy/host_dispatcher.h index f405f71..e38fca6 100644 --- a/ppapi/proxy/host_dispatcher.h +++ b/ppapi/proxy/host_dispatcher.h @@ -48,15 +48,12 @@ class HostDispatcher : public Dispatcher { HostDispatcher* dispatcher); static void RemoveForInstance(PP_Instance instance); - // Calls the plugin's PPP_InitializeModule function and returns true if - // the call succeeded. - bool InitializeModule(); - // Dispatcher overrides. virtual bool IsPlugin() const; // IPC::Channel::Listener. virtual bool OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelError(); // Proxied version of calling GetInterface on the plugin. This will check // if the plugin supports the given interface (with caching) and returns the diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc index b30f6da..1f4454c 100644 --- a/ppapi/proxy/plugin_dispatcher.cc +++ b/ppapi/proxy/plugin_dispatcher.cc @@ -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. @@ -16,6 +16,11 @@ #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/ppp_class_proxy.h" +#if defined(OS_POSIX) +#include "base/eintr_wrapper.h" +#include "ipc/ipc_channel_posix.h" +#endif + namespace pp { namespace proxy { @@ -24,23 +29,15 @@ namespace { typedef std::map<PP_Instance, PluginDispatcher*> InstanceToDispatcherMap; InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; -const void* GetInterfaceFromDispatcher(const char* interface) { - // All interfaces the plugin requests of the browser are "PPB". - const InterfaceProxy::Info* info = Dispatcher::GetPPBInterfaceInfo(interface); - if (!info) - return NULL; - return info->interface; -} - } // namespace PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, - GetInterfaceFunc get_interface, - InitModuleFunc init_module, - ShutdownModuleFunc shutdown_module) - : Dispatcher(remote_process_handle, get_interface), - init_module_(init_module), - shutdown_module_(shutdown_module) { + GetInterfaceFunc get_interface) + : Dispatcher(remote_process_handle, get_interface) +#if defined(OS_POSIX) + , renderer_fd_(-1) +#endif + { SetSerializationRules(new PluginVarSerializationRules); // As a plugin, we always support the PPP_Class interface. There's no @@ -49,8 +46,9 @@ PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, } PluginDispatcher::~PluginDispatcher() { - if (shutdown_module_) - shutdown_module_(); +#if defined(OS_POSIX) + CloseRendererFD(); +#endif } // static @@ -64,6 +62,16 @@ PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) { return found->second; } +// static +const void* PluginDispatcher::GetInterfaceFromDispatcher( + const char* interface) { + // All interfaces the plugin requests of the browser are "PPB". + const InterfaceProxy::Info* info = GetPPBInterfaceInfo(interface); + if (!info) + return NULL; + return info->interface; +} + bool PluginDispatcher::IsPlugin() const { return true; } @@ -78,8 +86,6 @@ bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) - IPC_MESSAGE_HANDLER(PpapiMsg_InitializeModule, OnMsgInitializeModule) - IPC_MESSAGE_HANDLER(PpapiMsg_Shutdown, OnMsgShutdown) IPC_END_MESSAGE_MAP() return handled; } @@ -122,6 +128,14 @@ bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { return proxy->OnMessageReceived(msg); } +void PluginDispatcher::OnChannelError() { + // The renderer has crashed. This channel and all instances associated with + // it are no longer valid. + ForceFreeAllInstances(); + // TODO(brettw) free resources too! + delete this; +} + void PluginDispatcher::DidCreateInstance(PP_Instance instance) { if (!g_instance_to_dispatcher) g_instance_to_dispatcher = new InstanceToDispatcherMap; @@ -152,16 +166,24 @@ InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) { return (it == instance_map_.end()) ? NULL : &it->second; } -void PluginDispatcher::OnMsgInitializeModule(PP_Module pp_module, - bool* result) { - set_pp_module(pp_module); - *result = init_module_(pp_module, &GetInterfaceFromDispatcher) == PP_OK; +#if defined(OS_POSIX) +int PluginDispatcher::GetRendererFD() { + if (renderer_fd_ == -1) + renderer_fd_ = channel()->GetClientFileDescriptor(); + return renderer_fd_; +} + +void PluginDispatcher::CloseRendererFD() { + if (renderer_fd_ != -1) { + if (HANDLE_EINTR(close(renderer_fd_)) < 0) + PLOG(ERROR) << "close"; + renderer_fd_ = -1; + } } +#endif -void PluginDispatcher::OnMsgShutdown() { - if (shutdown_module_) - shutdown_module_(); - MessageLoop::current()->Quit(); +void PluginDispatcher::ForceFreeAllInstances() { + // TODO(brettw) implement freeing instances on crash. } void PluginDispatcher::OnMsgSupportsInterface( diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h index 8f27ac0..0b219f4 100644 --- a/ppapi/proxy/plugin_dispatcher.h +++ b/ppapi/proxy/plugin_dispatcher.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. @@ -10,6 +10,7 @@ #include "base/hash_tables.h" #include "base/process.h" #include "base/scoped_ptr.h" +#include "build/build_config.h" #include "ppapi/c/pp_rect.h" #include "ppapi/c/pp_instance.h" #include "ppapi/proxy/dispatcher.h" @@ -36,9 +37,7 @@ class PluginDispatcher : public Dispatcher { // // You must call Dispatcher::InitWithChannel after the constructor. PluginDispatcher(base::ProcessHandle remote_process_handle, - GetInterfaceFunc get_interface, - InitModuleFunc init_module, - ShutdownModuleFunc shutdown_module); + GetInterfaceFunc get_interface); ~PluginDispatcher(); // The plugin side maintains a mapping from PP_Instance to Dispatcher so @@ -47,11 +46,14 @@ class PluginDispatcher : public Dispatcher { // DidCreateInstance/DidDestroyInstance. static PluginDispatcher* GetForInstance(PP_Instance instance); + static const void* GetInterfaceFromDispatcher(const char* interface); + // Dispatcher overrides. virtual bool IsPlugin() const; // IPC::Channel::Listener implementation. virtual bool OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelError(); // Keeps track of which dispatcher to use for each instance, active instances // and tracks associated data like the current size. @@ -62,16 +64,28 @@ class PluginDispatcher : public Dispatcher { // correspond to a known instance. InstanceData* GetInstanceData(PP_Instance instance); +#if defined(OS_POSIX) + // See renderer_fd_ below. + int GetRendererFD(); + void CloseRendererFD(); +#endif + private: friend class PluginDispatcherTest; + // Notifies all live instances that they're now closed. This is used when + // a renderer crashes or some other error is received. + void ForceFreeAllInstances(); + // IPC message handlers. - void OnMsgInitializeModule(PP_Module pp_module, bool* result); - void OnMsgShutdown(); void OnMsgSupportsInterface(const std::string& interface_name, bool* result); - InitModuleFunc init_module_; - ShutdownModuleFunc shutdown_module_; +#if defined(OS_POSIX) + // FD for the renderer end of the socket. It is closed when the IPC layer + // indicates that the channel is connected, proving that the renderer has + // access to its side of the socket. + int renderer_fd_; +#endif // All target proxies currently created. These are ones that receive // messages. diff --git a/ppapi/proxy/ppapi_messages_internal.h b/ppapi/proxy/ppapi_messages_internal.h index b181b2e..7cab708 100644 --- a/ppapi/proxy/ppapi_messages_internal.h +++ b/ppapi/proxy/ppapi_messages_internal.h @@ -12,16 +12,13 @@ // These are from the plugin to the renderer // Loads the given plugin. -IPC_MESSAGE_CONTROL3(PpapiMsg_LoadPlugin, - base::ProcessHandle /* host_process_handle */, - FilePath /* path */, - int /* renderer_id */) - -IPC_SYNC_MESSAGE_CONTROL1_1(PpapiMsg_InitializeModule, - PP_Module /* module_id */, - bool /* result */) +IPC_MESSAGE_CONTROL1(PpapiMsg_LoadPlugin, FilePath /* path */) -IPC_MESSAGE_CONTROL0(PpapiMsg_Shutdown) +// Creates a channel to talk to a renderer. The plugin will respond with +// PpapiHostMsg_ChannelCreated. +IPC_MESSAGE_CONTROL2(PpapiMsg_CreateChannel, + base::ProcessHandle /* host_process_handle */, + int /* renderer_id */); // Sent in both directions to see if the other side supports the given // interface. @@ -152,8 +149,12 @@ IPC_MESSAGE_ROUTED3(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack, // ----------------------------------------------------------------------------- // These are from the plugin to the renderer. -// Reply to PpapiMsg_LoadPlugin. -IPC_MESSAGE_CONTROL1(PpapiHostMsg_PluginLoaded, + +// Reply to PpapiMsg_CreateChannel. The handle will be NULL if the channel +// could not be established. This could be because the IPC could not be created +// for some weird reason, but more likely that the plugin failed to load or +// initialize properly. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_ChannelCreated, IPC::ChannelHandle /* handle */) // PPB_Audio. diff --git a/ppapi/proxy/ppapi_proxy_test.cc b/ppapi/proxy/ppapi_proxy_test.cc index 1b75001..fffb20c 100644 --- a/ppapi/proxy/ppapi_proxy_test.cc +++ b/ppapi/proxy/ppapi_proxy_test.cc @@ -94,9 +94,7 @@ void PluginProxyTest::SetUp() { plugin_dispatcher_.reset(new PluginDispatcher( base::Process::Current().handle(), - &MockGetInterface, - &MockInitModule, - &MockShutdownModuleFunc)); + &MockGetInterface)); plugin_dispatcher_->InitWithTestSink(&sink()); plugin_dispatcher_->DidCreateInstance(pp_instance()); } |