diff options
author | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-27 18:05:15 +0000 |
---|---|---|
committer | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-27 18:05:15 +0000 |
commit | 4912595f15ad54608207cbacaeeb085cf542e539 (patch) | |
tree | 0d32785d543ed97e3999673eda92fe81323773ef /content | |
parent | 6c36f5e4b14f45fd54d60fa9abe7fc99c749eb49 (diff) | |
download | chromium_src-4912595f15ad54608207cbacaeeb085cf542e539.zip chromium_src-4912595f15ad54608207cbacaeeb085cf542e539.tar.gz chromium_src-4912595f15ad54608207cbacaeeb085cf542e539.tar.bz2 |
Move plugin loading out of process on Mac and Linux.
This creates a new set of IPC messages for the utility process to load plugins
to get the WebPluginInfo data in a separate process. Previously this was done
in the browser process, but that involves loading arbitrary third-party code
into the address space and then executing it.
BUG=17863,95114
TEST=Plugins work as before.
Review URL: http://codereview.chromium.org/7889025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@102971 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r-- | content/browser/plugin_service.cc | 95 | ||||
-rw-r--r-- | content/browser/utility_process_host.cc | 15 | ||||
-rw-r--r-- | content/browser/utility_process_host.h | 10 | ||||
-rw-r--r-- | content/common/utility_messages.h | 16 | ||||
-rw-r--r-- | content/utility/utility_thread.cc | 39 | ||||
-rw-r--r-- | content/utility/utility_thread.h | 12 |
6 files changed, 178 insertions, 9 deletions
diff --git a/content/browser/plugin_service.cc b/content/browser/plugin_service.cc index 6be232a..873e55a 100644 --- a/content/browser/plugin_service.cc +++ b/content/browser/plugin_service.cc @@ -23,11 +23,13 @@ #include "content/browser/renderer_host/render_process_host.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/resource_context.h" +#include "content/browser/utility_process_host.h" #include "content/common/content_notification_types.h" #include "content/common/content_switches.h" #include "content/common/notification_service.h" #include "content/common/pepper_plugin_registry.h" #include "content/common/plugin_messages.h" +#include "content/common/utility_messages.h" #include "content/common/view_messages.h" #include "webkit/plugins/npapi/plugin_constants_win.h" #include "webkit/plugins/npapi/plugin_group.h" @@ -60,6 +62,76 @@ static void GetPluginsForGroupsCallback( callback.Run(groups); } +// Callback set on the PluginList to assert that plugin loading happens on the +// correct thread. +void WillLoadPluginsCallback() { + // TODO(rsesek): Change these to CHECKs. +#if defined(OS_WIN) + LOG_IF(ERROR, !BrowserThread::CurrentlyOn(BrowserThread::FILE)); +#else + LOG(ERROR) << "Plugin loading should happen out-of-process."; +#endif +} + +#if defined(OS_POSIX) +// Utility child process client that manages the IPC for loading plugins out of +// process. +class PluginLoaderClient : public UtilityProcessHost::Client { + public: + // Meant to be called on the IO thread. Will invoke the callback on the target + // loop when the plugins have been loaded. + static void LoadPluginsOutOfProcess( + base::MessageLoopProxy* target_loop, + const PluginService::GetPluginsCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + PluginLoaderClient* client = new PluginLoaderClient(target_loop, callback); + UtilityProcessHost* process_host = + new UtilityProcessHost(client, BrowserThread::IO); + process_host->set_no_sandbox(true); +#if defined(OS_MACOSX) + process_host->set_child_flags(ChildProcessHost::CHILD_ALLOW_HEAP_EXECUTION); +#endif + + std::vector<FilePath> extra_plugin_paths; + std::vector<FilePath> extra_plugin_dirs; + std::vector<webkit::WebPluginInfo> internal_plugins; + webkit::npapi::PluginList::Singleton()->GetPluginPathListsToLoad( + &extra_plugin_paths, &extra_plugin_dirs, &internal_plugins); + + process_host->Send(new UtilityMsg_LoadPlugins( + extra_plugin_paths, extra_plugin_dirs, internal_plugins)); + } + + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PluginLoaderClient, message) + IPC_MESSAGE_HANDLER(UtilityHostMsg_LoadedPlugins, OnGotPlugins) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; + } + + virtual void OnGotPlugins(const std::vector<webkit::WebPluginInfo>& plugins) { + webkit::npapi::PluginList::Singleton()->SetPlugins(plugins); + target_loop_->PostTask(FROM_HERE, + base::Bind(&RunGetPluginsCallback, callback_, plugins)); + } + + private: + PluginLoaderClient(base::MessageLoopProxy* target_loop, + const PluginService::GetPluginsCallback& callback) + : target_loop_(target_loop), + callback_(callback) { + } + + scoped_refptr<base::MessageLoopProxy> target_loop_; + PluginService::GetPluginsCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(PluginLoaderClient); +}; +#endif // OS_POSIX + } // namespace #if defined(OS_MACOSX) @@ -97,6 +169,9 @@ PluginService::PluginService() : ui_locale_( content::GetContentClient()->browser()->GetApplicationLocale()), filter_(NULL) { + webkit::npapi::PluginList::Singleton()->set_will_load_plugins_callback( + base::Bind(&WillLoadPluginsCallback)); + RegisterPepperPlugins(); // Load any specified on the command line as well. @@ -448,10 +523,26 @@ void PluginService::RefreshPluginList() { } void PluginService::GetPlugins(const GetPluginsCallback& callback) { + scoped_refptr<base::MessageLoopProxy> target_loop( + MessageLoop::current()->message_loop_proxy()); + +#if defined(OS_WIN) BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(&PluginService::GetPluginsInternal, base::Unretained(this), - MessageLoop::current()->message_loop_proxy(), - callback)); + target_loop, callback)); +#else + std::vector<webkit::WebPluginInfo> cached_plugins; + if (webkit::npapi::PluginList::Singleton()->GetPluginsIfNoRefreshNeeded( + &cached_plugins)) { + // Can't assume the caller is reentrant. + target_loop->PostTask(FROM_HERE, + base::Bind(&RunGetPluginsCallback, callback, cached_plugins)); + } else { + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&PluginLoaderClient::LoadPluginsOutOfProcess, + target_loop, callback)); + } +#endif } void PluginService::GetPluginGroups(const GetPluginGroupsCallback& callback) { diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc index c62ec3e..d7f57f3 100644 --- a/content/browser/utility_process_host.cc +++ b/content/browser/utility_process_host.cc @@ -33,6 +33,12 @@ UtilityProcessHost::UtilityProcessHost(Client* client, client_(client), client_thread_id_(client_thread_id), is_batch_mode_(false), + no_sandbox_(false), +#if defined(OS_LINUX) + child_flags_(CHILD_ALLOW_SELF), +#else + child_flags_(CHILD_NORMAL), +#endif started_(false) { } @@ -61,12 +67,7 @@ void UtilityProcessHost::EndBatchMode() { } FilePath UtilityProcessHost::GetUtilityProcessCmd() { -#if defined(OS_LINUX) - int flags = CHILD_ALLOW_SELF; -#else - int flags = CHILD_NORMAL; -#endif - return GetChildPath(flags); + return GetChildPath(child_flags_); } bool UtilityProcessHost::StartProcess() { @@ -100,7 +101,7 @@ bool UtilityProcessHost::StartProcess() { const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); if (browser_command_line.HasSwitch(switches::kChromeFrame)) cmd_line->AppendSwitch(switches::kChromeFrame); - if (browser_command_line.HasSwitch(switches::kNoSandbox)) + if (no_sandbox_ || browser_command_line.HasSwitch(switches::kNoSandbox)) cmd_line->AppendSwitch(switches::kNoSandbox); #if defined(OS_POSIX) diff --git a/content/browser/utility_process_host.h b/content/browser/utility_process_host.h index 9018818..69389a2 100644 --- a/content/browser/utility_process_host.h +++ b/content/browser/utility_process_host.h @@ -63,6 +63,10 @@ class CONTENT_EXPORT UtilityProcessHost : public BrowserChildProcessHost { void set_exposed_dir(const FilePath& dir) { exposed_dir_ = dir; } + void set_no_sandbox(bool flag) { no_sandbox_ = flag; } + + void set_child_flags(int flags) { child_flags_ = flags; } + protected: // Allow these methods to be overridden for tests. virtual FilePath GetUtilityProcessCmd(); @@ -90,6 +94,12 @@ class CONTENT_EXPORT UtilityProcessHost : public BrowserChildProcessHost { // the operation. FilePath exposed_dir_; + // Whether to pass switches::kNoSandbox to the child. + bool no_sandbox_; + + // Flags defined in ChildProcessHost with which to start the process. + int child_flags_; + bool started_; DISALLOW_COPY_AND_ASSIGN(UtilityProcessHost); diff --git a/content/common/utility_messages.h b/content/common/utility_messages.h index 9d7d78b..6b54221 100644 --- a/content/common/utility_messages.h +++ b/content/common/utility_messages.h @@ -13,6 +13,7 @@ #include "content/common/indexed_db_param_traits.h" #include "content/common/serialized_script_value.h" #include "ipc/ipc_message_macros.h" +#include "webkit/plugins/webplugininfo.h" #define IPC_MESSAGE_START UtilityMsgStart @@ -38,6 +39,14 @@ IPC_MESSAGE_CONTROL0(UtilityMsg_BatchMode_Started) // Tells the utility process that it can shutdown. IPC_MESSAGE_CONTROL0(UtilityMsg_BatchMode_Finished) +#if defined(OS_POSIX) +// Tells the utility process to load the plugins from disk and send a list of +// WebPluginInfo objects back. +IPC_MESSAGE_CONTROL3(UtilityMsg_LoadPlugins, + std::vector<FilePath>, /* extra plugin paths */ + std::vector<FilePath>, /* extra plugin dirs */ + std::vector<webkit::WebPluginInfo> /* internal plugins */) +#endif //------------------------------------------------------------------------------ // Utility process host messages: @@ -58,3 +67,10 @@ IPC_MESSAGE_CONTROL1(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Failed, // a SerializedScriptValue. IPC_MESSAGE_CONTROL1(UtilityHostMsg_InjectIDBKey_Finished, SerializedScriptValue /* new value */) + +#if defined(OS_POSIX) +// After loading plugins from disk and querying each for MIME information, this +// sends the resulting WebPluginInfo back to the browser process. +IPC_MESSAGE_CONTROL1(UtilityHostMsg_LoadedPlugins, + std::vector<webkit::WebPluginInfo> /* plugin infos */) +#endif // OS_POSIX diff --git a/content/utility/utility_thread.cc b/content/utility/utility_thread.cc index ac6c312..a642ea1 100644 --- a/content/utility/utility_thread.cc +++ b/content/utility/utility_thread.cc @@ -6,6 +6,7 @@ #include <stddef.h> +#include "base/file_path.h" #include "content/common/child_process.h" #include "content/common/indexed_db_key.h" #include "content/common/utility_messages.h" @@ -15,6 +16,7 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebSerializedScriptValue.h" #include "webkit/glue/idb_bindings.h" #include "webkit/glue/webkitplatformsupport_impl.h" +#include "webkit/plugins/npapi/plugin_list.h" namespace { @@ -50,6 +52,9 @@ bool UtilityThread::OnControlMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(UtilityMsg_InjectIDBKey, OnInjectIDBKey) IPC_MESSAGE_HANDLER(UtilityMsg_BatchMode_Started, OnBatchModeStarted) IPC_MESSAGE_HANDLER(UtilityMsg_BatchMode_Finished, OnBatchModeFinished) +#if defined(OS_POSIX) + IPC_MESSAGE_HANDLER(UtilityMsg_LoadPlugins, OnLoadPlugins) +#endif // OS_POSIX IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -91,6 +96,40 @@ void UtilityThread::OnBatchModeFinished() { ChildProcess::current()->ReleaseProcess(); } +#if defined(OS_POSIX) +void UtilityThread::OnLoadPlugins( + const std::vector<FilePath>& extra_plugin_paths, + const std::vector<FilePath>& extra_plugin_dirs, + const std::vector<webkit::WebPluginInfo>& internal_plugins) { + webkit::npapi::PluginList* plugin_list = + webkit::npapi::PluginList::Singleton(); + + // Create the PluginList and set the paths from which to load plugins. Iterate + // in reverse to preserve the order when pushing back. + std::vector<FilePath>::const_reverse_iterator it; + for (it = extra_plugin_paths.rbegin(); + it != extra_plugin_paths.rend(); + ++it) { + plugin_list->AddExtraPluginPath(*it); + } + for (it = extra_plugin_dirs.rbegin(); it != extra_plugin_dirs.rend(); ++it) { + plugin_list->AddExtraPluginDir(*it); + } + for (std::vector<webkit::WebPluginInfo>::const_reverse_iterator it = + internal_plugins.rbegin(); + it != internal_plugins.rend(); + ++it) { + plugin_list->RegisterInternalPlugin(*it); + } + + std::vector<webkit::WebPluginInfo> plugins; + plugin_list->GetPlugins(&plugins); + + Send(new UtilityHostMsg_LoadedPlugins(plugins)); + UtilityThread::current()->ReleaseProcessIfNeeded(); +} +#endif + void UtilityThread::ReleaseProcessIfNeeded() { if (!batch_mode_) ChildProcess::current()->ReleaseProcess(); diff --git a/content/utility/utility_thread.h b/content/utility/utility_thread.h index bc19482..8489a65 100644 --- a/content/utility/utility_thread.h +++ b/content/utility/utility_thread.h @@ -15,9 +15,14 @@ #include "content/common/child_thread.h" #include "content/common/content_export.h" +class FilePath; class IndexedDBKey; class SerializedScriptValue; +namespace webkit { +struct WebPluginInfo; +} + namespace webkit_glue { class WebKitPlatformSupportImpl; } @@ -51,6 +56,13 @@ class UtilityThread : public ChildThread { void OnBatchModeStarted(); void OnBatchModeFinished(); +#if defined(OS_POSIX) + void OnLoadPlugins( + const std::vector<FilePath>& extra_plugin_paths, + const std::vector<FilePath>& extra_plugin_dirs, + const std::vector<webkit::WebPluginInfo>& internal_plugins); +#endif // OS_POSIX + // True when we're running in batch mode. bool batch_mode_; |