diff options
39 files changed, 1012 insertions, 462 deletions
diff --git a/apps/shell/app_shell.gyp b/apps/shell/app_shell.gyp index 9ce5329..6da130d 100644 --- a/apps/shell/app_shell.gyp +++ b/apps/shell/app_shell.gyp @@ -130,6 +130,8 @@ 'browser/shell_extensions_browser_client.h', 'browser/shell_network_controller_chromeos.cc', 'browser/shell_network_controller_chromeos.h', + 'browser/shell_runtime_api_delegate.cc', + 'browser/shell_runtime_api_delegate.h', 'common/shell_app_runtime.cc', 'common/shell_app_runtime.h', 'common/shell_content_client.cc', @@ -149,6 +151,7 @@ 'conditions': [ ['chromeos==1', { 'dependencies': [ + '<(DEPTH)/chromeos/chromeos.gyp:chromeos', '<(DEPTH)/ui/chromeos/ui_chromeos.gyp:ui_chromeos', ], }], diff --git a/apps/shell/browser/shell_extensions_browser_client.cc b/apps/shell/browser/shell_extensions_browser_client.cc index 769350c..054a717 100644 --- a/apps/shell/browser/shell_extensions_browser_client.cc +++ b/apps/shell/browser/shell_extensions_browser_client.cc @@ -7,6 +7,7 @@ #include "apps/shell/browser/shell_app_sorting.h" #include "apps/shell/browser/shell_extension_system_factory.h" #include "apps/shell/browser/shell_extension_web_contents_observer.h" +#include "apps/shell/browser/shell_runtime_api_delegate.h" #include "apps/shell/common/api/generated_api.h" #include "base/prefs/pref_service.h" #include "base/prefs/pref_service_factory.h" @@ -235,4 +236,10 @@ void ShellExtensionsBrowserClient::RegisterExtensionFunctions( apps::shell_api::GeneratedFunctionRegistry::RegisterAll(registry); } +scoped_ptr<RuntimeAPIDelegate> +ShellExtensionsBrowserClient::CreateRuntimeAPIDelegate( + content::BrowserContext* context) const { + return scoped_ptr<RuntimeAPIDelegate>(new apps::ShellRuntimeAPIDelegate()); +} + } // namespace extensions diff --git a/apps/shell/browser/shell_extensions_browser_client.h b/apps/shell/browser/shell_extensions_browser_client.h index 0862dd5..67e937d 100644 --- a/apps/shell/browser/shell_extensions_browser_client.h +++ b/apps/shell/browser/shell_extensions_browser_client.h @@ -73,6 +73,8 @@ class ShellExtensionsBrowserClient : public ExtensionsBrowserClient { virtual ExtensionSystemProvider* GetExtensionSystemFactory() OVERRIDE; virtual void RegisterExtensionFunctions( ExtensionFunctionRegistry* registry) const OVERRIDE; + virtual scoped_ptr<RuntimeAPIDelegate> CreateRuntimeAPIDelegate( + content::BrowserContext* context) const OVERRIDE; private: // The single BrowserContext for app_shell. Not owned. diff --git a/apps/shell/browser/shell_runtime_api_delegate.cc b/apps/shell/browser/shell_runtime_api_delegate.cc new file mode 100644 index 0000000..fc475ba --- /dev/null +++ b/apps/shell/browser/shell_runtime_api_delegate.cc @@ -0,0 +1,68 @@ +// 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 "apps/shell/browser/shell_runtime_api_delegate.h" + +#include "extensions/common/api/runtime.h" + +#if defined(OS_CHROMEOS) +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" +#endif + +using extensions::core_api::runtime::PlatformInfo; + +namespace apps { + +ShellRuntimeAPIDelegate::ShellRuntimeAPIDelegate() { +} + +ShellRuntimeAPIDelegate::~ShellRuntimeAPIDelegate() { +} + +void ShellRuntimeAPIDelegate::AddUpdateObserver( + extensions::UpdateObserver* observer) { +} + +void ShellRuntimeAPIDelegate::RemoveUpdateObserver( + extensions::UpdateObserver* observer) { +} + +base::Version ShellRuntimeAPIDelegate::GetPreviousExtensionVersion( + const extensions::Extension* extension) { + return base::Version(); +} + +void ShellRuntimeAPIDelegate::ReloadExtension(const std::string& extension_id) { +} + +bool ShellRuntimeAPIDelegate::CheckForUpdates( + const std::string& extension_id, + const UpdateCheckCallback& callback) { + return false; +} + +void ShellRuntimeAPIDelegate::OpenURL(const GURL& uninstall_url) { +} + +bool ShellRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) { +#if defined(OS_CHROMEOS) + info->os = PlatformInfo::OS_CROS_; +#elif defined(OS_LINUX) + info->os = PlatformInfo::OS_LINUX_; +#endif + return true; +} + +bool ShellRuntimeAPIDelegate::RestartDevice(std::string* error_message) { +// We allow chrome.runtime.restart() to request a device restart on ChromeOS. +#if defined(OS_CHROMEOS) + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); + return true; +#endif + *error_message = "Restart is only supported on ChromeOS."; + return false; +} + +} // namespace apps diff --git a/apps/shell/browser/shell_runtime_api_delegate.h b/apps/shell/browser/shell_runtime_api_delegate.h new file mode 100644 index 0000000..fcef1b7 --- /dev/null +++ b/apps/shell/browser/shell_runtime_api_delegate.h @@ -0,0 +1,38 @@ +// 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 APPS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ +#define APPS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ + +#include "base/macros.h" +#include "extensions/browser/api/runtime/runtime_api_delegate.h" + +namespace apps { + +class ShellRuntimeAPIDelegate : public extensions::RuntimeAPIDelegate { + public: + ShellRuntimeAPIDelegate(); + virtual ~ShellRuntimeAPIDelegate(); + + // extensions::RuntimeAPIDelegate implementation. + virtual void AddUpdateObserver(extensions::UpdateObserver* observer) OVERRIDE; + virtual void RemoveUpdateObserver( + extensions::UpdateObserver* observer) OVERRIDE; + virtual base::Version GetPreviousExtensionVersion( + const extensions::Extension* extension) OVERRIDE; + virtual void ReloadExtension(const std::string& extension_id) OVERRIDE; + virtual bool CheckForUpdates(const std::string& extension_id, + const UpdateCheckCallback& callback) OVERRIDE; + virtual void OpenURL(const GURL& uninstall_url) OVERRIDE; + virtual bool GetPlatformInfo( + extensions::core_api::runtime::PlatformInfo* info) OVERRIDE; + virtual bool RestartDevice(std::string* error_message) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellRuntimeAPIDelegate); +}; + +} // namespace apps + +#endif // APPS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ diff --git a/apps/shell/common/shell_extensions_client.cc b/apps/shell/common/shell_extensions_client.cc index 9b96545..5c142d4 100644 --- a/apps/shell/common/shell_extensions_client.cc +++ b/apps/shell/common/shell_extensions_client.cc @@ -24,7 +24,6 @@ #include "extensions/common/permissions/permissions_provider.h" #include "extensions/common/url_pattern_set.h" #include "grit/app_shell_resources.h" -#include "grit/common_resources.h" #include "grit/extensions_resources.h" using extensions::APIPermissionInfo; @@ -129,18 +128,14 @@ scoped_ptr<FeatureProvider> ShellExtensionsClient::CreateFeatureProvider( if (name == "api") { source.LoadJSON(IDR_EXTENSION_API_FEATURES); source.LoadJSON(IDR_SHELL_EXTENSION_API_FEATURES); - // TODO(yoz): Don't include Chrome resources. - source.LoadJSON(IDR_CHROME_EXTENSION_API_FEATURES); return scoped_ptr<FeatureProvider>(new BaseFeatureProvider( source.dictionary(), CreateFeature<extensions::APIFeature>)); } else if (name == "manifest") { source.LoadJSON(IDR_EXTENSION_MANIFEST_FEATURES); - source.LoadJSON(IDR_CHROME_EXTENSION_MANIFEST_FEATURES); return scoped_ptr<FeatureProvider>(new BaseFeatureProvider( source.dictionary(), CreateFeature<extensions::ManifestFeature>)); } else if (name == "permission") { source.LoadJSON(IDR_EXTENSION_PERMISSION_FEATURES); - source.LoadJSON(IDR_CHROME_EXTENSION_PERMISSION_FEATURES); return scoped_ptr<FeatureProvider>(new BaseFeatureProvider( source.dictionary(), CreateFeature<extensions::PermissionFeature>)); } else { diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc b/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc index a488b51..e695674 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_app_update_service.cc @@ -10,11 +10,11 @@ #include "chrome/browser/browser_process_platform_part_chromeos.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" #include "chrome/browser/chromeos/system/automatic_reboot_manager.h" -#include "chrome/browser/extensions/api/runtime/runtime_api.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/profiles/profile.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "extensions/browser/api/runtime/runtime_api.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/extension_system_provider.h" #include "extensions/browser/extensions_browser_client.h" @@ -82,22 +82,22 @@ void KioskAppUpdateService::OnAppUpdateAvailable( extensions::RuntimeEventRouter::DispatchOnRestartRequiredEvent( profile_, app_id_, - extensions::api::runtime::OnRestartRequired::REASON_APP_UPDATE); + extensions::core_api::runtime::OnRestartRequired::REASON_APP_UPDATE); StartAppUpdateRestartTimer(); } void KioskAppUpdateService::OnRebootScheduled(Reason reason) { - extensions::api::runtime::OnRestartRequired::Reason restart_reason = - extensions::api::runtime::OnRestartRequired::REASON_NONE; + extensions::core_api::runtime::OnRestartRequired::Reason restart_reason = + extensions::core_api::runtime::OnRestartRequired::REASON_NONE; switch (reason) { case REBOOT_REASON_OS_UPDATE: restart_reason = - extensions::api::runtime::OnRestartRequired::REASON_OS_UPDATE; + extensions::core_api::runtime::OnRestartRequired::REASON_OS_UPDATE; break; case REBOOT_REASON_PERIODIC: restart_reason = - extensions::api::runtime::OnRestartRequired::REASON_PERIODIC; + extensions::core_api::runtime::OnRestartRequired::REASON_PERIODIC; break; default: NOTREACHED() << "Unknown reboot reason=" << reason; diff --git a/chrome/browser/extensions/api/messaging/message_property_provider.cc b/chrome/browser/extensions/api/messaging/message_property_provider.cc index c15c3ad..4871bc3 100644 --- a/chrome/browser/extensions/api/messaging/message_property_provider.cc +++ b/chrome/browser/extensions/api/messaging/message_property_provider.cc @@ -10,8 +10,8 @@ #include "base/strings/string_piece.h" #include "base/values.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/common/extensions/api/runtime.h" #include "content/public/browser/browser_thread.h" +#include "extensions/common/api/runtime.h" #include "net/base/completion_callback.h" #include "net/cert/asn1_util.h" #include "net/cert/jwk_serializer.h" diff --git a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc new file mode 100644 index 0000000..59e611c --- /dev/null +++ b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc @@ -0,0 +1,284 @@ +// 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 "chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h" + +#include "base/message_loop/message_loop.h" +#include "base/metrics/histogram.h" +#include "base/time/time.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_warning_service.h" +#include "chrome/browser/extensions/extension_warning_set.h" +#include "chrome/browser/extensions/updater/extension_updater.h" +#include "chrome/browser/omaha_query_params/omaha_query_params.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_navigator.h" +#include "chrome/browser/ui/browser_window.h" +#include "content/public/browser/notification_service.h" +#include "extensions/browser/extension_system.h" +#include "extensions/common/api/runtime.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" +#endif + +using extensions::Extension; +using extensions::ExtensionSystem; +using extensions::ExtensionUpdater; + +using extensions::core_api::runtime::PlatformInfo; + +namespace { + +const char kUpdateThrottled[] = "throttled"; +const char kUpdateNotFound[] = "no_update"; +const char kUpdateFound[] = "update_available"; + +// If an extension reloads itself within this many miliseconds of reloading +// itself, the reload is considered suspiciously fast. +const int kFastReloadTime = 10000; + +// After this many suspiciously fast consecutive reloads, an extension will get +// disabled. +const int kFastReloadCount = 5; + +} // namespace + +ChromeRuntimeAPIDelegate::ChromeRuntimeAPIDelegate( + content::BrowserContext* context) + : browser_context_(context), registered_for_updates_(false) { + registrar_.Add(this, + chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND, + content::NotificationService::AllSources()); +} + +ChromeRuntimeAPIDelegate::~ChromeRuntimeAPIDelegate() { +} + +void ChromeRuntimeAPIDelegate::AddUpdateObserver( + extensions::UpdateObserver* observer) { + registered_for_updates_ = true; + ExtensionSystem::Get(browser_context_) + ->extension_service() + ->AddUpdateObserver(observer); +} + +void ChromeRuntimeAPIDelegate::RemoveUpdateObserver( + extensions::UpdateObserver* observer) { + if (registered_for_updates_) { + ExtensionSystem::Get(browser_context_) + ->extension_service() + ->RemoveUpdateObserver(observer); + } +} + +base::Version ChromeRuntimeAPIDelegate::GetPreviousExtensionVersion( + const Extension* extension) { + // Get the previous version to check if this is an upgrade. + ExtensionService* service = + ExtensionSystem::Get(browser_context_)->extension_service(); + const Extension* old = service->GetExtensionById(extension->id(), true); + if (old) + return *old->version(); + return base::Version(); +} + +void ChromeRuntimeAPIDelegate::ReloadExtension( + const std::string& extension_id) { + std::pair<base::TimeTicks, int>& reload_info = + last_reload_time_[extension_id]; + base::TimeTicks now = base::TimeTicks::Now(); + if (reload_info.first.is_null() || + (now - reload_info.first).InMilliseconds() > kFastReloadTime) { + reload_info.second = 0; + } else { + reload_info.second++; + } + if (!reload_info.first.is_null()) { + UMA_HISTOGRAM_LONG_TIMES("Extensions.RuntimeReloadTime", + now - reload_info.first); + } + UMA_HISTOGRAM_COUNTS_100("Extensions.RuntimeReloadFastCount", + reload_info.second); + reload_info.first = now; + + ExtensionService* service = + ExtensionSystem::Get(browser_context_)->extension_service(); + if (reload_info.second >= kFastReloadCount) { + // Unloading an extension clears all warnings, so first terminate the + // extension, and then add the warning. Since this is called from an + // extension function unloading the extension has to be done + // asynchronously. Fortunately PostTask guarentees FIFO order so just + // post both tasks. + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&ExtensionService::TerminateExtension, + service->AsWeakPtr(), + extension_id)); + extensions::ExtensionWarningSet warnings; + warnings.insert( + extensions::ExtensionWarning::CreateReloadTooFrequentWarning( + extension_id)); + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&extensions::ExtensionWarningService::NotifyWarningsOnUI, + browser_context_, + warnings)); + } else { + // We can't call ReloadExtension directly, since when this method finishes + // it tries to decrease the reference count for the extension, which fails + // if the extension has already been reloaded; so instead we post a task. + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&ExtensionService::ReloadExtension, + service->AsWeakPtr(), + extension_id)); + } +} + +bool ChromeRuntimeAPIDelegate::CheckForUpdates( + const std::string& extension_id, + const UpdateCheckCallback& callback) { + ExtensionSystem* system = ExtensionSystem::Get(browser_context_); + ExtensionService* service = system->extension_service(); + ExtensionUpdater* updater = service->updater(); + if (!updater) { + return false; + } + if (!updater->CheckExtensionSoon( + extension_id, + base::Bind(&ChromeRuntimeAPIDelegate::UpdateCheckComplete, + base::Unretained(this), + extension_id))) { + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(callback, UpdateCheckResult(true, kUpdateThrottled, ""))); + } else { + UpdateCallbackList& callbacks = pending_update_checks_[extension_id]; + callbacks.push_back(callback); + } + return true; +} + +void ChromeRuntimeAPIDelegate::OpenURL(const GURL& uninstall_url) { +#if defined(ENABLE_EXTENSIONS) + Profile* profile = Profile::FromBrowserContext(browser_context_); + Browser* browser = + chrome::FindLastActiveWithProfile(profile, chrome::GetActiveDesktop()); + if (!browser) + browser = + new Browser(Browser::CreateParams(profile, chrome::GetActiveDesktop())); + + chrome::NavigateParams params( + browser, uninstall_url, content::PAGE_TRANSITION_CLIENT_REDIRECT); + params.disposition = NEW_FOREGROUND_TAB; + params.user_gesture = false; + chrome::Navigate(¶ms); +#endif +} + +bool ChromeRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) { + const char* os = chrome::OmahaQueryParams::GetOS(); + if (strcmp(os, "mac") == 0) { + info->os = PlatformInfo::OS_MAC_; + } else if (strcmp(os, "win") == 0) { + info->os = PlatformInfo::OS_WIN_; + } else if (strcmp(os, "android") == 0) { + info->os = PlatformInfo::OS_ANDROID_; + } else if (strcmp(os, "cros") == 0) { + info->os = PlatformInfo::OS_CROS_; + } else if (strcmp(os, "linux") == 0) { + info->os = PlatformInfo::OS_LINUX_; + } else if (strcmp(os, "openbsd") == 0) { + info->os = PlatformInfo::OS_OPENBSD_; + } else { + NOTREACHED(); + return false; + } + + const char* arch = chrome::OmahaQueryParams::GetArch(); + if (strcmp(arch, "arm") == 0) { + info->arch = PlatformInfo::ARCH_ARM; + } else if (strcmp(arch, "x86") == 0) { + info->arch = PlatformInfo::ARCH_X86_32; + } else if (strcmp(arch, "x64") == 0) { + info->arch = PlatformInfo::ARCH_X86_64; + } else { + NOTREACHED(); + return false; + } + + const char* nacl_arch = chrome::OmahaQueryParams::GetNaclArch(); + if (strcmp(nacl_arch, "arm") == 0) { + info->nacl_arch = PlatformInfo::NACL_ARCH_ARM; + } else if (strcmp(nacl_arch, "x86-32") == 0) { + info->nacl_arch = PlatformInfo::NACL_ARCH_X86_32; + } else if (strcmp(nacl_arch, "x86-64") == 0) { + info->nacl_arch = PlatformInfo::NACL_ARCH_X86_64; + } else { + NOTREACHED(); + return false; + } + + return true; +} + +bool ChromeRuntimeAPIDelegate::RestartDevice(std::string* error_message) { +#if defined(OS_CHROMEOS) + if (chromeos::UserManager::Get()->IsLoggedInAsKioskApp()) { + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->RequestRestart(); + return true; + } +#endif + *error_message = "Function available only for ChromeOS kiosk mode."; + return false; +} + +void ChromeRuntimeAPIDelegate::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK(type == chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND); + typedef const std::pair<std::string, Version> UpdateDetails; + const std::string& id = content::Details<UpdateDetails>(details)->first; + const Version& version = content::Details<UpdateDetails>(details)->second; + if (version.IsValid()) { + CallUpdateCallbacks( + id, UpdateCheckResult(true, kUpdateFound, version.GetString())); + } +} + +void ChromeRuntimeAPIDelegate::UpdateCheckComplete( + const std::string& extension_id) { + ExtensionSystem* system = ExtensionSystem::Get(browser_context_); + ExtensionService* service = system->extension_service(); + const Extension* update = service->GetPendingExtensionUpdate(extension_id); + if (update) { + CallUpdateCallbacks( + extension_id, + UpdateCheckResult(true, kUpdateFound, update->VersionString())); + } else { + CallUpdateCallbacks(extension_id, + UpdateCheckResult(true, kUpdateNotFound, "")); + } +} + +void ChromeRuntimeAPIDelegate::CallUpdateCallbacks( + const std::string& extension_id, + const UpdateCheckResult& result) { + UpdateCallbackList callbacks = pending_update_checks_[extension_id]; + pending_update_checks_.erase(extension_id); + for (UpdateCallbackList::const_iterator iter = callbacks.begin(); + iter != callbacks.end(); + ++iter) { + const UpdateCheckCallback& callback = *iter; + callback.Run(result); + } +} diff --git a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h new file mode 100644 index 0000000..cdb6e7a --- /dev/null +++ b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h @@ -0,0 +1,86 @@ +// 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 CHROME_BROWSER_EXTENSIONS_API_RUNTIME_CHROME_RUNTIME_API_DELEGATE_H_ +#define CHROME_BROWSER_EXTENSIONS_API_RUNTIME_CHROME_RUNTIME_API_DELEGATE_H_ + +#include <map> +#include <vector> + +#include "base/macros.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "extensions/browser/api/runtime/runtime_api.h" +#include "extensions/browser/api/runtime/runtime_api_delegate.h" + +namespace base { +class TimeTicks; +} + +namespace content { +class BrowserContext; +class NotificationDetails; +class NotificationSource; +} + +namespace extensions { +class RuntimeAPI; +class UpdateObserver; +} + +class ChromeRuntimeAPIDelegate : public extensions::RuntimeAPIDelegate, + public content::NotificationObserver { + public: + explicit ChromeRuntimeAPIDelegate(content::BrowserContext* context); + virtual ~ChromeRuntimeAPIDelegate(); + + private: + friend class extensions::RuntimeAPI; + + // extensions::RuntimeAPIDelegate implementation. + virtual void AddUpdateObserver(extensions::UpdateObserver* observer) OVERRIDE; + virtual void RemoveUpdateObserver( + extensions::UpdateObserver* observer) OVERRIDE; + virtual base::Version GetPreviousExtensionVersion( + const extensions::Extension* extension) OVERRIDE; + virtual void ReloadExtension(const std::string& extension_id) OVERRIDE; + virtual bool CheckForUpdates(const std::string& extension_id, + const UpdateCheckCallback& callback) OVERRIDE; + virtual void OpenURL(const GURL& uninstall_url) OVERRIDE; + virtual bool GetPlatformInfo( + extensions::core_api::runtime::PlatformInfo* info) OVERRIDE; + virtual bool RestartDevice(std::string* error_message) OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + void UpdateCheckComplete(const std::string& extension_id); + void CallUpdateCallbacks(const std::string& extension_id, + const UpdateCheckResult& result); + + content::BrowserContext* browser_context_; + + content::NotificationRegistrar registrar_; + + // Whether the API registered with the ExtensionService to receive + // update notifications. + bool registered_for_updates_; + + // Map to prevent extensions from getting stuck in reload loops. Maps + // extension id to the last time it was reloaded and the number of times + // it was reloaded with not enough time in between reloads. + std::map<std::string, std::pair<base::TimeTicks, int> > last_reload_time_; + + // Pending update checks. + typedef std::vector<UpdateCheckCallback> UpdateCallbackList; + typedef std::map<std::string, UpdateCallbackList> UpdateCallbackMap; + UpdateCallbackMap pending_update_checks_; + + private: + DISALLOW_COPY_AND_ASSIGN(ChromeRuntimeAPIDelegate); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_API_RUNTIME_CHROME_RUNTIME_API_DELEGATE_H_ diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc index d83454b..884f801 100644 --- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc +++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc @@ -38,7 +38,6 @@ #include "chrome/browser/extensions/api/preference/preference_api.h" #include "chrome/browser/extensions/api/processes/processes_api.h" #include "chrome/browser/extensions/api/push_messaging/push_messaging_api.h" -#include "chrome/browser/extensions/api/runtime/runtime_api.h" #include "chrome/browser/extensions/api/serial/serial_connection.h" #include "chrome/browser/extensions/api/sessions/sessions_api.h" #include "chrome/browser/extensions/api/settings_overrides/settings_overrides_api.h" @@ -143,7 +142,6 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() { extensions::PreferenceAPI::GetFactoryInstance(); extensions::ProcessesAPI::GetFactoryInstance(); extensions::PushMessagingAPI::GetFactoryInstance(); - extensions::RuntimeAPI::GetFactoryInstance(); extensions::SessionsAPI::GetFactoryInstance(); extensions::SettingsOverridesAPI::GetFactoryInstance(); extensions::SignedInDevicesManager::GetFactoryInstance(); diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc index cb0868a..fe53a07 100644 --- a/chrome/browser/extensions/chrome_extensions_browser_client.cc +++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc @@ -12,6 +12,7 @@ #include "chrome/browser/extensions/activity_log/activity_log.h" #include "chrome/browser/extensions/api/preference/chrome_direct_setting.h" #include "chrome/browser/extensions/api/preference/preference_api.h" +#include "chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h" #include "chrome/browser/extensions/api/web_request/web_request_api.h" #include "chrome/browser/extensions/chrome_app_sorting.h" #include "chrome/browser/extensions/chrome_extension_host_delegate.h" @@ -269,4 +270,11 @@ void ChromeExtensionsBrowserClient::RegisterExtensionFunctions( #endif } +scoped_ptr<extensions::RuntimeAPIDelegate> +ChromeExtensionsBrowserClient::CreateRuntimeAPIDelegate( + content::BrowserContext* context) const { + return scoped_ptr<extensions::RuntimeAPIDelegate>( + new ChromeRuntimeAPIDelegate(context)); +} + } // namespace extensions diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h index c47e851..0c5d160 100644 --- a/chrome/browser/extensions/chrome_extensions_browser_client.h +++ b/chrome/browser/extensions/chrome_extensions_browser_client.h @@ -87,6 +87,8 @@ class ChromeExtensionsBrowserClient : public ExtensionsBrowserClient { virtual ExtensionSystemProvider* GetExtensionSystemFactory() OVERRIDE; virtual void RegisterExtensionFunctions( ExtensionFunctionRegistry* registry) const OVERRIDE; + virtual scoped_ptr<extensions::RuntimeAPIDelegate> CreateRuntimeAPIDelegate( + content::BrowserContext* context) const OVERRIDE; private: friend struct base::DefaultLazyInstanceTraits<ChromeExtensionsBrowserClient>; diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc index 83f3356..5d219d8 100644 --- a/chrome/browser/extensions/extension_messages_apitest.cc +++ b/chrome/browser/extensions/extension_messages_apitest.cc @@ -21,7 +21,6 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/extensions/api/runtime.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_service.h" @@ -29,6 +28,7 @@ #include "extensions/browser/event_router.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/api/runtime.h" #include "extensions/common/extension_builder.h" #include "extensions/common/value_builder.h" #include "net/cert/asn1_util.h" diff --git a/chrome/browser/extensions/installed_loader.cc b/chrome/browser/extensions/installed_loader.cc index 5470083..2406160 100644 --- a/chrome/browser/extensions/installed_loader.cc +++ b/chrome/browser/extensions/installed_loader.cc @@ -11,7 +11,6 @@ #include "base/threading/thread_restrictions.h" #include "base/values.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/extensions/api/runtime/runtime_api.h" #include "chrome/browser/extensions/extension_action_manager.h" #include "chrome/browser/extensions/extension_error_reporter.h" #include "chrome/browser/extensions/extension_service.h" @@ -22,6 +21,7 @@ #include "chrome/common/pref_names.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/user_metrics.h" +#include "extensions/browser/api/runtime/runtime_api.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index 44ee3f8..fa3bb94 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -473,8 +473,6 @@ 'browser/extensions/api/push_messaging/push_messaging_invalidation_mapper.h', 'browser/extensions/api/reading_list_private/reading_list_private_api.cc', 'browser/extensions/api/reading_list_private/reading_list_private_api.h', - 'browser/extensions/api/runtime/runtime_api.cc', - 'browser/extensions/api/runtime/runtime_api.h', 'browser/extensions/api/serial/serial_api.cc', 'browser/extensions/api/serial/serial_api.h', 'browser/extensions/api/serial/serial_connection.cc', @@ -650,6 +648,8 @@ 'browser/extensions/chrome_extensions_browser_client.h', 'browser/extensions/chrome_notification_observer.cc', 'browser/extensions/chrome_notification_observer.h', + 'browser/extensions/api/runtime/chrome_runtime_api_delegate.cc', + 'browser/extensions/api/runtime/chrome_runtime_api_delegate.h', 'browser/extensions/component_loader.cc', 'browser/extensions/component_loader.h', 'browser/extensions/context_menu_matcher.cc', @@ -1010,7 +1010,7 @@ ['include', '^browser/extensions/api/preference/preference_api.cc'], ['include', '^browser/extensions/api/proxy/proxy_api.cc'], ['include', '^browser/extensions/api/proxy/proxy_api_constants.cc'], - ['include', '^browser/extensions/api/runtime/runtime_api.cc'], + ['include', '^browser/extensions/api/runtime/chrome_runtime_api_delegate.cc'], ['include', '^browser/extensions/api/tabs/tabs_constants.cc'], ['include', '^browser/extensions/api/web_navigation/frame_navigation_state.cc'], ['include', '^browser/extensions/api/web_navigation/web_navigation_api.cc'], diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index ecd3178..9b94b27 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -829,6 +829,8 @@ '../components/autofill/content/renderer/test_password_autofill_agent.cc', '../components/autofill/content/renderer/test_password_generation_agent.h', '../components/autofill/content/renderer/test_password_generation_agent.cc', + # TODO(rockot): Remove this once extensions_browsertests exists. + '../extensions/browser/api/runtime/runtime_apitest.cc', 'app/chrome_command_ids.h', 'app/chrome_dll.rc', 'app/chrome_dll_resource.h', @@ -1070,7 +1072,6 @@ 'browser/extensions/api/push_messaging/push_messaging_canary_test.cc', 'browser/extensions/api/push_messaging/sync_setup_helper.cc', 'browser/extensions/api/reading_list_private/reading_list_private_apitest.cc', - 'browser/extensions/api/runtime/runtime_apitest.cc', 'browser/extensions/api/serial/serial_apitest.cc', 'browser/extensions/api/sessions/sessions_apitest.cc', 'browser/extensions/api/settings_overrides/settings_overrides_browsertest.cc', diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json index f072603..4a2af1a 100644 --- a/chrome/common/extensions/api/_api_features.json +++ b/chrome/common/extensions/api/_api_features.json @@ -598,49 +598,6 @@ "dependencies": ["permission:rtcPrivate"], "contexts": ["blessed_extension"] }, - "runtime": { - "channel": "stable", - "extension_types": ["extension", "legacy_packaged_app", "platform_app"], - "contexts": ["blessed_extension"] - }, - "runtime.connect": { - "contexts": "all", - "matches": ["<all_urls>"] - }, - "runtime.getManifest": { - "contexts": ["blessed_extension", "unblessed_extension", "content_script"] - }, - "runtime.getURL": { - "contexts": ["blessed_extension", "unblessed_extension", "content_script"] - }, - "runtime.id": { - "contexts": ["blessed_extension", "unblessed_extension", "content_script"] - }, - "runtime.lastError": { - "contexts": "all", - "extension_types": "all", - "matches": ["<all_urls>"] - }, - "runtime.onConnect": { - "contexts": ["blessed_extension", "unblessed_extension", "content_script"] - }, - "runtime.onMessage": { - "contexts": ["blessed_extension", "unblessed_extension", "content_script"] - }, - "runtime.reload": { - "contexts": ["blessed_extension", "unblessed_extension", "content_script"] - }, - "runtime.requestUpdateCheck": { - "contexts": ["blessed_extension", "unblessed_extension", "content_script"] - }, - "runtime.sendMessage": { - "contexts": "all", - "matches": ["<all_urls>"] - }, - "runtime.setUninstallURL": { - "channel": "dev", - "contexts": ["blessed_extension", "unblessed_extension", "content_script"] - }, "scriptBadge": { "dependencies": ["manifest:script_badge"], "contexts": ["blessed_extension"] @@ -722,16 +679,6 @@ "dependencies": ["permission:ttsEngine"], "contexts": ["blessed_extension"] }, - "types": { - "channel": "stable", - "extension_types": ["extension", "legacy_packaged_app", "platform_app"], - "contexts": ["blessed_extension"] - }, - "types.private": { - "channel": "dev", - "extension_types": ["extension"], - "location": "component" - }, "virtualKeyboardPrivate": { "platforms": ["chromeos"], "dependencies": ["permission:virtualKeyboardPrivate"], diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index 08396be..8c0e927 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json @@ -752,12 +752,6 @@ "312745D9BF916161191143F6490085EEA0434997" // Google Talk debug ] }, - // Note: runtime is not actually a permission, but some systems check these - // values to verify restrictions. - "runtime": { - "channel": "stable", - "extension_types": ["extension", "legacy_packaged_app", "platform_app"] - }, "screenlockPrivate": { "channel": "stable", "extension_types": ["platform_app"], diff --git a/chrome/common/extensions/api/api.gyp b/chrome/common/extensions/api/api.gyp index f701e84..6911770 100644 --- a/chrome/common/extensions/api/api.gyp +++ b/chrome/common/extensions/api/api.gyp @@ -102,7 +102,6 @@ 'power.idl', 'push_messaging.idl', 'reading_list_private.json', - 'runtime.json', 'serial.idl', 'sessions.json', 'signed_in_devices.idl', @@ -145,7 +144,6 @@ 'manifest_types.json', 'omnibox.json', 'permissions.json', - 'runtime.json', 'sync_file_system.idl', 'tab_capture.idl', 'tabs.json', diff --git a/chrome/renderer/resources/extensions/last_error.js b/chrome/renderer/resources/extensions/last_error.js index 1d2b565..6d85b11 100644 --- a/chrome/renderer/resources/extensions/last_error.js +++ b/chrome/renderer/resources/extensions/last_error.js @@ -28,7 +28,7 @@ function set(name, message, stack, targetChrome) { clear(targetChrome); // in case somebody has set a sneaky getter/setter var errorObject = { message: message }; - if (GetAvailability('extension.lastError').is_available) + if (targetChrome && targetChrome.extension) targetChrome.extension.lastError = errorObject; assertRuntimeIsAvailable(); @@ -64,8 +64,8 @@ function clear(targetChrome) { if (!targetChrome) throw new Error('No target chrome to clear error'); - if (GetAvailability('extension.lastError').is_available) - delete targetChrome.extension.lastError; + if (targetChrome && targetChrome.extension) + delete targetChrome.extension.lastError; assertRuntimeIsAvailable(); delete targetChrome.runtime.lastError; diff --git a/extensions/DEPS b/extensions/DEPS index 11611da..9d6a6a0 100644 --- a/extensions/DEPS +++ b/extensions/DEPS @@ -26,16 +26,21 @@ specific_include_rules = { # Temporarily allowed testing includes. See above. # TODO(jamescook): Remove these. http://crbug.com/162530 + "+chrome/browser/apps/app_browsertest_util.h", + "+chrome/browser/extensions/api/management/management_api.h", "+chrome/browser/extensions/api/permissions/permissions_api.h", "+chrome/browser/extensions/extension_api_unittest.h", "+chrome/browser/extensions/extension_apitest.h", + "+chrome/browser/extensions/extension_function_test_utils.h", "+chrome/browser/extensions/extension_service_unittest.h", + "+chrome/browser/extensions/test_extension_dir.h", "+chrome/browser/extensions/test_extension_system.h", "+chrome/browser/ui/browser.h", "+chrome/common/chrome_paths.h", "+chrome/common/extensions/features/feature_channel.h", "+chrome/common/extensions/manifest_tests/extension_manifest_test.h", "+chrome/test/base/testing_profile.h", + "+chrome/test/base/ui_test_utils.h", ], "(simple|complex)_feature_unittest\.cc|base_feature_provider_unittest\.cc": [ "+chrome/common/extensions/features/chrome_channel_feature_filter.h", diff --git a/extensions/browser/DEPS b/extensions/browser/DEPS index dfc7fe1..af6e02ab 100644 --- a/extensions/browser/DEPS +++ b/extensions/browser/DEPS @@ -7,4 +7,5 @@ include_rules = [ "+sync", "+third_party/leveldatabase", "+third_party/skia/include", + "+webkit/browser/fileapi", ] diff --git a/chrome/browser/extensions/api/runtime/runtime_api.cc b/extensions/browser/api/runtime/runtime_api.cc index fbb35ed..942c3a60d 100644 --- a/chrome/browser/extensions/api/runtime/runtime_api.cc +++ b/extensions/browser/api/runtime/runtime_api.cc @@ -1,8 +1,8 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// 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 "chrome/browser/extensions/api/runtime/runtime_api.h" +#include "extensions/browser/api/runtime/runtime_api.h" #include <utility> @@ -11,48 +11,34 @@ #include "base/memory/scoped_ptr.h" #include "base/metrics/histogram.h" #include "base/values.h" -#include "chrome/browser/browser_process.h" +#include "base/version.h" #include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/extensions/extension_service.h" -#include "chrome/browser/extensions/extension_warning_service.h" -#include "chrome/browser/extensions/updater/extension_updater.h" -#include "chrome/browser/omaha_query_params/omaha_query_params.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/ui/browser_finder.h" -#include "chrome/browser/ui/browser_navigator.h" -#include "chrome/browser/ui/browser_window.h" -#include "chrome/common/extensions/api/runtime.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" +#include "extensions/browser/api/runtime/runtime_api_delegate.h" #include "extensions/browser/event_router.h" #include "extensions/browser/extension_host.h" +#include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/extensions_browser_client.h" #include "extensions/browser/lazy_background_task_queue.h" #include "extensions/browser/process_manager.h" +#include "extensions/common/api/runtime.h" #include "extensions/common/error_utils.h" #include "extensions/common/extension.h" #include "extensions/common/manifest_handlers/background_info.h" #include "url/gurl.h" #include "webkit/browser/fileapi/isolated_context.h" -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/user_manager.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/power_manager_client.h" -#endif - using content::BrowserContext; -namespace GetPlatformInfo = extensions::api::runtime::GetPlatformInfo; - namespace extensions { -namespace runtime = api::runtime; +namespace runtime = core_api::runtime; namespace { @@ -64,10 +50,9 @@ const char kInstallReasonUpdate[] = "update"; const char kInstallReasonInstall[] = "install"; const char kInstallPreviousVersion[] = "previousVersion"; const char kInvalidUrlError[] = "Invalid URL."; +const char kPlatformInfoUnavailable[] = "Platform information unavailable."; + const char kUpdatesDisabledError[] = "Autoupdate is not enabled."; -const char kUpdateFound[] = "update_available"; -const char kUpdateNotFound[] = "no_update"; -const char kUpdateThrottled[] = "throttled"; // A preference key storing the url loaded when an extension is uninstalled. const char kUninstallUrl[] = "uninstall_url"; @@ -77,14 +62,6 @@ const char kUninstallUrl[] = "uninstall_url"; // with the equivalent Pepper API. const char kPackageDirectoryPath[] = "crxfs"; -// If an extension reloads itself within this many miliseconds of reloading -// itself, the reload is considered suspiciously fast. -const int kFastReloadTime = 10000; - -// After this many suspiciously fast consecutive reloads, an extension will get -// disabled. -const int kFastReloadCount = 5; - void DispatchOnStartupEventImpl(BrowserContext* browser_context, const std::string& extension_id, bool first_call, @@ -113,27 +90,27 @@ void DispatchOnStartupEventImpl(BrowserContext* browser_context, extension_id); if (extension && BackgroundInfo::HasPersistentBackgroundPage(extension) && first_call && - system->lazy_background_task_queue()-> - ShouldEnqueueTask(browser_context, extension)) { + system->lazy_background_task_queue()->ShouldEnqueueTask(browser_context, + extension)) { system->lazy_background_task_queue()->AddPendingTask( - browser_context, extension_id, - base::Bind(&DispatchOnStartupEventImpl, - browser_context, extension_id, false)); + browser_context, + extension_id, + base::Bind( + &DispatchOnStartupEventImpl, browser_context, extension_id, false)); return; } scoped_ptr<base::ListValue> event_args(new base::ListValue()); - scoped_ptr<Event> event(new Event(runtime::OnStartup::kEventName, - event_args.Pass())); + scoped_ptr<Event> event( + new Event(runtime::OnStartup::kEventName, event_args.Pass())); system->event_router()->DispatchEventToExtension(extension_id, event.Pass()); } void SetUninstallURL(ExtensionPrefs* prefs, const std::string& extension_id, const std::string& url_string) { - prefs->UpdateExtensionPref(extension_id, - kUninstallUrl, - new base::StringValue(url_string)); + prefs->UpdateExtensionPref( + extension_id, kUninstallUrl, new base::StringValue(url_string)); } #if defined(ENABLE_EXTENSIONS) @@ -158,19 +135,23 @@ BrowserContextKeyedAPIFactory<RuntimeAPI>* RuntimeAPI::GetFactoryInstance() { } RuntimeAPI::RuntimeAPI(content::BrowserContext* context) - : browser_context_(context), - dispatch_chrome_updated_event_(false), - registered_for_updates_(false) { - registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, + : browser_context_(context), dispatch_chrome_updated_event_(false) { + registrar_.Add(this, + chrome::NOTIFICATION_EXTENSIONS_READY, content::Source<BrowserContext>(context)); registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, content::Source<BrowserContext>(context)); - registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, + registrar_.Add(this, + chrome::NOTIFICATION_EXTENSION_INSTALLED, content::Source<BrowserContext>(context)); - registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, + registrar_.Add(this, + chrome::NOTIFICATION_EXTENSION_UNINSTALLED, content::Source<BrowserContext>(context)); + delegate_ = ExtensionsBrowserClient::Get()->CreateRuntimeAPIDelegate( + browser_context_); + // Check if registered events are up-to-date. We can only do this once // per browser context, since it updates internal state when called. dispatch_chrome_updated_event_ = @@ -178,10 +159,7 @@ RuntimeAPI::RuntimeAPI(content::BrowserContext* context) } RuntimeAPI::~RuntimeAPI() { - if (registered_for_updates_) { - ExtensionSystem::Get(browser_context_)-> - extension_service()->RemoveUpdateObserver(this); - } + delegate_->RemoveUpdateObserver(this); } void RuntimeAPI::Observe(int type, @@ -220,16 +198,14 @@ void RuntimeAPI::OnExtensionsReady() { // We're done restarting Chrome after an update. dispatch_chrome_updated_event_ = false; - registered_for_updates_ = true; - - ExtensionSystem* extension_system = ExtensionSystem::Get(browser_context_); - extension_system->extension_service()->AddUpdateObserver(this); + delegate_->AddUpdateObserver(this); // RuntimeAPI is redirected in incognito, so |browser_context_| is never // incognito. We don't observe incognito ProcessManagers but that is OK // because we don't send onStartup events to incognito browser contexts. DCHECK(!browser_context_->IsOffTheRecord()); // Some tests use partially constructed Profiles without a process manager. + ExtensionSystem* extension_system = ExtensionSystem::Get(browser_context_); if (extension_system->process_manager()) extension_system->process_manager()->AddObserver(this); } @@ -254,13 +230,7 @@ void RuntimeAPI::OnExtensionInstalled(const Extension* extension) { if (extension->is_ephemeral()) return; - // Get the previous version to check if this is an upgrade. - ExtensionService* service = ExtensionSystem::Get( - browser_context_)->extension_service(); - const Extension* old = service->GetExtensionById(extension->id(), true); - Version old_version; - if (old) - old_version = *old->version(); + Version old_version = delegate_->GetPreviousExtensionVersion(extension); // Dispatch the onInstalled event. base::MessageLoop::current()->PostTask( @@ -270,7 +240,6 @@ void RuntimeAPI::OnExtensionInstalled(const Extension* extension) { extension->id(), old_version, false)); - } void RuntimeAPI::OnExtensionUninstalled(const Extension* extension) { @@ -279,8 +248,7 @@ void RuntimeAPI::OnExtensionUninstalled(const Extension* extension) { if (extension->is_ephemeral()) return; - Profile* profile = Profile::FromBrowserContext(browser_context_); - RuntimeEventRouter::OnExtensionUninstalled(profile, extension->id()); + RuntimeEventRouter::OnExtensionUninstalled(browser_context_, extension->id()); } void RuntimeAPI::Shutdown() { @@ -294,76 +262,46 @@ void RuntimeAPI::Shutdown() { } void RuntimeAPI::OnAppUpdateAvailable(const Extension* extension) { - Profile* profile = Profile::FromBrowserContext(browser_context_); RuntimeEventRouter::DispatchOnUpdateAvailableEvent( - profile, extension->id(), extension->manifest()->value()); + browser_context_, extension->id(), extension->manifest()->value()); } void RuntimeAPI::OnChromeUpdateAvailable() { - Profile* profile = Profile::FromBrowserContext(browser_context_); - RuntimeEventRouter::DispatchOnBrowserUpdateAvailableEvent(profile); + RuntimeEventRouter::DispatchOnBrowserUpdateAvailableEvent(browser_context_); } void RuntimeAPI::OnBackgroundHostStartup(const Extension* extension) { RuntimeEventRouter::DispatchOnStartupEvent(browser_context_, extension->id()); } -void RuntimeAPI::MaybeReloadExtension(const std::string& extension_id) { - std::pair<base::TimeTicks, int>& reload_info = - last_reload_time_[extension_id]; - base::TimeTicks now = base::TimeTicks::Now(); - if (reload_info.first.is_null() || - (now - reload_info.first).InMilliseconds() > kFastReloadTime) { - reload_info.second = 0; - } else { - reload_info.second++; - } - if (!reload_info.first.is_null()) { - UMA_HISTOGRAM_LONG_TIMES("Extensions.RuntimeReloadTime", - now - reload_info.first); - } - UMA_HISTOGRAM_COUNTS_100("Extensions.RuntimeReloadFastCount", - reload_info.second); - reload_info.first = now; - - ExtensionService* service = - ExtensionSystem::Get(browser_context_)->extension_service(); - if (reload_info.second >= kFastReloadCount) { - // Unloading an extension clears all warnings, so first terminate the - // extension, and then add the warning. Since this is called from an - // extension function unloading the extension has to be done - // asynchronously. Fortunately PostTask guarentees FIFO order so just - // post both tasks. - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&ExtensionService::TerminateExtension, - service->AsWeakPtr(), - extension_id)); - ExtensionWarningSet warnings; - warnings.insert( - ExtensionWarning::CreateReloadTooFrequentWarning(extension_id)); - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&ExtensionWarningService::NotifyWarningsOnUI, - browser_context_, - warnings)); - } else { - // We can't call ReloadExtension directly, since when this method finishes - // it tries to decrease the reference count for the extension, which fails - // if the extension has already been reloaded; so instead we post a task. - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&ExtensionService::ReloadExtension, - service->AsWeakPtr(), - extension_id)); - } +void RuntimeAPI::ReloadExtension(const std::string& extension_id) { + delegate_->ReloadExtension(extension_id); +} + +bool RuntimeAPI::CheckForUpdates( + const std::string& extension_id, + const RuntimeAPIDelegate::UpdateCheckCallback& callback) { + return delegate_->CheckForUpdates(extension_id, callback); +} + +void RuntimeAPI::OpenURL(const GURL& update_url) { + delegate_->OpenURL(update_url); +} + +bool RuntimeAPI::GetPlatformInfo(runtime::PlatformInfo* info) { + return delegate_->GetPlatformInfo(info); +} + +bool RuntimeAPI::RestartDevice(std::string* error_message) { + return delegate_->RestartDevice(error_message); } /////////////////////////////////////////////////////////////////////////////// // static void RuntimeEventRouter::DispatchOnStartupEvent( - content::BrowserContext* context, const std::string& extension_id) { + content::BrowserContext* context, + const std::string& extension_id) { DispatchOnStartupEventImpl(context, extension_id, true, NULL); } @@ -391,55 +329,55 @@ void RuntimeEventRouter::DispatchOnInstalledEvent( info->SetString(kInstallReason, kInstallReasonInstall); } DCHECK(system->event_router()); - scoped_ptr<Event> event(new Event(runtime::OnInstalled::kEventName, - event_args.Pass())); + scoped_ptr<Event> event( + new Event(runtime::OnInstalled::kEventName, event_args.Pass())); system->event_router()->DispatchEventWithLazyListener(extension_id, event.Pass()); } // static void RuntimeEventRouter::DispatchOnUpdateAvailableEvent( - Profile* profile, + content::BrowserContext* context, const std::string& extension_id, const base::DictionaryValue* manifest) { - ExtensionSystem* system = ExtensionSystem::Get(profile); + ExtensionSystem* system = ExtensionSystem::Get(context); if (!system) return; scoped_ptr<base::ListValue> args(new base::ListValue); args->Append(manifest->DeepCopy()); DCHECK(system->event_router()); - scoped_ptr<Event> event(new Event(runtime::OnUpdateAvailable::kEventName, - args.Pass())); + scoped_ptr<Event> event( + new Event(runtime::OnUpdateAvailable::kEventName, args.Pass())); system->event_router()->DispatchEventToExtension(extension_id, event.Pass()); } // static void RuntimeEventRouter::DispatchOnBrowserUpdateAvailableEvent( - Profile* profile) { - ExtensionSystem* system = ExtensionSystem::Get(profile); + content::BrowserContext* context) { + ExtensionSystem* system = ExtensionSystem::Get(context); if (!system) return; scoped_ptr<base::ListValue> args(new base::ListValue); DCHECK(system->event_router()); - scoped_ptr<Event> event(new Event( - runtime::OnBrowserUpdateAvailable::kEventName, args.Pass())); + scoped_ptr<Event> event( + new Event(runtime::OnBrowserUpdateAvailable::kEventName, args.Pass())); system->event_router()->BroadcastEvent(event.Pass()); } // static void RuntimeEventRouter::DispatchOnRestartRequiredEvent( - Profile* profile, + content::BrowserContext* context, const std::string& app_id, - api::runtime::OnRestartRequired::Reason reason) { - ExtensionSystem* system = ExtensionSystem::Get(profile); + core_api::runtime::OnRestartRequired::Reason reason) { + ExtensionSystem* system = ExtensionSystem::Get(context); if (!system) return; scoped_ptr<Event> event( new Event(runtime::OnRestartRequired::kEventName, - api::runtime::OnRestartRequired::Create(reason))); + core_api::runtime::OnRestartRequired::Create(reason))); DCHECK(system->event_router()); system->event_router()->DispatchEventToExtension(app_id, event.Pass()); @@ -447,214 +385,116 @@ void RuntimeEventRouter::DispatchOnRestartRequiredEvent( // static void RuntimeEventRouter::OnExtensionUninstalled( - Profile* profile, + content::BrowserContext* context, const std::string& extension_id) { #if defined(ENABLE_EXTENSIONS) - GURL uninstall_url(GetUninstallURL(ExtensionPrefs::Get(profile), - extension_id)); + GURL uninstall_url( + GetUninstallURL(ExtensionPrefs::Get(context), extension_id)); if (uninstall_url.is_empty()) return; - Browser* browser = chrome::FindLastActiveWithProfile(profile, - chrome::GetActiveDesktop()); - if (!browser) - browser = new Browser(Browser::CreateParams(profile, - chrome::GetActiveDesktop())); - - chrome::NavigateParams params(browser, uninstall_url, - content::PAGE_TRANSITION_CLIENT_REDIRECT); - params.disposition = NEW_FOREGROUND_TAB; - params.user_gesture = false; - chrome::Navigate(¶ms); + RuntimeAPI::GetFactoryInstance()->Get(context)->OpenURL(uninstall_url); #endif // defined(ENABLE_EXTENSIONS) } -bool RuntimeGetBackgroundPageFunction::RunAsync() { - ExtensionSystem* system = ExtensionSystem::Get(GetProfile()); - ExtensionHost* host = system->process_manager()-> - GetBackgroundHostForExtension(extension_id()); - if (system->lazy_background_task_queue()->ShouldEnqueueTask(GetProfile(), +ExtensionFunction::ResponseAction RuntimeGetBackgroundPageFunction::Run() { + ExtensionSystem* system = ExtensionSystem::Get(browser_context()); + ExtensionHost* host = + system->process_manager()->GetBackgroundHostForExtension(extension_id()); + if (system->lazy_background_task_queue()->ShouldEnqueueTask(browser_context(), GetExtension())) { system->lazy_background_task_queue()->AddPendingTask( - GetProfile(), + browser_context(), extension_id(), base::Bind(&RuntimeGetBackgroundPageFunction::OnPageLoaded, this)); } else if (host) { OnPageLoaded(host); } else { - error_ = kNoBackgroundPageError; - return false; + return RespondNow(Error(kNoBackgroundPageError)); } - return true; + return RespondLater(); } void RuntimeGetBackgroundPageFunction::OnPageLoaded(ExtensionHost* host) { if (host) { - SendResponse(true); + Respond(NoArguments()); } else { - error_ = kPageLoadError; - SendResponse(false); + Respond(Error(kPageLoadError)); } } -bool RuntimeSetUninstallURLFunction::RunSync() { +ExtensionFunction::ResponseAction RuntimeSetUninstallURLFunction::Run() { std::string url_string; - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url_string)); + EXTENSION_FUNCTION_VALIDATE_TYPESAFE(args_->GetString(0, &url_string)); GURL url(url_string); if (!url.is_valid()) { - error_ = ErrorUtils::FormatErrorMessage(kInvalidUrlError, url_string); - return false; + return RespondNow( + Error(ErrorUtils::FormatErrorMessage(kInvalidUrlError, url_string))); } - SetUninstallURL( - ExtensionPrefs::Get(GetProfile()), extension_id(), url_string); - return true; + ExtensionPrefs::Get(browser_context()), extension_id(), url_string); + return RespondNow(NoArguments()); } -bool RuntimeReloadFunction::RunSync() { - RuntimeAPI::GetFactoryInstance()->Get(GetProfile())->MaybeReloadExtension( +ExtensionFunction::ResponseAction RuntimeReloadFunction::Run() { + RuntimeAPI::GetFactoryInstance()->Get(browser_context())->ReloadExtension( extension_id()); - return true; + return RespondNow(NoArguments()); } -RuntimeRequestUpdateCheckFunction::RuntimeRequestUpdateCheckFunction() { - registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND, - content::NotificationService::AllSources()); -} - -bool RuntimeRequestUpdateCheckFunction::RunAsync() { - ExtensionSystem* system = ExtensionSystem::Get(GetProfile()); - ExtensionService* service = system->extension_service(); - ExtensionUpdater* updater = service->updater(); - if (!updater) { - error_ = kUpdatesDisabledError; - return false; - } - - did_reply_ = false; - if (!updater->CheckExtensionSoon(extension_id(), base::Bind( - &RuntimeRequestUpdateCheckFunction::CheckComplete, this))) { - did_reply_ = true; - SetResult(new base::StringValue(kUpdateThrottled)); - SendResponse(true); +ExtensionFunction::ResponseAction RuntimeRequestUpdateCheckFunction::Run() { + if (!RuntimeAPI::GetFactoryInstance() + ->Get(browser_context()) + ->CheckForUpdates( + extension_id(), + base::Bind(&RuntimeRequestUpdateCheckFunction::CheckComplete, + this))) { + return RespondNow(Error(kUpdatesDisabledError)); } - return true; -} - -void RuntimeRequestUpdateCheckFunction::CheckComplete() { - if (did_reply_) - return; - - did_reply_ = true; - - // Since no UPDATE_FOUND notification was seen, this generally would mean - // that no update is found, but a previous update check might have already - // queued up an update, so check for that here to make sure we return the - // right value. - ExtensionSystem* system = ExtensionSystem::Get(GetProfile()); - ExtensionService* service = system->extension_service(); - const Extension* update = service->GetPendingExtensionUpdate(extension_id()); - if (update) { - ReplyUpdateFound(update->VersionString()); + return RespondLater(); +} + +void RuntimeRequestUpdateCheckFunction::CheckComplete( + const RuntimeAPIDelegate::UpdateCheckResult& result) { + if (result.success) { + base::ListValue* results = new base::ListValue; + results->AppendString(result.response); + base::DictionaryValue* details = new base::DictionaryValue; + results->Append(details); + details->SetString("version", result.version); + Respond(MultipleArguments(results)); } else { - SetResult(new base::StringValue(kUpdateNotFound)); + Respond(SingleArgument(new base::StringValue(result.response))); } - SendResponse(true); } -void RuntimeRequestUpdateCheckFunction::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - if (did_reply_) - return; - - DCHECK(type == chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND); - typedef const std::pair<std::string, Version> UpdateDetails; - const std::string& id = content::Details<UpdateDetails>(details)->first; - const Version& version = content::Details<UpdateDetails>(details)->second; - if (id == extension_id()) { - ReplyUpdateFound(version.GetString()); +ExtensionFunction::ResponseAction RuntimeRestartFunction::Run() { + std::string message; + bool result = + RuntimeAPI::GetFactoryInstance()->Get(browser_context())->RestartDevice( + &message); + if (!result) { + return RespondNow(Error(message)); } + return RespondNow(NoArguments()); } -void RuntimeRequestUpdateCheckFunction::ReplyUpdateFound( - const std::string& version) { - did_reply_ = true; - results_.reset(new base::ListValue); - results_->AppendString(kUpdateFound); - base::DictionaryValue* details = new base::DictionaryValue; - results_->Append(details); - details->SetString("version", version); - SendResponse(true); -} - -bool RuntimeRestartFunction::RunSync() { -#if defined(OS_CHROMEOS) - if (chromeos::UserManager::Get()->IsLoggedInAsKioskApp()) { - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->RequestRestart(); - return true; - } -#endif - SetError("Function available only for ChromeOS kiosk mode."); - return false; -} - -bool RuntimeGetPlatformInfoFunction::RunSync() { - GetPlatformInfo::Results::PlatformInfo info; - - const char* os = chrome::OmahaQueryParams::GetOS(); - if (strcmp(os, "mac") == 0) { - info.os = GetPlatformInfo::Results::PlatformInfo::OS_MAC_; - } else if (strcmp(os, "win") == 0) { - info.os = GetPlatformInfo::Results::PlatformInfo::OS_WIN_; - } else if (strcmp(os, "android") == 0) { - info.os = GetPlatformInfo::Results::PlatformInfo::OS_ANDROID_; - } else if (strcmp(os, "cros") == 0) { - info.os = GetPlatformInfo::Results::PlatformInfo::OS_CROS_; - } else if (strcmp(os, "linux") == 0) { - info.os = GetPlatformInfo::Results::PlatformInfo::OS_LINUX_; - } else if (strcmp(os, "openbsd") == 0) { - info.os = GetPlatformInfo::Results::PlatformInfo::OS_OPENBSD_; - } else { - NOTREACHED(); - return false; +ExtensionFunction::ResponseAction RuntimeGetPlatformInfoFunction::Run() { + runtime::PlatformInfo info; + if (!RuntimeAPI::GetFactoryInstance() + ->Get(browser_context()) + ->GetPlatformInfo(&info)) { + return RespondNow(Error(kPlatformInfoUnavailable)); } - - const char* arch = chrome::OmahaQueryParams::GetArch(); - if (strcmp(arch, "arm") == 0) { - info.arch = GetPlatformInfo::Results::PlatformInfo::ARCH_ARM; - } else if (strcmp(arch, "x86") == 0) { - info.arch = GetPlatformInfo::Results::PlatformInfo::ARCH_X86_32; - } else if (strcmp(arch, "x64") == 0) { - info.arch = GetPlatformInfo::Results::PlatformInfo::ARCH_X86_64; - } else { - NOTREACHED(); - return false; - } - - const char* nacl_arch = chrome::OmahaQueryParams::GetNaclArch(); - if (strcmp(nacl_arch, "arm") == 0) { - info.nacl_arch = GetPlatformInfo::Results::PlatformInfo::NACL_ARCH_ARM; - } else if (strcmp(nacl_arch, "x86-32") == 0) { - info.nacl_arch = GetPlatformInfo::Results::PlatformInfo::NACL_ARCH_X86_32; - } else if (strcmp(nacl_arch, "x86-64") == 0) { - info.nacl_arch = GetPlatformInfo::Results::PlatformInfo::NACL_ARCH_X86_64; - } else { - NOTREACHED(); - return false; - } - - results_ = GetPlatformInfo::Results::Create(info); - return true; + return RespondNow(MultipleArguments( + runtime::GetPlatformInfo::Results::Create(info).release())); } -bool RuntimeGetPackageDirectoryEntryFunction::RunSync() { +ExtensionFunction::ResponseAction +RuntimeGetPackageDirectoryEntryFunction::Run() { fileapi::IsolatedContext* isolated_context = fileapi::IsolatedContext::GetInstance(); DCHECK(isolated_context); @@ -669,10 +509,9 @@ bool RuntimeGetPackageDirectoryEntryFunction::RunSync() { content::ChildProcessSecurityPolicy::GetInstance(); policy->GrantReadFileSystem(renderer_id, filesystem_id); base::DictionaryValue* dict = new base::DictionaryValue(); - SetResult(dict); dict->SetString("fileSystemId", filesystem_id); dict->SetString("baseName", relative_path); - return true; + return RespondNow(SingleArgument(dict)); } -} // namespace extensions +} // namespace extensions diff --git a/chrome/browser/extensions/api/runtime/runtime_api.h b/extensions/browser/api/runtime/runtime_api.h index f648be1..e341398 100644 --- a/chrome/browser/extensions/api/runtime/runtime_api.h +++ b/extensions/browser/api/runtime/runtime_api.h @@ -1,21 +1,20 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// 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 CHROME_BROWSER_EXTENSIONS_API_RUNTIME_RUNTIME_API_H_ -#define CHROME_BROWSER_EXTENSIONS_API_RUNTIME_RUNTIME_API_H_ +#ifndef EXTENSIONS_BROWSER_API_RUNTIME_RUNTIME_API_H_ +#define EXTENSIONS_BROWSER_API_RUNTIME_RUNTIME_API_H_ #include <string> -#include "chrome/browser/extensions/chrome_extension_function.h" -#include "chrome/common/extensions/api/runtime.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "extensions/browser/api/runtime/runtime_api_delegate.h" #include "extensions/browser/browser_context_keyed_api_factory.h" +#include "extensions/browser/extension_function.h" #include "extensions/browser/process_manager_observer.h" #include "extensions/browser/update_observer.h" - -class Profile; +#include "extensions/common/api/runtime.h" namespace base { class Version; @@ -26,6 +25,13 @@ class BrowserContext; } namespace extensions { + +namespace core_api { +namespace runtime { +struct PlatformInfo; +} +} + class Extension; class ExtensionHost; @@ -47,7 +53,12 @@ class RuntimeAPI : public BrowserContextKeyedAPI, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; - void MaybeReloadExtension(const std::string& extension_id); + void ReloadExtension(const std::string& extension_id); + bool CheckForUpdates(const std::string& extension_id, + const RuntimeAPIDelegate::UpdateCheckCallback& callback); + void OpenURL(const GURL& uninstall_url); + bool GetPlatformInfo(core_api::runtime::PlatformInfo* info); + bool RestartDevice(std::string* error_message); private: friend class BrowserContextKeyedAPIFactory<RuntimeAPI>; @@ -70,23 +81,16 @@ class RuntimeAPI : public BrowserContextKeyedAPI, // ProcessManagerObserver implementation: virtual void OnBackgroundHostStartup(const Extension* extension) OVERRIDE; + scoped_ptr<RuntimeAPIDelegate> delegate_; + content::BrowserContext* browser_context_; // True if we should dispatch the chrome.runtime.onInstalled event with // reason "chrome_update" upon loading each extension. bool dispatch_chrome_updated_event_; - // Whether the API registered with the ExtensionService to receive - // update notifications. - bool registered_for_updates_; - content::NotificationRegistrar registrar_; - // Map to prevent extensions from getting stuck in reload loops. Maps - // extension id to the last time it was reloaded and the number of times - // it was reloaded with not enough time in between reloads. - std::map<std::string, std::pair<base::TimeTicks, int> > last_reload_time_; - DISALLOW_COPY_AND_ASSIGN(RuntimeAPI); }; @@ -104,108 +108,99 @@ class RuntimeEventRouter { // Dispatches the onUpdateAvailable event to the given extension. static void DispatchOnUpdateAvailableEvent( - Profile* profile, + content::BrowserContext* context, const std::string& extension_id, const base::DictionaryValue* manifest); // Dispatches the onBrowserUpdateAvailable event to all extensions. - static void DispatchOnBrowserUpdateAvailableEvent(Profile* profile); + static void DispatchOnBrowserUpdateAvailableEvent( + content::BrowserContext* context); // Dispatches the onRestartRequired event to the given app. static void DispatchOnRestartRequiredEvent( - Profile* profile, + content::BrowserContext* context, const std::string& app_id, - api::runtime::OnRestartRequired::Reason reason); + core_api::runtime::OnRestartRequired::Reason reason); // Does any work needed at extension uninstall (e.g. load uninstall url). - static void OnExtensionUninstalled(Profile* profile, + static void OnExtensionUninstalled(content::BrowserContext* context, const std::string& extension_id); }; -class RuntimeGetBackgroundPageFunction : public ChromeAsyncExtensionFunction { +class RuntimeGetBackgroundPageFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("runtime.getBackgroundPage", RUNTIME_GETBACKGROUNDPAGE) protected: virtual ~RuntimeGetBackgroundPageFunction() {} - virtual bool RunAsync() OVERRIDE; + virtual ResponseAction Run() OVERRIDE; private: void OnPageLoaded(ExtensionHost*); }; -class RuntimeSetUninstallURLFunction : public ChromeSyncExtensionFunction { +class RuntimeSetUninstallURLFunction : public UIThreadExtensionFunction { public: - DECLARE_EXTENSION_FUNCTION("runtime.setUninstallURL", - RUNTIME_SETUNINSTALLURL) + DECLARE_EXTENSION_FUNCTION("runtime.setUninstallURL", RUNTIME_SETUNINSTALLURL) protected: virtual ~RuntimeSetUninstallURLFunction() {} - virtual bool RunSync() OVERRIDE; + virtual ResponseAction Run() OVERRIDE; }; -class RuntimeReloadFunction : public ChromeSyncExtensionFunction { +class RuntimeReloadFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("runtime.reload", RUNTIME_RELOAD) protected: virtual ~RuntimeReloadFunction() {} - virtual bool RunSync() OVERRIDE; + virtual ResponseAction Run() OVERRIDE; }; -class RuntimeRequestUpdateCheckFunction : public ChromeAsyncExtensionFunction, - public content::NotificationObserver { +class RuntimeRequestUpdateCheckFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("runtime.requestUpdateCheck", RUNTIME_REQUESTUPDATECHECK) - RuntimeRequestUpdateCheckFunction(); protected: virtual ~RuntimeRequestUpdateCheckFunction() {} - virtual bool RunAsync() OVERRIDE; + virtual ResponseAction Run() OVERRIDE; - // Implements content::NotificationObserver interface. - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; private: - void CheckComplete(); - void ReplyUpdateFound(const std::string& version); - - content::NotificationRegistrar registrar_; - bool did_reply_; + void CheckComplete(const RuntimeAPIDelegate::UpdateCheckResult& result); }; -class RuntimeRestartFunction : public ChromeSyncExtensionFunction { +class RuntimeRestartFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("runtime.restart", RUNTIME_RESTART) protected: virtual ~RuntimeRestartFunction() {} - virtual bool RunSync() OVERRIDE; + virtual ResponseAction Run() OVERRIDE; }; -class RuntimeGetPlatformInfoFunction : public ChromeSyncExtensionFunction { +class RuntimeGetPlatformInfoFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("runtime.getPlatformInfo", RUNTIME_GETPLATFORMINFO); + protected: virtual ~RuntimeGetPlatformInfoFunction() {} - virtual bool RunSync() OVERRIDE; + virtual ResponseAction Run() OVERRIDE; }; class RuntimeGetPackageDirectoryEntryFunction - : public ChromeSyncExtensionFunction { + : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("runtime.getPackageDirectoryEntry", RUNTIME_GETPACKAGEDIRECTORYENTRY) protected: virtual ~RuntimeGetPackageDirectoryEntryFunction() {} - virtual bool RunSync() OVERRIDE; + virtual ResponseAction Run() OVERRIDE; }; } // namespace extensions -#endif // CHROME_BROWSER_EXTENSIONS_API_RUNTIME_RUNTIME_API_H_ +#endif // EXTENSIONS_BROWSER_API_RUNTIME_RUNTIME_API_H_ diff --git a/extensions/browser/api/runtime/runtime_api_delegate.cc b/extensions/browser/api/runtime/runtime_api_delegate.cc new file mode 100644 index 0000000..3ead8b6 --- /dev/null +++ b/extensions/browser/api/runtime/runtime_api_delegate.cc @@ -0,0 +1,16 @@ +// 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/api/runtime/runtime_api_delegate.h" + +namespace extensions { + +RuntimeAPIDelegate::UpdateCheckResult::UpdateCheckResult( + bool success, + const std::string& response, + const std::string& version) + : success(success), response(response), version(version) { +} + +} // namespace extensions diff --git a/extensions/browser/api/runtime/runtime_api_delegate.h b/extensions/browser/api/runtime/runtime_api_delegate.h new file mode 100644 index 0000000..98b4963 --- /dev/null +++ b/extensions/browser/api/runtime/runtime_api_delegate.h @@ -0,0 +1,77 @@ +// 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_API_RUNTIME_RUNTIME_API_DELEGATE_H +#define EXTENSIONS_BROWSER_API_RUNTIME_RUNTIME_API_DELEGATE_H + +#include "base/callback.h" +#include "base/version.h" + +class GURL; + +namespace extensions { + +namespace core_api { +namespace runtime { +struct PlatformInfo; +} +} + +class Extension; +class UpdateObserver; + +// This is a delegate interface for chrome.runtime API behavior. Clients must +// vend some implementation of this interface through +// ExtensionsBrowserClient::CreateRuntimeAPIDelegate. +class RuntimeAPIDelegate { + public: + struct UpdateCheckResult { + bool success; + std::string response; + std::string version; + + UpdateCheckResult(bool success, + const std::string& response, + const std::string& version); + }; + + virtual ~RuntimeAPIDelegate() {} + + // The callback given to RequestUpdateCheck. + typedef base::Callback<void(const UpdateCheckResult&)> UpdateCheckCallback; + + // Registers an UpdateObserver on behalf of the runtime API. + virtual void AddUpdateObserver(UpdateObserver* observer) = 0; + + // Unregisters an UpdateObserver on behalf of the runtime API. + virtual void RemoveUpdateObserver(UpdateObserver* observer) = 0; + + // Determines an extension's previously installed version if applicable. + virtual base::Version GetPreviousExtensionVersion( + const Extension* extension) = 0; + + // Reloads an extension. + virtual void ReloadExtension(const std::string& extension_id) = 0; + + // Requests an extensions update update check. Returns |false| if updates + // are disabled. Otherwise |callback| is called with the result of the + // update check. + virtual bool CheckForUpdates(const std::string& extension_id, + const UpdateCheckCallback& callback) = 0; + + // Navigates the browser to a URL on behalf of the runtime API. + virtual void OpenURL(const GURL& uninstall_url) = 0; + + // Populates platform info to be provided by the getPlatformInfo function. + // Returns false iff no info is provided. + virtual bool GetPlatformInfo(core_api::runtime::PlatformInfo* info) = 0; + + // Request a restart of the host device. Returns false iff the device + // will not be restarted. + virtual bool RestartDevice(std::string* error_message) = 0; +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_API_RUNTIME_RUNTIME_API_DELEGATE_H diff --git a/chrome/browser/extensions/api/runtime/runtime_apitest.cc b/extensions/browser/api/runtime/runtime_apitest.cc index ccb45ce..6fd81f1 100644 --- a/chrome/browser/extensions/api/runtime/runtime_apitest.cc +++ b/extensions/browser/api/runtime/runtime_apitest.cc @@ -1,15 +1,15 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// 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 "chrome/browser/apps/app_browsertest_util.h" #include "chrome/browser/extensions/api/management/management_api.h" -#include "chrome/browser/extensions/api/runtime/runtime_api.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_function_test_utils.h" #include "chrome/browser/extensions/test_extension_dir.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/notification_service.h" +#include "extensions/browser/api/runtime/runtime_api.h" #include "extensions/browser/extension_registry.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -34,9 +34,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeRuntimeUnprivileged) { IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeRuntimeUninstallURL) { // Auto-confirm the uninstall dialog. extensions::ManagementUninstallFunction::SetAutoConfirmForTest(true); - ASSERT_TRUE(LoadExtension( - test_data_dir_.AppendASCII("runtime").AppendASCII("uninstall_url"). - AppendASCII("sets_uninstall_url"))); + ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("runtime") + .AppendASCII("uninstall_url") + .AppendASCII("sets_uninstall_url"))); ASSERT_TRUE(RunExtensionTest("runtime/uninstall_url")) << message_; } @@ -45,9 +45,7 @@ namespace extensions { IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeRuntimeGetPlatformInfo) { scoped_ptr<base::Value> result( extension_function_test_utils::RunFunctionAndReturnSingleResult( - new RuntimeGetPlatformInfoFunction(), - "[]", - browser())); + new RuntimeGetPlatformInfoFunction(), "[]", browser())); ASSERT_TRUE(result.get() != NULL); base::DictionaryValue* dict = extension_function_test_utils::ToDictionary(result.get()); diff --git a/extensions/browser/browser_context_keyed_service_factories.cc b/extensions/browser/browser_context_keyed_service_factories.cc index 38ee253..6091a0f 100644 --- a/extensions/browser/browser_context_keyed_service_factories.cc +++ b/extensions/browser/browser_context_keyed_service_factories.cc @@ -5,6 +5,7 @@ #include "extensions/browser/browser_context_keyed_service_factories.h" #include "extensions/browser/api/api_resource_manager.h" +#include "extensions/browser/api/runtime/runtime_api.h" #include "extensions/browser/api/socket/socket.h" #include "extensions/browser/api/socket/tcp_socket.h" #include "extensions/browser/api/socket/udp_socket.h" @@ -26,9 +27,10 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() { core_api::TCPServerSocketEventDispatcher::GetFactoryInstance(); core_api::TCPSocketEventDispatcher::GetFactoryInstance(); core_api::UDPSocketEventDispatcher::GetFactoryInstance(); - extensions::ExtensionPrefsFactory::GetInstance(); - extensions::RendererStartupHelperFactory::GetInstance(); - extensions::StorageFrontend::GetFactoryInstance(); + ExtensionPrefsFactory::GetInstance(); + RendererStartupHelperFactory::GetInstance(); + RuntimeAPI::GetFactoryInstance(); + StorageFrontend::GetFactoryInstance(); } } // namespace extensions diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h index e3b91b2..9356aa6 100644 --- a/extensions/browser/extensions_browser_client.h +++ b/extensions/browser/extensions_browser_client.h @@ -40,6 +40,7 @@ class ExtensionPrefsObserver; class ExtensionSystem; class ExtensionSystemProvider; class InfoMap; +class RuntimeAPIDelegate; // Interface to allow the extensions module to make browser-process-specific // queries of the embedder. Should be Set() once in the browser process. @@ -166,6 +167,12 @@ class ExtensionsBrowserClient { virtual void RegisterExtensionFunctions( ExtensionFunctionRegistry* registry) const = 0; + // Creates a RuntimeAPIDelegate responsible for handling extensions + // management-related events such as update and installation on behalf of the + // core runtime API implementation. + virtual scoped_ptr<RuntimeAPIDelegate> CreateRuntimeAPIDelegate( + content::BrowserContext* context) const = 0; + // Returns the single instance of |this|. static ExtensionsBrowserClient* Get(); diff --git a/extensions/browser/test_extensions_browser_client.cc b/extensions/browser/test_extensions_browser_client.cc index 6e919ea..7708ca7 100644 --- a/extensions/browser/test_extensions_browser_client.cc +++ b/extensions/browser/test_extensions_browser_client.cc @@ -7,6 +7,7 @@ #include "content/public/browser/browser_context.h" #include "extensions/browser/app_sorting.h" #include "extensions/browser/extension_host_delegate.h" +#include "extensions/browser/test_runtime_api_delegate.h" using content::BrowserContext; @@ -155,4 +156,10 @@ TestExtensionsBrowserClient::GetExtensionSystemFactory() { void TestExtensionsBrowserClient::RegisterExtensionFunctions( ExtensionFunctionRegistry* registry) const {} +scoped_ptr<RuntimeAPIDelegate> +TestExtensionsBrowserClient::CreateRuntimeAPIDelegate( + content::BrowserContext* context) const { + return scoped_ptr<RuntimeAPIDelegate>(new TestRuntimeAPIDelegate()); +} + } // namespace extensions diff --git a/extensions/browser/test_extensions_browser_client.h b/extensions/browser/test_extensions_browser_client.h index f7401fe..ff09ae3 100644 --- a/extensions/browser/test_extensions_browser_client.h +++ b/extensions/browser/test_extensions_browser_client.h @@ -73,6 +73,8 @@ class TestExtensionsBrowserClient : public ExtensionsBrowserClient { virtual ExtensionSystemProvider* GetExtensionSystemFactory() OVERRIDE; virtual void RegisterExtensionFunctions( ExtensionFunctionRegistry* registry) const OVERRIDE; + virtual scoped_ptr<RuntimeAPIDelegate> CreateRuntimeAPIDelegate( + content::BrowserContext* context) const OVERRIDE; private: content::BrowserContext* main_context_; // Not owned. diff --git a/extensions/browser/test_runtime_api_delegate.cc b/extensions/browser/test_runtime_api_delegate.cc new file mode 100644 index 0000000..9394050 --- /dev/null +++ b/extensions/browser/test_runtime_api_delegate.cc @@ -0,0 +1,53 @@ +// 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/test_runtime_api_delegate.h" + +#include "extensions/common/api/runtime.h" + +namespace extensions { + +using core_api::runtime::PlatformInfo; + +TestRuntimeAPIDelegate::TestRuntimeAPIDelegate() { +} + +TestRuntimeAPIDelegate::~TestRuntimeAPIDelegate() { +} + +void TestRuntimeAPIDelegate::AddUpdateObserver(UpdateObserver* observer) { +} + +void TestRuntimeAPIDelegate::RemoveUpdateObserver(UpdateObserver* observer) { +} + +base::Version TestRuntimeAPIDelegate::GetPreviousExtensionVersion( + const Extension* extension) { + return base::Version(); +} + +void TestRuntimeAPIDelegate::ReloadExtension(const std::string& extension_id) { +} + +bool TestRuntimeAPIDelegate::CheckForUpdates( + const std::string& extension_id, + const UpdateCheckCallback& callback) { + return false; +} + +void TestRuntimeAPIDelegate::OpenURL(const GURL& uninstall_url) { +} + +bool TestRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) { + // TODO(rockot): This probably isn't right. Maybe this delegate should just + // support manual PlatformInfo override for tests if necessary. + info->os = PlatformInfo::OS_CROS_; + return true; +} + +bool TestRuntimeAPIDelegate::RestartDevice(std::string* error_message) { + return false; +} + +} // namespace extensions diff --git a/extensions/browser/test_runtime_api_delegate.h b/extensions/browser/test_runtime_api_delegate.h new file mode 100644 index 0000000..8922bd5 --- /dev/null +++ b/extensions/browser/test_runtime_api_delegate.h @@ -0,0 +1,36 @@ +// 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 EXENSIONS_BROWSER_TEST_RUNTIME_API_DELEGATE_H_ +#define EXENSIONS_BROWSER_TEST_RUNTIME_API_DELEGATE_H_ + +#include "base/macros.h" +#include "extensions/browser/api/runtime/runtime_api_delegate.h" + +namespace extensions { + +class TestRuntimeAPIDelegate : public RuntimeAPIDelegate { + public: + TestRuntimeAPIDelegate(); + virtual ~TestRuntimeAPIDelegate(); + + // RuntimeAPIDelegate implementation. + virtual void AddUpdateObserver(UpdateObserver* observer) OVERRIDE; + virtual void RemoveUpdateObserver(UpdateObserver* observer) OVERRIDE; + virtual base::Version GetPreviousExtensionVersion( + const Extension* extension) OVERRIDE; + virtual void ReloadExtension(const std::string& extension_id) OVERRIDE; + virtual bool CheckForUpdates(const std::string& extension_id, + const UpdateCheckCallback& callback) OVERRIDE; + virtual void OpenURL(const GURL& uninstall_url) OVERRIDE; + virtual bool GetPlatformInfo(core_api::runtime::PlatformInfo* info) OVERRIDE; + virtual bool RestartDevice(std::string* error_message) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(TestRuntimeAPIDelegate); +}; + +} // namespace extensions + +#endif // EXENSIONS_BROWSER_TEST_RUNTIME_API_DELEGATE_H_ diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json index 4ea9b9e..6fa7d8b 100644 --- a/extensions/common/api/_api_features.json +++ b/extensions/common/api/_api_features.json @@ -14,6 +14,49 @@ "dependencies": ["permission:dns"], "contexts": ["blessed_extension"] }, + "runtime": { + "channel": "stable", + "extension_types": ["extension", "legacy_packaged_app", "platform_app"], + "contexts": ["blessed_extension"] + }, + "runtime.getManifest": { + "contexts": ["blessed_extension", "unblessed_extension", "content_script"] + }, + "runtime.connect": { + "contexts": "all", + "matches": ["<all_urls>"] + }, + "runtime.getURL": { + "contexts": ["blessed_extension", "unblessed_extension", "content_script"] + }, + "runtime.id": { + "contexts": ["blessed_extension", "unblessed_extension", "content_script"] + }, + "runtime.lastError": { + "contexts": "all", + "extension_types": "all", + "matches": ["<all_urls>"] + }, + "runtime.onConnect": { + "contexts": ["blessed_extension", "unblessed_extension", "content_script"] + }, + "runtime.onMessage": { + "contexts": ["blessed_extension", "unblessed_extension", "content_script"] + }, + "runtime.reload": { + "contexts": ["blessed_extension", "unblessed_extension", "content_script"] + }, + "runtime.requestUpdateCheck": { + "contexts": ["blessed_extension", "unblessed_extension", "content_script"] + }, + "runtime.sendMessage": { + "contexts": "all", + "matches": ["<all_urls>"] + }, + "runtime.setUninstallURL": { + "channel": "dev", + "contexts": ["blessed_extension", "unblessed_extension", "content_script"] + }, "socket": { "dependencies": ["permission:socket"], "contexts": ["blessed_extension"] @@ -40,6 +83,16 @@ "extension_types": "all", "contexts": ["blessed_extension", "unblessed_extension", "content_script"] }, + "types": { + "channel": "stable", + "extension_types": ["extension", "legacy_packaged_app", "platform_app"], + "contexts": ["blessed_extension"] + }, + "types.private": { + "channel": "dev", + "extension_types": ["extension"], + "location": "component" + }, "usb": { "dependencies": ["permission:usb"], "contexts": ["blessed_extension"] diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json index 3447aac..4a24afe 100644 --- a/extensions/common/api/_permission_features.json +++ b/extensions/common/api/_permission_features.json @@ -33,6 +33,12 @@ ] } ], + // Note: runtime is not actually a permission, but some systems check these + // values to verify restrictions. + "runtime": { + "channel": "stable", + "extension_types": ["extension", "legacy_packaged_app", "platform_app"] + }, "socket": [ { "channel": "stable", diff --git a/extensions/common/api/api.gyp b/extensions/common/api/api.gyp index b124637..400701d 100644 --- a/extensions/common/api/api.gyp +++ b/extensions/common/api/api.gyp @@ -24,6 +24,7 @@ 'schema_files': [ 'dns.idl', 'extensions_manifest_types.json', + 'runtime.json', 'socket.idl', 'sockets_tcp.idl', 'sockets_tcp_server.idl', diff --git a/chrome/common/extensions/api/runtime.json b/extensions/common/api/runtime.json index 55704f1e..6009576 100644 --- a/chrome/common/extensions/api/runtime.json +++ b/extensions/common/api/runtime.json @@ -1,7 +1,10 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// 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. +// Note: Many of these functions and events are implemented by hand and should +// not elicit any code generation from the schema compiler. These items are +// marked "nocompile." [ { "namespace": "runtime", @@ -29,6 +32,7 @@ { "id": "MessageSender", "type": "object", + "nocompile": true, "description": "An object containing information about the script context that sent a message or request.", "properties": { "tab": {"$ref": "tabs.Tab", "optional": true, "description": "The $(ref:tabs.Tab) which opened the connection, if any. This property will <strong>only</strong> be present when the connection was opened from a tab (including content scripts), and <strong>only</strong> if the receiver is an extension, not an app."}, @@ -36,6 +40,28 @@ "url": {"type": "string", "optional": true, "description": "The URL of the page or frame that opened the connection, if any. This property will <strong>only</strong> be present when the connection was opened from a tab or content script."}, "tlsChannelId": {"type": "string", "optional": true, "description": "The TLS channel ID of the web page that opened the connection, if requested by the extension or app, and if available."} } + }, + { + "id": "PlatformInfo", + "type": "object", + "description": "An object containing information about the current platform.", + "properties": { + "os": { + "type": "string", + "description": "The operating system chrome is running on.", + "enum": ["mac", "win", "android", "cros", "linux", "openbsd"] + }, + "arch": { + "type": "string", + "enum": ["arm", "x86-32", "x86-64"], + "description": "The machine's processor architecture." + }, + "nacl_arch" : { + "description": "The native client architecture. This may be different from arch on some platforms.", + "type": "string", + "enum": ["arm", "x86-32", "x86-64"] + } + } } ], "properties": { @@ -283,24 +309,7 @@ "parameters": [ { "name": "platformInfo", - "type": "object", - "properties": { - "os": { - "type": "string", - "description": "The operating system chrome is running on.", - "enum": ["mac", "win", "android", "cros", "linux", "openbsd"] - }, - "arch": { - "type": "string", - "enum": ["arm", "x86-32", "x86-64"], - "description": "The machine's processor architecture." - }, - "nacl_arch" : { - "description": "The native client architecture. This may be different from arch on some platforms.", - "type": "string", - "enum": ["arm", "x86-32", "x86-64"] - } - } + "$ref": "PlatformInfo" } ] } @@ -423,6 +432,7 @@ "options": { "unmanaged": true }, + "nocompile": true, "description": "Fired when a message is sent from either an extension process or a content script.", "parameters": [ {"name": "message", "type": "any", "optional": true, "description": "The message sent by the calling script."}, @@ -441,6 +451,7 @@ "options": { "unmanaged": true }, + "nocompile": true, "description": "Fired when a message is sent from another extension/app. Cannot be used in a content script.", "parameters": [ {"name": "message", "type": "any", "optional": true, "description": "The message sent by the calling script."}, diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp index 2ec0dcd..f2774b2 100644 --- a/extensions/extensions.gyp +++ b/extensions/extensions.gyp @@ -255,6 +255,10 @@ 'browser/api/dns/host_resolver_wrapper.h', 'browser/api/extensions_api_client.cc', 'browser/api/extensions_api_client.h', + 'browser/api/runtime/runtime_api.cc', + 'browser/api/runtime/runtime_api.h', + 'browser/api/runtime/runtime_api_delegate.cc', + 'browser/api/runtime/runtime_api_delegate.h', 'browser/api/socket/socket.cc', 'browser/api/socket/socket.h', 'browser/api/socket/socket_api.cc', @@ -407,6 +411,8 @@ # when enable_extensions==0. 'sources/': [ ['exclude', '^browser/api/'], + ['include', '^browser/api/runtime/runtime_api.cc'], + ['include', '^browser/api/runtime/runtime_api_delegate.cc'], ], 'sources!': [ 'browser/browser_context_keyed_service_factories.cc', @@ -549,17 +555,21 @@ 'dependencies': [ '../base/base.gyp:base', '../testing/gtest.gyp:gtest', + 'common/api/api.gyp:extensions_api', 'extensions_browser', 'extensions_common', ], 'include_dirs': [ '..', + '<(SHARED_INTERMEDIATE_DIR)', ], 'sources': [ 'browser/test_extensions_browser_client.cc', 'browser/test_extensions_browser_client.h', 'browser/test_management_policy.cc', 'browser/test_management_policy.h', + 'browser/test_runtime_api_delegate.cc', + 'browser/test_runtime_api_delegate.h', 'common/extension_builder.cc', 'common/extension_builder.h', 'common/test_util.cc', |