diff options
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser.vcproj | 8 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service.cc | 230 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service.h | 40 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service_unittest.cc | 14 | ||||
-rw-r--r-- | chrome/browser/sandbox_policy.cc | 23 | ||||
-rw-r--r-- | chrome/browser/sandbox_policy.h | 6 | ||||
-rw-r--r-- | chrome/browser/utility_process_host.cc | 87 | ||||
-rw-r--r-- | chrome/browser/utility_process_host.h | 79 |
8 files changed, 389 insertions, 98 deletions
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj index 07b0fb27c..bb869e6 100644 --- a/chrome/browser/browser.vcproj +++ b/chrome/browser/browser.vcproj @@ -2734,6 +2734,14 @@ RelativePath=".\toolbar_model.h" > </File> + <File + RelativePath=".\utility_process_host.cc" + > + </File> + <File + RelativePath=".\utility_process_host.h" + > + </File> </Files> <Globals> </Globals> diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index 05815a3..23c37fe 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -16,6 +16,7 @@ #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/chrome_thread.h" #include "chrome/browser/extensions/extension.h" #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extension_error_reporter.h" @@ -23,6 +24,8 @@ #include "chrome/browser/extensions/user_script_master.h" #include "chrome/browser/plugin_service.h" #include "chrome/browser/profile.h" +#include "chrome/browser/utility_process_host.h" +#include "chrome/common/extensions/extension_unpacker.h" #include "chrome/common/json_value_serializer.h" #include "chrome/common/notification_service.h" #include "chrome/common/unzip.h" @@ -69,15 +72,117 @@ const wchar_t kRegistryExtensionVersion[] = L"version"; // source. const char kExternalInstallFile[] = "EXTERNAL_INSTALL"; +// A temporary subdirectory where we unpack extensions. +const char* kUnpackExtensionDir = "TEMP_UNPACK"; + // The version of the extension package that this code understands. const uint32 kExpectedVersion = 1; } +// This class coordinates an extension unpack task which is run in a separate +// process. Results are sent back to this class, which we route to the +// ExtensionServiceBackend. +class ExtensionsServiceBackend::UnpackerClient + : public UtilityProcessHost::Client { + public: + UnpackerClient(ExtensionsServiceBackend* backend, + const FilePath& extension_path, + const std::string& expected_id, + bool from_external) + : backend_(backend), extension_path_(extension_path), + expected_id_(expected_id), from_external_(from_external) { + } + + // Starts the unpack task. We call back to the backend when the task is done, + // or a problem occurs. + void Start() { + AddRef(); // balanced in OnUnpackExtensionReply() + + // TODO(mpcomplete): handle multiple installs + FilePath temp_dir = backend_->install_directory_.AppendASCII( + kUnpackExtensionDir); + if (!file_util::CreateDirectory(temp_dir)) { + backend_->ReportExtensionInstallError(extension_path_, + "Failed to create temporary directory."); + return; + } + + temp_extension_path_ = temp_dir.Append(extension_path_.BaseName()); + if (!file_util::CopyFile(extension_path_, temp_extension_path_)) { + backend_->ReportExtensionInstallError(extension_path_, + "Failed to copy extension file to temporary directory."); + return; + } + + if (backend_->resource_dispatcher_host_) { + ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask(FROM_HERE, + NewRunnableMethod(this, &UnpackerClient::StartProcessOnIOThread, + backend_->resource_dispatcher_host_, + MessageLoop::current())); + } else { + // Cheesy... but if we don't have a ResourceDispatcherHost, assume we're + // in a unit test and run the unpacker directly in-process. + ExtensionUnpacker unpacker(temp_extension_path_); + bool success = unpacker.Run(); + OnUnpackExtensionReply(success, unpacker.error_message()); + } + } + + private: + // UtilityProcessHost::Client + virtual void OnProcessCrashed() { + OnUnpackExtensionReply(false, "Chrome crashed while trying to install"); + } + + virtual void OnUnpackExtensionReply(bool success, + const std::string& error_message) { + if (success) { + // The extension was unpacked to the temp dir inside our unpacking dir. + FilePath extension_dir = temp_extension_path_.DirName().AppendASCII( + ExtensionsServiceBackend::kTempExtensionName); + backend_->OnExtensionUnpacked(extension_path_, extension_dir, + expected_id_, from_external_); + } else { + backend_->ReportExtensionInstallError(extension_path_, error_message); + } + Cleanup(); + Release(); // balanced in Run() + } + + // Cleans up our temp directory. + void Cleanup() { + file_util::Delete(temp_extension_path_.DirName(), true); + } + + // Starts the utility process that unpacks our extension. + void StartProcessOnIOThread(ResourceDispatcherHost* rdh, + MessageLoop* file_loop) { + UtilityProcessHost* host = new UtilityProcessHost(rdh, this, file_loop); + host->StartExtensionUnpacker(temp_extension_path_); + } + + scoped_refptr<ExtensionsServiceBackend> backend_; + + // The path to the crx file that we're installing. + FilePath extension_path_; + + // The path to the copy of the crx file in the temporary directory where we're + // unpacking it. + FilePath temp_extension_path_; + + // The ID we expect this extension to have, if any. + std::string expected_id_; + + // True if this is being installed from an external source. + bool from_external_; +}; + ExtensionsService::ExtensionsService(Profile* profile, UserScriptMaster* user_script_master) : message_loop_(MessageLoop::current()), install_directory_(profile->GetPath().AppendASCII(kInstallDirectoryName)), - backend_(new ExtensionsServiceBackend(install_directory_)), + backend_(new ExtensionsServiceBackend( + install_directory_, g_browser_process->resource_dispatcher_host())), user_script_master_(user_script_master) { } @@ -677,100 +782,80 @@ void ExtensionsServiceBackend::InstallExtension( frontend_ = frontend; alert_on_error_ = false; - bool was_update = false; - FilePath destination_path; - if (InstallOrUpdateExtension(extension_path, - std::string(), // no expected id - &destination_path, &was_update)) - ReportExtensionInstalled(destination_path.DirName(), was_update); + bool from_external = false; + InstallOrUpdateExtension(extension_path, std::string(), from_external); } -bool ExtensionsServiceBackend::InstallOrUpdateExtension( - const FilePath& source_file, const std::string& expected_id, - FilePath* version_dir, bool* was_update) { - if (was_update) - *was_update = false; +void ExtensionsServiceBackend::InstallOrUpdateExtension( + const FilePath& extension_path, const std::string& expected_id, + bool from_external) { + UnpackerClient* client = + new UnpackerClient(this, extension_path, expected_id, from_external); + client->Start(); +} - // Read and verify the extension. - scoped_ptr<DictionaryValue> manifest(ReadManifest(source_file)); +void ExtensionsServiceBackend::OnExtensionUnpacked( + const FilePath& extension_path, + const FilePath& temp_extension_dir, + const std::string expected_id, + bool from_external) { + // TODO(mpcomplete): the utility process should pass up a parsed manifest that + // we rewrite in the browser. + // Bug http://code.google.com/p/chromium/issues/detail?id=11680 + scoped_ptr<DictionaryValue> manifest(ReadManifest(extension_path)); if (!manifest.get()) { // ReadManifest has already reported the extension error. - return false; + return; } - DictionaryValue* dict = manifest.get(); + Extension extension; std::string error; - if (!extension.InitFromValue(*dict, + if (!extension.InitFromValue(*manifest, true, // require ID &error)) { - ReportExtensionInstallError(source_file, - "Invalid extension manifest."); - return false; - } - - // ID is required for installed extensions. - if (extension.id().empty()) { - ReportExtensionInstallError(source_file, "Required value 'id' is missing."); - return false; + ReportExtensionInstallError(extension_path, "Invalid extension manifest."); + return; } // If an expected id was provided, make sure it matches. - if (expected_id.length() && expected_id != extension.id()) { - ReportExtensionInstallError(source_file, + if (!expected_id.empty() && expected_id != extension.id()) { + ReportExtensionInstallError(extension_path, "ID in new extension manifest does not match expected ID."); - return false; + return; } // <profile>/Extensions/<id> FilePath dest_dir = install_directory_.AppendASCII(extension.id()); std::string version = extension.VersionString(); std::string current_version; + bool was_update = false; if (ReadCurrentVersion(dest_dir, ¤t_version)) { if (!CheckCurrentVersion(version, current_version, dest_dir)) - return false; - if (was_update) - *was_update = true; - } - - // <profile>/Extensions/INSTALL_TEMP - FilePath temp_dir = install_directory_.AppendASCII(kTempExtensionName); - - // Ensure we're starting with a clean slate. - if (file_util::PathExists(temp_dir)) { - if (!file_util::Delete(temp_dir, true)) { - ReportExtensionInstallError(source_file, - "Couldn't delete existing temporary directory."); - return false; - } - } - ScopedTempDir scoped_temp; - scoped_temp.Set(temp_dir); - if (!scoped_temp.IsValid()) { - ReportExtensionInstallError(source_file, - "Couldn't create temporary directory."); - return false; - } - - // <profile>/Extensions/INSTALL_TEMP/<version> - FilePath temp_version = temp_dir.AppendASCII(version); - file_util::CreateDirectory(temp_version); - if (!Unzip(source_file, temp_version, NULL)) { - ReportExtensionInstallError(source_file, "Couldn't unzip extension."); - return false; + return; + was_update = true; } // <profile>/Extensions/<dir_name>/<version> - *version_dir = dest_dir.AppendASCII(version); - if (!InstallDirSafely(temp_version, *version_dir)) - return false; + FilePath version_dir = dest_dir.AppendASCII(version); + if (!InstallDirSafely(temp_extension_dir, version_dir)) + return; if (!SetCurrentVersion(dest_dir, version)) { - if (!file_util::Delete(*version_dir, true)) + if (!file_util::Delete(version_dir, true)) LOG(WARNING) << "Can't remove " << dest_dir.value(); - return false; + return; } - return true; + // To mark that this extension was installed from an external source, create a + // zero-length file. At load time, this is used to indicate that the + // extension should be uninstalled. + // TODO(erikkay): move this into per-extension config storage when it appears. + if (from_external) { + FilePath marker = version_dir.AppendASCII(kExternalInstallFile); + file_util::WriteFile(marker, NULL, 0); + } + + ReportExtensionInstalled(dest_dir, was_update); } void ExtensionsServiceBackend::ReportExtensionInstallError( @@ -847,18 +932,9 @@ void ExtensionsServiceBackend::CheckForExternalUpdates( std::wstring extension_version; if (key.ReadValue(kRegistryExtensionVersion, &extension_version)) { if (ShouldInstall(id, WideToASCII(extension_version))) { - FilePath version_dir; - if (InstallOrUpdateExtension(FilePath(extension_path), id, - &version_dir, NULL)) { - // To mark that this extension was installed from an external - // source, create a zero-length file. At load time, this is used - // to indicate that the extension should be uninstalled. - // TODO(erikkay): move this into per-extension config storage when - // it appears. - FilePath marker = version_dir.AppendASCII( - kExternalInstallFile); - file_util::WriteFile(marker, NULL, 0); - } + bool from_external = true; + InstallOrUpdateExtension(FilePath(extension_path), id, + from_external); } } else { // TODO(erikkay): find a way to get this into about:extensions diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h index 481cdd2..b601b73 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -19,6 +19,7 @@ class Extension; class ExtensionsServiceBackend; class GURL; class Profile; +class ResourceDispatcherHost; class SiteInstance; class UserScriptMaster; typedef std::vector<Extension*> ExtensionList; @@ -118,8 +119,10 @@ class ExtensionsService : public ExtensionsServiceFrontendInterface { class ExtensionsServiceBackend : public base::RefCountedThreadSafe<ExtensionsServiceBackend> { public: - explicit ExtensionsServiceBackend(const FilePath& install_directory) - : install_directory_(install_directory) {} + explicit ExtensionsServiceBackend(const FilePath& install_directory, + ResourceDispatcherHost* rdh) + : install_directory_(install_directory), + resource_dispatcher_host_(rdh) {} // Loads extensions from the install directory. The extensions are assumed to // be unpacked in directories that are direct children of the specified path. @@ -157,6 +160,9 @@ class ExtensionsServiceBackend void UninstallExtension(const std::string& extension_id); private: + class UnpackerClient; + friend class UnpackerClient; + // Load a single extension from |extension_path|, the top directory of // a specific extension where its manifest file lives. Extension* LoadExtension(const FilePath& extension_path, bool require_id); @@ -165,18 +171,23 @@ class ExtensionsServiceBackend // a versioned extension where its Current Version file lives. Extension* LoadExtensionCurrentVersion(const FilePath& extension_path); - // Install a crx file at |source_file|. If |expected_id| is not empty, it's - // verified against the extension's manifest before installation. If the - // extension is already installed, install the new version only if its version - // number is greater than the current installed version. On success, sets - // |version_dir| to the versioned directory the extension was installed to and - // |was_update| to whether the extension turned out to be an update to an - // already installed version. Both |version_dir| and |was_update| can be NULL - // if the caller doesn't care. - bool InstallOrUpdateExtension(const FilePath& source_file, + // Install a crx file at |extension_path|. If |expected_id| is not empty, it's + // verified against the extension's manifest before installation. If + // |from_external| is true, this extension install is from an external source, + // ie the Windows registry, and will be marked as such. If the extension is + // already installed, install the new version only if its version number is + // greater than the current installed version. + void InstallOrUpdateExtension(const FilePath& extension_path, const std::string& expected_id, - FilePath* version_dir, - bool* was_update); + bool from_external); + + // Finish installing an extension after it has been unpacked to + // |temp_extension_dir| by our utility process. If |expected_id| is not + // empty, it's verified against the extension's manifest before installation. + void OnExtensionUnpacked(const FilePath& extension_path, + const FilePath& temp_extension_dir, + const std::string expected_id, + bool from_external); // Notify the frontend that there was an error loading an extension. void ReportExtensionLoadError(const FilePath& extension_path, @@ -238,6 +249,9 @@ class ExtensionsServiceBackend // The top-level extensions directory being installed to. FilePath install_directory_; + // We only need a pointer to this to pass along to other interfaces. + ResourceDispatcherHost* resource_dispatcher_host_; + // Whether errors result in noisy alerts. bool alert_on_error_; diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc index bc1a3e3..ea01c25 100644 --- a/chrome/browser/extensions/extensions_service_unittest.cc +++ b/chrome/browser/extensions/extensions_service_unittest.cc @@ -152,7 +152,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) { extensions_path = extensions_path.AppendASCII("good"); scoped_refptr<ExtensionsServiceBackend> backend( - new ExtensionsServiceBackend(extensions_path)); + new ExtensionsServiceBackend(extensions_path, NULL)); scoped_refptr<ExtensionsServiceTestFrontend> frontend( new ExtensionsServiceTestFrontend); @@ -234,7 +234,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectoryFail) { extensions_path = extensions_path.AppendASCII("bad"); scoped_refptr<ExtensionsServiceBackend> backend( - new ExtensionsServiceBackend(extensions_path)); + new ExtensionsServiceBackend(extensions_path, NULL)); scoped_refptr<ExtensionsServiceTestFrontend> frontend( new ExtensionsServiceTestFrontend); @@ -273,7 +273,7 @@ TEST_F(ExtensionsServiceTest, InstallExtension) { file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("ext_test"), &install_dir); scoped_refptr<ExtensionsServiceBackend> backend( - new ExtensionsServiceBackend(install_dir)); + new ExtensionsServiceBackend(install_dir, NULL)); scoped_refptr<ExtensionsServiceTestFrontend> frontend( new ExtensionsServiceTestFrontend); @@ -313,7 +313,7 @@ TEST_F(ExtensionsServiceTest, UninstallExtension) { file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("ext_test"), &install_path); scoped_refptr<ExtensionsServiceBackend> backend( - new ExtensionsServiceBackend(install_path)); + new ExtensionsServiceBackend(install_path, NULL)); scoped_refptr<ExtensionsServiceTestFrontend> frontend( new ExtensionsServiceTestFrontend); @@ -356,7 +356,7 @@ TEST_F(ExtensionsServiceTest, ReinstallExtension) { file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("ext_test"), &install_dir); scoped_refptr<ExtensionsServiceBackend> backend( - new ExtensionsServiceBackend(install_dir)); + new ExtensionsServiceBackend(install_dir, NULL)); scoped_refptr<ExtensionsServiceTestFrontend> frontend( new ExtensionsServiceTestFrontend); @@ -409,7 +409,7 @@ TEST_F(ExtensionsServiceTest, LoadExtension) { extensions_path = extensions_path.AppendASCII("extensions"); scoped_refptr<ExtensionsServiceBackend> backend( - new ExtensionsServiceBackend(extensions_path)); + new ExtensionsServiceBackend(extensions_path, NULL)); scoped_refptr<ExtensionsServiceTestFrontend> frontend( new ExtensionsServiceTestFrontend); @@ -437,7 +437,7 @@ TEST_F(ExtensionsServiceTest, GenerateID) { extensions_path = extensions_path.AppendASCII("extensions"); scoped_refptr<ExtensionsServiceBackend> backend( - new ExtensionsServiceBackend(extensions_path)); + new ExtensionsServiceBackend(extensions_path, NULL)); scoped_refptr<ExtensionsServiceTestFrontend> frontend( new ExtensionsServiceTestFrontend); diff --git a/chrome/browser/sandbox_policy.cc b/chrome/browser/sandbox_policy.cc index 32c1f44..a50e01b 100644 --- a/chrome/browser/sandbox_policy.cc +++ b/chrome/browser/sandbox_policy.cc @@ -244,7 +244,6 @@ bool ApplyPolicyForUntrustedPlugin(sandbox::TargetPolicy* policy) { sandbox::TargetPolicy::FILES_ALLOW_ANY, policy)) return false; - if (!AddDirectoryAndChildren(base::DIR_APP_DATA, NULL, sandbox::TargetPolicy::FILES_ALLOW_READONLY, policy)) @@ -343,6 +342,11 @@ void AddPolicyForRenderer(HDESK desktop, sandbox::TargetPolicy* policy) { namespace sandbox { base::ProcessHandle StartProcess(CommandLine* cmd_line) { + return StartProcessWithAccess(cmd_line, FilePath()); +} + +base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line, + const FilePath& exposed_dir) { base::ProcessHandle process = 0; const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); ChildProcessInfo::ProcessType type; @@ -353,6 +357,8 @@ base::ProcessHandle StartProcess(CommandLine* cmd_line) { type = ChildProcessInfo::PLUGIN_PROCESS; } else if (type_str == switches::kWorkerProcess) { type = ChildProcessInfo::WORKER_PROCESS; + } else if (type_str == switches::kUtilityProcess) { + type = ChildProcessInfo::UTILITY_PROCESS; } else { NOTREACHED(); return 0; @@ -395,6 +401,21 @@ base::ProcessHandle StartProcess(CommandLine* cmd_line) { AddPolicyForRenderer(desktop, policy); } + if (!exposed_dir.empty()) { + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, + sandbox::TargetPolicy::FILES_ALLOW_ANY, + exposed_dir.ToWStringHack().c_str()); + if (result != sandbox::SBOX_ALL_OK) + return 0; + + FilePath exposed_files = exposed_dir.AppendASCII("*"); + result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, + sandbox::TargetPolicy::FILES_ALLOW_ANY, + exposed_files.ToWStringHack().c_str()); + if (result != sandbox::SBOX_ALL_OK) + return 0; + } + if (!AddGenericPolicy(policy)) { NOTREACHED(); if (desktop) diff --git a/chrome/browser/sandbox_policy.h b/chrome/browser/sandbox_policy.h index cc9b538..664f279 100644 --- a/chrome/browser/sandbox_policy.h +++ b/chrome/browser/sandbox_policy.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_SANDBOX_POLICY_H_ #include "base/process.h" +#include "base/file_path.h" class CommandLine; @@ -14,6 +15,11 @@ namespace sandbox { // Starts a sandboxed process and returns a handle to it. base::ProcessHandle StartProcess(CommandLine* cmd_line); +// Starts a sandboxed process with the given directory unsandboxed +// and returns a handle to it. +base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line, + const FilePath& exposed_dir); + } // namespace sandbox; #endif // CHROME_BROWSER_SANDBOX_POLICY_H_ diff --git a/chrome/browser/utility_process_host.cc b/chrome/browser/utility_process_host.cc new file mode 100644 index 0000000..20b34d5 --- /dev/null +++ b/chrome/browser/utility_process_host.cc @@ -0,0 +1,87 @@ +// Copyright (c) 2009 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 "chrome/browser/utility_process_host.h" + +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/process_util.h" +#include "base/task.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/render_messages.h" + +#if defined(OS_WIN) +#include "chrome/browser/sandbox_policy.h" +#endif + +UtilityProcessHost::UtilityProcessHost(ResourceDispatcherHost* rdh, + Client* client, + MessageLoop* client_loop) + : ChildProcessHost(UTILITY_PROCESS, rdh), + client_(client), + client_loop_(client_loop) { +} + +UtilityProcessHost::~UtilityProcessHost() { +} + +bool UtilityProcessHost::StartExtensionUnpacker(const FilePath& extension) { + // Grant the subprocess access to the entire subdir the extension file is + // in, so that it can unpack to that dir. + if (!StartProcess(extension.DirName())) + return false; + + Send(new UtilityMsg_UnpackExtension(extension)); + return true; +} + +bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) { + if (!CreateChannel()) + return false; + + std::wstring exe_path; + if (!PathService::Get(base::FILE_EXE, &exe_path)) + return false; + + CommandLine cmd_line(exe_path); + cmd_line.AppendSwitchWithValue(switches::kProcessType, + switches::kUtilityProcess); + cmd_line.AppendSwitchWithValue(switches::kProcessChannelID, channel_id()); + + base::ProcessHandle process; +#if defined(OS_WIN) + process = sandbox::StartProcessWithAccess(&cmd_line, exposed_dir); +#else + // TODO(port): sandbox + base::LaunchApp(cmd_line, false, false, &process); +#endif + if (!process) + return false; + SetHandle(process); + + return true; +} + +void UtilityProcessHost::OnMessageReceived(const IPC::Message& message) { + client_loop_->PostTask(FROM_HERE, + NewRunnableMethod(client_.get(), &Client::OnMessageReceived, message)); +} + +void UtilityProcessHost::OnChannelError() { + bool child_exited; + bool did_crash = base::DidProcessCrash(&child_exited, handle()); + if (did_crash) { + client_loop_->PostTask(FROM_HERE, + NewRunnableMethod(client_.get(), &Client::OnProcessCrashed)); + } +} + +void UtilityProcessHost::Client::OnMessageReceived( + const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(UtilityProcessHost, message) + IPC_MESSAGE_HANDLER(UtilityHostMsg_UnpackExtension_Reply, + Client::OnUnpackExtensionReply) + IPC_END_MESSAGE_MAP_EX() +} diff --git a/chrome/browser/utility_process_host.h b/chrome/browser/utility_process_host.h new file mode 100644 index 0000000..8cb281e --- /dev/null +++ b/chrome/browser/utility_process_host.h @@ -0,0 +1,79 @@ +// Copyright (c) 2009 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 CHROME_BROWSER_UTILITY_PROCESS_HOST_H_ +#define CHROME_BROWSER_UTILITY_PROCESS_HOST_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "base/task.h" +#include "chrome/common/child_process_host.h" +#include "chrome/common/ipc_channel.h" + +class CommandLine; +class MessageLoop; + +// This class acts as the browser-side host to a utility child process. A +// utility process is a short-lived sandboxed process that is created to run +// a specific task. This class lives solely on the IO thread. +class UtilityProcessHost : public ChildProcessHost { + public: + // An interface to be implemented by consumers of the utility process to + // get results back. All functions are called on the thread passed along + // to UtilityProcessHost. + class Client : public base::RefCountedThreadSafe<Client> { + public: + Client() {} + virtual ~Client() {} + + // Called when the process has crashed. + virtual void OnProcessCrashed() {} + + // Called when the process sends a reply to an UnpackExtension message. + // If success if false, error_message contains a description of the problem. + virtual void OnUnpackExtensionReply(bool success, + const std::string& error_message) {} + private: + friend class UtilityProcessHost; + void OnMessageReceived(const IPC::Message& message); + + DISALLOW_COPY_AND_ASSIGN(Client); + }; + + UtilityProcessHost(ResourceDispatcherHost* rdh, Client* client, + MessageLoop* client_loop); + ~UtilityProcessHost(); + + // Start a process to unpack the extension at the given path. The process + // will be given access to the directory subtree that the extension file is + // in, so the caller is expected to have moved that file into a quarantined + // location first. + bool StartExtensionUnpacker(const FilePath& extension); + + private: + // Starts the process. Returns true iff it succeeded. + bool StartProcess(const FilePath& exposed_dir); + + // IPC messages: + void OnMessageReceived(const IPC::Message& message); + + // ChildProcessHost: + virtual void OnChannelError(); + virtual bool CanShutdown() { return true; } + virtual URLRequestContext* GetRequestContext( + uint32 request_id, + const ViewHostMsg_Resource_Request& request_data) { + return NULL; + } + + // A pointer to our client interface, who will be informed of progress. + scoped_refptr<Client> client_; + MessageLoop* client_loop_; + + DISALLOW_COPY_AND_ASSIGN(UtilityProcessHost); +}; + +#endif // CHROME_BROWSER_UTILITY_PROCESS_HOST_H_ |