summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/chrome_utility.gypi1
-rw-r--r--chrome/utility/BUILD.gn1
-rw-r--r--chrome/utility/extensions/DEPS1
-rw-r--r--chrome/utility/extensions/extensions_handler.cc24
-rw-r--r--chrome/utility/extensions/extensions_handler.h6
-rw-r--r--content/public/utility/content_utility_client.h2
-rw-r--r--extensions/browser/BUILD.gn4
-rw-r--r--extensions/browser/DEPS1
-rw-r--r--extensions/browser/updater/update_service.cc78
-rw-r--r--extensions/browser/updater/update_service.h71
-rw-r--r--extensions/browser/updater/update_service_browsertest.cc208
-rw-r--r--extensions/browser/updater/update_service_factory.cc42
-rw-r--r--extensions/browser/updater/update_service_factory.h37
-rw-r--r--extensions/extensions.gyp20
-rw-r--r--extensions/shell/BUILD.gn5
-rw-r--r--extensions/shell/app/shell_main_delegate.cc11
-rw-r--r--extensions/shell/app/shell_main_delegate.h3
-rw-r--r--extensions/shell/app_shell.gyp6
-rw-r--r--extensions/shell/browser/shell_browser_context_keyed_service_factories.cc19
-rw-r--r--extensions/shell/browser/shell_browser_context_keyed_service_factories.h18
-rw-r--r--extensions/shell/browser/shell_browser_main_parts.cc20
-rw-r--r--extensions/shell/common/switches.cc3
-rw-r--r--extensions/shell/common/switches.h1
-rw-r--r--extensions/shell/utility/DEPS3
-rw-r--r--extensions/shell/utility/shell_content_utility_client.cc23
-rw-r--r--extensions/shell/utility/shell_content_utility_client.h28
-rw-r--r--extensions/utility/BUILD.gn26
-rw-r--r--extensions/utility/DEPS3
-rw-r--r--extensions/utility/utility_handler.cc67
-rw-r--r--extensions/utility/utility_handler.h37
30 files changed, 746 insertions, 23 deletions
diff --git a/chrome/chrome_utility.gypi b/chrome/chrome_utility.gypi
index 66da977..32763b5 100644
--- a/chrome/chrome_utility.gypi
+++ b/chrome/chrome_utility.gypi
@@ -142,6 +142,7 @@
}],
['enable_extensions==1', {
'dependencies': [
+ '../extensions/extensions.gyp:extensions_utility',
'../third_party/libexif/libexif.gyp:libexif',
'common/extensions/api/api.gyp:chrome_api',
],
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
index 69acf0d..e2ad7f0 100644
--- a/chrome/utility/BUILD.gn
+++ b/chrome/utility/BUILD.gn
@@ -38,6 +38,7 @@ static_library("utility") {
if (enable_extensions) {
deps += [
"//chrome/common/extensions/api",
+ "//extensions/utility",
#"//third_party/libexif", TODO(GYP)
]
diff --git a/chrome/utility/extensions/DEPS b/chrome/utility/extensions/DEPS
index 08b52cb..0d5b964 100644
--- a/chrome/utility/extensions/DEPS
+++ b/chrome/utility/extensions/DEPS
@@ -1,3 +1,4 @@
include_rules = [
"+extensions/common",
+ "+extensions/utility",
]
diff --git a/chrome/utility/extensions/extensions_handler.cc b/chrome/utility/extensions/extensions_handler.cc
index 0e90718..a642436 100644
--- a/chrome/utility/extensions/extensions_handler.cc
+++ b/chrome/utility/extensions/extensions_handler.cc
@@ -19,7 +19,6 @@
#include "extensions/common/extension_l10n_util.h"
#include "extensions/common/extension_utility_messages.h"
#include "extensions/common/manifest.h"
-#include "extensions/common/update_manifest.h"
#include "media/base/media.h"
#include "media/base/media_file_checker.h"
#include "third_party/zlib/google/zip.h"
@@ -77,11 +76,9 @@ void ExtensionsHandler::PreSandboxStartup() {
media::InitializeMediaLibrary(media_path);
}
+// static
void ExtensionsHandler::UtilityThreadStarted() {
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- std::string lang = command_line->GetSwitchValueASCII(switches::kLang);
- if (!lang.empty())
- extension_l10n_util::SetProcessLocale(lang);
+ UtilityHandler::UtilityThreadStarted();
}
bool ExtensionsHandler::OnMessageReceived(const IPC::Message& message) {
@@ -116,12 +113,9 @@ bool ExtensionsHandler::OnMessageReceived(const IPC::Message& message) {
OnGetWiFiCredentials)
#endif // defined(OS_WIN)
- IPC_MESSAGE_HANDLER(ExtensionUtilityMsg_ParseUpdateManifest,
- OnParseUpdateManifest)
-
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
- return handled;
+ return handled || utility_handler_.OnMessageReceived(message);
}
void ExtensionsHandler::OnUnpackExtension(
@@ -160,18 +154,6 @@ void ExtensionsHandler::OnUnzipToDir(const base::FilePath& zip_path,
ReleaseProcessIfNeeded();
}
-void ExtensionsHandler::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();
-}
-
void ExtensionsHandler::OnDecodeImageBase64(
const std::string& encoded_string) {
std::string decoded_string;
diff --git a/chrome/utility/extensions/extensions_handler.h b/chrome/utility/extensions/extensions_handler.h
index 90275ae..43810f2 100644
--- a/chrome/utility/extensions/extensions_handler.h
+++ b/chrome/utility/extensions/extensions_handler.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "chrome/common/media_galleries/picasa_types.h"
#include "chrome/utility/utility_message_handler.h"
+#include "extensions/utility/utility_handler.h"
#if !defined(ENABLE_EXTENSIONS)
#error "Extensions must be enabled"
@@ -31,7 +32,7 @@ class ExtensionsHandler : public UtilityMessageHandler {
static void PreSandboxStartup();
static void UtilityThreadStarted();
- // IPC::Listener:
+ // UtilityMessageHandler:
bool OnMessageReceived(const IPC::Message& message) override;
private:
@@ -40,7 +41,6 @@ class ExtensionsHandler : public UtilityMessageHandler {
const std::string& extension_id,
int location, int creation_flags);
void OnUnzipToDir(const base::FilePath& zip_path, const base::FilePath& dir);
- void OnParseUpdateManifest(const std::string& xml);
void OnDecodeImageBase64(const std::string& encoded_data);
void OnParseJSON(const std::string& json);
void OnCheckMediaFile(int64 milliseconds_of_decoding,
@@ -71,6 +71,8 @@ class ExtensionsHandler : public UtilityMessageHandler {
void OnGetWiFiCredentials(const std::string& network_guid);
#endif // defined(OS_WIN)
+ UtilityHandler utility_handler_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionsHandler);
};
diff --git a/content/public/utility/content_utility_client.h b/content/public/utility/content_utility_client.h
index 8f1ec4c..5a5d0e5 100644
--- a/content/public/utility/content_utility_client.h
+++ b/content/public/utility/content_utility_client.h
@@ -12,6 +12,8 @@ namespace content {
// Embedder API for participating in renderer logic.
class CONTENT_EXPORT ContentUtilityClient {
public:
+ virtual ~ContentUtilityClient() {}
+
// Notifies us that the UtilityThread has been created.
virtual void UtilityThreadStarted() {}
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<void(bool)>& 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<int>& 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<int>& 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 <string>
+
+#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<void(bool)>& 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<int>& 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<int>& 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<ExtensionDownloader> downloader_;
+ base::Callback<void(bool)> 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 <map>
+#include <string>
+#include <utility>
+
+#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<std::string, net::HttpStatusCode>;
+
+// 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(
+ "<gupdate xmlns=\"http://www.google.com/update2/response\" "
+ " protocol=\"2.0\" server=\"prod\">\n"
+ " <daystart elapsed_days=\"2860\" elapsed_seconds=\"42042\"/>\n"
+ " <app appid=\"%s\" status=\"ok\">\n"
+ " <updatecheck codebase=\"%s\" fp=\"0\" hash=\"\" hash_sha256=\"\" "
+ " size=\"%d\" status=\"ok\" version=\"1\"/>\n"
+ " </app>\n"
+ "</gupdate>\n",
+ id.c_str(),
+ base::StringPrintf("https://fake-omaha-hostname/%s.crx",
+ id.c_str()).c_str(),
+ static_cast<int>(crx_length));
+ return std::make_pair(response_text, net::HTTP_OK);
+}
+
+FakeResponse CreateFakeOmahaNotFoundResponse() {
+ return std::make_pair(
+ std::string(
+ "<gupdate xmlns=\"http://www.google.com/update2/response\" "
+ " protocol=\"2.0\" server=\"prod\">\n"
+ " <daystart elapsed_days=\"4242\" elapsed_seconds=\"42042\"/>\n"
+ " <app appid=\"\" status=\"error-invalidAppId\">\n"
+ "</gupdate>"),
+ 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<int>(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<std::string, std::string> 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<FakeUpdateURLFetcherFactory> default_url_fetcher_factory_;
+ scoped_ptr<net::FakeURLFetcherFactory> 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<UpdateService*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+UpdateServiceFactory* UpdateServiceFactory::GetInstance() {
+ return Singleton<UpdateServiceFactory>::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();
+ ~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<content::ZygoteForkDelegate>* 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<content::ZygoteForkDelegate>* 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::ContentClient> content_client_;
scoped_ptr<content::ContentBrowserClient> browser_client_;
scoped_ptr<content::ContentRendererClient> renderer_client_;
+ scoped_ptr<content::ContentUtilityClient> 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 <string>
+
+#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_