From 3813023bde420950c60d9d12a8610510b76da337 Mon Sep 17 00:00:00 2001 From: rockot Date: Thu, 6 Nov 2014 10:50:01 -0800 Subject: Add rudimentary UpdateService to app_shell It can download a CRX from the web store using an ID given at the command line. This wires up utility process support for app_shell and establishes a base for factoring additional extensions utility IPCs out of //chrome in the near future. BUG=398671 TBR=asargent@chromium.org for cloned dependency on omaha_query_params Review URL: https://codereview.chromium.org/693233003 Cr-Commit-Position: refs/heads/master@{#303055} --- extensions/browser/BUILD.gn | 4 + extensions/browser/DEPS | 1 + extensions/browser/updater/update_service.cc | 78 ++++++++ extensions/browser/updater/update_service.h | 71 +++++++ .../browser/updater/update_service_browsertest.cc | 208 +++++++++++++++++++++ .../browser/updater/update_service_factory.cc | 42 +++++ .../browser/updater/update_service_factory.h | 37 ++++ extensions/extensions.gyp | 20 ++ extensions/shell/BUILD.gn | 5 + extensions/shell/app/shell_main_delegate.cc | 11 ++ extensions/shell/app/shell_main_delegate.h | 3 + extensions/shell/app_shell.gyp | 6 + ...hell_browser_context_keyed_service_factories.cc | 19 ++ ...shell_browser_context_keyed_service_factories.h | 18 ++ .../shell/browser/shell_browser_main_parts.cc | 20 ++ extensions/shell/common/switches.cc | 3 + extensions/shell/common/switches.h | 1 + extensions/shell/utility/DEPS | 3 + .../shell/utility/shell_content_utility_client.cc | 23 +++ .../shell/utility/shell_content_utility_client.h | 28 +++ extensions/utility/BUILD.gn | 26 +++ extensions/utility/DEPS | 3 + extensions/utility/utility_handler.cc | 67 +++++++ extensions/utility/utility_handler.h | 37 ++++ 24 files changed, 734 insertions(+) create mode 100644 extensions/browser/updater/update_service.cc create mode 100644 extensions/browser/updater/update_service.h create mode 100644 extensions/browser/updater/update_service_browsertest.cc create mode 100644 extensions/browser/updater/update_service_factory.cc create mode 100644 extensions/browser/updater/update_service_factory.h create mode 100644 extensions/shell/browser/shell_browser_context_keyed_service_factories.cc create mode 100644 extensions/shell/browser/shell_browser_context_keyed_service_factories.h create mode 100644 extensions/shell/utility/DEPS create mode 100644 extensions/shell/utility/shell_content_utility_client.cc create mode 100644 extensions/shell/utility/shell_content_utility_client.h create mode 100644 extensions/utility/BUILD.gn create mode 100644 extensions/utility/DEPS create mode 100644 extensions/utility/utility_handler.cc create mode 100644 extensions/utility/utility_handler.h (limited to 'extensions') diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn index 4a653bb..b7ac66f 100644 --- a/extensions/browser/BUILD.gn +++ b/extensions/browser/BUILD.gn @@ -469,6 +469,10 @@ source_set("browser") { "updater/request_queue_impl.h", "updater/safe_manifest_parser.cc", "updater/safe_manifest_parser.h", + "updater/update_service.cc", + "updater/update_service.h", + "updater/update_service_factory.cc", + "updater/update_service_factory.h", "url_request_util.cc", "url_request_util.h", "value_store/leveldb_value_store.cc", diff --git a/extensions/browser/DEPS b/extensions/browser/DEPS index ea65597..117bedd 100644 --- a/extensions/browser/DEPS +++ b/extensions/browser/DEPS @@ -1,5 +1,6 @@ include_rules = [ "+components/keyed_service", + "+components/omaha_query_params", "+components/pref_registry", "+components/sessions", "+components/storage_monitor", diff --git a/extensions/browser/updater/update_service.cc b/extensions/browser/updater/update_service.cc new file mode 100644 index 0000000..286d137 --- /dev/null +++ b/extensions/browser/updater/update_service.cc @@ -0,0 +1,78 @@ +// Copyright 2014 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 "extensions/browser/updater/update_service.h" + +#include "base/message_loop/message_loop.h" +#include "components/omaha_query_params/omaha_query_params.h" +#include "content/public/browser/browser_context.h" +#include "extensions/browser/updater/extension_downloader.h" +#include "extensions/browser/updater/update_service_factory.h" +#include "extensions/common/extension_urls.h" + +using omaha_query_params::OmahaQueryParams; + +namespace extensions { + +// static +UpdateService* UpdateService::Get(content::BrowserContext* context) { + return UpdateServiceFactory::GetForBrowserContext(context); +} + +void UpdateService::DownloadAndInstall( + const std::string& id, + const base::Callback& callback) { + DCHECK(download_callback_.is_null()); + download_callback_ = callback; + downloader_->AddPendingExtension(id, extension_urls::GetWebstoreUpdateUrl(), + 0); + downloader_->StartAllPending(nullptr); +} + +UpdateService::UpdateService(content::BrowserContext* context) + : browser_context_(context), + downloader_(new ExtensionDownloader(this, context->GetRequestContext())) { + downloader_->set_manifest_query_params( + OmahaQueryParams::Get(OmahaQueryParams::CRX)); +} + +UpdateService::~UpdateService() { +} + +void UpdateService::OnExtensionDownloadFailed( + const std::string& id, + Error error, + const PingResult& ping, + const std::set& request_ids) { + auto callback = download_callback_; + download_callback_.Reset(); + callback.Run(false); +} + +void UpdateService::OnExtensionDownloadFinished( + const std::string& id, + const base::FilePath& path, + bool file_ownership_passed, + const GURL& download_url, + const std::string& version, + const PingResult& ping, + const std::set& request_id) { + // TODO(rockot): Actually unpack and install the CRX. + auto callback = download_callback_; + download_callback_.Reset(); + callback.Run(true); +} + +bool UpdateService::IsExtensionPending(const std::string& id) { + // TODO(rockot): Implement this. For now all IDs are "pending". + return true; +} + +bool UpdateService::GetExtensionExistingVersion(const std::string& id, + std::string* version) { + // TODO(rockot): Implement this. + return false; +} + +} // namespace extensions diff --git a/extensions/browser/updater/update_service.h b/extensions/browser/updater/update_service.h new file mode 100644 index 0000000..008917d --- /dev/null +++ b/extensions/browser/updater/update_service.h @@ -0,0 +1,71 @@ +// Copyright 2014 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 EXTENSIONS_BROWSER_UPDATER_UPDATE_SERVICE_H_ +#define EXTENSIONS_BROWSER_UPDATER_UPDATE_SERVICE_H_ + +#include + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "components/keyed_service/core/keyed_service.h" +#include "extensions/browser/updater/extension_downloader_delegate.h" + +namespace content { +class BrowserContext; +} + +namespace extensions { + +class ExtensionDownloader; +class UpdateServiceFactory; +class UpdateServiceTest; + +// This service manages the download, update, and installation of extensions. +// It is currently only used by app_shell, but should eventually replace +// ExtensionUpdater in Chrome. +// TODO(rockot): Replace ExtensionUpdater with this service. +class UpdateService : public KeyedService, public ExtensionDownloaderDelegate { + public: + static UpdateService* Get(content::BrowserContext* context); + + // TODO(rockot): Remove this. It's a placeholder for a real service interface. + // Downloads and (TODO) installs a CRX within the current browser context. + void DownloadAndInstall(const std::string& id, + const base::Callback& callback); + + private: + friend class UpdateServiceFactory; + friend class UpdateServiceTest; + + explicit UpdateService(content::BrowserContext* context); + ~UpdateService() override; + + // ExtensionDownloaderDelegate: + void OnExtensionDownloadFailed(const std::string& id, + Error error, + const PingResult& ping, + const std::set& request_ids) override; + void OnExtensionDownloadFinished(const std::string& id, + const base::FilePath& path, + bool file_ownership_passed, + const GURL& download_url, + const std::string& version, + const PingResult& ping, + const std::set& request_id) override; + bool IsExtensionPending(const std::string& id) override; + bool GetExtensionExistingVersion(const std::string& id, + std::string* version) override; + + content::BrowserContext* browser_context_; + scoped_ptr downloader_; + base::Callback download_callback_; + + DISALLOW_COPY_AND_ASSIGN(UpdateService); +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_UPDATER_UPDATE_SERVICE_H_ diff --git a/extensions/browser/updater/update_service_browsertest.cc b/extensions/browser/updater/update_service_browsertest.cc new file mode 100644 index 0000000..0ec702a --- /dev/null +++ b/extensions/browser/updater/update_service_browsertest.cc @@ -0,0 +1,208 @@ +// Copyright 2014 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 +#include +#include + +#include "base/bind.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "content/public/test/test_utils.h" +#include "extensions/browser/api/extensions_api_client.h" +#include "extensions/browser/extensions_browser_client.h" +#include "extensions/browser/updater/update_service.h" +#include "extensions/common/extension_urls.h" +#include "extensions/shell/test/shell_test.h" +#include "net/base/escape.h" +#include "net/http/http_status_code.h" +#include "net/url_request/test_url_fetcher_factory.h" + +namespace extensions { + +namespace { + +using FakeResponse = std::pair; + +// TODO(rockot): In general there's enough mock-Omaha-noise that this might be +// better placed into some test library code in //components/omaha_client (which +// would be renamed from omaha_query_params). +FakeResponse CreateFakeOmahaResponse(const std::string& id, size_t crx_length) { + std::string response_text = base::StringPrintf( + "\n" + " \n" + " \n" + " \n" + " \n" + "\n", + id.c_str(), + base::StringPrintf("https://fake-omaha-hostname/%s.crx", + id.c_str()).c_str(), + static_cast(crx_length)); + return std::make_pair(response_text, net::HTTP_OK); +} + +FakeResponse CreateFakeOmahaNotFoundResponse() { + return std::make_pair( + std::string( + "\n" + " \n" + " \n" + ""), + net::HTTP_OK); +} + +bool ExtractKeyValueFromComponent(const std::string& component_str, + const std::string& target_key, + std::string* extracted_value) { + url::Component component(0, static_cast(component_str.length())); + url::Component key, value; + while (url::ExtractQueryKeyValue(component_str.c_str(), &component, &key, + &value)) { + if (target_key == component_str.substr(key.begin, key.len)) { + *extracted_value = component_str.substr(value.begin, value.len); + return true; + } + } + return false; +} + +// This extracts an extension ID from an Omaha update query. Queries have the +// form https://foo/bar/update?x=id%3Dabcdefghijklmnopqrstuvwxyzaaaaaa%26... +// This function extracts the 'x' query parameter (e.g. "id%3Dabcdef...."), +// unescapes its value (to become e.g., "id=abcdef...", and then extracts the +// 'id' value from the result (e.g. "abcdef..."). +bool ExtractIdFromOmahaQuery(const std::string& query_str, std::string* id) { + std::string data_string; + if (!ExtractKeyValueFromComponent(query_str, "x", &data_string)) + return false; + data_string = net::UnescapeURLComponent(data_string, + net::UnescapeRule::URL_SPECIAL_CHARS); + if (!ExtractKeyValueFromComponent(data_string, "id", id)) + return false; + EXPECT_EQ(32u, id->size()); + return true; +} + +void ExpectDownloadSuccess(const base::Closure& continuation, bool success) { + EXPECT_TRUE(success) << "Download failed."; + continuation.Run(); +} + +class FakeUpdateURLFetcherFactory : public net::URLFetcherFactory { + public: + ~FakeUpdateURLFetcherFactory() override {} + + void RegisterFakeExtension(const std::string& id, + const std::string& contents) { + CHECK(id.size() == 32); + fake_extensions_.insert(std::make_pair(id, contents)); + } + + // net::URLFetcherFactory: + net::URLFetcher* CreateURLFetcher( + int id, + const GURL& url, + net::URLFetcher::RequestType request_type, + net::URLFetcherDelegate* delegate) override { + if (url.spec().find(extension_urls::GetWebstoreUpdateUrl().spec()) == 0) { + // Handle fake Omaha requests. + return CreateUpdateManifestFetcher(url, delegate); + } else if (url.spec().find("https://fake-omaha-hostname") == 0) { + // Handle a fake CRX request. + return CreateCrxFetcher(url, delegate); + } + NOTREACHED(); + return nullptr; + } + + private: + net::URLFetcher* CreateUpdateManifestFetcher( + const GURL& url, + net::URLFetcherDelegate* delegate) { + // If we have a fake CRX for the ID, return a fake update blob for it. + // Otherwise return an invalid-ID response. + FakeResponse response; + std::string extension_id; + if (!ExtractIdFromOmahaQuery(url.query(), &extension_id)) { + response = CreateFakeOmahaNotFoundResponse(); + } else { + const auto& iter = fake_extensions_.find(extension_id); + if (iter == fake_extensions_.end()) + response = CreateFakeOmahaNotFoundResponse(); + else + response = CreateFakeOmahaResponse(extension_id, iter->second.size()); + } + return new net::FakeURLFetcher(url, delegate, response.first, + response.second, + net::URLRequestStatus::SUCCESS); + } + + net::URLFetcher* CreateCrxFetcher(const GURL& url, + net::URLFetcherDelegate* delegate) { + FakeResponse response; + std::string extension_id = url.path().substr(1, 32); + const auto& iter = fake_extensions_.find(extension_id); + if (iter == fake_extensions_.end()) + response = std::make_pair(std::string(), net::HTTP_NOT_FOUND); + else + response = std::make_pair(iter->second, net::HTTP_OK); + net::TestURLFetcher* fetcher = + new net::FakeURLFetcher(url, delegate, response.first, response.second, + net::URLRequestStatus::SUCCESS); + fetcher->SetResponseFilePath(base::FilePath::FromUTF8Unsafe(url.path())); + return fetcher; + } + + std::map fake_extensions_; +}; + +} // namespace + +class UpdateServiceTest : public AppShellTest { + public: + UpdateServiceTest() {} + ~UpdateServiceTest() override {} + + void SetUpOnMainThread() override { + AppShellTest::SetUpOnMainThread(); + + update_service_ = UpdateService::Get(browser_context()); + + default_url_fetcher_factory_.reset(new FakeUpdateURLFetcherFactory()); + url_fetcher_factory_.reset( + new net::FakeURLFetcherFactory(default_url_fetcher_factory_.get())); + } + + protected: + void RegisterFakeExtension(const std::string& id, + const std::string& crx_contents) { + default_url_fetcher_factory_->RegisterFakeExtension(id, crx_contents); + } + + UpdateService* update_service() const { return update_service_; } + + private: + scoped_ptr default_url_fetcher_factory_; + scoped_ptr url_fetcher_factory_; + + UpdateService* update_service_; +}; + +IN_PROC_BROWSER_TEST_F(UpdateServiceTest, DownloadAndInstall) { + const char kCrxId[] = "abcdefghijklmnopqrstuvwxyzaaaaaa"; + const char kCrxContents[] = "Hello, world!"; + RegisterFakeExtension(kCrxId, kCrxContents); + + base::RunLoop run_loop; + update_service()->DownloadAndInstall( + kCrxId, base::Bind(ExpectDownloadSuccess, run_loop.QuitClosure())); + run_loop.Run(); +} + +} // namespace extensions diff --git a/extensions/browser/updater/update_service_factory.cc b/extensions/browser/updater/update_service_factory.cc new file mode 100644 index 0000000..a85cb06 --- /dev/null +++ b/extensions/browser/updater/update_service_factory.cc @@ -0,0 +1,42 @@ +// Copyright 2014 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 "extensions/browser/updater/update_service_factory.h" + +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "extensions/browser/extension_registry_factory.h" +#include "extensions/browser/process_manager_factory.h" +#include "extensions/browser/updater/update_service.h" + +namespace extensions { + +// static +UpdateService* UpdateServiceFactory::GetForBrowserContext( + content::BrowserContext* context) { + return static_cast( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +UpdateServiceFactory* UpdateServiceFactory::GetInstance() { + return Singleton::get(); +} + +UpdateServiceFactory::UpdateServiceFactory() + : BrowserContextKeyedServiceFactory( + "UpdateService", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(extensions::ExtensionRegistryFactory::GetInstance()); + DependsOn(extensions::ProcessManagerFactory::GetInstance()); +} + +UpdateServiceFactory::~UpdateServiceFactory() { +} + +KeyedService* UpdateServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new UpdateService(context); +} + +} // namespace extensions diff --git a/extensions/browser/updater/update_service_factory.h b/extensions/browser/updater/update_service_factory.h new file mode 100644 index 0000000..7b2726e --- /dev/null +++ b/extensions/browser/updater/update_service_factory.h @@ -0,0 +1,37 @@ +// Copyright 2014 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 EXTENSIONS_BROWSER_UPDATER_UPDATE_SERVICE_FACTORY_H_ +#define EXTENSIONS_BROWSER_UPDATER_UPDATE_SERVICE_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +namespace extensions { + +class UpdateService; + +// Service factory to construct UpdateService instances per BrowserContext. +// Note that OTR browser contexts do not get an UpdateService. +class UpdateServiceFactory : public BrowserContextKeyedServiceFactory { + public: + static UpdateService* GetForBrowserContext(content::BrowserContext* context); + static UpdateServiceFactory* GetInstance(); + + private: + friend struct DefaultSingletonTraits; + + UpdateServiceFactory(); + ~UpdateServiceFactory() override; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + + DISALLOW_COPY_AND_ASSIGN(UpdateServiceFactory); +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_UPDATER_UPDATE_SERVICE_FACTORY_H_ diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp index bfc275f..90ef78f 100644 --- a/extensions/extensions.gyp +++ b/extensions/extensions.gyp @@ -747,6 +747,10 @@ 'browser/updater/request_queue_impl.h', 'browser/updater/safe_manifest_parser.cc', 'browser/updater/safe_manifest_parser.h', + 'browser/updater/update_service.cc', + 'browser/updater/update_service.h', + 'browser/updater/update_service_factory.cc', + 'browser/updater/update_service_factory.h', 'browser/url_request_util.cc', 'browser/url_request_util.h', 'browser/value_store/leveldb_value_store.cc', @@ -979,6 +983,22 @@ 'msvs_disabled_warnings': [ 4267, ], }, { + # GN version: //extensions/utility + 'target_name': 'extensions_utility', + 'type': 'static_library', + 'dependencies': [ + '../content/content.gyp:content_utility', + 'extensions_common', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'utility/utility_handler.cc', + 'utility/utility_handler.h', + ], + }, + { # GN version: //extensions:test_support 'target_name': 'extensions_test_support', 'type': 'static_library', diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn index b948a7f..7d436ce 100644 --- a/extensions/shell/BUILD.gn +++ b/extensions/shell/BUILD.gn @@ -43,6 +43,7 @@ source_set("app_shell_lib") { "//extensions/renderer", "//extensions/shell/common/api", "//extensions/shell/common/api:api_registration", + "//extensions/utility", "//extensions:extensions_resources", "//extensions:shell_and_test_pak", "//mojo/edk/system", @@ -75,6 +76,8 @@ source_set("app_shell_lib") { "browser/shell_audio_controller_chromeos.h", "browser/shell_browser_context.cc", "browser/shell_browser_context.h", + "browser/shell_browser_context_keyed_service_factories.cc", + "browser/shell_browser_context_keyed_service_factories.h", "browser/shell_browser_main_delegate.h", "browser/shell_browser_main_parts.cc", "browser/shell_browser_main_parts.h", @@ -123,6 +126,8 @@ source_set("app_shell_lib") { "renderer/shell_content_renderer_client.h", "renderer/shell_extensions_renderer_client.cc", "renderer/shell_extensions_renderer_client.h", + "utility/shell_content_utility_client.cc", + "utility/shell_content_utility_client.h", ] if (is_chromeos) { deps += [ diff --git a/extensions/shell/app/shell_main_delegate.cc b/extensions/shell/app/shell_main_delegate.cc index e452e48..d7aa5ab 100644 --- a/extensions/shell/app/shell_main_delegate.cc +++ b/extensions/shell/app/shell_main_delegate.cc @@ -15,6 +15,7 @@ #include "extensions/shell/browser/shell_content_browser_client.h" #include "extensions/shell/common/shell_content_client.h" #include "extensions/shell/renderer/shell_content_renderer_client.h" +#include "extensions/shell/utility/shell_content_utility_client.h" #include "ui/base/resource/resource_bundle.h" #if defined(OS_CHROMEOS) @@ -87,6 +88,11 @@ ShellMainDelegate::CreateContentRendererClient() { return renderer_client_.get(); } +content::ContentUtilityClient* ShellMainDelegate::CreateContentUtilityClient() { + utility_client_.reset(CreateShellContentUtilityClient()); + return utility_client_.get(); +} + #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) void ShellMainDelegate::ZygoteStarting( ScopedVector* delegates) { @@ -110,6 +116,11 @@ ShellMainDelegate::CreateShellContentRendererClient() { return new ShellContentRendererClient(); } +content::ContentUtilityClient* +ShellMainDelegate::CreateShellContentUtilityClient() { + return new ShellContentUtilityClient(); +} + void ShellMainDelegate::InitializeResourceBundle() { base::FilePath extensions_shell_and_test_pak_path; PathService::Get(base::DIR_MODULE, &extensions_shell_and_test_pak_path); diff --git a/extensions/shell/app/shell_main_delegate.h b/extensions/shell/app/shell_main_delegate.h index 11eba41..587de92 100644 --- a/extensions/shell/app/shell_main_delegate.h +++ b/extensions/shell/app/shell_main_delegate.h @@ -29,6 +29,7 @@ class ShellMainDelegate : public content::ContentMainDelegate { void PreSandboxStartup() override; content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentRendererClient* CreateContentRendererClient() override; + content::ContentUtilityClient* CreateContentUtilityClient() override; #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) void ZygoteStarting( ScopedVector* delegates) override; @@ -39,6 +40,7 @@ class ShellMainDelegate : public content::ContentMainDelegate { virtual content::ContentClient* CreateContentClient(); virtual content::ContentBrowserClient* CreateShellContentBrowserClient(); virtual content::ContentRendererClient* CreateShellContentRendererClient(); + virtual content::ContentUtilityClient* CreateShellContentUtilityClient(); // Initializes the resource bundle and resources.pak. virtual void InitializeResourceBundle(); @@ -51,6 +53,7 @@ class ShellMainDelegate : public content::ContentMainDelegate { scoped_ptr content_client_; scoped_ptr browser_client_; scoped_ptr renderer_client_; + scoped_ptr utility_client_; DISALLOW_COPY_AND_ASSIGN(ShellMainDelegate); }; diff --git a/extensions/shell/app_shell.gyp b/extensions/shell/app_shell.gyp index d709e3b..2682d5e 100644 --- a/extensions/shell/app_shell.gyp +++ b/extensions/shell/app_shell.gyp @@ -31,6 +31,7 @@ '<(DEPTH)/extensions/extensions.gyp:extensions_common', '<(DEPTH)/extensions/extensions.gyp:extensions_renderer', '<(DEPTH)/extensions/extensions.gyp:extensions_shell_and_test_pak', + '<(DEPTH)/extensions/extensions.gyp:extensions_utility', '<(DEPTH)/extensions/extensions_resources.gyp:extensions_resources', '<(DEPTH)/extensions/shell/browser/api/api_registration.gyp:shell_api_registration', '<(DEPTH)/extensions/shell/common/api/api.gyp:shell_api', @@ -55,6 +56,8 @@ 'browser/api/shell_gcd/shell_gcd_api.h', 'browser/api/shell_window/shell_window_api.cc', 'browser/api/shell_window/shell_window_api.h', + 'browser/shell_browser_context_keyed_service_factories.cc', + 'browser/shell_browser_context_keyed_service_factories.h', 'browser/default_shell_browser_main_delegate.cc', 'browser/default_shell_browser_main_delegate.h', 'browser/desktop_controller.cc', @@ -117,6 +120,8 @@ 'renderer/shell_content_renderer_client.h', 'renderer/shell_extensions_renderer_client.cc', 'renderer/shell_extensions_renderer_client.h', + 'utility/shell_content_utility_client.cc', + 'utility/shell_content_utility_client.h', ], 'conditions': [ ['chromeos==1', { @@ -209,6 +214,7 @@ '../browser/guest_view/web_view/web_view_apitest.h', '../browser/guest_view/web_view/web_view_apitest.cc', '../browser/guest_view/web_view/web_view_media_access_apitest.cc', + '../browser/updater/update_service_browsertest.cc', 'browser/shell_browsertest.cc', 'test/shell_apitest.cc', 'test/shell_apitest.h', diff --git a/extensions/shell/browser/shell_browser_context_keyed_service_factories.cc b/extensions/shell/browser/shell_browser_context_keyed_service_factories.cc new file mode 100644 index 0000000..f2d0bfe --- /dev/null +++ b/extensions/shell/browser/shell_browser_context_keyed_service_factories.cc @@ -0,0 +1,19 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_browser_context_keyed_service_factories.h" + +#include "extensions/browser/updater/update_service_factory.h" + +namespace extensions { +namespace shell { + +void EnsureBrowserContextKeyedServiceFactoriesBuilt() { + // TODO(rockot): Remove this once UpdateService is supported across all + // extensions embedders (and namely chrome.) + UpdateServiceFactory::GetInstance(); +} + +} // namespace shell +} // namespace extensions diff --git a/extensions/shell/browser/shell_browser_context_keyed_service_factories.h b/extensions/shell/browser/shell_browser_context_keyed_service_factories.h new file mode 100644 index 0000000..e252181 --- /dev/null +++ b/extensions/shell/browser/shell_browser_context_keyed_service_factories.h @@ -0,0 +1,18 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_BROWSER_CONTEXT_KEYED_SERVICE_FACTORIES_H_ +#define EXTENSIONS_SHELL_BROWSER_BROWSER_CONTEXT_KEYED_SERVICE_FACTORIES_H_ + +namespace extensions { +namespace shell { + +// Ensures the existence of any BrowserContextKeyedServiceFactory provided by +// the core extensions code. +void EnsureBrowserContextKeyedServiceFactoriesBuilt(); + +} // namespace shell +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_BROWSER_CONTEXT_KEYED_SERVICE_FACTORIES_H_ diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc index 7681b66..29da404 100644 --- a/extensions/shell/browser/shell_browser_main_parts.cc +++ b/extensions/shell/browser/shell_browser_main_parts.cc @@ -18,9 +18,11 @@ #include "extensions/browser/app_window/app_window_client.h" #include "extensions/browser/browser_context_keyed_service_factories.h" #include "extensions/browser/extension_system.h" +#include "extensions/browser/updater/update_service.h" #include "extensions/common/constants.h" #include "extensions/common/switches.h" #include "extensions/shell/browser/shell_browser_context.h" +#include "extensions/shell/browser/shell_browser_context_keyed_service_factories.h" #include "extensions/shell/browser/shell_browser_main_delegate.h" #include "extensions/shell/browser/shell_desktop_controller.h" #include "extensions/shell/browser/shell_device_client.h" @@ -60,6 +62,13 @@ using content::BrowserThread; namespace extensions { +namespace { + +void CrxInstallComplete(bool success) { + VLOG(1) << "CRX download complete. Success: " << success; +} +} + ShellBrowserMainParts::ShellBrowserMainParts( const content::MainFunctionParams& parameters, ShellBrowserMainDelegate* browser_main_delegate) @@ -176,6 +185,17 @@ void ShellBrowserMainParts::PreMainMessageLoopRun() { base::Bind(nacl::NaClProcessHost::EarlyStartup)); #endif + // TODO(rockot): Remove this temporary hack test. + std::string install_crx_id = + cmd->GetSwitchValueASCII(switches::kAppShellInstallCrx); + if (install_crx_id.size() != 0) { + CHECK(install_crx_id.size() == 32) + << "Extension ID must be exactly 32 characters long."; + UpdateService* update_service = UpdateService::Get(browser_context_.get()); + update_service->DownloadAndInstall(install_crx_id, + base::Bind(CrxInstallComplete)); + } + // CreateHttpHandler retains ownership over DevToolsHttpHandler. devtools_http_handler_ = content::ShellDevToolsManagerDelegate::CreateHttpHandler( diff --git a/extensions/shell/common/switches.cc b/extensions/shell/common/switches.cc index 4b0ccc0..eef7cc9 100644 --- a/extensions/shell/common/switches.cc +++ b/extensions/shell/common/switches.cc @@ -13,6 +13,9 @@ const char kAppShellAppPath[] = "app-shell-app-path"; // Bounds for the host window to create (i.e. "800x600"). const char kAppShellHostWindowBounds[] = "app-shell-host-window-bounds"; +// ID of an extension CRX to be downloaded from the web store. +const char kAppShellInstallCrx[] = "app-shell-install-crx"; + // SSID of the preferred WiFi network. const char kAppShellPreferredNetwork[] = "app-shell-preferred-network"; diff --git a/extensions/shell/common/switches.h b/extensions/shell/common/switches.h index 30196ae..2c57677 100644 --- a/extensions/shell/common/switches.h +++ b/extensions/shell/common/switches.h @@ -12,6 +12,7 @@ namespace switches { // alongside the definition of their values in the .cc file. extern const char kAppShellAppPath[]; extern const char kAppShellHostWindowBounds[]; +extern const char kAppShellInstallCrx[]; extern const char kAppShellPreferredNetwork[]; extern const char kAppShellRefreshToken[]; extern const char kAppShellUser[]; diff --git a/extensions/shell/utility/DEPS b/extensions/shell/utility/DEPS new file mode 100644 index 0000000..8ad521e --- /dev/null +++ b/extensions/shell/utility/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+content/public/utility", +] diff --git a/extensions/shell/utility/shell_content_utility_client.cc b/extensions/shell/utility/shell_content_utility_client.cc new file mode 100644 index 0000000..5fe8c57 --- /dev/null +++ b/extensions/shell/utility/shell_content_utility_client.cc @@ -0,0 +1,23 @@ +// Copyright 2014 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 "extensions/shell/utility/shell_content_utility_client.h" + +namespace extensions { + +ShellContentUtilityClient::ShellContentUtilityClient() { +} + +ShellContentUtilityClient::~ShellContentUtilityClient() { +} + +void ShellContentUtilityClient::UtilityThreadStarted() { + UtilityHandler::UtilityThreadStarted(); +} + +bool ShellContentUtilityClient::OnMessageReceived(const IPC::Message& message) { + return utility_handler_.OnMessageReceived(message); +} + +} // namespace extensions diff --git a/extensions/shell/utility/shell_content_utility_client.h b/extensions/shell/utility/shell_content_utility_client.h new file mode 100644 index 0000000..c987427 --- /dev/null +++ b/extensions/shell/utility/shell_content_utility_client.h @@ -0,0 +1,28 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_ +#define EXTENSIONS_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_ + +#include "content/public/utility/content_utility_client.h" +#include "extensions/utility/utility_handler.h" + +namespace extensions { + +class ShellContentUtilityClient : public content::ContentUtilityClient { + public: + ShellContentUtilityClient(); + ~ShellContentUtilityClient() override; + + // content::ContentUtilityClient: + void UtilityThreadStarted() override; + bool OnMessageReceived(const IPC::Message& message) override; + + private: + UtilityHandler utility_handler_; +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_ diff --git a/extensions/utility/BUILD.gn b/extensions/utility/BUILD.gn new file mode 100644 index 0000000..ad884a2 --- /dev/null +++ b/extensions/utility/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2014 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. + +import("//build/config/features.gni") + +assert(enable_extensions) + +# GYP version: extensions/extensions.gyp:extensions_utility +source_set("utility") { + sources = [ + "utility_handler.cc", + "utility_handler.h", + ] + + deps = [ + "//content/public/utility", + "//extensions/common", + ] + + if (is_win) { + cflags = [ + "/wd4267", # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + ] + } +} diff --git a/extensions/utility/DEPS b/extensions/utility/DEPS new file mode 100644 index 0000000..8ad521e --- /dev/null +++ b/extensions/utility/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+content/public/utility", +] diff --git a/extensions/utility/utility_handler.cc b/extensions/utility/utility_handler.cc new file mode 100644 index 0000000..1298933 --- /dev/null +++ b/extensions/utility/utility_handler.cc @@ -0,0 +1,67 @@ +// Copyright 2014 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 "extensions/utility/utility_handler.h" + +#include "base/command_line.h" +#include "content/public/utility/utility_thread.h" +#include "extensions/common/extension.h" +#include "extensions/common/extension_l10n_util.h" +#include "extensions/common/extension_utility_messages.h" +#include "extensions/common/update_manifest.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_macros.h" +#include "ui/base/ui_base_switches.h" + +namespace extensions { + +namespace { + +bool Send(IPC::Message* message) { + return content::UtilityThread::Get()->Send(message); +} + +void ReleaseProcessIfNeeded() { + content::UtilityThread::Get()->ReleaseProcessIfNeeded(); +} + +} // namespace + +UtilityHandler::UtilityHandler() { +} + +UtilityHandler::~UtilityHandler() { +} + +// static +void UtilityHandler::UtilityThreadStarted() { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + std::string lang = command_line->GetSwitchValueASCII(switches::kLang); + if (!lang.empty()) + extension_l10n_util::SetProcessLocale(lang); +} + +bool UtilityHandler::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(UtilityHandler, message) + IPC_MESSAGE_HANDLER(ExtensionUtilityMsg_ParseUpdateManifest, + OnParseUpdateManifest) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void UtilityHandler::OnParseUpdateManifest(const std::string& xml) { + UpdateManifest manifest; + if (!manifest.Parse(xml)) { + Send(new ExtensionUtilityHostMsg_ParseUpdateManifest_Failed( + manifest.errors())); + } else { + Send(new ExtensionUtilityHostMsg_ParseUpdateManifest_Succeeded( + manifest.results())); + } + ReleaseProcessIfNeeded(); +} + +} // namespace extensions diff --git a/extensions/utility/utility_handler.h b/extensions/utility/utility_handler.h new file mode 100644 index 0000000..0ae31ec --- /dev/null +++ b/extensions/utility/utility_handler.h @@ -0,0 +1,37 @@ +// Copyright 2014 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 EXTENSIONS_UTILITY_UTILITY_HANDLER_ +#define EXTENSIONS_UTILITY_UTILITY_HANDLER_ + +#include + +#include "base/macros.h" + +namespace IPC { +class Message; +} + +namespace extensions { + +// A handler for extensions-related IPC from within utility processes. +class UtilityHandler { + public: + UtilityHandler(); + ~UtilityHandler(); + + static void UtilityThreadStarted(); + + bool OnMessageReceived(const IPC::Message& message); + + private: + // IPC message handlers. + void OnParseUpdateManifest(const std::string& xml); + + DISALLOW_COPY_AND_ASSIGN(UtilityHandler); +}; + +} // namespace extensions + +#endif // EXTENSIONS_UTILITY_UTILITY_HANDLER_ -- cgit v1.1