diff options
author | Kristian Monsen <kristianm@google.com> | 2011-05-11 20:53:37 +0100 |
---|---|---|
committer | Kristian Monsen <kristianm@google.com> | 2011-05-16 13:54:48 +0100 |
commit | 21d179b334e59e9a3bfcaed4c4430bef1bc5759d (patch) | |
tree | 64e2bb6da27af6a5c93ca34f6051584aafbfcb9e /chrome/browser/extensions | |
parent | 0c63f00edd6ed0482fd5cbcea937ca088baf7858 (diff) | |
download | external_chromium-21d179b334e59e9a3bfcaed4c4430bef1bc5759d.zip external_chromium-21d179b334e59e9a3bfcaed4c4430bef1bc5759d.tar.gz external_chromium-21d179b334e59e9a3bfcaed4c4430bef1bc5759d.tar.bz2 |
Merge Chromium at 10.0.621.0: Initial merge by git.
Change-Id: I070cc91c608dfa4a968a5a54c173260765ac8097
Diffstat (limited to 'chrome/browser/extensions')
160 files changed, 3446 insertions, 2544 deletions
diff --git a/chrome/browser/extensions/alert_apitest.cc b/chrome/browser/extensions/alert_apitest.cc index 292e1bd..10b310b 100644 --- a/chrome/browser/extensions/alert_apitest.cc +++ b/chrome/browser/extensions/alert_apitest.cc @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/app_modal_dialog.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/renderer_host/render_view_host.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/ui_test_utils.h" diff --git a/chrome/browser/extensions/all_urls_apitest.cc b/chrome/browser/extensions/all_urls_apitest.cc index e0e2a4a..522610e 100644 --- a/chrome/browser/extensions/all_urls_apitest.cc +++ b/chrome/browser/extensions/all_urls_apitest.cc @@ -3,9 +3,9 @@ // found in the LICENSE file. #include "chrome/browser/extensions/extension_apitest.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_test_message_listener.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/extensions/extension.h" #include "chrome/test/ui_test_utils.h" @@ -44,7 +44,7 @@ IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, WhitelistedExtension) { // Then load extensions. Checkpoint("LoadExtension1", start_time); - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const size_t size_before = service->extensions()->size(); ASSERT_TRUE(LoadExtension(extension_dir1)); Checkpoint("LoadExtension2", start_time); @@ -123,7 +123,7 @@ IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, DISABLED_RegularExtensions) { FilePath extension_dir2 = test_data_dir_.AppendASCII("all_urls") .AppendASCII("execute_script"); - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const size_t size_before = service->extensions()->size(); ASSERT_TRUE(LoadExtension(extension_dir1)); ASSERT_TRUE(LoadExtension(extension_dir2)); diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc index 1d1b707..dece83c 100644 --- a/chrome/browser/extensions/app_process_apitest.cc +++ b/chrome/browser/extensions/app_process_apitest.cc @@ -7,7 +7,7 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_process_manager.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" @@ -84,7 +84,8 @@ IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcess) { // The app under test acts on URLs whose host is "localhost", // so the URLs we navigate to must have host "localhost". GURL::Replacements replace_host; - replace_host.SetHostStr("localhost"); + std::string host_str("localhost"); // must stay in scope with replace_host + replace_host.SetHostStr(host_str); base_url = base_url.ReplaceComponents(replace_host); browser()->NewTab(); diff --git a/chrome/browser/extensions/autoupdate_interceptor.cc b/chrome/browser/extensions/autoupdate_interceptor.cc index ef0091f..e919189 100644 --- a/chrome/browser/extensions/autoupdate_interceptor.cc +++ b/chrome/browser/extensions/autoupdate_interceptor.cc @@ -15,7 +15,7 @@ // code relies on. class AutoUpdateTestRequestJob : public URLRequestTestJob { public: - AutoUpdateTestRequestJob(URLRequest* request, + AutoUpdateTestRequestJob(net::URLRequest* request, const std::string& response_data) : URLRequestTestJob( request, URLRequestTestJob::test_headers(), response_data, true) {} virtual int GetResponseCode() const { return 200; } @@ -26,15 +26,15 @@ class AutoUpdateTestRequestJob : public URLRequestTestJob { AutoUpdateInterceptor::AutoUpdateInterceptor() { - URLRequest::RegisterRequestInterceptor(this); + net::URLRequest::RegisterRequestInterceptor(this); } AutoUpdateInterceptor::~AutoUpdateInterceptor() { - URLRequest::UnregisterRequestInterceptor(this); + net::URLRequest::UnregisterRequestInterceptor(this); } - -URLRequestJob* AutoUpdateInterceptor::MaybeIntercept(URLRequest* request) { +net::URLRequestJob* AutoUpdateInterceptor::MaybeIntercept( + net::URLRequest* request) { EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (request->url().scheme() != "http" || request->url().host() != "localhost") { diff --git a/chrome/browser/extensions/autoupdate_interceptor.h b/chrome/browser/extensions/autoupdate_interceptor.h index 219941a..a2e0891 100644 --- a/chrome/browser/extensions/autoupdate_interceptor.h +++ b/chrome/browser/extensions/autoupdate_interceptor.h @@ -15,7 +15,7 @@ // This url request interceptor lets us respond to localhost http request urls // with the contents of files on disk for use in tests. class AutoUpdateInterceptor - : public URLRequest::Interceptor, + : public net::URLRequest::Interceptor, public base::RefCountedThreadSafe<AutoUpdateInterceptor> { public: AutoUpdateInterceptor(); diff --git a/chrome/browser/extensions/browser_action_apitest.cc b/chrome/browser/extensions/browser_action_apitest.cc index 59e56ca..8c413e4 100644 --- a/chrome/browser/extensions/browser_action_apitest.cc +++ b/chrome/browser/extensions/browser_action_apitest.cc @@ -13,8 +13,8 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_switches.h" @@ -286,7 +286,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoBasic) { // Now enable the extension in incognito mode, and test that the browser // action shows up. Note that we don't update the existing window at the // moment, so we just create a new one. - browser()->profile()->GetExtensionsService()->extension_prefs()-> + browser()->profile()->GetExtensionService()->extension_prefs()-> SetIsIncognitoEnabled(extension->id(), true); incognito_browser->CloseWindow(); @@ -299,7 +299,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoBasic) { } IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoDragging) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); // The tooltips for each respective browser action. const char kTooltipA[] = "Make this page red"; diff --git a/chrome/browser/extensions/browser_action_test_util_mac.mm b/chrome/browser/extensions/browser_action_test_util_mac.mm index bc46a88..3b6dcc6 100644 --- a/chrome/browser/extensions/browser_action_test_util_mac.mm +++ b/chrome/browser/extensions/browser_action_test_util_mac.mm @@ -5,13 +5,13 @@ #include "browser_action_test_util.h" #include "base/sys_string_conversions.h" -#import "chrome/browser/cocoa/browser_window_cocoa.h" -#import "chrome/browser/cocoa/browser_window_controller.h" -#import "chrome/browser/cocoa/extensions/browser_actions_controller.h" -#import "chrome/browser/cocoa/extensions/extension_popup_controller.h" -#import "chrome/browser/cocoa/info_bubble_window.h" -#import "chrome/browser/cocoa/toolbar_controller.h" #include "chrome/browser/ui/browser.h" +#import "chrome/browser/ui/cocoa/browser_window_cocoa.h" +#import "chrome/browser/ui/cocoa/browser_window_controller.h" +#import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h" +#import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h" +#import "chrome/browser/ui/cocoa/info_bubble_window.h" +#import "chrome/browser/ui/cocoa/toolbar_controller.h" #include "gfx/rect.h" #include "gfx/size.h" diff --git a/chrome/browser/extensions/content_script_extension_process_apitest.cc b/chrome/browser/extensions/content_script_extension_process_apitest.cc index f6748de..100e77b 100644 --- a/chrome/browser/extensions/content_script_extension_process_apitest.cc +++ b/chrome/browser/extensions/content_script_extension_process_apitest.cc @@ -3,8 +3,7 @@ // found in the LICENSE file. #include "chrome/browser/extensions/extension_apitest.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/extensions/extension.h" #include "chrome/test/ui_test_utils.h" diff --git a/chrome/browser/extensions/convert_user_script.cc b/chrome/browser/extensions/convert_user_script.cc index 89caec4..bcb0f5a 100644 --- a/chrome/browser/extensions/convert_user_script.cc +++ b/chrome/browser/extensions/convert_user_script.cc @@ -34,6 +34,11 @@ scoped_refptr<Extension> ConvertUserScriptToExtension( return NULL; } + if (!IsStringUTF8(content)) { + *error = "User script must be UTF8 encoded."; + return NULL; + } + UserScript script; if (!UserScriptMaster::ScriptReloader::ParseMetadataHeader(content, &script)) { diff --git a/chrome/browser/extensions/convert_user_script_unittest.cc b/chrome/browser/extensions/convert_user_script_unittest.cc index a0e1b8b..e9c73cb 100644 --- a/chrome/browser/extensions/convert_user_script_unittest.cc +++ b/chrome/browser/extensions/convert_user_script_unittest.cc @@ -92,3 +92,18 @@ TEST(ExtensionFromUserScript, NoMetdata) { // Cleanup file_util::Delete(extension->path(), true); } + +TEST(ExtensionFromUserScript, NotUTF8) { + FilePath test_file; + + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_file)); + test_file = test_file.AppendASCII("extensions") + .AppendASCII("user_script_not_utf8.user.js"); + + std::string error; + scoped_refptr<Extension> extension(ConvertUserScriptToExtension( + test_file, GURL("http://www.google.com/foo/bar.user.js?monkey"), &error)); + + ASSERT_FALSE(extension.get()); + EXPECT_EQ("User script must be UTF8 encoded.", error); +} diff --git a/chrome/browser/extensions/convert_web_app.cc b/chrome/browser/extensions/convert_web_app.cc index 11303ff..e1c8c92 100644 --- a/chrome/browser/extensions/convert_web_app.cc +++ b/chrome/browser/extensions/convert_web_app.cc @@ -101,6 +101,9 @@ scoped_refptr<Extension> ConvertWebAppToExtension( root->SetString(keys::kDescription, UTF16ToUTF8(web_app.description)); root->SetString(keys::kLaunchWebURL, web_app.app_url.spec()); + if (!web_app.launch_container.empty()) + root->SetString(keys::kLaunchContainer, web_app.launch_container); + // Add the icons. DictionaryValue* icons = new DictionaryValue(); root->Set(keys::kIcons, icons); diff --git a/chrome/browser/extensions/convert_web_app_browsertest.cc b/chrome/browser/extensions/convert_web_app_browsertest.cc index a6cdb19..bb2ea24 100644 --- a/chrome/browser/extensions/convert_web_app_browsertest.cc +++ b/chrome/browser/extensions/convert_web_app_browsertest.cc @@ -4,9 +4,9 @@ #include <string> -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/notification_details.h" @@ -47,7 +47,7 @@ class ExtensionFromWebAppTest IN_PROC_BROWSER_TEST_F(ExtensionFromWebAppTest, Basic) { ASSERT_TRUE(test_server()->Start()); - browser()->profile()->GetExtensionsService()->set_show_extensions_prompts( + browser()->profile()->GetExtensionService()->set_show_extensions_prompts( false); NotificationRegistrar registrar; @@ -65,4 +65,22 @@ IN_PROC_BROWSER_TEST_F(ExtensionFromWebAppTest, Basic) { EXPECT_TRUE(installed_extension_); EXPECT_TRUE(installed_extension_->is_hosted_app()); + EXPECT_EQ("Test application", installed_extension_->name()); + EXPECT_EQ("the description is", installed_extension_->description()); + EXPECT_EQ(extension_misc::LAUNCH_PANEL, + installed_extension_->launch_container()); + + ASSERT_EQ(2u, installed_extension_->api_permissions().size()); + EXPECT_TRUE(installed_extension_->api_permissions().find("geolocation") != + installed_extension_->api_permissions().end()); + EXPECT_TRUE(installed_extension_->api_permissions().find("notifications") != + installed_extension_->api_permissions().end()); + + ASSERT_EQ(3u, installed_extension_->icons().map().size()); + EXPECT_EQ("icons/16.png", installed_extension_->icons().Get( + 16, ExtensionIconSet::MATCH_EXACTLY)); + EXPECT_EQ("icons/48.png", installed_extension_->icons().Get( + 48, ExtensionIconSet::MATCH_EXACTLY)); + EXPECT_EQ("icons/128.png", installed_extension_->icons().Get( + 128, ExtensionIconSet::MATCH_EXACTLY)); } diff --git a/chrome/browser/extensions/crashed_extension_infobar.cc b/chrome/browser/extensions/crashed_extension_infobar.cc index 053b4b4..fbed6e6 100644 --- a/chrome/browser/extensions/crashed_extension_infobar.cc +++ b/chrome/browser/extensions/crashed_extension_infobar.cc @@ -7,7 +7,7 @@ #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/common/extensions/extension.h" #include "grit/browser_resources.h" #include "grit/generated_resources.h" @@ -15,7 +15,7 @@ CrashedExtensionInfoBarDelegate::CrashedExtensionInfoBarDelegate( TabContents* tab_contents, - ExtensionsService* extensions_service, + ExtensionService* extensions_service, const Extension* extension) : ConfirmInfoBarDelegate(tab_contents), extensions_service_(extensions_service), @@ -30,6 +30,11 @@ AsCrashedExtensionInfoBarDelegate() { return this; } +bool CrashedExtensionInfoBarDelegate::ShouldExpire( + const NavigationController::LoadCommittedDetails& details) const { + return false; +} + string16 CrashedExtensionInfoBarDelegate::GetMessageText() const { return l10n_util::GetStringFUTF16(IDS_EXTENSION_CRASHED_INFOBAR_MESSAGE, UTF8ToUTF16(extension_name_)); diff --git a/chrome/browser/extensions/crashed_extension_infobar.h b/chrome/browser/extensions/crashed_extension_infobar.h index 1508ae5..201e606 100644 --- a/chrome/browser/extensions/crashed_extension_infobar.h +++ b/chrome/browser/extensions/crashed_extension_infobar.h @@ -12,7 +12,7 @@ #include "chrome/browser/tab_contents/infobar_delegate.h" class Extension; -class ExtensionsService; +class ExtensionService; class SkBitmap; // This infobar will be displayed when an extension process crashes. It allows @@ -21,15 +21,17 @@ class CrashedExtensionInfoBarDelegate : public ConfirmInfoBarDelegate { public: // |tab_contents| should point to the TabContents the infobar will be added // to. |extension| should be the crashed extension, and |extensions_service| - // the ExtensionsService which manages that extension. + // the ExtensionService which manages that extension. CrashedExtensionInfoBarDelegate(TabContents* tab_contents, - ExtensionsService* extensions_service, + ExtensionService* extensions_service, const Extension* extension); const std::string extension_id() { return extension_id_; } // InfoBarDelegate virtual CrashedExtensionInfoBarDelegate* AsCrashedExtensionInfoBarDelegate(); + virtual bool ShouldExpire( + const NavigationController::LoadCommittedDetails& details) const; // ConfirmInfoBarDelegate virtual string16 GetMessageText() const; @@ -41,7 +43,7 @@ class CrashedExtensionInfoBarDelegate : public ConfirmInfoBarDelegate { virtual bool Accept(); private: - ExtensionsService* extensions_service_; + ExtensionService* extensions_service_; const std::string extension_id_; const std::string extension_name_; diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc index 8441baa..f6708c5 100644 --- a/chrome/browser/extensions/crx_installer.cc +++ b/chrome/browser/extensions/crx_installer.cc @@ -9,9 +9,9 @@ #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "base/file_util.h" +#include "base/lazy_instance.h" #include "base/path_service.h" #include "base/scoped_temp_dir.h" -#include "base/singleton.h" #include "base/stl_util-inl.h" #include "base/stringprintf.h" #include "base/time.h" @@ -23,9 +23,8 @@ #include "chrome/browser/browser_thread.h" #include "chrome/browser/extensions/convert_user_script.h" #include "chrome/browser/extensions/convert_web_app.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_error_reporter.h" -#include "chrome/browser/profile.h" #include "chrome/browser/shell_integration.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/common/chrome_paths.h" @@ -51,25 +50,28 @@ struct WhitelistedInstallData { std::set<std::string> ids; }; +static base::LazyInstance<WhitelistedInstallData> + g_whitelisted_install_data(base::LINKER_INITIALIZED); + } // namespace // static void CrxInstaller::SetWhitelistedInstallId(const std::string& id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - Singleton<WhitelistedInstallData>::get()->ids.insert(id); + g_whitelisted_install_data.Get().ids.insert(id); } // static bool CrxInstaller::IsIdWhitelisted(const std::string& id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - std::set<std::string>& ids = Singleton<WhitelistedInstallData>::get()->ids; + std::set<std::string>& ids = g_whitelisted_install_data.Get().ids; return ContainsKey(ids, id); } // static bool CrxInstaller::ClearWhitelistedInstallId(const std::string& id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - std::set<std::string>& ids = Singleton<WhitelistedInstallData>::get()->ids; + std::set<std::string>& ids = g_whitelisted_install_data.Get().ids; if (ContainsKey(ids, id)) { ids.erase(id); return true; @@ -77,7 +79,7 @@ bool CrxInstaller::ClearWhitelistedInstallId(const std::string& id) { return false; } -CrxInstaller::CrxInstaller(ExtensionsService* frontend, +CrxInstaller::CrxInstaller(ExtensionService* frontend, ExtensionInstallUI* client) : install_directory_(frontend->install_directory()), install_source_(Extension::INTERNAL), @@ -308,8 +310,7 @@ void CrxInstaller::ConfirmInstall() { GURL overlapping_url; const Extension* overlapping_extension = frontend_->GetExtensionByOverlappingWebExtent(extension_->web_extent()); - if (overlapping_extension && - overlapping_extension->id() != extension_->id()) { + if (overlapping_extension) { ReportFailureFromUIThread(l10n_util::GetStringFUTF8( IDS_EXTENSION_OVERLAPPING_WEB_EXTENT, UTF8ToUTF16(overlapping_extension->name()))); diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h index c22a4a9..4a6aa28 100644 --- a/chrome/browser/extensions/crx_installer.h +++ b/chrome/browser/extensions/crx_installer.h @@ -15,7 +15,7 @@ #include "chrome/common/extensions/extension.h" #include "chrome/common/web_apps.h" -class ExtensionsService; +class ExtensionService; class SkBitmap; // This class installs a crx file into a profile. @@ -65,7 +65,7 @@ class CrxInstaller // frontend->install_directory() then registered with |frontend|. Any install // UI will be displayed using |client|. Pass NULL for |client| for silent // install. - CrxInstaller(ExtensionsService* frontend, + CrxInstaller(ExtensionService* frontend, ExtensionInstallUI* client); // Install the crx in |source_file|. @@ -182,7 +182,7 @@ class CrxInstaller bool create_app_shortcut_; // The extension we're installing. We own this and either pass it off to - // ExtensionsService on success, or delete it on failure. + // ExtensionService on success, or delete it on failure. scoped_refptr<const Extension> extension_; // If non-empty, contains the current version of the extension we're @@ -197,7 +197,7 @@ class CrxInstaller FilePath temp_dir_; // The frontend we will report results back to. - scoped_refptr<ExtensionsService> frontend_; + scoped_refptr<ExtensionService> frontend_; // The client we will work with to do the installation. This can be NULL, in // which case the install is silent. diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc index f49c577..e1a412f 100644 --- a/chrome/browser/extensions/crx_installer_browsertest.cc +++ b/chrome/browser/extensions/crx_installer_browsertest.cc @@ -5,8 +5,8 @@ #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_install_ui.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/ui_test_utils.h" @@ -48,7 +48,7 @@ class ExtensionCrxInstallerTest : public ExtensionBrowserTest { // happened or not. bool DidWhitelistInstallPrompt(const std::string& crx_relpath, const std::string& id) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); MockInstallUI* mock_install_ui = new MockInstallUI(browser()->profile()); scoped_refptr<CrxInstaller> installer( diff --git a/chrome/browser/extensions/default_apps.cc b/chrome/browser/extensions/default_apps.cc index cee5c32..a9e305f 100644 --- a/chrome/browser/extensions/default_apps.cc +++ b/chrome/browser/extensions/default_apps.cc @@ -18,146 +18,89 @@ void DefaultApps::RegisterUserPrefs(PrefService* prefs) { prefs->RegisterIntegerPref(prefs::kAppsPromoCounter, 0); } -DefaultApps::DefaultApps(PrefService* prefs, - const std::string& application_locale) - : prefs_(prefs), application_locale_(application_locale) { +DefaultApps::DefaultApps(PrefService* prefs) + : prefs_(prefs) { +#if !defined(OS_CHROMEOS) // Poppit, Entanglement ids_.insert("mcbkbpnkkkipelfledbfocopglifcfmi"); ids_.insert("aciahcmjmecflokailenpkdchphgkefd"); +#endif // OS_CHROMEOS } DefaultApps::~DefaultApps() {} -const ExtensionIdSet& DefaultApps::default_apps() const { - return ids_; -} - -bool DefaultApps::DefaultAppSupported() { - // On Chrome OS the default apps are installed via a different mechanism. -#if defined(OS_CHROMEOS) - return false; -#else - return DefaultAppsSupportedForLanguage(); -#endif +const ExtensionIdSet* DefaultApps::GetAppsToInstall() const { + if (GetDefaultAppsInstalled()) + return NULL; + else + return &ids_; } -bool DefaultApps::DefaultAppsSupportedForLanguage() { - return application_locale_ == "en-US"; +const ExtensionIdSet* DefaultApps::GetDefaultApps() const { + return &ids_; } -bool DefaultApps::ShouldInstallDefaultApps( - const ExtensionIdSet& installed_ids) { - if (!DefaultAppSupported()) - return false; - - if (GetDefaultAppsInstalled()) - return false; - - // If there are any non-default apps installed, we should never try to install - // the default apps again, even if the non-default apps are later removed. - if (NonDefaultAppIsInstalled(installed_ids)) { +void DefaultApps::DidInstallApp(const ExtensionIdSet& installed_ids) { + // If all the default apps have been installed, stop trying to install them. + // Note that we use std::includes here instead of == because apps might have + // been manually installed while the the default apps were installing and we + // wouldn't want to keep trying to install them in that case. + if (!GetDefaultAppsInstalled() && + std::includes(installed_ids.begin(), installed_ids.end(), + ids_.begin(), ids_.end())) { SetDefaultAppsInstalled(true); - return false; } - - return true; } -bool DefaultApps::ShouldShowAppLauncher(const ExtensionIdSet& installed_ids) { - // On Chrome OS the default apps are installed via a separate mechanism that - // is always enabled. Therefore we always show the launcher. -#if defined(OS_CHROME) - return true; -#else - // The app store only supports en-us at the moment, so we don't show the apps - // section by default for users in other locales. But we do show it if a user - // from a non-supported locale somehow installs an app (eg by navigating - // directly to the store). - if (!DefaultAppsSupportedForLanguage()) - return !installed_ids.empty(); - - // For supported locales, we need to wait for all the default apps to be - // installed before showing the apps section. We also show it if any - // non-default app is installed (eg because the user installed the app in a - // previous version of Chrome). - if (GetDefaultAppsInstalled() || NonDefaultAppIsInstalled(installed_ids)) - return true; - else - return false; +bool DefaultApps::CheckShouldShowPromo(const ExtensionIdSet& installed_ids) { +#if defined(OS_CHROMEOS) + // Don't show the promo at all on Chrome OS. + return false; #endif -} - -bool DefaultApps::ShouldShowPromo(const ExtensionIdSet& installed_ids, - bool* just_expired) { - *just_expired = false; - if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kForceAppsPromoVisible)) { return true; } - if (!DefaultAppSupported()) - return false; - - if (!GetDefaultAppsInstalled()) - return false; - - int promo_counter = GetPromoCounter(); - if (promo_counter <= kAppsPromoCounterMax) { + if (GetDefaultAppsInstalled() && GetPromoCounter() < kAppsPromoCounterMax) { // If we have the exact set of default apps, show the promo. If we don't // have the exact set of default apps, this means that the user manually - // installed or uninstalled one. The promo doesn't make sense if it shows - // apps the user manually installed, so expire it immediately in that - // situation. - if (ids_ != installed_ids) { - SetPromoHidden(); - return false; - } - - if (promo_counter == kAppsPromoCounterMax) { - *just_expired = true; - UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, - extension_misc::PROMO_EXPIRE, - extension_misc::PROMO_BUCKET_BOUNDARY); - SetPromoCounter(++promo_counter); - return false; - } else { - UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, - extension_misc::PROMO_SEEN, - extension_misc::PROMO_BUCKET_BOUNDARY); - SetPromoCounter(++promo_counter); + // installed one. The promo doesn't make sense if it shows apps the user + // manually installed, so expire it immediately in that situation. + if (installed_ids == ids_) return true; - } + else + SetPromoHidden(); } return false; } -void DefaultApps::DidInstallApp(const ExtensionIdSet& installed_ids) { - // If all the default apps have been installed, stop trying to install them. - // Note that we use std::includes here instead of == because apps might have - // been manually installed while the the default apps were installing and we - // wouldn't want to keep trying to install them in that case. - if (!GetDefaultAppsInstalled() && - std::includes(installed_ids.begin(), installed_ids.end(), - ids_.begin(), ids_.end())) { - SetDefaultAppsInstalled(true); +void DefaultApps::DidShowPromo() { + if (!GetDefaultAppsInstalled()) { + NOTREACHED() << "Should not show promo until default apps are installed."; + return; } -} -bool DefaultApps::NonDefaultAppIsInstalled( - const ExtensionIdSet& installed_ids) const { - for (ExtensionIdSet::const_iterator iter = installed_ids.begin(); - iter != installed_ids.end(); ++iter) { - if (ids_.find(*iter) == ids_.end()) - return true; + int promo_counter = GetPromoCounter(); + if (promo_counter == kAppsPromoCounterMax) { + NOTREACHED() << "Promo has already been shown the maximum number of times."; + return; } - return false; + if (promo_counter < kAppsPromoCounterMax) { + if (promo_counter + 1 == kAppsPromoCounterMax) + UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, + extension_misc::PROMO_EXPIRE, + extension_misc::PROMO_BUCKET_BOUNDARY); + SetPromoCounter(++promo_counter); + } else { + SetPromoHidden(); + } } void DefaultApps::SetPromoHidden() { - SetPromoCounter(kAppsPromoCounterMax + 1); + SetPromoCounter(kAppsPromoCounterMax); } int DefaultApps::GetPromoCounter() const { diff --git a/chrome/browser/extensions/default_apps.h b/chrome/browser/extensions/default_apps.h index 2ff8801..b03f6ec 100644 --- a/chrome/browser/extensions/default_apps.h +++ b/chrome/browser/extensions/default_apps.h @@ -13,60 +13,65 @@ class PrefService; -// Encapsulates business logic for: -// - Whether to install default apps on Chrome startup -// - Whether to show the app launcher -// - Whether to show the apps promo in the launcher +// Manages the installation of the set of default apps into Chrome, and the +// promotion of those apps in the launcher. +// +// It implements the following rules: +// +// - Only install default apps once per-profile. +// - Don't install default apps if any apps are already installed. +// - Do not start showing the promo until all default apps have been installed. +// - Do not show the promo if it has been hidden by the user. +// - Do not show promo after one app has been manually installed or uninstalled. +// - Do not show promo if the set of installed apps is different than the set of +// default apps. +// - Only show promo a certain amount of times. +// +// The promo can also be forced on with --force-apps-promo-visible. class DefaultApps { public: - // The maximum number of times to show the apps promo. The promo counter - // actually goes up to this number + 1 because we need to differentiate - // between the first time we overflow and subsequent times. + // The maximum number of times to show the apps promo. static const int kAppsPromoCounterMax; // Register our preferences. static void RegisterUserPrefs(PrefService* prefs); - explicit DefaultApps(PrefService* prefs, - const std::string& application_locale); + explicit DefaultApps(PrefService* prefs); ~DefaultApps(); - // Gets the set of default apps. - const ExtensionIdSet& default_apps() const; + // Gets the list of default apps that should be installed. Can return NULL if + // no apps need to be installed. + const ExtensionIdSet* GetAppsToInstall() const; - // Returns true if the default apps should be installed. - bool ShouldInstallDefaultApps(const ExtensionIdSet& installed_ids); + // Gets the list of default apps. + const ExtensionIdSet* GetDefaultApps() const; - // Returns true if the app launcher in the NTP should be shown. - bool ShouldShowAppLauncher(const ExtensionIdSet& installed_ids); + // Returns true if the default apps have been installed. False otherwise. + bool GetDefaultAppsInstalled() const; + + // Should be called after each app is installed. Once installed_ids contains + // all the default apps, GetAppsToInstall() will start returning NULL. + void DidInstallApp(const ExtensionIdSet& installed_ids); // Returns true if the apps promo should be displayed in the launcher. // // NOTE: If the default apps have been installed, but |installed_ids| is // different than GetDefaultApps(), this will permanently expire the promo. - bool ShouldShowPromo(const ExtensionIdSet& installed_ids, bool* just_expired); + bool CheckShouldShowPromo(const ExtensionIdSet& installed_ids); - // Should be called after each app is installed. Once installed_ids contains - // all the default apps, GetAppsToInstall() will start returning NULL. - void DidInstallApp(const ExtensionIdSet& installed_ids); + // Should be called after each time the promo is installed. + void DidShowPromo(); // Force the promo to be hidden. void SetPromoHidden(); private: - FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, HappyPath); - FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, UnsupportedLocale); + FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, Basics); FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, HidePromo); FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, InstallingAnAppHidesPromo); FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, ManualAppInstalledWhileInstallingDefaultApps); - bool DefaultAppSupported(); - bool DefaultAppsSupportedForLanguage(); - - bool NonDefaultAppIsInstalled(const ExtensionIdSet& installed_ids) const; - - bool GetDefaultAppsInstalled() const; void SetDefaultAppsInstalled(bool val); int GetPromoCounter() const; @@ -75,9 +80,6 @@ class DefaultApps { // Our permanent state is stored in this PrefService instance. PrefService* prefs_; - // The locale the browser is currently in. - std::string application_locale_; - // The set of default extensions. Initialized to a static list in the // constructor. ExtensionIdSet ids_; diff --git a/chrome/browser/extensions/default_apps_unittest.cc b/chrome/browser/extensions/default_apps_unittest.cc index 316568d..4fa9bc2 100644 --- a/chrome/browser/extensions/default_apps_unittest.cc +++ b/chrome/browser/extensions/default_apps_unittest.cc @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/logging.h" #include "chrome/browser/extensions/default_apps.h" #include "chrome/common/extensions/extension.h" #include "chrome/test/testing_pref_service.h" @@ -11,180 +10,94 @@ // TODO(dpolukhin): On Chrome OS all apps are installed via external extensions, // and the web store promo is never shown. #if !defined(OS_CHROMEOS) -TEST(ExtensionDefaultApps, HappyPath) { +TEST(ExtensionDefaultApps, Basics) { TestingPrefService pref_service; DefaultApps::RegisterUserPrefs(&pref_service); - DefaultApps default_apps(&pref_service, "en-US"); + DefaultApps default_apps(&pref_service); - const ExtensionIdSet& default_app_ids = default_apps.default_apps(); + ExtensionIdSet default_app_ids = *default_apps.GetAppsToInstall(); ASSERT_GT(default_app_ids.size(), 0u); EXPECT_FALSE(default_apps.GetDefaultAppsInstalled()); EXPECT_EQ(0, default_apps.GetPromoCounter()); - - // If no apps are installed, the default apps should be installed. - ExtensionIdSet installed_app_ids; - EXPECT_TRUE(default_apps.ShouldInstallDefaultApps(installed_app_ids)); - - // The launcher should not be shown until the default apps have been - // installed. - EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_app_ids)); + EXPECT_EQ(default_app_ids, *default_apps.GetDefaultApps()); // The promo should not be shown until the default apps have been installed. - bool promo_just_expired = false; - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); + ExtensionIdSet installed_app_ids; + EXPECT_FALSE(default_apps.CheckShouldShowPromo(installed_app_ids)); // Simulate installing the apps one by one and notifying default_apps after // each intallation. Nothing should change until we have installed all the // default apps. - for (size_t i = 0; i < default_app_ids.size() - 1; ++i) { - ExtensionIdSet::const_iterator iter = default_app_ids.begin(); - for (size_t j = 0; j <= i; ++j) - ++iter; - installed_app_ids.insert(*iter); - default_apps.DidInstallApp(installed_app_ids); + ExtensionIdSet extension_id_sets[] = { + default_app_ids, + default_app_ids, + default_app_ids + }; + extension_id_sets[0].clear(); + extension_id_sets[1].erase(extension_id_sets[1].begin()); + extension_id_sets[2].erase(extension_id_sets[2].begin(), + ++extension_id_sets[2].begin()); + for (size_t i = 0; i < arraysize(extension_id_sets); ++i) { + default_apps.DidInstallApp(extension_id_sets[i]); + EXPECT_TRUE(default_app_ids == *default_apps.GetAppsToInstall()); EXPECT_FALSE(default_apps.GetDefaultAppsInstalled()); - EXPECT_TRUE(default_apps.ShouldInstallDefaultApps(installed_app_ids)); - EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_app_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); + EXPECT_FALSE(default_apps.CheckShouldShowPromo(extension_id_sets[i])); } // Simulate all the default apps being installed. Now we should stop getting // default apps to install. - installed_app_ids = default_app_ids; - default_apps.DidInstallApp(installed_app_ids); + default_apps.DidInstallApp(default_app_ids); + EXPECT_EQ(NULL, default_apps.GetAppsToInstall()); EXPECT_TRUE(default_apps.GetDefaultAppsInstalled()); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_app_ids)); - // And the promo and launcher should become available. - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_app_ids)); - EXPECT_TRUE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); + // And the promo should become available. + EXPECT_TRUE(default_apps.CheckShouldShowPromo(default_app_ids)); // The promo should be available up to the max allowed times, then stop. - // We start counting at 1 because of the call to ShouldShowPromo() above. - for (int i = 1; i < DefaultApps::kAppsPromoCounterMax; ++i) { - EXPECT_TRUE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); + for (int i = 0; i < DefaultApps::kAppsPromoCounterMax; ++i) { + EXPECT_TRUE(default_apps.CheckShouldShowPromo(default_app_ids)); + default_apps.DidShowPromo(); EXPECT_EQ(i + 1, default_apps.GetPromoCounter()); } - - // The first time, should_show_promo should flip to true, then back to false. - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_TRUE(promo_just_expired); - EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1, - default_apps.GetPromoCounter()); - - // Even if all the apps are subsequently removed, the apps section should - // remain. - installed_app_ids.clear(); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_app_ids)); - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_app_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1, - default_apps.GetPromoCounter()); -} - -TEST(ExtensionDefaultApps, UnsupportedLocale) { - TestingPrefService pref_service; - DefaultApps::RegisterUserPrefs(&pref_service); - DefaultApps default_apps(&pref_service, "fr"); - - const ExtensionIdSet& default_app_ids = default_apps.default_apps(); - EXPECT_GT(default_app_ids.size(), 0u); - - // Since the store only supports en-US at the moment, we don't install default - // apps or promote the store. - ExtensionIdSet installed_ids; - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_ids)); - - bool promo_just_expired = false; - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - - // If the user installs an app manually, then we show the apps section, but - // no promotion or default apps. - installed_ids.insert(*(default_app_ids.begin())); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - - // Even if the user installs the exact set of default apps, we don't show the - // promo. - installed_ids = default_app_ids; - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - - // If the user uninstalls the apps again, we go back to not showing the - // apps section. - installed_ids.clear(); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); + EXPECT_FALSE(default_apps.CheckShouldShowPromo(default_app_ids)); + EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter()); } TEST(ExtensionDefaultApps, HidePromo) { TestingPrefService pref_service; DefaultApps::RegisterUserPrefs(&pref_service); - DefaultApps default_apps(&pref_service, "en-US"); + DefaultApps default_apps(&pref_service); - const ExtensionIdSet& default_app_ids = default_apps.default_apps(); + ExtensionIdSet default_app_ids = *default_apps.GetAppsToInstall(); default_apps.DidInstallApp(default_app_ids); - bool promo_just_expired = false; - EXPECT_TRUE(default_apps.ShouldShowPromo(default_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); + EXPECT_TRUE(default_apps.CheckShouldShowPromo(default_app_ids)); + default_apps.DidShowPromo(); EXPECT_EQ(1, default_apps.GetPromoCounter()); default_apps.SetPromoHidden(); - EXPECT_FALSE(default_apps.ShouldShowPromo(default_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1, - default_apps.GetPromoCounter()); + EXPECT_FALSE(default_apps.CheckShouldShowPromo(default_app_ids)); + EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter()); } TEST(ExtensionDefaultApps, InstallingAnAppHidesPromo) { TestingPrefService pref_service; DefaultApps::RegisterUserPrefs(&pref_service); - DefaultApps default_apps(&pref_service, "en-US"); + DefaultApps default_apps(&pref_service); - const ExtensionIdSet& default_app_ids = default_apps.default_apps(); + ExtensionIdSet default_app_ids = *default_apps.GetAppsToInstall(); ExtensionIdSet installed_app_ids = default_app_ids; default_apps.DidInstallApp(installed_app_ids); - bool promo_just_expired = false; - EXPECT_TRUE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); + EXPECT_TRUE(default_apps.CheckShouldShowPromo(installed_app_ids)); + default_apps.DidShowPromo(); EXPECT_EQ(1, default_apps.GetPromoCounter()); // Now simulate a new extension being installed. This should cause the promo // to be hidden. installed_app_ids.insert("foo"); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1, - default_apps.GetPromoCounter()); + EXPECT_FALSE(default_apps.CheckShouldShowPromo(installed_app_ids)); + EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter()); } TEST(ExtensionDefaultApps, ManualAppInstalledWhileInstallingDefaultApps) { @@ -198,39 +111,27 @@ TEST(ExtensionDefaultApps, ManualAppInstalledWhileInstallingDefaultApps) { // the default ones. TestingPrefService pref_service; DefaultApps::RegisterUserPrefs(&pref_service); - DefaultApps default_apps(&pref_service, "en-US"); + DefaultApps default_apps(&pref_service); // Simulate an app getting installed before the complete set of default apps. - // This should stop the default apps from trying to be installed. The launcher - // should also immediately show up. + // This shouldn't affect us installing default apps. We should keep trying. ExtensionIdSet installed_ids; installed_ids.insert("foo"); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); + default_apps.DidInstallApp(installed_ids); + EXPECT_FALSE(default_apps.GetDefaultAppsInstalled()); + EXPECT_TRUE(default_apps.GetAppsToInstall()); + + // Now add all the default apps in addition to the extra app. We should stop + // trying to install default apps. + installed_ids = *default_apps.GetAppsToInstall(); + installed_ids.insert("foo"); + default_apps.DidInstallApp(installed_ids); EXPECT_TRUE(default_apps.GetDefaultAppsInstalled()); - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids)); + EXPECT_FALSE(default_apps.GetAppsToInstall()); // The promo shouldn't turn on though, because it would look weird with the // user's extra, manually installed extensions. - bool promo_just_expired = false; - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1, - default_apps.GetPromoCounter()); - - // Going back to a subset of the default apps shouldn't allow the default app - // install to continue. - installed_ids.clear(); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); - EXPECT_TRUE(default_apps.GetDefaultAppsInstalled()); - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - - // Going to the exact set of default apps shouldn't show the promo. - EXPECT_FALSE(default_apps.ShouldShowPromo(default_apps.default_apps(), - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); + EXPECT_FALSE(default_apps.CheckShouldShowPromo(installed_ids)); + EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter()); } #endif // OS_CHROMEOS diff --git a/chrome/browser/extensions/execute_code_in_tab_function.cc b/chrome/browser/extensions/execute_code_in_tab_function.cc index 1659af3..b3bfee0 100644 --- a/chrome/browser/extensions/execute_code_in_tab_function.cc +++ b/chrome/browser/extensions/execute_code_in_tab_function.cc @@ -9,12 +9,12 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/extensions/extension_tabs_module_constants.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/file_reader.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents_wrapper.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_error_utils.h" diff --git a/chrome/browser/extensions/extension_accessibility_api.cc b/chrome/browser/extensions/extension_accessibility_api.cc index 3dd0345..fa0ee0e 100644 --- a/chrome/browser/extensions/extension_accessibility_api.cc +++ b/chrome/browser/extensions/extension_accessibility_api.cc @@ -14,8 +14,8 @@ #include "chrome/browser/extensions/extension_accessibility_api_constants.h" #include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/notification_service.h" diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc index f65d8eb..dbb47cd 100644 --- a/chrome/browser/extensions/extension_apitest.cc +++ b/chrome/browser/extensions/extension_apitest.cc @@ -7,8 +7,8 @@ #include "base/string_util.h" #include "base/stringprintf.h" #include "chrome/browser/extensions/extension_test_api.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/notification_registrar.h" #include "chrome/test/ui_test_utils.h" @@ -143,7 +143,7 @@ bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name, DCHECK(!std::string(extension_name).empty()) << "Relative page_url given with no extension_name"; - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const Extension* extension = service->GetExtensionById(last_loaded_extension_id_, false); if (!extension) @@ -166,7 +166,7 @@ bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name, // Test that exactly one extension loaded. const Extension* ExtensionApiTest::GetSingleLoadedExtension() { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); int found_extension_index = -1; for (size_t i = 0; i < service->extensions()->size(); ++i) { diff --git a/chrome/browser/extensions/extension_apitest.h b/chrome/browser/extensions/extension_apitest.h index b2079a6..4f76d28 100644 --- a/chrome/browser/extensions/extension_apitest.h +++ b/chrome/browser/extensions/extension_apitest.h @@ -11,7 +11,6 @@ #include "base/values.h" #include "chrome/browser/extensions/extension_browsertest.h" -#include "chrome/common/notification_service.h" class Extension; diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.cc b/chrome/browser/extensions/extension_bookmark_manager_api.cc index cc38ad1..67963b2 100644 --- a/chrome/browser/extensions/extension_bookmark_manager_api.cc +++ b/chrome/browser/extensions/extension_bookmark_manager_api.cc @@ -18,7 +18,7 @@ #include "chrome/browser/extensions/extension_bookmarks_module_constants.h" #include "chrome/browser/extensions/extension_dom_ui.h" #include "chrome/browser/extensions/extension_event_router.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "grit/generated_resources.h" diff --git a/chrome/browser/extensions/extension_bookmarks_module.cc b/chrome/browser/extensions/extension_bookmarks_module.cc index f805a1e..180a5bb 100644 --- a/chrome/browser/extensions/extension_bookmarks_module.cc +++ b/chrome/browser/extensions/extension_bookmarks_module.cc @@ -22,7 +22,7 @@ #include "chrome/browser/importer/importer.h" #include "chrome/browser/importer/importer_data_types.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/notification_service.h" #include "chrome/common/pref_names.h" @@ -75,7 +75,7 @@ void BookmarksFunction::Observe(NotificationType type, } // static -ExtensionBookmarkEventRouter* ExtensionBookmarkEventRouter::GetSingleton() { +ExtensionBookmarkEventRouter* ExtensionBookmarkEventRouter::GetInstance() { return Singleton<ExtensionBookmarkEventRouter>::get(); } diff --git a/chrome/browser/extensions/extension_bookmarks_module.h b/chrome/browser/extensions/extension_bookmarks_module.h index e8e91a1..21b9ad8 100644 --- a/chrome/browser/extensions/extension_bookmarks_module.h +++ b/chrome/browser/extensions/extension_bookmarks_module.h @@ -21,7 +21,7 @@ // the extension system. class ExtensionBookmarkEventRouter : public BookmarkModelObserver { public: - static ExtensionBookmarkEventRouter* GetSingleton(); + static ExtensionBookmarkEventRouter* GetInstance(); virtual ~ExtensionBookmarkEventRouter(); // Call this for each model to observe. Safe to call multiple times per @@ -179,8 +179,9 @@ class BookmarksIOFunction : public BookmarksFunction, // Overridden from SelectFileDialog::Listener: virtual void FileSelected(const FilePath& path, int index, void* params) = 0; - void MultiFilesSelected(const std::vector<FilePath>& files, void* params); - void FileSelectionCanceled(void* params); + virtual void MultiFilesSelected(const std::vector<FilePath>& files, + void* params); + virtual void FileSelectionCanceled(void* params); void SelectFile(SelectFileDialog::Type type); protected: @@ -190,8 +191,8 @@ class BookmarksIOFunction : public BookmarksFunction, class ImportBookmarksFunction : public BookmarksIOFunction { public: // Override BookmarkManagerIOFunction. - bool RunImpl(); - void FileSelected(const FilePath& path, int index, void* params); + virtual bool RunImpl(); + virtual void FileSelected(const FilePath& path, int index, void* params); private: DECLARE_EXTENSION_FUNCTION_NAME("bookmarks.import"); @@ -200,8 +201,8 @@ class ImportBookmarksFunction : public BookmarksIOFunction { class ExportBookmarksFunction : public BookmarksIOFunction { public: // Override BookmarkManagerIOFunction. - bool RunImpl(); - void FileSelected(const FilePath& path, int index, void* params); + virtual bool RunImpl(); + virtual void FileSelected(const FilePath& path, int index, void* params); private: DECLARE_EXTENSION_FUNCTION_NAME("bookmarks.export"); diff --git a/chrome/browser/extensions/extension_browser_event_router.cc b/chrome/browser/extensions/extension_browser_event_router.cc index b49c1a9..6df9ede 100644 --- a/chrome/browser/extensions/extension_browser_event_router.cc +++ b/chrome/browser/extensions/extension_browser_event_router.cc @@ -10,13 +10,12 @@ #include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_page_actions_module_constants.h" #include "chrome/browser/extensions/extension_tabs_module_constants.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents_wrapper.h" -#include "chrome/browser/tab_contents_wrapper.h" #include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/notification_service.h" diff --git a/chrome/browser/extensions/extension_browser_event_router.h b/chrome/browser/extensions/extension_browser_event_router.h index e951290..cdf2efe 100644 --- a/chrome/browser/extensions/extension_browser_event_router.h +++ b/chrome/browser/extensions/extension_browser_event_router.h @@ -92,9 +92,9 @@ class ExtensionBrowserEventRouter : public TabStripModelObserver, Browser* browser); // NotificationObserver. - void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); private: // "Synthetic" event. Called from TabInsertedAt if new tab is detected. void TabCreatedAt(TabContents* contents, int index, bool foreground); diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc index ae90a66..8178848 100644 --- a/chrome/browser/extensions/extension_browsertest.cc +++ b/chrome/browser/extensions/extension_browsertest.cc @@ -15,10 +15,10 @@ #include "chrome/browser/extensions/extension_error_reporter.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_install_ui.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/location_bar.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/omnibox/location_bar.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/notification_registrar.h" @@ -46,7 +46,7 @@ void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) { #if defined(OS_CHROMEOS) // This makes sure that we create the Default profile first, with no - // ExtensionsService and then the real profile with one, as we do when + // ExtensionService and then the real profile with one, as we do when // running on chromeos. command_line->AppendSwitchASCII(switches::kLoginUser, "TestUser@gmail.com"); @@ -57,7 +57,7 @@ void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) { bool ExtensionBrowserTest::LoadExtensionImpl(const FilePath& path, bool incognito_enabled) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); { NotificationRegistrar registrar; registrar.Add(this, NotificationType::EXTENSION_LOADED, @@ -124,7 +124,7 @@ bool ExtensionBrowserTest::InstallOrUpdateExtension(const std::string& id, const FilePath& path, InstallUIType ui_type, int expected_change) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); service->set_show_extensions_prompts(false); size_t num_before = service->extensions()->size(); @@ -174,7 +174,7 @@ bool ExtensionBrowserTest::InstallOrUpdateExtension(const std::string& id, } void ExtensionBrowserTest::ReloadExtension(const std::string& extension_id) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); service->ReloadExtension(extension_id); ui_test_utils::RegisterAndWait(this, NotificationType::EXTENSION_LOADED, @@ -182,22 +182,22 @@ void ExtensionBrowserTest::ReloadExtension(const std::string& extension_id) { } void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); - service->UnloadExtension(extension_id); + ExtensionService* service = browser()->profile()->GetExtensionService(); + service->UnloadExtension(extension_id, UnloadedExtensionInfo::DISABLE); } void ExtensionBrowserTest::UninstallExtension(const std::string& extension_id) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); service->UninstallExtension(extension_id, false); } void ExtensionBrowserTest::DisableExtension(const std::string& extension_id) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); service->DisableExtension(extension_id); } void ExtensionBrowserTest::EnableExtension(const std::string& extension_id) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); service->EnableExtension(extension_id); } @@ -272,7 +272,7 @@ void ExtensionBrowserTest::WaitForExtensionLoad() { bool ExtensionBrowserTest::WaitForExtensionCrash( const std::string& extension_id) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); if (!service->GetExtensionById(extension_id, true)) { // The extension is already unloaded, presumably due to a crash. diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc index 4787fc5..df03580 100644 --- a/chrome/browser/extensions/extension_browsertests_misc.cc +++ b/chrome/browser/extensions/extension_browsertests_misc.cc @@ -13,18 +13,17 @@ #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_updater.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/site_instance.h" #include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents_wrapper.h" #include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/extensions/extension_action.h" -#include "chrome/common/notification_service.h" #include "chrome/common/url_constants.h" #include "chrome/test/ui_test_utils.h" #include "net/base/mock_host_resolver.h" @@ -173,6 +172,23 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TabContents) { EXPECT_TRUE(result); } +// Tests that GPU-related WebKit preferences are set for extension background +// pages. See http://crbug.com/64512. +IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WebKitPrefsBackgroundPage) { + ASSERT_TRUE(LoadExtension( + test_data_dir_.AppendASCII("good").AppendASCII("Extensions") + .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") + .AppendASCII("1.0.0.0"))); + + ExtensionProcessManager* manager = + browser()->profile()->GetExtensionProcessManager(); + ExtensionHost* host = FindHostWithPath(manager, "/backgroundpage.html", 1); + WebPreferences prefs = host->GetWebkitPrefs(); + ASSERT_FALSE(prefs.experimental_webgl_enabled); + ASSERT_FALSE(prefs.accelerated_compositing_enabled); + ASSERT_FALSE(prefs.accelerated_2d_canvas_enabled); +} + // Tests that we can load page actions in the Omnibox. IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageAction) { ASSERT_TRUE(test_server()->Start()); @@ -252,7 +268,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, UnloadPageAction) { IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageActionRefreshCrash) { base::TimeTicks start_time = base::TimeTicks::Now(); - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); size_t size_before = service->extensions()->size(); @@ -321,7 +337,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSMultiRelLink) { // Tests that tooltips of a browser action icon can be specified using UTF8. // See http://crbug.com/25349. IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationBrowserAction) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const size_t size_before = service->extensions()->size(); FilePath extension_path(test_data_dir_.AppendASCII("browsertest") .AppendASCII("title_localized")); @@ -344,7 +360,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationBrowserAction) { IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationPageAction) { ASSERT_TRUE(test_server()->Start()); - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const size_t size_before = service->extensions()->size(); FilePath extension_path(test_data_dir_.AppendASCII("browsertest") @@ -443,7 +459,7 @@ void NavigateToFeedAndValidate(net::TestServer* server, // TODO(finnur): Implement this is a non-flaky way. } - ExtensionsService* service = browser->profile()->GetExtensionsService(); + ExtensionService* service = browser->profile()->GetExtensionService(); const Extension* extension = service->extensions()->back(); std::string id = extension->id(); @@ -745,7 +761,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MAYBE_PluginLoadUnload) { tab->render_view_host(), L"", L"testPluginWorks()", &result)); EXPECT_FALSE(result); - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const size_t size_before = service->extensions()->size(); ASSERT_TRUE(LoadExtension(extension_dir)); EXPECT_EQ(size_before + 1, service->extensions()->size()); @@ -797,7 +813,7 @@ static const wchar_t* jscript_click_option_button = IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_OptionsPage) { // Install an extension with an options page. ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("options.crx"), 1)); - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const ExtensionList* extensions = service->extensions(); ASSERT_EQ(1u, extensions->size()); const Extension* extension = extensions->at(0); diff --git a/chrome/browser/extensions/extension_clipboard_api.cc b/chrome/browser/extensions/extension_clipboard_api.cc index f80be6b..8cde22f 100644 --- a/chrome/browser/extensions/extension_clipboard_api.cc +++ b/chrome/browser/extensions/extension_clipboard_api.cc @@ -9,7 +9,7 @@ #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents_wrapper.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/extensions/extension_error_utils.h" namespace { diff --git a/chrome/browser/extensions/extension_context_menu_api.cc b/chrome/browser/extensions/extension_context_menu_api.cc index a004b97..78f4f03 100644 --- a/chrome/browser/extensions/extension_context_menu_api.cc +++ b/chrome/browser/extensions/extension_context_menu_api.cc @@ -9,8 +9,8 @@ #include "base/values.h" #include "base/string_number_conversions.h" #include "base/string_util.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/extension_error_utils.h" const char kCheckedKey[] = "checked"; @@ -213,7 +213,7 @@ bool CreateContextMenuFunction::RunImpl() { return false; ExtensionMenuManager* menu_manager = - profile()->GetExtensionsService()->menu_manager(); + profile()->GetExtensionService()->menu_manager(); ExtensionMenuItem::ContextList contexts(ExtensionMenuItem::PAGE); if (!ParseContexts(*properties, kContextsKey, &contexts)) @@ -268,7 +268,7 @@ bool UpdateContextMenuFunction::RunImpl() { ExtensionMenuItem::Id item_id(profile(), extension_id(), 0); EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &item_id.uid)); - ExtensionsService* service = profile()->GetExtensionsService(); + ExtensionService* service = profile()->GetExtensionService(); ExtensionMenuManager* manager = service->menu_manager(); ExtensionMenuItem* item = manager->GetItemById(item_id); if (!item || item->extension_id() != extension_id()) { @@ -282,7 +282,7 @@ bool UpdateContextMenuFunction::RunImpl() { EXTENSION_FUNCTION_VALIDATE(properties != NULL); ExtensionMenuManager* menu_manager = - profile()->GetExtensionsService()->menu_manager(); + profile()->GetExtensionService()->menu_manager(); // Type. ExtensionMenuItem::Type type; @@ -334,7 +334,7 @@ bool UpdateContextMenuFunction::RunImpl() { bool RemoveContextMenuFunction::RunImpl() { ExtensionMenuItem::Id id(profile(), extension_id(), 0); EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &id.uid)); - ExtensionsService* service = profile()->GetExtensionsService(); + ExtensionService* service = profile()->GetExtensionService(); ExtensionMenuManager* manager = service->menu_manager(); ExtensionMenuItem* item = manager->GetItemById(id); @@ -349,7 +349,7 @@ bool RemoveContextMenuFunction::RunImpl() { } bool RemoveAllContextMenusFunction::RunImpl() { - ExtensionsService* service = profile()->GetExtensionsService(); + ExtensionService* service = profile()->GetExtensionService(); ExtensionMenuManager* manager = service->menu_manager(); manager->RemoveAllContextItems(extension_id()); return true; diff --git a/chrome/browser/extensions/extension_context_menu_browsertest.cc b/chrome/browser/extensions/extension_context_menu_browsertest.cc index 2397aa7..fe893f9 100644 --- a/chrome/browser/extensions/extension_context_menu_browsertest.cc +++ b/chrome/browser/extensions/extension_context_menu_browsertest.cc @@ -3,12 +3,13 @@ // found in the LICENSE file. #include "app/menus/menu_model.h" +#include "base/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_test_message_listener.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/render_view_context_menu.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" @@ -145,14 +146,14 @@ class ExtensionContextMenuBrowserTest : public ExtensionBrowserTest { // Shortcut to return the current ExtensionMenuManager. ExtensionMenuManager* menu_manager() { - return browser()->profile()->GetExtensionsService()->menu_manager(); + return browser()->profile()->GetExtensionService()->menu_manager(); } // Returns a pointer to the currently loaded extension with |name|, or null // if not found. const Extension* GetExtensionNamed(std::string name) { const ExtensionList* extensions = - browser()->profile()->GetExtensionsService()->extensions(); + browser()->profile()->GetExtensionService()->extensions(); ExtensionList::const_iterator i; for (i = extensions->begin(); i != extensions->end(); ++i) { if ((*i)->name() == name) { diff --git a/chrome/browser/extensions/extension_context_menu_model.cc b/chrome/browser/extensions/extension_context_menu_model.cc index 047af99..70d4189 100644 --- a/chrome/browser/extensions/extension_context_menu_model.cc +++ b/chrome/browser/extensions/extension_context_menu_model.cc @@ -5,11 +5,10 @@ #include "chrome/browser/extensions/extension_context_menu_model.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/extensions/extension_action.h" #include "chrome/common/extensions/extension_constants.h" @@ -118,12 +117,12 @@ void ExtensionContextMenuModel::ExecuteCommand(int command_id) { browser_); break; case HIDE: { - ExtensionsService* extension_service = profile_->GetExtensionsService(); + ExtensionService* extension_service = profile_->GetExtensionService(); extension_service->SetBrowserActionVisibility(extension, false); break; } case DISABLE: { - ExtensionsService* extension_service = profile_->GetExtensionsService(); + ExtensionService* extension_service = profile_->GetExtensionService(); extension_service->DisableExtension(extension_id_); break; } @@ -150,7 +149,7 @@ void ExtensionContextMenuModel::ExecuteCommand(int command_id) { void ExtensionContextMenuModel::InstallUIProceed() { if (GetExtension()) - profile_->GetExtensionsService()->UninstallExtension(extension_id_, false); + profile_->GetExtensionService()->UninstallExtension(extension_id_, false); Release(); } @@ -160,6 +159,6 @@ void ExtensionContextMenuModel::InstallUIAbort() { } const Extension* ExtensionContextMenuModel::GetExtension() const { - ExtensionsService* extension_service = profile_->GetExtensionsService(); + ExtensionService* extension_service = profile_->GetExtensionService(); return extension_service->GetExtensionById(extension_id_, false); } diff --git a/chrome/browser/extensions/extension_cookies_api.cc b/chrome/browser/extensions/extension_cookies_api.cc index e66c4b3..0f61602 100644 --- a/chrome/browser/extensions/extension_cookies_api.cc +++ b/chrome/browser/extensions/extension_cookies_api.cc @@ -14,7 +14,7 @@ #include "chrome/browser/extensions/extension_cookies_api_constants.h" #include "chrome/browser/extensions/extension_cookies_helpers.h" #include "chrome/browser/extensions/extension_event_router.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_error_utils.h" #include "chrome/common/net/url_request_context_getter.h" @@ -191,7 +191,7 @@ void GetCookieFunction::GetCookieOnIOThread() { void GetCookieFunction::RespondOnUIThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - net::CookieMonster::CookieList::iterator it; + net::CookieList::iterator it; for (it = cookie_list_.begin(); it != cookie_list_.end(); ++it) { // Return the first matching cookie. Relies on the fact that the // CookieMonster returns them in canonical order (longest path, then @@ -425,7 +425,7 @@ bool GetAllCookieStoresFunction::RunImpl() { scoped_ptr<ListValue> original_tab_ids(new ListValue()); Profile* incognito_profile = NULL; scoped_ptr<ListValue> incognito_tab_ids; - if (include_incognito()) { + if (include_incognito() && profile()->HasOffTheRecordProfile()) { incognito_profile = profile()->GetOffTheRecordProfile(); if (incognito_profile) incognito_tab_ids.reset(new ListValue()); diff --git a/chrome/browser/extensions/extension_cookies_api.h b/chrome/browser/extensions/extension_cookies_api.h index 50b922b..dc81731 100644 --- a/chrome/browser/extensions/extension_cookies_api.h +++ b/chrome/browser/extensions/extension_cookies_api.h @@ -106,7 +106,7 @@ class GetCookieFunction : public CookiesFunction { GURL url_; std::string store_id_; scoped_refptr<URLRequestContextGetter> store_context_; - net::CookieMonster::CookieList cookie_list_; + net::CookieList cookie_list_; }; // Implements the cookies.getAll() extension function. @@ -125,7 +125,7 @@ class GetAllCookiesFunction : public CookiesFunction { GURL url_; std::string store_id_; scoped_refptr<URLRequestContextGetter> store_context_; - net::CookieMonster::CookieList cookie_list_; + net::CookieList cookie_list_; }; // Implements the cookies.set() extension function. diff --git a/chrome/browser/extensions/extension_cookies_helpers.cc b/chrome/browser/extensions/extension_cookies_helpers.cc index a140c8e..42e2fae 100644 --- a/chrome/browser/extensions/extension_cookies_helpers.cc +++ b/chrome/browser/extensions/extension_cookies_helpers.cc @@ -10,10 +10,10 @@ #include "base/values.h" #include "chrome/browser/extensions/extension_cookies_api_constants.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tabs/tab_strip_model.h" -#include "chrome/browser/tab_contents_wrapper.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/url_constants.h" #include "googleurl/src/gurl.h" @@ -30,7 +30,8 @@ Profile* ChooseProfileFromStoreId(const std::string& store_id, bool include_incognito) { DCHECK(profile); bool allow_original = !profile->IsOffTheRecord(); - bool allow_incognito = profile->IsOffTheRecord() || include_incognito; + bool allow_incognito = profile->IsOffTheRecord() || + (include_incognito && profile->HasOffTheRecordProfile()); if (store_id == kOriginalProfileStoreId && allow_original) return profile->GetOriginalProfile(); if (store_id == kOffTheRecordProfileStoreId && allow_incognito) @@ -75,7 +76,7 @@ DictionaryValue* CreateCookieStoreValue(Profile* profile, return result; } -net::CookieMonster::CookieList GetCookieListFromStore( +net::CookieList GetCookieListFromStore( net::CookieStore* cookie_store, const GURL& url) { DCHECK(cookie_store); net::CookieMonster* monster = cookie_store->GetCookieMonster(); @@ -97,12 +98,12 @@ GURL GetURLFromCanonicalCookie( } void AppendMatchingCookiesToList( - const net::CookieMonster::CookieList& all_cookies, + const net::CookieList& all_cookies, const std::string& store_id, const GURL& url, const DictionaryValue* details, const Extension* extension, ListValue* match_list) { - net::CookieMonster::CookieList::const_iterator it; + net::CookieList::const_iterator it; for (it = all_cookies.begin(); it != all_cookies.end(); ++it) { // Ignore any cookie whose domain doesn't match the extension's // host permissions. diff --git a/chrome/browser/extensions/extension_cookies_helpers.h b/chrome/browser/extensions/extension_cookies_helpers.h index 7bb33d2..18bbf8d 100644 --- a/chrome/browser/extensions/extension_cookies_helpers.h +++ b/chrome/browser/extensions/extension_cookies_helpers.h @@ -49,7 +49,7 @@ DictionaryValue* CreateCookieStoreValue(Profile* profile, // Retrieves all cookies from the given cookie store corresponding to the given // URL. If the URL is empty, all cookies in the cookie store are retrieved. // This can only be called on the IO thread. -net::CookieMonster::CookieList GetCookieListFromStore( +net::CookieList GetCookieListFromStore( net::CookieStore* cookie_store, const GURL& url); // Constructs a URL from a cookie's information for use in checking @@ -63,7 +63,7 @@ GURL GetURLFromCanonicalCookie( // match list all the cookies that both match the given URL and cookie details // and are allowed by extension host permissions. void AppendMatchingCookiesToList( - const net::CookieMonster::CookieList& all_cookies, + const net::CookieList& all_cookies, const std::string& store_id, const GURL& url, const DictionaryValue* details, const Extension* extension, diff --git a/chrome/browser/extensions/extension_cookies_unittest.cc b/chrome/browser/extensions/extension_cookies_unittest.cc index 6665052..2aa34a3 100644 --- a/chrome/browser/extensions/extension_cookies_unittest.cc +++ b/chrome/browser/extensions/extension_cookies_unittest.cc @@ -42,6 +42,10 @@ class OtrTestingProfile : public TestingProfile { return linked_profile_; } + virtual bool HasOffTheRecordProfile() { + return (!IsOffTheRecord() && linked_profile_); + } + static void LinkProfiles(OtrTestingProfile* profile1, OtrTestingProfile* profile2) { profile1->set_linked_profile(profile2); diff --git a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc index 898de6b..cb489a1 100644 --- a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc +++ b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc @@ -7,19 +7,21 @@ #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_process_manager.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/tab_contents/infobar_delegate.h" #include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/browser/ui/browser.h" +#include "chrome/common/result_codes.h" #include "chrome/test/ui_test_utils.h" class ExtensionCrashRecoveryTest : public ExtensionBrowserTest { protected: - ExtensionsService* GetExtensionsService() { - return browser()->profile()->GetExtensionsService(); + ExtensionService* GetExtensionService() { + return browser()->profile()->GetExtensionService(); } ExtensionProcessManager* GetExtensionProcessManager() { @@ -50,9 +52,9 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest { } void CrashExtension(size_t index) { - ASSERT_LT(index, GetExtensionsService()->extensions()->size()); + ASSERT_LT(index, GetExtensionService()->extensions()->size()); const Extension* extension = - GetExtensionsService()->extensions()->at(index); + GetExtensionService()->extensions()->at(index); ASSERT_TRUE(extension); std::string extension_id(extension->id()); ExtensionHost* extension_host = @@ -61,17 +63,16 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest { RenderProcessHost* extension_rph = extension_host->render_view_host()->process(); - base::KillProcess(extension_rph->GetHandle(), - base::PROCESS_END_KILLED_BY_USER, false); + base::KillProcess(extension_rph->GetHandle(), ResultCodes::KILLED, false); ASSERT_TRUE(WaitForExtensionCrash(extension_id)); ASSERT_FALSE( GetExtensionProcessManager()->GetBackgroundHostForExtension(extension)); } void CheckExtensionConsistency(size_t index) { - ASSERT_LT(index, GetExtensionsService()->extensions()->size()); + ASSERT_LT(index, GetExtensionService()->extensions()->size()); const Extension* extension = - GetExtensionsService()->extensions()->at(index); + GetExtensionService()->extensions()->at(index); ASSERT_TRUE(extension); ExtensionHost* extension_host = GetExtensionProcessManager()->GetBackgroundHostForExtension(extension); @@ -84,21 +85,21 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest { void LoadTestExtension() { ExtensionBrowserTest::SetUpInProcessBrowserTestFixture(); - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); ASSERT_TRUE(LoadExtension( test_data_dir_.AppendASCII("common").AppendASCII("background_page"))); - const Extension* extension = GetExtensionsService()->extensions()->back(); + const Extension* extension = GetExtensionService()->extensions()->back(); ASSERT_TRUE(extension); first_extension_id_ = extension->id(); CheckExtensionConsistency(size_before); } void LoadSecondExtension() { - int offset = GetExtensionsService()->extensions()->size(); + int offset = GetExtensionService()->extensions()->size(); ASSERT_TRUE(LoadExtension( test_data_dir_.AppendASCII("install").AppendASCII("install"))); const Extension* extension = - GetExtensionsService()->extensions()->at(offset); + GetExtensionService()->extensions()->at(offset); ASSERT_TRUE(extension); second_extension_id_ = extension->id(); CheckExtensionConsistency(offset); @@ -109,10 +110,10 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest { }; IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, Basic) { - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); LoadTestExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); AcceptCrashedExtensionInfobar(0); SCOPED_TRACE("after clicking the infobar"); @@ -120,10 +121,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, Basic) { } IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, CloseAndReload) { - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); LoadTestExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); CancelCrashedExtensionInfobar(0); ReloadExtension(first_extension_id_); @@ -132,10 +133,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, CloseAndReload) { } IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, ReloadIndependently) { - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); LoadTestExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); ReloadExtension(first_extension_id_); @@ -150,22 +151,148 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, ReloadIndependently) { ASSERT_EQ(0, current_tab->infobar_delegate_count()); } +IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, + ReloadIndependentlyChangeTabs) { + const size_t size_before = GetExtensionService()->extensions()->size(); + LoadTestExtension(); + CrashExtension(size_before); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); + + TabContents* original_tab = browser()->GetSelectedTabContents(); + ASSERT_TRUE(original_tab); + ASSERT_EQ(1, original_tab->infobar_delegate_count()); + + // Open a new tab so the info bar will not be in the current tab. + browser()->NewTab(); + TabContents* new_current_tab = browser()->GetSelectedTabContents(); + ASSERT_TRUE(new_current_tab); + ASSERT_NE(new_current_tab, original_tab); + ASSERT_EQ(0, new_current_tab->infobar_delegate_count()); + + ReloadExtension(first_extension_id_); + + SCOPED_TRACE("after reloading"); + CheckExtensionConsistency(size_before); + + // The infobar should automatically hide after the extension is successfully + // reloaded. + ASSERT_EQ(0, original_tab->infobar_delegate_count()); +} + +IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, + ReloadIndependentlyNavigatePage) { + const size_t size_before = GetExtensionService()->extensions()->size(); + LoadTestExtension(); + CrashExtension(size_before); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); + + TabContents* current_tab = browser()->GetSelectedTabContents(); + ASSERT_TRUE(current_tab); + ASSERT_EQ(1, current_tab->infobar_delegate_count()); + + // Navigate to another page. + ui_test_utils::NavigateToURL(browser(), + ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), + FilePath(FILE_PATH_LITERAL("title1.html")))); + ASSERT_EQ(1, current_tab->infobar_delegate_count()); + + ReloadExtension(first_extension_id_); + + SCOPED_TRACE("after reloading"); + CheckExtensionConsistency(size_before); + + // The infobar should automatically hide after the extension is successfully + // reloaded. + ASSERT_EQ(0, current_tab->infobar_delegate_count()); +} + +IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, + ReloadIndependentlyTwoInfoBars) { + const size_t size_before = GetExtensionService()->extensions()->size(); + LoadTestExtension(); + + // Open a new window so that there will be an info bar in each. + Browser* browser2 = CreateBrowser(browser()->profile()); + + CrashExtension(size_before); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); + + TabContents* current_tab = browser()->GetSelectedTabContents(); + ASSERT_TRUE(current_tab); + ASSERT_EQ(1, current_tab->infobar_delegate_count()); + + TabContents* current_tab2 = browser2->GetSelectedTabContents(); + ASSERT_TRUE(current_tab2); + ASSERT_EQ(1, current_tab2->infobar_delegate_count()); + + ReloadExtension(first_extension_id_); + + SCOPED_TRACE("after reloading"); + CheckExtensionConsistency(size_before); + + // Both infobars should automatically hide after the extension is successfully + // reloaded. + ASSERT_EQ(0, current_tab->infobar_delegate_count()); + ASSERT_EQ(0, current_tab2->infobar_delegate_count()); +} + +IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, + ReloadIndependentlyTwoInfoBarsSameBrowser) { + const size_t size_before = GetExtensionService()->extensions()->size(); + LoadTestExtension(); + + // Open a new window so that there will be an info bar in each. + Browser* browser2 = CreateBrowser(browser()->profile()); + + CrashExtension(size_before); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); + + TabContents* current_tab = browser()->GetSelectedTabContents(); + ASSERT_TRUE(current_tab); + ASSERT_EQ(1, current_tab->infobar_delegate_count()); + + TabContents* current_tab2 = browser2->GetSelectedTabContents(); + ASSERT_TRUE(current_tab2); + ASSERT_EQ(1, current_tab2->infobar_delegate_count()); + + // Move second window into first browser so there will be multiple tabs + // with the info bar for the same extension in one browser. + TabContentsWrapper* contents = + browser2->tabstrip_model()->DetachTabContentsAt(0); + browser()->tabstrip_model()->AppendTabContents(contents, true); + current_tab2 = browser()->GetSelectedTabContents(); + ASSERT_EQ(1, current_tab2->infobar_delegate_count()); + ASSERT_NE(current_tab2, current_tab); + + ReloadExtension(first_extension_id_); + + SCOPED_TRACE("after reloading"); + CheckExtensionConsistency(size_before); + + // Both infobars should automatically hide after the extension is successfully + // reloaded. + ASSERT_EQ(0, current_tab2->infobar_delegate_count()); + browser()->SelectPreviousTab(); + ASSERT_EQ(current_tab, browser()->GetSelectedTabContents()); + ASSERT_EQ(0, current_tab->infobar_delegate_count()); +} + // Make sure that when we don't do anything about the crashed extension // and close the browser, it doesn't crash. The browser is closed implicitly // at the end of each browser test. IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, ShutdownWhileCrashed) { - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); LoadTestExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); } IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsCrashFirst) { - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); LoadTestExtension(); LoadSecondExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size()); AcceptCrashedExtensionInfobar(0); SCOPED_TRACE("after clicking the infobar"); @@ -174,11 +301,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsCrashFirst) { } IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsCrashSecond) { - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); LoadTestExtension(); LoadSecondExtension(); CrashExtension(size_before + 1); - ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size()); AcceptCrashedExtensionInfobar(0); SCOPED_TRACE("after clicking the infobar"); @@ -188,13 +315,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsCrashSecond) { IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsCrashBothAtOnce) { - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); LoadTestExtension(); LoadSecondExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size()); CrashExtension(size_before); - ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); { SCOPED_TRACE("first infobar"); @@ -211,13 +338,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, } IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsOneByOne) { - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); LoadTestExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); LoadSecondExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); { SCOPED_TRACE("first infobar"); @@ -238,42 +365,42 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsOneByOne) { // at the end of each browser test. IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsShutdownWhileCrashed) { - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); LoadTestExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); LoadSecondExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); } IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsIgnoreFirst) { - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); LoadTestExtension(); LoadSecondExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size()); CrashExtension(size_before); - ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); CancelCrashedExtensionInfobar(0); AcceptCrashedExtensionInfobar(1); SCOPED_TRACE("infobars done"); - ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size()); CheckExtensionConsistency(size_before); } IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsReloadIndependently) { - const size_t size_before = GetExtensionsService()->extensions()->size(); + const size_t size_before = GetExtensionService()->extensions()->size(); LoadTestExtension(); LoadSecondExtension(); CrashExtension(size_before); - ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size()); CrashExtension(size_before); - ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); + ASSERT_EQ(size_before, GetExtensionService()->extensions()->size()); { SCOPED_TRACE("first: reload"); diff --git a/chrome/browser/extensions/extension_data_deleter.cc b/chrome/browser/extensions/extension_data_deleter.cc index 14ea9a2..f98ac86 100644 --- a/chrome/browser/extensions/extension_data_deleter.cc +++ b/chrome/browser/extensions/extension_data_deleter.cc @@ -5,13 +5,14 @@ #include "chrome/browser/extensions/extension_data_deleter.h" #include "chrome/browser/in_process_webkit/webkit_context.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/net/url_request_context_getter.h" #include "net/base/cookie_monster.h" #include "net/base/net_errors.h" #include "webkit/database/database_util.h" #include "webkit/database/database_tracker.h" +#include "webkit/fileapi/sandboxed_file_system_context.h" ExtensionDataDeleter::ExtensionDataDeleter(Profile* profile, const GURL& extension_url) { @@ -19,6 +20,7 @@ ExtensionDataDeleter::ExtensionDataDeleter(Profile* profile, webkit_context_ = profile->GetWebKitContext(); database_tracker_ = profile->GetDatabaseTracker(); extension_request_context_ = profile->GetRequestContextForExtensions(); + file_system_context_ = profile->GetFileSystemContext(); extension_url_ = extension_url; origin_id_ = webkit_database::DatabaseUtil::GetOriginIdentifier(extension_url_); @@ -48,6 +50,11 @@ void ExtensionDataDeleter::StartDeleting() { BrowserThread::FILE, FROM_HERE, NewRunnableMethod( this, &ExtensionDataDeleter::DeleteDatabaseOnFileThread)); + + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod( + this, &ExtensionDataDeleter::DeleteFileSystemOnFileThread)); } void ExtensionDataDeleter::DeleteCookiesOnIOThread() { @@ -74,3 +81,8 @@ void ExtensionDataDeleter::DeleteIndexedDBOnWebkitThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); webkit_context_->indexed_db_context()->DeleteIndexedDBForOrigin(origin_id_); } + +void ExtensionDataDeleter::DeleteFileSystemOnFileThread() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + file_system_context_->DeleteDataForOriginOnFileThread(extension_url_); +} diff --git a/chrome/browser/extensions/extension_data_deleter.h b/chrome/browser/extensions/extension_data_deleter.h index 0a535fe..960f06f 100644 --- a/chrome/browser/extensions/extension_data_deleter.h +++ b/chrome/browser/extensions/extension_data_deleter.h @@ -15,13 +15,17 @@ namespace webkit_database { class DatabaseTracker; } +namespace fileapi { +class SandboxedFileSystemContext; +} + class Profile; class URLRequestContextGetter; class WebKitContext; // A helper class that takes care of removing local storage, databases and // cookies for a given extension. This is used by -// ExtensionsService::ClearExtensionData() upon uninstalling an extension. +// ExtensionService::ClearExtensionData() upon uninstalling an extension. class ExtensionDataDeleter : public base::RefCountedThreadSafe<ExtensionDataDeleter, BrowserThread::DeleteOnUIThread> { @@ -52,6 +56,10 @@ class ExtensionDataDeleter // webkit thread. void DeleteIndexedDBOnWebkitThread(); + // Deletes filesystem files for the extension. May only be called on the + // file thread. + void DeleteFileSystemOnFileThread(); + // The database context for deleting the database. scoped_refptr<webkit_database::DatabaseTracker> database_tracker_; @@ -67,6 +75,8 @@ class ExtensionDataDeleter // Webkit context for accessing the DOM storage helper. scoped_refptr<WebKitContext> webkit_context_; + scoped_refptr<fileapi::SandboxedFileSystemContext> file_system_context_; + DISALLOW_COPY_AND_ASSIGN(ExtensionDataDeleter); }; diff --git a/chrome/browser/extensions/extension_devtools_bridge.cc b/chrome/browser/extensions/extension_devtools_bridge.cc index 3a8f525..8394ad0 100644 --- a/chrome/browser/extensions/extension_devtools_bridge.cc +++ b/chrome/browser/extensions/extension_devtools_bridge.cc @@ -12,9 +12,9 @@ #include "chrome/browser/extensions/extension_devtools_manager.h" #include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents_wrapper.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/devtools_messages.h" ExtensionDevToolsBridge::ExtensionDevToolsBridge(int tab_id, diff --git a/chrome/browser/extensions/extension_devtools_browsertests.cc b/chrome/browser/extensions/extension_devtools_browsertests.cc index cc61b3d..c29a4ca 100644 --- a/chrome/browser/extensions/extension_devtools_browsertests.cc +++ b/chrome/browser/extensions/extension_devtools_browsertests.cc @@ -11,9 +11,9 @@ #include "chrome/browser/extensions/extension_error_reporter.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_process_manager.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/site_instance.h" #include "chrome/browser/tab_contents/tab_contents.h" @@ -21,7 +21,6 @@ #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/devtools_messages.h" -#include "chrome/common/notification_service.h" #include "chrome/common/url_constants.h" #include "chrome/test/ui_test_utils.h" #include "net/base/net_util.h" diff --git a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc index 354fea9..28e0709 100644 --- a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc +++ b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc @@ -8,16 +8,16 @@ #include "app/l10n_util.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/browser_thread.h" #include "chrome/browser/extensions/extension_install_ui.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/tab_contents/infobar_delegate.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/browser_list.h" #include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/extensions/extension_resource.h" +#include "chrome/common/notification_details.h" #include "chrome/common/notification_registrar.h" -#include "chrome/common/notification_service.h" +#include "chrome/common/notification_source.h" #include "grit/generated_resources.h" class ExtensionDisabledDialogDelegate @@ -25,7 +25,7 @@ class ExtensionDisabledDialogDelegate public base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate> { public: ExtensionDisabledDialogDelegate(Profile* profile, - ExtensionsService* service, + ExtensionService* service, const Extension* extension) : service_(service), extension_(extension) { AddRef(); // Balanced in Proceed or Abort. @@ -52,7 +52,7 @@ class ExtensionDisabledDialogDelegate // The UI for showing the install dialog when enabling. scoped_ptr<ExtensionInstallUI> install_ui_; - ExtensionsService* service_; + ExtensionService* service_; const Extension* extension_; }; @@ -61,7 +61,7 @@ class ExtensionDisabledInfobarDelegate public NotificationObserver { public: ExtensionDisabledInfobarDelegate(TabContents* tab_contents, - ExtensionsService* service, + ExtensionService* service, const Extension* extension) : ConfirmInfoBarDelegate(tab_contents), tab_contents_(tab_contents), @@ -70,7 +70,7 @@ class ExtensionDisabledInfobarDelegate // The user might re-enable the extension in other ways, so watch for that. registrar_.Add(this, NotificationType::EXTENSION_LOADED, Source<Profile>(service->profile())); - registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, + registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, Source<Profile>(service->profile())); } virtual ~ExtensionDisabledInfobarDelegate() { @@ -106,27 +106,34 @@ class ExtensionDisabledInfobarDelegate const NotificationDetails& details) { // TODO(mpcomplete): RemoveInfoBar doesn't seem to always result in us // getting deleted. + const Extension* extension = NULL; switch (type.value) { case NotificationType::EXTENSION_LOADED: - case NotificationType::EXTENSION_UNLOADED_DISABLED: { - const Extension* extension = Details<const Extension>(details).ptr(); - if (extension == extension_) - tab_contents_->RemoveInfoBar(this); + extension = Details<const Extension>(details).ptr(); + break; + case NotificationType::EXTENSION_UNLOADED: { + UnloadedExtensionInfo* info = + Details<UnloadedExtensionInfo>(details).ptr(); + if (info->reason == UnloadedExtensionInfo::DISABLE) + extension = info->extension; break; } default: NOTREACHED(); + return; } + if (extension == extension_) + tab_contents_->RemoveInfoBar(this); } private: NotificationRegistrar registrar_; TabContents* tab_contents_; - ExtensionsService* service_; + ExtensionService* service_; const Extension* extension_; }; -void ShowExtensionDisabledUI(ExtensionsService* service, Profile* profile, +void ShowExtensionDisabledUI(ExtensionService* service, Profile* profile, const Extension* extension) { Browser* browser = BrowserList::GetLastActiveWithProfile(profile); if (!browser) @@ -140,7 +147,7 @@ void ShowExtensionDisabledUI(ExtensionsService* service, Profile* profile, tab_contents, service, extension)); } -void ShowExtensionDisabledDialog(ExtensionsService* service, Profile* profile, +void ShowExtensionDisabledDialog(ExtensionService* service, Profile* profile, const Extension* extension) { // This object manages its own lifetime. new ExtensionDisabledDialogDelegate(profile, service, extension); diff --git a/chrome/browser/extensions/extension_disabled_infobar_delegate.h b/chrome/browser/extensions/extension_disabled_infobar_delegate.h index 430e652..665b0eb 100644 --- a/chrome/browser/extensions/extension_disabled_infobar_delegate.h +++ b/chrome/browser/extensions/extension_disabled_infobar_delegate.h @@ -7,16 +7,16 @@ #pragma once class Extension; -class ExtensionsService; +class ExtensionService; class Profile; // Shows UI to inform the user that an extension was disabled after upgrading // to higher permissions. -void ShowExtensionDisabledUI(ExtensionsService* service, Profile* profile, +void ShowExtensionDisabledUI(ExtensionService* service, Profile* profile, const Extension* extension); // Shows the extension install dialog. -void ShowExtensionDisabledDialog(ExtensionsService* service, Profile* profile, +void ShowExtensionDisabledDialog(ExtensionService* service, Profile* profile, const Extension* extension); #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_DISABLED_INFOBAR_DELEGATE_H_ diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc index faaa74b..97889d7 100644 --- a/chrome/browser/extensions/extension_dom_ui.cc +++ b/chrome/browser/extensions/extension_dom_ui.cc @@ -5,17 +5,17 @@ #include "chrome/browser/extensions/extension_dom_ui.h" #include <set> +#include <vector> #include "net/base/file_stream.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/browser_list.h" -#include "chrome/browser/browser_thread.h" #include "chrome/browser/extensions/extension_bookmark_manager_api.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/image_loading_tracker.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" @@ -64,7 +64,7 @@ class ExtensionDOMUIImageLoadingTracker : public ImageLoadingTracker::Observer { extension_(NULL) { // Even when the extensions service is enabled by default, it's still // disabled in incognito mode. - ExtensionsService* service = profile->GetExtensionsService(); + ExtensionService* service = profile->GetExtensionService(); if (service) extension_ = service->GetExtensionByURL(page_url); } @@ -125,7 +125,7 @@ const char ExtensionDOMUI::kExtensionURLOverrides[] = ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents, const GURL& url) : DOMUI(tab_contents), url_(url) { - ExtensionsService* service = tab_contents->profile()->GetExtensionsService(); + ExtensionService* service = tab_contents->profile()->GetExtensionService(); const Extension* extension = service->GetExtensionByURL(url); if (!extension) extension = service->GetExtensionByWebExtent(url); @@ -242,7 +242,7 @@ bool ExtensionDOMUI::HandleChromeURLOverride(GURL* url, Profile* profile) { if (!overrides || !overrides->GetList(page, &url_list)) return false; - ExtensionsService* service = profile->GetExtensionsService(); + ExtensionService* service = profile->GetExtensionService(); size_t i = 0; while (i < url_list->GetSize()) { diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc index 4fc48e3..0b4f799 100644 --- a/chrome/browser/extensions/extension_event_router.cc +++ b/chrome/browser/extensions/extension_event_router.cc @@ -10,8 +10,8 @@ #include "chrome/browser/extensions/extension_processes_api.h" #include "chrome/browser/extensions/extension_processes_api_constants.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/notification_service.h" @@ -56,7 +56,7 @@ struct ExtensionEventRouter::EventListener { bool ExtensionEventRouter::CanCrossIncognito(Profile* profile, const std::string& extension_id) { const Extension* extension = - profile->GetExtensionsService()->GetExtensionById(extension_id, false); + profile->GetExtensionService()->GetExtensionById(extension_id, false); return CanCrossIncognito(profile, extension); } @@ -66,7 +66,7 @@ bool ExtensionEventRouter::CanCrossIncognito(Profile* profile, // We allow the extension to see events and data from another profile iff it // uses "spanning" behavior and it has incognito access. "split" mode // extensions only see events for a matching profile. - return (profile->GetExtensionsService()->IsIncognitoEnabled(extension) && + return (profile->GetExtensionService()->IsIncognitoEnabled(extension) && !extension->incognito_split_mode()); } @@ -168,7 +168,7 @@ void ExtensionEventRouter::DispatchEventImpl( return; std::set<EventListener>& listeners = it->second; - ExtensionsService* service = profile_->GetExtensionsService(); + ExtensionService* service = profile_->GetExtensionService(); // Send the event only to renderers that are listening for it. for (std::set<EventListener>::iterator listener = listeners.begin(); diff --git a/chrome/browser/extensions/extension_fileapi_apitest.cc b/chrome/browser/extensions/extension_fileapi_apitest.cc new file mode 100644 index 0000000..782a600 --- /dev/null +++ b/chrome/browser/extensions/extension_fileapi_apitest.cc @@ -0,0 +1,9 @@ +// Copyright (c) 2010 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/extension_apitest.h" + +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FileAPI) { + ASSERT_TRUE(RunExtensionTest("fileapi")) << message_; +} diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc index 88a6c9e..054c882 100644 --- a/chrome/browser/extensions/extension_function.cc +++ b/chrome/browser/extensions/extension_function.cc @@ -7,8 +7,8 @@ #include "base/json/json_writer.h" #include "base/logging.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" ExtensionFunction::ExtensionFunction() : request_id_(-1), @@ -22,7 +22,7 @@ ExtensionFunction::~ExtensionFunction() { } const Extension* ExtensionFunction::GetExtension() { - ExtensionsService* service = profile_->GetExtensionsService(); + ExtensionService* service = profile_->GetExtensionService(); DCHECK(service); return service->GetExtensionById(extension_id_, false); } diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 7c86ed7..3c98cf3 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -50,10 +50,12 @@ #include "chrome/browser/extensions/extension_tts_api.h" #include "chrome/browser/extensions/extension_webstore_private_api.h" #include "chrome/browser/extensions/extensions_quota_service.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/metrics/user_metrics.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/common/notification_service.h" #include "chrome/common/render_messages.h" #include "chrome/common/render_messages_params.h" #include "chrome/common/result_codes.h" @@ -75,7 +77,7 @@ ExtensionFunction* NewExtensionFunction() { // create instances of them. class FactoryRegistry { public: - static FactoryRegistry* instance(); + static FactoryRegistry* GetInstance(); FactoryRegistry() { ResetFunctions(); } // Resets all functions to their default values. @@ -102,7 +104,7 @@ class FactoryRegistry { FactoryMap factories_; }; -FactoryRegistry* FactoryRegistry::instance() { +FactoryRegistry* FactoryRegistry::GetInstance() { return Singleton<FactoryRegistry>::get(); } @@ -239,6 +241,7 @@ void FactoryRegistry::ResetFunctions() { RegisterFunction<ExtensionTtsSpeakFunction>(); RegisterFunction<ExtensionTtsStopSpeakingFunction>(); RegisterFunction<ExtensionTtsIsSpeakingFunction>(); + RegisterFunction<ExtensionTtsSpeakCompletedFunction>(); // Clipboard. RegisterFunction<ExecuteCopyClipboardFunction>(); @@ -325,24 +328,24 @@ ExtensionFunction* FactoryRegistry::NewFunction(const std::string& name) { void ExtensionFunctionDispatcher::GetAllFunctionNames( std::vector<std::string>* names) { - FactoryRegistry::instance()->GetAllNames(names); + FactoryRegistry::GetInstance()->GetAllNames(names); } bool ExtensionFunctionDispatcher::OverrideFunction( const std::string& name, ExtensionFunctionFactory factory) { - return FactoryRegistry::instance()->OverrideFunction(name, factory); + return FactoryRegistry::GetInstance()->OverrideFunction(name, factory); } void ExtensionFunctionDispatcher::ResetFunctions() { - FactoryRegistry::instance()->ResetFunctions(); + FactoryRegistry::GetInstance()->ResetFunctions(); } ExtensionFunctionDispatcher* ExtensionFunctionDispatcher::Create( RenderViewHost* render_view_host, Delegate* delegate, const GURL& url) { - ExtensionsService* service = - render_view_host->process()->profile()->GetExtensionsService(); + ExtensionService* service = + render_view_host->process()->profile()->GetExtensionService(); DCHECK(service); if (!service->ExtensionBindingsAllowed(url)) @@ -387,7 +390,7 @@ ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( DOMUIFavIconSource* favicon_source = new DOMUIFavIconSource(profile_); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - NewRunnableMethod(Singleton<ChromeURLDataManager>::get(), + NewRunnableMethod(ChromeURLDataManager::GetInstance(), &ChromeURLDataManager::AddDataSource, make_scoped_refptr(favicon_source))); } @@ -444,7 +447,7 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser( void ExtensionFunctionDispatcher::HandleRequest( const ViewHostMsg_DomMessage_Params& params) { scoped_refptr<ExtensionFunction> function( - FactoryRegistry::instance()->NewFunction(params.name)); + FactoryRegistry::GetInstance()->NewFunction(params.name)); function->set_dispatcher_peer(peer_); function->set_profile(profile_); function->set_extension_id(extension_id()); @@ -453,7 +456,7 @@ void ExtensionFunctionDispatcher::HandleRequest( function->set_request_id(params.request_id); function->set_has_callback(params.has_callback); function->set_user_gesture(params.user_gesture); - ExtensionsService* service = profile()->GetExtensionsService(); + ExtensionService* service = profile()->GetExtensionService(); DCHECK(service); const Extension* extension = service->GetExtensionById(extension_id(), false); DCHECK(extension); @@ -493,6 +496,7 @@ void ExtensionFunctionDispatcher::HandleBadMessage(ExtensionFunction* api) { CHECK(false); } else { NOTREACHED(); + UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD")); base::KillProcess(render_view_host_->process()->GetHandle(), ResultCodes::KILLED_BAD_MESSAGE, false); } diff --git a/chrome/browser/extensions/extension_history_api.cc b/chrome/browser/extensions/extension_history_api.cc index 6c07488..5ff98e3 100644 --- a/chrome/browser/extensions/extension_history_api.cc +++ b/chrome/browser/extensions/extension_history_api.cc @@ -14,7 +14,7 @@ #include "chrome/browser/extensions/extension_history_api_constants.h" #include "chrome/browser/history/history.h" #include "chrome/browser/history/history_types.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/notification_type.h" #include "chrome/common/notification_service.h" diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index 4aea841..1d60390 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -21,12 +21,11 @@ #include "chrome/browser/dom_ui/dom_ui_factory.h" #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/file_select_helper.h" -#include "chrome/browser/message_box_handler.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_widget_host.h" @@ -37,6 +36,7 @@ #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" #include "chrome/browser/themes/browser_theme_provider.h" +#include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/bindings_policy.h" #include "chrome/common/extensions/extension.h" @@ -66,7 +66,7 @@ bool ExtensionHost::enable_dom_automation_ = false; // ExtensionHosts, to avoid blocking the UI. class ExtensionHost::ProcessCreationQueue { public: - static ProcessCreationQueue* get() { + static ProcessCreationQueue* GetInstance() { return Singleton<ProcessCreationQueue>::get(); } @@ -155,7 +155,7 @@ ExtensionHost::~ExtensionHost() { NotificationType::EXTENSION_HOST_DESTROYED, Source<Profile>(profile_), Details<ExtensionHost>(this)); - ProcessCreationQueue::get()->Remove(this); + ProcessCreationQueue::GetInstance()->Remove(this); render_view_host_->Shutdown(); // deletes render_view_host } @@ -177,6 +177,10 @@ void ExtensionHost::CreateView(Browser* browser) { #endif } +TabContents* ExtensionHost::associated_tab_contents() const { + return associated_tab_contents_; +} + RenderProcessHost* ExtensionHost::render_process_host() const { return render_view_host_->process(); } @@ -197,7 +201,7 @@ void ExtensionHost::CreateRenderViewSoon(RenderWidgetHostView* host_view) { // to defer. CreateRenderViewNow(); } else { - ProcessCreationQueue::get()->CreateSoon(this); + ProcessCreationQueue::GetInstance()->CreateSoon(this); } } @@ -206,7 +210,7 @@ void ExtensionHost::CreateRenderViewNow() { NavigateToURL(url_); DCHECK(IsRenderViewLive()); if (is_background_page()) - profile_->GetExtensionsService()->DidCreateRenderViewForBackgroundPage( + profile_->GetExtensionService()->DidCreateRenderViewForBackgroundPage( this); } @@ -231,7 +235,7 @@ void ExtensionHost::NavigateToURL(const GURL& url) { url_ = url; if (!is_background_page() && - !profile_->GetExtensionsService()->IsBackgroundPageReady(extension_)) { + !profile_->GetExtensionService()->IsBackgroundPageReady(extension_)) { // Make sure the background page loads before any others. registrar_.Add(this, NotificationType::EXTENSION_BACKGROUND_PAGE_READY, Source<Extension>(extension_)); @@ -246,7 +250,7 @@ void ExtensionHost::Observe(NotificationType type, const NotificationDetails& details) { switch (type.value) { case NotificationType::EXTENSION_BACKGROUND_PAGE_READY: - DCHECK(profile_->GetExtensionsService()-> + DCHECK(profile_->GetExtensionService()-> IsBackgroundPageReady(extension_)); NavigateToURL(url_); break; @@ -261,7 +265,7 @@ void ExtensionHost::Observe(NotificationType type, // sent. NULL it out so that dirty pointer issues don't arise in cases // when multiple ExtensionHost objects pointing to the same Extension are // present. - if (extension_ == Details<const Extension>(details).ptr()) + if (extension_ == Details<UnloadedExtensionInfo>(details)->extension) extension_ = NULL; break; default: @@ -284,7 +288,9 @@ void ExtensionHost::ClearInspectorSettings() { RenderViewHostDelegateHelper::ClearInspectorSettings(profile()); } -void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host) { +void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host, + base::TerminationStatus status, + int error_code) { // During browser shutdown, we may use sudden termination on an extension // process, so it is expected to lose our connection to the render view. // Do nothing. @@ -391,7 +397,7 @@ void ExtensionHost::DocumentAvailableInMainFrame(RenderViewHost* rvh) { document_element_available_ = true; if (is_background_page()) { - profile_->GetExtensionsService()->SetBackgroundPageReady(extension_); + profile_->GetExtensionService()->SetBackgroundPageReady(extension_); } else { switch (extension_host_type_) { case ViewType::EXTENSION_INFOBAR: @@ -444,6 +450,14 @@ gfx::NativeWindow ExtensionHost::GetMessageBoxRootWindow() { return NULL; } +TabContents* ExtensionHost::AsTabContents() { + return NULL; +} + +ExtensionHost* ExtensionHost::AsExtensionHost() { + return this; +} + void ExtensionHost::OnMessageBoxClosed(IPC::Message* reply_msg, bool success, const std::wstring& prompt) { @@ -487,6 +501,14 @@ WebPreferences ExtensionHost::GetWebkitPrefs() { extension_host_type_ == ViewType::EXTENSION_INFOBAR) webkit_prefs.allow_scripts_to_close_windows = true; + // Disable anything that requires the GPU process for background pages. + // See http://crbug.com/64512 and http://crbug.com/64841. + if (extension_host_type_ == ViewType::EXTENSION_BACKGROUND_PAGE) { + webkit_prefs.experimental_webgl_enabled = false; + webkit_prefs.accelerated_compositing_enabled = false; + webkit_prefs.accelerated_2d_canvas_enabled = false; + } + // TODO(dcheng): incorporate this setting into kClipboardPermission check. webkit_prefs.javascript_can_access_clipboard = true; @@ -734,6 +756,10 @@ ViewType::Type ExtensionHost::GetRenderViewType() const { return extension_host_type_; } +const GURL& ExtensionHost::GetURL() const { + return url_; +} + void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) { if (view_.get()) view_->RenderViewCreated(); diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index d121145..801bdab 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -12,13 +12,13 @@ #include "base/perftimer.h" #include "base/scoped_ptr.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" -#include "chrome/browser/js_modal_dialog.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" #include "chrome/browser/tab_contents/render_view_host_delegate_helper.h" +#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h" #if defined(TOOLKIT_VIEWS) #include "chrome/browser/views/extensions/extension_view.h" #elif defined(OS_MACOSX) -#include "chrome/browser/cocoa/extension_view_mac.h" +#include "chrome/browser/ui/cocoa/extension_view_mac.h" #elif defined(TOOLKIT_GTK) #include "chrome/browser/gtk/extension_view_gtk.h" #endif @@ -83,9 +83,7 @@ class ExtensionHost : public RenderViewHostDelegate, ViewType::Type extension_host_type() const { return extension_host_type_; } // ExtensionFunctionDispatcher::Delegate - virtual TabContents* associated_tab_contents() const { - return associated_tab_contents_; - } + virtual TabContents* associated_tab_contents() const; void set_associated_tab_contents(TabContents* associated_tab_contents) { associated_tab_contents_ = associated_tab_contents; } @@ -109,12 +107,14 @@ class ExtensionHost : public RenderViewHostDelegate, void DisableScrollbarsForSmallWindows(const gfx::Size& size_limit); // RenderViewHostDelegate::View implementation. - virtual const GURL& GetURL() const { return url_; } + virtual const GURL& GetURL() const; virtual void RenderViewCreated(RenderViewHost* render_view_host); virtual ViewType::Type GetRenderViewType() const; virtual FileSelect* GetFileSelectDelegate(); virtual int GetBrowserWindowID() const; - virtual void RenderViewGone(RenderViewHost* render_view_host); + virtual void RenderViewGone(RenderViewHost* render_view_host, + base::TerminationStatus status, + int error_code); virtual void DidNavigate(RenderViewHost* render_view_host, const ViewHostMsg_FrameNavigate_Params& params); virtual void DidStopLoading(); @@ -192,8 +192,8 @@ class ExtensionHost : public RenderViewHostDelegate, const std::wstring& prompt); virtual void SetSuppressMessageBoxes(bool suppress_message_boxes) {} virtual gfx::NativeWindow GetMessageBoxRootWindow(); - virtual TabContents* AsTabContents() { return NULL; } - virtual ExtensionHost* AsExtensionHost() { return this; } + virtual TabContents* AsTabContents(); + virtual ExtensionHost* AsExtensionHost(); protected: // Internal functions used to support the CreateNewWidget() method. If a diff --git a/chrome/browser/extensions/extension_host_mac.mm b/chrome/browser/extensions/extension_host_mac.mm index d6de067..67bc851 100644 --- a/chrome/browser/extensions/extension_host_mac.mm +++ b/chrome/browser/extensions/extension_host_mac.mm @@ -4,10 +4,10 @@ #include "chrome/browser/extensions/extension_host_mac.h" -#import "chrome/browser/cocoa/chrome_event_processing_window.h" -#import "chrome/browser/cocoa/extensions/extension_popup_controller.h" -#import "chrome/browser/cocoa/info_bubble_window.h" #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" +#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h" +#import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h" +#import "chrome/browser/ui/cocoa/info_bubble_window.h" #include "chrome/common/native_web_keyboard_event.h" ExtensionHostMac::~ExtensionHostMac() { diff --git a/chrome/browser/extensions/extension_i18n_api.cc b/chrome/browser/extensions/extension_i18n_api.cc index 40964a7..def4380 100644 --- a/chrome/browser/extensions/extension_i18n_api.cc +++ b/chrome/browser/extensions/extension_i18n_api.cc @@ -7,7 +7,7 @@ #include "base/string_piece.h" #include "base/utf_string_conversions.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" // Errors. diff --git a/chrome/browser/extensions/extension_idle_api.cc b/chrome/browser/extensions/extension_idle_api.cc index 76144a4..b43e6c8 100644 --- a/chrome/browser/extensions/extension_idle_api.cc +++ b/chrome/browser/extensions/extension_idle_api.cc @@ -17,11 +17,11 @@ #include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_idle_api_constants.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/extensions/extension.h" -#include "chrome/common/notification_service.h" namespace keys = extension_idle_api_constants; diff --git a/chrome/browser/extensions/extension_idle_api.h b/chrome/browser/extensions/extension_idle_api.h index d6e0c89..9f40481 100644 --- a/chrome/browser/extensions/extension_idle_api.h +++ b/chrome/browser/extensions/extension_idle_api.h @@ -7,9 +7,10 @@ #pragma once #include "chrome/browser/idle.h" -#include "chrome/browser/profile.h" #include "chrome/browser/extensions/extension_function.h" +class Profile; + // Event router class for events related to the idle API. class ExtensionIdleEventRouter { public: diff --git a/chrome/browser/extensions/extension_incognito_apitest.cc b/chrome/browser/extensions/extension_incognito_apitest.cc index 52ee7c3..315ac99 100644 --- a/chrome/browser/extensions/extension_incognito_apitest.cc +++ b/chrome/browser/extensions/extension_incognito_apitest.cc @@ -6,10 +6,10 @@ #include "chrome/browser/browser_window.h" #include "chrome/browser/extensions/browser_action_test_util.h" #include "chrome/browser/extensions/extension_apitest.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_test_message_listener.h" #include "chrome/browser/extensions/user_script_master.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_switches.h" @@ -86,8 +86,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoYesScript) { // accidentially create and incognito profile. IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DontCreateIncognitoProfile) { ASSERT_FALSE(browser()->profile()->HasOffTheRecordProfile()); - ASSERT_TRUE( - RunExtensionTestIncognito("incognito/enumerate_tabs")) << message_; + ASSERT_TRUE(RunExtensionTestIncognito( + "incognito/dont_create_profile")) << message_; ASSERT_FALSE(browser()->profile()->HasOffTheRecordProfile()); } diff --git a/chrome/browser/extensions/extension_infobar_apitest.cc b/chrome/browser/extensions/extension_infobar_apitest.cc index 5932185..0ca70c8 100644 --- a/chrome/browser/extensions/extension_infobar_apitest.cc +++ b/chrome/browser/extensions/extension_infobar_apitest.cc @@ -6,7 +6,7 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/common/chrome_switches.h" -#if defined(TOOLKIT_VIEWS) +#if defined(OS_WIN) #define MAYBE_Infobars Infobars #else // Need to finish port to Linux. See http://crbug.com/39916 for details. diff --git a/chrome/browser/extensions/extension_infobar_delegate.cc b/chrome/browser/extensions/extension_infobar_delegate.cc index 3f9b861..140a82f 100644 --- a/chrome/browser/extensions/extension_infobar_delegate.cc +++ b/chrome/browser/extensions/extension_infobar_delegate.cc @@ -6,9 +6,10 @@ #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_process_manager.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" +#include "chrome/common/extensions/extension.h" #include "chrome/common/notification_details.h" #include "chrome/common/notification_source.h" #include "chrome/common/notification_type.h" @@ -38,6 +39,10 @@ ExtensionInfoBarDelegate::~ExtensionInfoBarDelegate() { observer_->OnDelegateDeleted(); } +void ExtensionInfoBarDelegate::InfoBarDismissed() { + closing_ = true; +} + bool ExtensionInfoBarDelegate::EqualsDelegate(InfoBarDelegate* delegate) const { ExtensionInfoBarDelegate* extension_delegate = delegate->AsExtensionInfoBarDelegate(); @@ -78,7 +83,8 @@ void ExtensionInfoBarDelegate::Observe(NotificationType type, break; } case NotificationType::EXTENSION_UNLOADED: { - const Extension* extension = Details<const Extension>(details).ptr(); + const Extension* extension = + Details<UnloadedExtensionInfo>(details)->extension; if (extension_ == extension) tab_contents_->RemoveInfoBar(this); break; diff --git a/chrome/browser/extensions/extension_infobar_delegate.h b/chrome/browser/extensions/extension_infobar_delegate.h index e929fee..f286a11 100644 --- a/chrome/browser/extensions/extension_infobar_delegate.h +++ b/chrome/browser/extensions/extension_infobar_delegate.h @@ -37,7 +37,7 @@ class ExtensionInfoBarDelegate : public InfoBarDelegate, void set_observer(DelegateObserver* observer) { observer_ = observer; } // Overridden from InfoBarDelegate: - virtual void InfoBarDismissed() { closing_ = true; } + virtual void InfoBarDismissed(); virtual bool EqualsDelegate(InfoBarDelegate* delegate) const; virtual void InfoBarClosed(); virtual InfoBar* CreateInfoBar(); diff --git a/chrome/browser/extensions/extension_infobar_module.cc b/chrome/browser/extensions/extension_infobar_module.cc index 21d94ae..707630c 100644 --- a/chrome/browser/extensions/extension_infobar_module.cc +++ b/chrome/browser/extensions/extension_infobar_module.cc @@ -14,8 +14,8 @@ #include "chrome/browser/extensions/extension_tabs_module_constants.h" #include "chrome/browser/tab_contents/infobar_delegate.h" #include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents_wrapper.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_error_utils.h" #include "chrome/common/url_constants.h" diff --git a/chrome/browser/extensions/extension_input_api.cc b/chrome/browser/extensions/extension_input_api.cc index 850a344..cc5cb43 100644 --- a/chrome/browser/extensions/extension_input_api.cc +++ b/chrome/browser/extensions/extension_input_api.cc @@ -11,7 +11,6 @@ #include "chrome/browser/browser_window.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/renderer_host/render_view_host.h" -#include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/views/frame/browser_view.h" #include "chrome/common/native_web_keyboard_event.h" diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc index aca3de6..391a54c 100644 --- a/chrome/browser/extensions/extension_install_ui.cc +++ b/chrome/browser/extensions/extension_install_ui.cc @@ -10,6 +10,7 @@ #include "app/resource_bundle.h" #include "base/command_line.h" #include "base/file_util.h" +#include "base/i18n/rtl.h" #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" @@ -17,7 +18,7 @@ #include "chrome/browser/browser_window.h" #include "chrome/browser/extensions/theme_installed_infobar_delegate.h" #include "chrome/browser/platform_util.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/common/chrome_switches.h" @@ -33,7 +34,7 @@ #include "grit/theme_resources.h" #if defined(OS_MACOSX) -#include "chrome/browser/cocoa/extension_installed_bubble_bridge.h" +#include "chrome/browser/ui/cocoa/extension_installed_bubble_bridge.h" #endif #if defined(TOOLKIT_VIEWS) @@ -76,22 +77,7 @@ ExtensionInstallUI::ExtensionInstallUI(Profile* profile) extension_(NULL), delegate_(NULL), prompt_type_(NUM_PROMPT_TYPES), - ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) { - // Remember the current theme in case the user presses undo. - if (profile_) { - const Extension* previous_theme = profile_->GetTheme(); - if (previous_theme) - previous_theme_id_ = previous_theme->id(); -#if defined(TOOLKIT_GTK) - // On Linux, we also need to take the user's system settings into account - // to undo theme installation. - previous_use_system_theme_ = - GtkThemeProvider::GetFrom(profile_)->UseGtkTheme(); -#else - DCHECK(!previous_use_system_theme_); -#endif - } -} + ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {} ExtensionInstallUI::~ExtensionInstallUI() { } @@ -106,6 +92,20 @@ void ExtensionInstallUI::ConfirmInstall(Delegate* delegate, // immediately installed, and then we show an infobar (see OnInstallSuccess) // to allow the user to revert if they don't like it. if (extension->is_theme()) { + // Remember the current theme in case the user pressed undo. + const Extension* previous_theme = profile_->GetTheme(); + if (previous_theme) + previous_theme_id_ = previous_theme->id(); + +#if defined(TOOLKIT_GTK) + // On Linux, we also need to take the user's system settings into account + // to undo theme installation. + previous_use_system_theme_ = + GtkThemeProvider::GetFrom(profile_)->UseGtkTheme(); +#else + DCHECK(!previous_use_system_theme_); +#endif + delegate->InstallUIProceed(); return; } @@ -296,9 +296,11 @@ void ExtensionInstallUI::ShowGenericExtensionInstalledInfoBar( if (!tab_contents) return; + string16 extension_name = UTF8ToUTF16(new_extension->name()); + base::i18n::AdjustStringForLocaleDirection(&extension_name); string16 msg = l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALLED_HEADING, - UTF8ToUTF16(new_extension->name())) + + extension_name) + UTF8ToUTF16(" ") + l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_INFO_MAC); InfoBarDelegate* delegate = new SimpleAlertInfoBarDelegate( diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc index 818c414..6866325 100644 --- a/chrome/browser/extensions/extension_install_ui_browsertest.cc +++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc @@ -3,9 +3,9 @@ // found in the LICENSE file. #include "chrome/browser/extensions/extension_browsertest.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/theme_installed_infobar_delegate.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/ui_test_utils.h" diff --git a/chrome/browser/extensions/extension_management_api.cc b/chrome/browser/extensions/extension_management_api.cc index bcb12c6..50117c4 100644 --- a/chrome/browser/extensions/extension_management_api.cc +++ b/chrome/browser/extensions/extension_management_api.cc @@ -13,9 +13,9 @@ #include "base/string_util.h" #include "chrome/browser/extensions/extension_event_names.h" #include "chrome/browser/extensions/extension_event_router.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_updater.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_error_utils.h" @@ -47,8 +47,8 @@ const char kNoExtensionError[] = "No extension with id *"; const char kNotAnAppError[] = "Extension * is not an App"; } -ExtensionsService* ExtensionManagementFunction::service() { - return profile()->GetExtensionsService(); +ExtensionService* ExtensionManagementFunction::service() { + return profile()->GetExtensionService(); } static DictionaryValue* CreateExtensionInfo(const Extension& extension, @@ -267,9 +267,14 @@ void ExtensionManagementEventRouter::Observe( Details<UninstalledExtensionInfo>(details).ptr()->extension_id; args.Append(Value::CreateStringValue(extension_id)); } else { - const Extension* extension = Details<const Extension>(details).ptr(); + const Extension* extension = NULL; + if (event_name == events::kOnExtensionDisabled) { + extension = Details<UnloadedExtensionInfo>(details)->extension; + } else { + extension = Details<const Extension>(details).ptr(); + } CHECK(extension); - ExtensionsService* service = profile->GetExtensionsService(); + ExtensionService* service = profile->GetExtensionService(); bool enabled = service->GetExtensionById(extension->id(), false) != NULL; args.Append(CreateExtensionInfo(*extension, enabled)); } diff --git a/chrome/browser/extensions/extension_management_api.h b/chrome/browser/extensions/extension_management_api.h index 864741f..5349955 100644 --- a/chrome/browser/extensions/extension_management_api.h +++ b/chrome/browser/extensions/extension_management_api.h @@ -11,11 +11,11 @@ #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" -class ExtensionsService; +class ExtensionService; class ExtensionManagementFunction : public SyncExtensionFunction { protected: - ExtensionsService* service(); + ExtensionService* service(); }; class GetAllExtensionsFunction : public ExtensionManagementFunction { diff --git a/chrome/browser/extensions/extension_management_apitest.cc b/chrome/browser/extensions/extension_management_apitest.cc index bdbb057..9883f5d 100644 --- a/chrome/browser/extensions/extension_management_apitest.cc +++ b/chrome/browser/extensions/extension_management_apitest.cc @@ -3,8 +3,8 @@ // found in the LICENSE file. #include "chrome/browser/extensions/extension_apitest.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" class ExtensionManagementApiTest : public ExtensionApiTest { @@ -19,7 +19,7 @@ class ExtensionManagementApiTest : public ExtensionApiTest { ASSERT_TRUE(LoadExtension(basedir.AppendASCII("permissions"))); // Load 2 disabled items. - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); ASSERT_TRUE(LoadExtension(basedir.AppendASCII("disabled_extension"))); service->DisableExtension(last_loaded_extension_id_); ASSERT_TRUE(LoadExtension(basedir.AppendASCII("disabled_app"))); diff --git a/chrome/browser/extensions/extension_management_browsertest.cc b/chrome/browser/extensions/extension_management_browsertest.cc index 6120c73..a1eb2f6 100644 --- a/chrome/browser/extensions/extension_management_browsertest.cc +++ b/chrome/browser/extensions/extension_management_browsertest.cc @@ -6,11 +6,12 @@ #include "chrome/browser/extensions/autoupdate_interceptor.h" #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_host.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_test_message_listener.h" #include "chrome/browser/extensions/extension_updater.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/prefs/scoped_pref_update.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/pref_names.h" @@ -56,7 +57,7 @@ class ExtensionManagementTest : public ExtensionBrowserTest { // to the second version requiring increased permissions. Returns whether // the operation was completed successfully. bool InstallAndUpdateIncreasingPermissionsExtension() { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); size_t size_before = service->extensions()->size(); // Install the initial version, which should happen just fine. @@ -81,7 +82,7 @@ class ExtensionManagementTest : public ExtensionBrowserTest { // Tests that installing the same version overwrites. IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallSameVersion) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const size_t size_before = service->extensions()->size(); ASSERT_TRUE(InstallExtension( test_data_dir_.AppendASCII("install/install.crx"), 1)); @@ -99,7 +100,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallSameVersion) { } IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallOlderVersion) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const size_t size_before = service->extensions()->size(); ASSERT_TRUE(InstallExtension( test_data_dir_.AppendASCII("install/install.crx"), 1)); @@ -110,7 +111,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallOlderVersion) { } IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallThenCancel) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const size_t size_before = service->extensions()->size(); ASSERT_TRUE(InstallExtension( test_data_dir_.AppendASCII("install/install.crx"), 1)); @@ -137,7 +138,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, Incognito) { // Tests the process of updating an extension to one that requires higher // permissions. IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UpdatePermissions) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension()); const size_t size_before = service->extensions()->size(); @@ -149,7 +150,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UpdatePermissions) { // Tests that we can uninstall a disabled extension. IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UninstallDisabled) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension()); const size_t size_before = service->extensions()->size(); @@ -163,7 +164,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UninstallDisabled) { IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, DisableEnable) { ExtensionProcessManager* manager = browser()->profile()-> GetExtensionProcessManager(); - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const size_t size_before = service->extensions()->size(); // Load an extension, expect the background page to be available. @@ -206,7 +207,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) { // Install version 1 of the extension. ExtensionTestMessageListener listener1("v1 installed", false); - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const size_t size_before = service->extensions()->size(); ASSERT_TRUE(service->disabled_extensions()->empty()); ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v1.crx"), 1)); @@ -252,7 +253,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) { // See http://crbug.com/57378 for flakiness details. IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const char* kExtensionId = "ogjcoiohnmldgjemafoockdghcjciccf"; // We don't want autoupdate blacklist checks. service->updater()->set_blacklist_checks_enabled(false); @@ -272,7 +273,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) { ASSERT_TRUE(service->disabled_extensions()->empty()); // The code that reads external_extensions.json uses this method to inform - // the ExtensionsService of an extension to download. Using the real code + // the ExtensionService of an extension to download. Using the real code // is race-prone, because instantating the ExtensionService starts a read // of external_extensions.json before this test function starts. service->AddPendingExtensionFromExternalUpdateUrl( @@ -292,31 +293,39 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) { UninstallExtension(kExtensionId); - std::set<std::string> killed_ids; - service->extension_prefs()->GetKilledExtensionIds(&killed_ids); - EXPECT_TRUE(killed_ids.end() != killed_ids.find(kExtensionId)) + ExtensionPrefs* extension_prefs = service->extension_prefs(); + EXPECT_TRUE(extension_prefs->IsExtensionKilled(kExtensionId)) << "Uninstalling should set kill bit on externaly installed extension."; + // Try to install the extension again from an external source. It should fail + // because of the killbit. + service->AddPendingExtensionFromExternalUpdateUrl( + kExtensionId, GURL("http://localhost/autoupdate/manifest"), + Extension::EXTERNAL_PREF_DOWNLOAD); + const PendingExtensionMap& pending_extensions = + service->pending_extensions(); + EXPECT_TRUE( + pending_extensions.find(kExtensionId) == pending_extensions.end()) + << "External reinstall of a killed extension shouldn't work."; + EXPECT_TRUE(extension_prefs->IsExtensionKilled(kExtensionId)) + << "External reinstall of a killed extension should leave it killed."; + // Installing from non-external source. ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v2.crx"), 1)); - killed_ids.clear(); - service->extension_prefs()->GetKilledExtensionIds(&killed_ids); - EXPECT_TRUE(killed_ids.end() == killed_ids.find(kExtensionId)) + EXPECT_FALSE(extension_prefs->IsExtensionKilled(kExtensionId)) << "Reinstalling should clear the kill bit."; // Uninstalling from a non-external source should not set the kill bit. UninstallExtension(kExtensionId); - killed_ids.clear(); - service->extension_prefs()->GetKilledExtensionIds(&killed_ids); - EXPECT_TRUE(killed_ids.end() == killed_ids.find(kExtensionId)) + EXPECT_FALSE(extension_prefs->IsExtensionKilled(kExtensionId)) << "Uninstalling non-external extension should not set kill bit."; } // See http://crbug.com/57378 for flakiness details. IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); const char* kExtensionId = "ogjcoiohnmldgjemafoockdghcjciccf"; // We don't want autoupdate blacklist checks. service->updater()->set_blacklist_checks_enabled(false); @@ -335,15 +344,17 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) { const size_t size_before = service->extensions()->size(); ASSERT_TRUE(service->disabled_extensions()->empty()); - // Set the policy as a user preference and fire notification observers. PrefService* prefs = browser()->profile()->GetPrefs(); - ListValue* forcelist = - prefs->GetMutableList(prefs::kExtensionInstallForceList); - ASSERT_TRUE(forcelist->empty()); - forcelist->Append(Value::CreateStringValue( - "ogjcoiohnmldgjemafoockdghcjciccf;" - "http://localhost/autoupdate/manifest")); - prefs->pref_notifier()->FireObservers(prefs::kExtensionInstallForceList); + { + // Set the policy as a user preference and fire notification observers. + ScopedPrefUpdate pref_update(prefs, prefs::kExtensionInstallForceList); + ListValue* forcelist = + prefs->GetMutableList(prefs::kExtensionInstallForceList); + ASSERT_TRUE(forcelist->empty()); + forcelist->Append(Value::CreateStringValue( + "ogjcoiohnmldgjemafoockdghcjciccf;" + "http://localhost/autoupdate/manifest")); + } // Check if the extension got installed. ASSERT_TRUE(WaitForExtensionInstall()); @@ -356,5 +367,4 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) { // Check that emptying the list doesn't cause any trouble. prefs->ClearPref(prefs::kExtensionInstallForceList); - prefs->pref_notifier()->FireObservers(prefs::kExtensionInstallForceList); } diff --git a/chrome/browser/extensions/extension_menu_manager.cc b/chrome/browser/extensions/extension_menu_manager.cc index eae74f6..0d3c891 100644 --- a/chrome/browser/extensions/extension_menu_manager.cc +++ b/chrome/browser/extensions/extension_menu_manager.cc @@ -15,8 +15,9 @@ #include "base/json/json_writer.h" #include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/extension.h" +#include "chrome/common/notification_service.h" #include "gfx/favicon_size.h" #include "webkit/glue/context_menu.h" @@ -73,10 +74,8 @@ string16 ExtensionMenuItem::TitleWithReplacement( // put "%s" in titles that won't get substituted. ReplaceSubstringsAfterOffset(&result, 0, ASCIIToUTF16("%s"), selection); - if (result.length() > max_length) { - result = WideToUTF16(l10n_util::TruncateString(UTF16ToWideHack(result), - max_length)); - } + if (result.length() > max_length) + result = l10n_util::TruncateString(result, max_length); return result; } @@ -412,8 +411,7 @@ void ExtensionMenuManager::ExecuteCommand( AddURLProperty(properties, "frameUrl", params.frame_url); if (params.selection_text.length() > 0) - properties->SetString("selectionText", - WideToUTF16Hack(params.selection_text)); + properties->SetString("selectionText", params.selection_text); properties->SetBoolean("editable", params.is_editable); @@ -455,7 +453,8 @@ void ExtensionMenuManager::Observe(NotificationType type, NOTREACHED(); return; } - const Extension* extension = Details<const Extension>(details).ptr(); + const Extension* extension = + Details<UnloadedExtensionInfo>(details)->extension; if (ContainsKey(context_items_, extension->id())) { RemoveAllContextItems(extension->id()); } diff --git a/chrome/browser/extensions/extension_menu_manager_unittest.cc b/chrome/browser/extensions/extension_menu_manager_unittest.cc index cbd9a52..ca844cc 100644 --- a/chrome/browser/extensions/extension_menu_manager_unittest.cc +++ b/chrome/browser/extensions/extension_menu_manager_unittest.cc @@ -8,6 +8,7 @@ #include "base/path_service.h" #include "base/scoped_temp_dir.h" #include "base/scoped_vector.h" +#include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/browser_thread.h" #include "chrome/browser/extensions/extension_event_router.h" @@ -321,9 +322,10 @@ TEST_F(ExtensionMenuManagerTest, ExtensionUnloadRemovesMenuItems) { // Notify that the extension was unloaded, and make sure the right item is // gone. + UnloadedExtensionInfo details(extension1, UnloadedExtensionInfo::DISABLE); notifier->Notify(NotificationType::EXTENSION_UNLOADED, Source<Profile>(NULL), - Details<const Extension>(extension1)); + Details<UnloadedExtensionInfo>(&details)); ASSERT_EQ(NULL, manager_.MenuItems(extension1->id())); ASSERT_EQ(1u, manager_.MenuItems(extension2->id())->size()); ASSERT_TRUE(manager_.GetItemById(id1) == NULL); @@ -419,7 +421,7 @@ TEST_F(ExtensionMenuManagerTest, ExecuteCommand) { params.media_type = WebKit::WebContextMenuData::MediaTypeImage; params.src_url = GURL("http://foo.bar/image.png"); params.page_url = GURL("http://foo.bar"); - params.selection_text = L"Hello World"; + params.selection_text = ASCIIToUTF16("Hello World"); params.is_editable = false; Extension* extension = AddExtension("test"); @@ -471,8 +473,9 @@ TEST_F(ExtensionMenuManagerTest, ExecuteCommand) { ASSERT_TRUE(info->GetString("pageUrl", &tmp)); ASSERT_EQ(params.page_url.spec(), tmp); - ASSERT_TRUE(info->GetString("selectionText", &tmp)); - ASSERT_EQ(WideToUTF8(params.selection_text), tmp); + string16 tmp16; + ASSERT_TRUE(info->GetString("selectionText", &tmp16)); + ASSERT_EQ(params.selection_text, tmp16); bool bool_tmp = true; ASSERT_TRUE(info->GetBoolean("editable", &bool_tmp)); diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc index 67c6e71..c72c9d8 100644 --- a/chrome/browser/extensions/extension_message_service.cc +++ b/chrome/browser/extensions/extension_message_service.cc @@ -11,12 +11,12 @@ #include "chrome/browser/child_process_security_policy.h" #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_util.h" -#include "chrome/browser/tab_contents_wrapper.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/notification_service.h" #include "chrome/common/render_messages.h" diff --git a/chrome/browser/extensions/extension_message_service.h b/chrome/browser/extensions/extension_message_service.h index 9135a1c..30c771d 100644 --- a/chrome/browser/extensions/extension_message_service.h +++ b/chrome/browser/extensions/extension_message_service.h @@ -134,9 +134,9 @@ class ExtensionMessageService bool notify_other_port); // NotificationObserver interface. - void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); // An IPC sender that might be in our list of channels has closed. void OnSenderClosed(IPC::Message::Sender* sender); diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc index 760a627..24291a5 100644 --- a/chrome/browser/extensions/extension_messages_apitest.cc +++ b/chrome/browser/extensions/extension_messages_apitest.cc @@ -4,8 +4,9 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_event_router.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_service.h" #include "googleurl/src/gurl.h" namespace { diff --git a/chrome/browser/extensions/extension_metrics_apitest.cc b/chrome/browser/extensions/extension_metrics_apitest.cc index c9464d2..81875b6 100644 --- a/chrome/browser/extensions/extension_metrics_apitest.cc +++ b/chrome/browser/extensions/extension_metrics_apitest.cc @@ -5,11 +5,11 @@ #include <map> #include "base/metrics/histogram.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_service.h" namespace { diff --git a/chrome/browser/extensions/extension_module.cc b/chrome/browser/extensions/extension_module.cc index 84c3789..1ef27a9 100644 --- a/chrome/browser/extensions/extension_module.cc +++ b/chrome/browser/extensions/extension_module.cc @@ -7,11 +7,11 @@ #include <string> #include "chrome/browser/extensions/extension_prefs.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" ExtensionPrefs* SetUpdateUrlDataFunction::extension_prefs() { - return profile()->GetExtensionsService()->extension_prefs(); + return profile()->GetExtensionService()->extension_prefs(); } bool SetUpdateUrlDataFunction::RunImpl() { diff --git a/chrome/browser/extensions/extension_omnibox_api.cc b/chrome/browser/extensions/extension_omnibox_api.cc index 605374b..4981c98 100644 --- a/chrome/browser/extensions/extension_omnibox_api.cc +++ b/chrome/browser/extensions/extension_omnibox_api.cc @@ -5,13 +5,13 @@ #include "chrome/browser/extensions/extension_omnibox_api.h" #include "base/json/json_writer.h" -#include "base/singleton.h" +#include "base/lazy_instance.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/extensions/extension_event_router.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/common/notification_service.h" @@ -36,8 +36,11 @@ const char kDescriptionStylesType[] = "type"; const char kDescriptionStylesOffset[] = "offset"; const char kDescriptionStylesLength[] = "length"; +static base::LazyInstance<PropertyAccessor<ExtensionOmniboxSuggestion> > + g_extension_omnibox_suggestion_property_accessor(base::LINKER_INITIALIZED); + PropertyAccessor<ExtensionOmniboxSuggestion>& GetPropertyAccessor() { - return *Singleton< PropertyAccessor<ExtensionOmniboxSuggestion> >::get(); + return g_extension_omnibox_suggestion_property_accessor.Get(); } // Returns the suggestion object set by the extension via the @@ -45,11 +48,11 @@ PropertyAccessor<ExtensionOmniboxSuggestion>& GetPropertyAccessor() { const ExtensionOmniboxSuggestion* GetDefaultSuggestionForExtension( Profile* profile, const std::string& extension_id) { const Extension* extension = - profile->GetExtensionsService()->GetExtensionById(extension_id, false); + profile->GetExtensionService()->GetExtensionById(extension_id, false); if (!extension) return NULL; return GetPropertyAccessor().GetProperty( - profile->GetExtensionsService()->GetPropertyBag(extension)); + profile->GetExtensionService()->GetPropertyBag(extension)); } }; // namespace @@ -161,7 +164,7 @@ bool OmniboxSetDefaultSuggestionFunction::RunImpl() { // Store the suggestion in the extension's runtime data. GetPropertyAccessor().SetProperty( - profile_->GetExtensionsService()->GetPropertyBag(GetExtension()), + profile_->GetExtensionService()->GetPropertyBag(GetExtension()), suggestion); NotificationService::current()->Notify( diff --git a/chrome/browser/extensions/extension_omnibox_apitest.cc b/chrome/browser/extensions/extension_omnibox_apitest.cc index 854662d..0eba9be 100644 --- a/chrome/browser/extensions/extension_omnibox_apitest.cc +++ b/chrome/browser/extensions/extension_omnibox_apitest.cc @@ -12,11 +12,11 @@ #include "chrome/browser/autocomplete/autocomplete_popup_model.h" #include "chrome/browser/browser_window.h" #include "chrome/browser/extensions/extension_apitest.h" -#include "chrome/browser/location_bar.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/omnibox/location_bar.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/notification_type.h" #include "chrome/common/url_constants.h" diff --git a/chrome/browser/extensions/extension_override_apitest.cc b/chrome/browser/extensions/extension_override_apitest.cc index 3f0c801..4fd73f4 100644 --- a/chrome/browser/extensions/extension_override_apitest.cc +++ b/chrome/browser/extensions/extension_override_apitest.cc @@ -5,9 +5,9 @@ #include "chrome/browser/browser_list.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_dom_ui.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/url_constants.h" @@ -115,7 +115,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, ShouldNotCreateDuplicateEntries) { for (size_t i = 0; i < 3; ++i) { ExtensionDOMUI::RegisterChromeURLOverrides( browser()->profile(), - browser()->profile()->GetExtensionsService()->extensions()->back()-> + browser()->profile()->GetExtensionService()->extensions()->back()-> GetChromeURLOverrides()); } @@ -161,7 +161,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, OverrideKeyboard) { // Unload the failing version. We should be back to passing now. const ExtensionList *extensions = - browser()->profile()->GetExtensionsService()->extensions(); + browser()->profile()->GetExtensionService()->extensions(); UnloadExtension((*extensions->rbegin())->id()); { ResultCatcher catcher; diff --git a/chrome/browser/extensions/extension_page_actions_module.cc b/chrome/browser/extensions/extension_page_actions_module.cc index c9dc2a3..0e26d60 100644 --- a/chrome/browser/extensions/extension_page_actions_module.cc +++ b/chrome/browser/extensions/extension_page_actions_module.cc @@ -8,12 +8,12 @@ #include "chrome/browser/browser_list.h" #include "chrome/browser/extensions/extension_page_actions_module_constants.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents_wrapper.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_action.h" #include "chrome/common/extensions/extension_error_utils.h" diff --git a/chrome/browser/extensions/extension_popup_api.cc b/chrome/browser/extensions/extension_popup_api.cc index 2af847e..25d3657 100644 --- a/chrome/browser/extensions/extension_popup_api.cc +++ b/chrome/browser/extensions/extension_popup_api.cc @@ -4,6 +4,8 @@ #include "chrome/browser/extensions/extension_popup_api.h" +#include <string> + #include "base/json/json_writer.h" #include "base/string_util.h" #include "base/stringprintf.h" @@ -11,14 +13,13 @@ #include "chrome/browser/extensions/extension_dom_ui.h" #include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_host.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" -#include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/window_sizer.h" +#include "chrome/browser/ui/window_sizer.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/notification_details.h" #include "chrome/common/notification_service.h" diff --git a/chrome/browser/extensions/extension_pref_store.cc b/chrome/browser/extensions/extension_pref_store.cc index 27719ed..b3aba44 100644 --- a/chrome/browser/extensions/extension_pref_store.cc +++ b/chrome/browser/extensions/extension_pref_store.cc @@ -4,196 +4,25 @@ #include "chrome/browser/extensions/extension_pref_store.h" -#include "base/logging.h" -#include "base/values.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" -#include "chrome/common/extensions/extension.h" -#include "chrome/common/notification_service.h" - -ExtensionPrefStore::ExtensionPrefStore(Profile* profile, - PrefNotifier::PrefStoreType type) - : prefs_(new DictionaryValue()), - profile_(profile), - type_(type) { - RegisterObservers(); +ExtensionPrefStore::ExtensionPrefStore() + : initialization_complete_(false) { } -ExtensionPrefStore::~ExtensionPrefStore() { - STLDeleteElements(&extension_stack_); - notification_registrar_.RemoveAll(); +void ExtensionPrefStore::SetExtensionPref(const std::string& key, + Value* value) { + SetValue(key, value); } -void ExtensionPrefStore::InstallExtensionPref(const Extension* extension, - const char* new_pref_path, - Value* new_pref_value) { - ExtensionStack::iterator i; - for (i = extension_stack_.begin(); i != extension_stack_.end(); ++i) { - if ((*i)->extension == extension) - break; - } - - // If this extension is not already in the stack, add it. Otherwise, update - // or add the value of this preference, but don't change the extension's - // position in the stack. We store the extension even if this preference - // isn't registered with our PrefService, so that the ordering of extensions - // is consistent among all local-state and user ExtensionPrefStores. - PrefService* pref_service = GetPrefService(); - // The pref_service may be NULL in unit testing. - bool is_registered_pref = (pref_service == NULL || - pref_service->FindPreference(new_pref_path) != NULL); - PrefValueMap* pref_values; - if (i == extension_stack_.end()) { - pref_values = new PrefValueMap(); - if (is_registered_pref) - (*pref_values)[new_pref_path] = new_pref_value; - - ExtensionPrefs* extension_prefs = new ExtensionPrefs(extension, - pref_values); - extension_stack_.push_front(extension_prefs); - } else if (is_registered_pref) { - pref_values = (*i)->pref_values; - delete (*pref_values)[new_pref_path]; - (*pref_values)[new_pref_path] = new_pref_value; - } - - // Apply the preference to our local |prefs_| store. - UpdateOnePref(new_pref_path); +void ExtensionPrefStore::RemoveExtensionPref(const std::string& key) { + RemoveValue(key); } -void ExtensionPrefStore::UninstallExtension(const Extension* extension) { - // Remove this extension from the stack. - for (ExtensionStack::iterator i = extension_stack_.begin(); - i != extension_stack_.end(); ++i) { - if ((*i)->extension == extension) { - scoped_ptr<ExtensionPrefs> to_be_deleted(*i); - extension_stack_.erase(i); - UpdatePrefs(to_be_deleted->pref_values); - return; - } - } +void ExtensionPrefStore::OnInitializationCompleted() { + DCHECK(!initialization_complete_); + initialization_complete_ = true; + NotifyInitializationCompleted(); } -void ExtensionPrefStore::GetExtensionIDs(std::vector<std::string>* result) { - for (ExtensionStack::iterator i = extension_stack_.begin(); - i != extension_stack_.end(); ++i) { - (*result).push_back((*i)->extension->id()); - } -} - -// This could be sped up by keeping track of which extension currently controls -// a given preference, among other optimizations. But probably fewer than 10 -// installed extensions will be trying to control any preferences, so stick -// with this simpler algorithm until it causes a problem. -void ExtensionPrefStore::UpdateOnePref(const char* path) { - PrefService* pref_service = GetPrefService(); - - // There are at least two PrefServices, one for local state and one for - // user prefs. (See browser_main.cc.) Different preferences are registered - // in each; if this one doesn't have the desired pref registered, we ignore - // it and let the other one handle it. - // The pref_service may be NULL in unit testing. - if (pref_service && !pref_service->FindPreference(path)) - return; - - // Save the old value before removing it from the local cache. - Value* my_old_value_ptr = NULL; - prefs_->Get(path, &my_old_value_ptr); - scoped_ptr<Value> my_old_value; - if (my_old_value_ptr) - my_old_value.reset(my_old_value_ptr->DeepCopy()); - - // DictionaryValue::Set complains if a key is overwritten with the same - // value, so remove it first. - prefs_->Remove(path, NULL); - - // Find the first extension that wants to set this pref and use its value. - Value* my_new_value = NULL; - for (ExtensionStack::iterator ext_iter = extension_stack_.begin(); - ext_iter != extension_stack_.end(); ++ext_iter) { - PrefValueMap::iterator value_iter = (*ext_iter)->pref_values->find(path); - if (value_iter != (*ext_iter)->pref_values->end()) { - prefs_->Set(path, (*value_iter).second->DeepCopy()); - my_new_value = (*value_iter).second; - break; - } - } - - if (pref_service) { - bool value_changed = true; - if (!my_old_value.get() && !my_new_value) { - value_changed = false; - } else if (my_old_value.get() && - my_new_value && - my_old_value->Equals(my_new_value)) { - value_changed = false; - } - - if (value_changed) - pref_service->pref_notifier()->OnPreferenceSet(path, type_); - } -} - -void ExtensionPrefStore::UpdatePrefs(const PrefValueMap* pref_values) { - if (!pref_values) - return; - - for (PrefValueMap::const_iterator i = pref_values->begin(); - i != pref_values->end(); ++i) { - UpdateOnePref(i->first); - } -} - -PrefService* ExtensionPrefStore::GetPrefService() { - if (profile_) - return profile_->GetPrefs(); - return g_browser_process->local_state(); -} - -void ExtensionPrefStore::RegisterObservers() { - notification_registrar_.Add(this, - NotificationType::EXTENSION_PREF_CHANGED, - NotificationService::AllSources()); - - notification_registrar_.Add(this, - NotificationType::EXTENSION_UNLOADED, - NotificationService::AllSources()); -} - -void ExtensionPrefStore::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - switch (type.value) { - case NotificationType::EXTENSION_PREF_CHANGED: { - Profile* extension_profile = Source<Profile>(source).ptr(); - // The ExtensionPrefStore for the local state watches all profiles. - if (!profile_ || profile_ == extension_profile) { - ExtensionPrefStore::ExtensionPrefDetails* data = - Details<ExtensionPrefStore::ExtensionPrefDetails>(details).ptr(); - InstallExtensionPref(data->first, data->second.first, - data->second.second); - } - break; - } - case NotificationType::EXTENSION_UNLOADED: { - Profile* extension_profile = Source<Profile>(source).ptr(); - const Extension* extension = Details<const Extension>(details).ptr(); - // The ExtensionPrefStore for the local state watches all profiles. - if (profile_ == NULL || profile_ == extension_profile) - UninstallExtension(extension); - break; - } - default: { - NOTREACHED(); - } - } -} - -ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs(const Extension* extension, - PrefValueMap* values) : extension(extension), pref_values(values) {} - -ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() { - STLDeleteValues(pref_values); - delete pref_values; +bool ExtensionPrefStore::IsInitializationComplete() const { + return initialization_complete_; } diff --git a/chrome/browser/extensions/extension_pref_store.h b/chrome/browser/extensions/extension_pref_store.h index f176758..f2db809 100644 --- a/chrome/browser/extensions/extension_pref_store.h +++ b/chrome/browser/extensions/extension_pref_store.h @@ -6,119 +6,31 @@ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_PREF_STORE_H_ #pragma once -#include <list> -#include <map> -#include <string> -#include <utility> -#include <vector> +#include "chrome/browser/prefs/value_map_pref_store.h" -#include "base/basictypes.h" -#include "base/scoped_ptr.h" -#include "base/stl_util-inl.h" -#include "chrome/browser/prefs/pref_notifier.h" -#include "chrome/common/notification_observer.h" -#include "chrome/common/notification_registrar.h" -#include "chrome/common/pref_store.h" - -class DictionaryValue; -class Extension; -class PrefService; -class Profile; -class Value; - -// This PrefStore keeps track of preferences set by extensions: for example, -// proxy settings. A stack of relevant extensions is stored in order of -// their addition to this PrefStore. For each preference, the last-added -// enabled extension that tries to set it overrules any others. -class ExtensionPrefStore : public PrefStore, - public NotificationObserver { +// A PrefStore implementation that holds preferences set by extensions. +class ExtensionPrefStore : public ValueMapPrefStore { public: - // Maps preference paths to their values. - typedef std::map<const char*, Value*> PrefValueMap; - - // The type passed as Details for an EXTENSION_PREF_CHANGED notification. - // The nested pairs are <extension, <pref_path, pref_value> >. This is here, - // rather than in (say) notification_type.h, to keep the dependency on - // std::pair out of the many places that include notification_type.h. - typedef std::pair<const Extension*, std::pair<const char*, Value*> > - ExtensionPrefDetails; - - ExtensionPrefStore(Profile* profile, PrefNotifier::PrefStoreType type); - virtual ~ExtensionPrefStore(); - - // Begins tracking the preference and value an extension wishes to set. This - // must be called each time an extension API tries to set a preference. - // The ExtensionPrefStore will take ownership of the |pref_value|. - virtual void InstallExtensionPref(const Extension* extension, - const char* pref_path, - Value* pref_value); + ExtensionPrefStore(); + virtual ~ExtensionPrefStore() {} - // Removes an extension and all its preference settings from this PrefStore. - // This must be called when an extension is uninstalled or disabled. - virtual void UninstallExtension(const Extension* extension); + // Set an extension preference |value| for |key|. Takes ownership of |value|. + void SetExtensionPref(const std::string& key, Value* value); - // PrefStore methods: - virtual DictionaryValue* prefs() const { return prefs_.get(); } + // Remove the extension preference value for |key|. + void RemoveExtensionPref(const std::string& key); - virtual PrefReadError ReadPrefs() { return PREF_READ_ERROR_NONE; } - - protected: - // Returns a vector of the extension IDs in the extension_stack_. - // This should only be accessed by subclasses for unit-testing. - void GetExtensionIDs(std::vector<std::string>* result); - - // Returns the applicable pref service from the profile (if we have one) or - // the browser's local state. This should only be accessed or overridden by - // subclasses for unit-testing. - virtual PrefService* GetPrefService(); + // Tell the store it's now fully initialized. + void OnInitializationCompleted(); private: - // Associates an extension with the prefs it sets. Owns the pref values. - struct ExtensionPrefs { - ExtensionPrefs(const Extension* extension, PrefValueMap* values); - ~ExtensionPrefs(); - - const Extension* extension; - PrefValueMap* pref_values; - }; - - // A pseudo-stack of extensions and their preferences. Extensions are always - // added to the head, but may be removed from the middle. - typedef std::list<ExtensionPrefs*> ExtensionStack; + // PrefStore overrides: + virtual bool IsInitializationComplete() const; - // Applies the highest-priority extension's setting for the given preference - // path to the |prefs_| store, or clears the setting there if no extensions - // wish to control it. - void UpdateOnePref(const char* path); - - // Updates each preference in the key set of the |pref_values| map. - void UpdatePrefs(const PrefValueMap* pref_values); - - // Registers this as an observer for relevant notifications. - void RegisterObservers(); - - // Responds to observed notifications. - void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - - // A cache of the highest-priority values for each preference that any - // extension is controlling, for quick read access. Owns the stored values. - scoped_ptr<DictionaryValue> prefs_; - - ExtensionStack extension_stack_; - - NotificationRegistrar notification_registrar_; - - // Weak reference to the profile whose extensions we're interested in. May be - // NULL (for the local-state preferences), in which case we watch all - // extensions. - Profile* profile_; - - // My PrefStore type, assigned by the PrefValueStore. - PrefNotifier::PrefStoreType type_; + bool initialization_complete_; DISALLOW_COPY_AND_ASSIGN(ExtensionPrefStore); }; + #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_PREF_STORE_H_ diff --git a/chrome/browser/extensions/extension_pref_store_unittest.cc b/chrome/browser/extensions/extension_pref_store_unittest.cc deleted file mode 100644 index 580dd3e..0000000 --- a/chrome/browser/extensions/extension_pref_store_unittest.cc +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright (c) 2010 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 <string> -#include <vector> - -#include "base/scoped_ptr.h" -#include "base/scoped_temp_dir.h" -#include "base/values.h" -#include "chrome/browser/extensions/extension_pref_store.h" -#include "chrome/browser/prefs/default_pref_store.h" -#include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/prefs/pref_value_store.h" -#include "chrome/common/extensions/extension.h" -#include "chrome/test/testing_pref_service.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace keys = extension_manifest_keys; - -namespace { - -class TestExtensionPrefStore : public ExtensionPrefStore { - public: - TestExtensionPrefStore() - : ExtensionPrefStore(NULL, PrefNotifier::EXTENSION_STORE), - ext1(NULL), - ext2(NULL), - ext3(NULL), - pref_service_(NULL) { - // Can't use ASSERT_TRUE here because a constructor can't return a value. - if (!temp_dir_.CreateUniqueTempDir()) { - ADD_FAILURE() << "Failed to create temp dir"; - return; - } - DictionaryValue simple_dict; - std::string error; - - simple_dict.SetString(keys::kVersion, "1.0.0.0"); - simple_dict.SetString(keys::kName, "unused"); - - ext1_scoped_ = Extension::Create( - temp_dir_.path().AppendASCII("ext1"), Extension::INVALID, - simple_dict, false, &error); - ext2_scoped_ = Extension::Create( - temp_dir_.path().AppendASCII("ext2"), Extension::INVALID, - simple_dict, false, &error); - ext3_scoped_ = Extension::Create( - temp_dir_.path().AppendASCII("ext3"), Extension::INVALID, - simple_dict, false, &error); - - ext1 = ext1_scoped_.get(); - ext2 = ext2_scoped_.get(); - ext3 = ext3_scoped_.get(); - } - - typedef std::vector<std::string> ExtensionIDs; - void GetExtensionIDList(ExtensionIDs* result) { - GetExtensionIDs(result); - } - - void SetPrefService(PrefService* pref_service) { - pref_service_ = pref_service; - } - - // Overridden from ExtensionPrefStore. - virtual PrefService* GetPrefService() { - return pref_service_; - } - - // Weak references, for convenience. - Extension* ext1; - Extension* ext2; - Extension* ext3; - - private: - ScopedTempDir temp_dir_; - - scoped_refptr<Extension> ext1_scoped_; - scoped_refptr<Extension> ext2_scoped_; - scoped_refptr<Extension> ext3_scoped_; - - // Weak reference. - PrefService* pref_service_; -}; - -// Mock PrefNotifier that allows the notifications to be tracked. -class MockPrefNotifier : public PrefNotifier { - public: - MockPrefNotifier(PrefService* service, PrefValueStore* value_store) - : PrefNotifier(service, value_store) {} - - virtual ~MockPrefNotifier() {} - - MOCK_METHOD1(FireObservers, void(const char* path)); -}; - -// Mock PrefService that allows the PrefNotifier to be injected. -class MockPrefService : public PrefService { - public: - explicit MockPrefService(PrefValueStore* pref_value_store) - : PrefService(pref_value_store) { - } - - void SetPrefNotifier(MockPrefNotifier* notifier) { - pref_notifier_.reset(notifier); - } -}; - -// Use constants to avoid confusing std::map with hard-coded strings. -const char kPref1[] = "path1.subpath"; -const char kPref2[] = "path2"; -const char kPref3[] = "path3"; -const char kPref4[] = "path4"; - -} // namespace - -TEST(ExtensionPrefStoreTest, InstallOneExtension) { - TestExtensionPrefStore eps; - ASSERT_TRUE(eps.ext1 != NULL); - eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1")); - - TestExtensionPrefStore::ExtensionIDs ids; - eps.GetExtensionIDList(&ids); - EXPECT_EQ(1u, ids.size()); - EXPECT_EQ(eps.ext1->id(), ids[0]); - - DictionaryValue* prefs = eps.prefs(); - ASSERT_EQ(1u, prefs->size()); - std::string actual; - ASSERT_TRUE(prefs->GetString(kPref1, &actual)); - EXPECT_EQ("val1", actual); -} - -// Make sure the last-installed extension wins. -TEST(ExtensionPrefStoreTest, InstallMultipleExtensions) { - TestExtensionPrefStore eps; - ASSERT_TRUE(eps.ext1 != NULL); - eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1")); - eps.InstallExtensionPref(eps.ext2, kPref1, Value::CreateStringValue("val2")); - eps.InstallExtensionPref(eps.ext3, kPref1, Value::CreateStringValue("val3")); - - TestExtensionPrefStore::ExtensionIDs ids; - eps.GetExtensionIDList(&ids); - EXPECT_EQ(3u, ids.size()); - EXPECT_EQ(eps.ext3->id(), ids[0]); - EXPECT_EQ(eps.ext2->id(), ids[1]); - EXPECT_EQ(eps.ext1->id(), ids[2]); - - DictionaryValue* prefs = eps.prefs(); - ASSERT_EQ(1u, prefs->size()); - std::string actual; - ASSERT_TRUE(prefs->GetString(kPref1, &actual)); - EXPECT_EQ("val3", actual); -} - -// Make sure the last-installed extension wins for each preference. -TEST(ExtensionPrefStoreTest, InstallOverwrittenExtensions) { - TestExtensionPrefStore eps; - ASSERT_TRUE(eps.ext1 != NULL); - eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1")); - eps.InstallExtensionPref(eps.ext2, kPref1, Value::CreateStringValue("val2")); - eps.InstallExtensionPref(eps.ext3, kPref1, Value::CreateStringValue("val3")); - - eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val4")); - eps.InstallExtensionPref(eps.ext2, kPref2, Value::CreateStringValue("val5")); - - eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val6")); - eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val7")); - eps.InstallExtensionPref(eps.ext1, kPref3, Value::CreateStringValue("val8")); - - TestExtensionPrefStore::ExtensionIDs ids; - eps.GetExtensionIDList(&ids); - EXPECT_EQ(3u, ids.size()); - EXPECT_EQ(eps.ext3->id(), ids[0]); - EXPECT_EQ(eps.ext2->id(), ids[1]); - EXPECT_EQ(eps.ext1->id(), ids[2]); - - DictionaryValue* prefs = eps.prefs(); - ASSERT_EQ(3u, prefs->size()); - std::string actual; - EXPECT_TRUE(prefs->GetString(kPref1, &actual)); - EXPECT_EQ("val3", actual); - EXPECT_TRUE(prefs->GetString(kPref2, &actual)); - EXPECT_EQ("val5", actual); - EXPECT_TRUE(prefs->GetString(kPref3, &actual)); - EXPECT_EQ("val8", actual); -} - -// Make sure the last-installed extension wins even if other extensions set -// the same or different preferences later. -TEST(ExtensionPrefStoreTest, InstallInterleavedExtensions) { - TestExtensionPrefStore eps; - ASSERT_TRUE(eps.ext1 != NULL); - eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1")); - eps.InstallExtensionPref(eps.ext2, kPref2, Value::CreateStringValue("val2")); - eps.InstallExtensionPref(eps.ext3, kPref3, Value::CreateStringValue("val3")); - - eps.InstallExtensionPref(eps.ext3, kPref3, Value::CreateStringValue("val4")); - eps.InstallExtensionPref(eps.ext2, kPref3, Value::CreateStringValue("val5")); - eps.InstallExtensionPref(eps.ext1, kPref3, Value::CreateStringValue("val6")); - - eps.InstallExtensionPref(eps.ext3, kPref1, Value::CreateStringValue("val7")); - - TestExtensionPrefStore::ExtensionIDs ids; - eps.GetExtensionIDList(&ids); - EXPECT_EQ(3u, ids.size()); - EXPECT_EQ(eps.ext3->id(), ids[0]); - EXPECT_EQ(eps.ext2->id(), ids[1]); - EXPECT_EQ(eps.ext1->id(), ids[2]); - - DictionaryValue* prefs = eps.prefs(); - ASSERT_EQ(3u, prefs->size()); - std::string actual; - EXPECT_TRUE(prefs->GetString(kPref1, &actual)); - EXPECT_EQ("val7", actual); - EXPECT_TRUE(prefs->GetString(kPref2, &actual)); - EXPECT_EQ("val2", actual); - EXPECT_TRUE(prefs->GetString(kPref3, &actual)); - EXPECT_EQ("val4", actual); -} - -TEST(ExtensionPrefStoreTest, UninstallOnlyExtension) { - TestExtensionPrefStore eps; - ASSERT_TRUE(eps.ext1 != NULL); - eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1")); - eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val2")); - - // No need to check the state here; the Install* tests cover that. - eps.UninstallExtension(eps.ext1); - - TestExtensionPrefStore::ExtensionIDs ids; - eps.GetExtensionIDList(&ids); - EXPECT_EQ(0u, ids.size()); - - DictionaryValue* prefs = eps.prefs(); - std::string actual; - // "path1.name" has been removed, but an empty "path1" dictionary is still - // present. - ASSERT_EQ(1u, prefs->size()); - EXPECT_FALSE(prefs->GetString(kPref1, &actual)); - EXPECT_FALSE(prefs->GetString(kPref2, &actual)); -} - -// Tests uninstalling an extension that wasn't winning for any preferences. -TEST(ExtensionPrefStoreTest, UninstallIrrelevantExtension) { - TestExtensionPrefStore eps; - ASSERT_TRUE(eps.ext1 != NULL); - eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1")); - eps.InstallExtensionPref(eps.ext2, kPref1, Value::CreateStringValue("val2")); - - eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val3")); - eps.InstallExtensionPref(eps.ext2, kPref2, Value::CreateStringValue("val4")); - - eps.UninstallExtension(eps.ext1); - - TestExtensionPrefStore::ExtensionIDs ids; - eps.GetExtensionIDList(&ids); - EXPECT_EQ(1u, ids.size()); - EXPECT_EQ(eps.ext2->id(), ids[0]); - - DictionaryValue* prefs = eps.prefs(); - ASSERT_EQ(2u, prefs->size()); - std::string actual; - EXPECT_TRUE(prefs->GetString(kPref1, &actual)); - EXPECT_EQ("val2", actual); - EXPECT_TRUE(prefs->GetString(kPref2, &actual)); - EXPECT_EQ("val4", actual); -} - -// Tests uninstalling an extension that was winning for all preferences. -TEST(ExtensionPrefStoreTest, UninstallExtensionFromTop) { - TestExtensionPrefStore eps; - ASSERT_TRUE(eps.ext1 != NULL); - eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1")); - eps.InstallExtensionPref(eps.ext2, kPref1, Value::CreateStringValue("val2")); - eps.InstallExtensionPref(eps.ext3, kPref1, Value::CreateStringValue("val3")); - - eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val4")); - eps.InstallExtensionPref(eps.ext3, kPref2, Value::CreateStringValue("val5")); - - eps.UninstallExtension(eps.ext3); - - TestExtensionPrefStore::ExtensionIDs ids; - eps.GetExtensionIDList(&ids); - EXPECT_EQ(2u, ids.size()); - EXPECT_EQ(eps.ext2->id(), ids[0]); - EXPECT_EQ(eps.ext1->id(), ids[1]); - - DictionaryValue* prefs = eps.prefs(); - ASSERT_EQ(2u, prefs->size()); - std::string actual; - EXPECT_TRUE(prefs->GetString(kPref1, &actual)); - EXPECT_EQ("val2", actual); - EXPECT_TRUE(prefs->GetString(kPref2, &actual)); - EXPECT_EQ("val4", actual); -} - -// Tests uninstalling an extension that was winning for only some preferences. -TEST(ExtensionPrefStoreTest, UninstallExtensionFromMiddle) { - TestExtensionPrefStore eps; - ASSERT_TRUE(eps.ext1 != NULL); - eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1")); - eps.InstallExtensionPref(eps.ext2, kPref1, Value::CreateStringValue("val2")); - eps.InstallExtensionPref(eps.ext3, kPref1, Value::CreateStringValue("val3")); - - eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val4")); - eps.InstallExtensionPref(eps.ext2, kPref2, Value::CreateStringValue("val5")); - - eps.InstallExtensionPref(eps.ext1, kPref3, Value::CreateStringValue("val6")); - - eps.InstallExtensionPref(eps.ext2, kPref4, Value::CreateStringValue("val7")); - - eps.UninstallExtension(eps.ext2); - - TestExtensionPrefStore::ExtensionIDs ids; - eps.GetExtensionIDList(&ids); - EXPECT_EQ(2u, ids.size()); - EXPECT_EQ(eps.ext3->id(), ids[0]); - EXPECT_EQ(eps.ext1->id(), ids[1]); - - DictionaryValue* prefs = eps.prefs(); - ASSERT_EQ(3u, prefs->size()); - std::string actual; - EXPECT_TRUE(prefs->GetString(kPref1, &actual)); - EXPECT_EQ("val3", actual); - EXPECT_TRUE(prefs->GetString(kPref2, &actual)); - EXPECT_EQ("val4", actual); - EXPECT_TRUE(prefs->GetString(kPref3, &actual)); - EXPECT_EQ("val6", actual); - EXPECT_FALSE(prefs->GetString(kPref4, &actual)); -} - -TEST(ExtensionPrefStoreTest, NotifyWhenNeeded) { - using testing::Mock; - - TestExtensionPrefStore* eps = new TestExtensionPrefStore; - DefaultPrefStore* dps = new DefaultPrefStore; - ASSERT_TRUE(eps->ext1 != NULL); - - // The PrefValueStore takes ownership of the PrefStores; in this case, that's - // only an ExtensionPrefStore. Likewise, the PrefService takes ownership of - // the PrefValueStore and PrefNotifier. - PrefValueStore* value_store = new TestingPrefService::TestingPrefValueStore( - NULL, NULL, eps, NULL, NULL, NULL, dps); - scoped_ptr<MockPrefService> pref_service(new MockPrefService(value_store)); - MockPrefNotifier* pref_notifier = new MockPrefNotifier(pref_service.get(), - value_store); - pref_service->SetPrefNotifier(pref_notifier); - - eps->SetPrefService(pref_service.get()); - pref_service->RegisterStringPref(kPref1, std::string()); - - EXPECT_CALL(*pref_notifier, FireObservers(kPref1)); - eps->InstallExtensionPref(eps->ext1, kPref1, - Value::CreateStringValue("https://www.chromium.org")); - Mock::VerifyAndClearExpectations(pref_notifier); - - EXPECT_CALL(*pref_notifier, FireObservers(kPref1)).Times(0); - eps->InstallExtensionPref(eps->ext1, kPref1, - Value::CreateStringValue("https://www.chromium.org")); - Mock::VerifyAndClearExpectations(pref_notifier); - - EXPECT_CALL(*pref_notifier, FireObservers(kPref1)).Times(2); - eps->InstallExtensionPref(eps->ext1, kPref1, - Value::CreateStringValue("chrome://newtab")); - eps->UninstallExtension(eps->ext1); -} diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc index 0cc2ec5..1f128ab 100644 --- a/chrome/browser/extensions/extension_prefs.cc +++ b/chrome/browser/extensions/extension_prefs.cc @@ -7,6 +7,8 @@ #include "base/string_util.h" #include "base/string_number_conversions.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/extensions/extension_pref_store.h" +#include "chrome/browser/prefs/pref_notifier.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/url_pattern.h" #include "chrome/common/notification_service.h" @@ -91,6 +93,12 @@ const char kPrefGrantedPermissionsAPI[] = "granted_permissions.api"; const char kPrefGrantedPermissionsHost[] = "granted_permissions.host"; const char kPrefGrantedPermissionsAll[] = "granted_permissions.full"; +// A preference that indicates when an extension was installed. +const char kPrefInstallTime[] = "install_time"; + +// A preference that contains any extension-controlled preferences. +const char kPrefPreferences[] = "preferences"; + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -133,14 +141,19 @@ static void ExtentToStringSet(const ExtensionExtent& host_extent, } // namespace -ExtensionPrefs::ExtensionPrefs(PrefService* prefs, const FilePath& root_dir) +ExtensionPrefs::ExtensionPrefs(PrefService* prefs, + const FilePath& root_dir, + ExtensionPrefStore* pref_store) : prefs_(prefs), - install_directory_(root_dir) { + install_directory_(root_dir), + pref_store_(pref_store) { // TODO(asargent) - Remove this in a couple of months. (See comment above // CleanupBadExtensionKeys). - CleanupBadExtensionKeys(prefs); + CleanupBadExtensionKeys(prefs_); MakePathsRelative(); + + InitPrefStore(); } ExtensionPrefs::~ExtensionPrefs() {} @@ -325,7 +338,9 @@ void ExtensionPrefs::AddToExtensionPrefStringSet( void ExtensionPrefs::SavePrefsAndNotify() { prefs_->ScheduleSavePersistentPrefs(); - prefs_->pref_notifier()->OnUserPreferenceSet(kExtensionsPref); + // TODO(mnissler, danno): Don't use pref_notifier() here, but tell the + // PrefService by some other means that we changed the pref value. + prefs_->pref_notifier()->OnPreferenceChanged(kExtensionsPref); } bool ExtensionPrefs::IsBlacklistBitSet(DictionaryValue* ext) { @@ -622,36 +637,17 @@ void ExtensionPrefs::SetLaunchType(const std::string& extension_id, SavePrefsAndNotify(); } -void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) { - const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref); - if (!dict || dict->empty()) - return; - - for (DictionaryValue::key_iterator i = dict->begin_keys(); - i != dict->end_keys(); ++i) { - const std::string& key_name(*i); - if (!Extension::IdIsValid(key_name)) { - LOG(WARNING) << "Invalid external extension ID encountered: " << key_name; - continue; - } - - DictionaryValue* extension; - if (!dict->GetDictionary(key_name, &extension)) { - NOTREACHED(); - continue; - } - - // Check to see if the extension has been killed. - int state; - if (extension->GetInteger(kPrefState, &state) && - state == static_cast<int>(Extension::KILLBIT)) { - killed_ids->insert(StringToLowerASCII(key_name)); - } - } +bool ExtensionPrefs::IsExtensionKilled(const std::string& id) { + DictionaryValue* extension = GetExtensionPref(id); + if (!extension) + return false; + int state = 0; + return extension->GetInteger(kPrefState, &state) && + state == static_cast<int>(Extension::KILLBIT); } std::vector<std::string> ExtensionPrefs::GetToolbarOrder() { - std::vector<std::string> extension_ids; + ExtensionPrefs::ExtensionIdSet extension_ids; const ListValue* toolbar_order = prefs_->GetList(kExtensionToolbar); if (toolbar_order) { for (size_t i = 0; i < toolbar_order->GetSize(); ++i) { @@ -678,12 +674,18 @@ void ExtensionPrefs::OnExtensionInstalled( const Extension* extension, Extension::State initial_state, bool initial_incognito_enabled) { const std::string& id = extension->id(); + const base::Time install_time = GetCurrentTime(); UpdateExtensionPref(id, kPrefState, Value::CreateIntegerValue(initial_state)); UpdateExtensionPref(id, kPrefIncognitoEnabled, Value::CreateBooleanValue(initial_incognito_enabled)); UpdateExtensionPref(id, kPrefLocation, Value::CreateIntegerValue(extension->location())); + UpdateExtensionPref(id, kPrefInstallTime, + Value::CreateStringValue( + base::Int64ToString(install_time.ToInternalValue()))); + UpdateExtensionPref(id, kPrefPreferences, new DictionaryValue()); + FilePath::StringType path = MakePathRelative(install_directory_, extension->path(), NULL); UpdateExtensionPref(id, kPrefPath, Value::CreateStringValue(path)); @@ -701,6 +703,9 @@ void ExtensionPrefs::OnExtensionInstalled( void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id, const Extension::Location& location, bool external_uninstall) { + PrefKeySet pref_keys; + GetExtensionControlledPrefKeys(extension_id, &pref_keys); + // For external extensions, we save a preference reminding ourself not to try // and install the extension anymore (except when |external_uninstall| is // true, which signifies that the registry key was deleted or the pref file @@ -712,10 +717,12 @@ void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id, } else { DeleteExtensionPrefs(extension_id); } + + UpdatePrefStore(pref_keys); } Extension::State ExtensionPrefs::GetExtensionState( - const std::string& extension_id) { + const std::string& extension_id) const { DictionaryValue* extension = GetExtensionPref(extension_id); // If the extension doesn't have a pref, it's a --load-extension. @@ -736,6 +743,11 @@ void ExtensionPrefs::SetExtensionState(const Extension* extension, Extension::State state) { UpdateExtensionPref(extension->id(), kPrefState, Value::CreateIntegerValue(state)); + + PrefKeySet pref_keys; + GetExtensionControlledPrefKeys(extension->id(), &pref_keys); + UpdatePrefStore(pref_keys); + SavePrefsAndNotify(); } @@ -841,6 +853,18 @@ DictionaryValue* ExtensionPrefs::GetExtensionPref( return extension; } +DictionaryValue* ExtensionPrefs::GetExtensionControlledPrefs( + const std::string& extension_id) const { + DictionaryValue* extension = GetExtensionPref(extension_id); + if (!extension) { + NOTREACHED(); + return NULL; + } + DictionaryValue* preferences = NULL; + extension->GetDictionary(kPrefPreferences, &preferences); + return preferences; +} + // Helper function for GetInstalledExtensionsInfo. static ExtensionInfo* GetInstalledExtensionInfoImpl( DictionaryValue* extension_data, @@ -1100,6 +1124,175 @@ std::string ExtensionPrefs::GetUpdateUrlData(const std::string& extension_id) { return data; } +base::Time ExtensionPrefs::GetCurrentTime() const { + return base::Time::Now(); +} + +base::Time ExtensionPrefs::GetInstallTime( + const std::string& extension_id) const { + const DictionaryValue* extension = GetExtensionPref(extension_id); + if (!extension) { + NOTREACHED(); + return base::Time(); + } + std::string install_time_str("0"); + extension->GetString(kPrefInstallTime, &install_time_str); + int64 install_time_i64 = 0; + base::StringToInt64(install_time_str, &install_time_i64); + LOG_IF(ERROR, install_time_i64 == 0) + << "Error parsing installation time of an extension."; + return base::Time::FromInternalValue(install_time_i64); +} + +void ExtensionPrefs::GetEnabledExtensions(ExtensionIdSet* out) const { + CHECK(out); + const DictionaryValue* extensions = + pref_service()->GetDictionary(kExtensionsPref); + + for (DictionaryValue::key_iterator ext_id = extensions->begin_keys(); + ext_id != extensions->end_keys(); ++ext_id) { + if (GetExtensionState(*ext_id) != Extension::ENABLED) + continue; + out->push_back(*ext_id); + } +} + +void ExtensionPrefs::FixMissingPrefs(const ExtensionIdSet& extension_ids) { + // Fix old entries that did not get an installation time entry when they + // were installed or don't have a preferences field. + bool persist_required = false; + for (ExtensionIdSet::const_iterator ext_id = extension_ids.begin(); + ext_id != extension_ids.end(); ++ext_id) { + DictionaryValue* extension = GetExtensionPref(*ext_id); + CHECK(extension); + + if (GetInstallTime(*ext_id) == base::Time()) { + const base::Time install_time = GetCurrentTime(); + extension->Set(kPrefInstallTime, + Value::CreateStringValue( + base::Int64ToString(install_time.ToInternalValue()))); + persist_required = true; + } + } + if (persist_required) + SavePrefsAndNotify(); +} + +void ExtensionPrefs::InitPrefStore() { + // When this is called, the PrefService is initialized and provides access + // to the user preferences stored in a JSON file. + ExtensionIdSet extension_ids; + GetEnabledExtensions(&extension_ids); + FixMissingPrefs(extension_ids); + + // Collect the unique extension controlled preference keys of all extensions. + PrefKeySet ext_controlled_prefs; + for (ExtensionIdSet::iterator ext_id = extension_ids.begin(); + ext_id != extension_ids.end(); ++ext_id) { + GetExtensionControlledPrefKeys(*ext_id, &ext_controlled_prefs); + } + + // Store winning preference for each extension controlled preference. + UpdatePrefStore(ext_controlled_prefs); + pref_store_->OnInitializationCompleted(); +} + +const Value* ExtensionPrefs::GetWinningExtensionControlledPrefValue( + const std::string& key) const { + Value *winner = NULL; + base::Time winners_install_time = base::Time(); + + ExtensionIdSet extension_ids; + GetEnabledExtensions(&extension_ids); + for (ExtensionIdSet::iterator ext_id = extension_ids.begin(); + ext_id != extension_ids.end(); ++ext_id) { + base::Time extension_install_time = GetInstallTime(*ext_id); + + // We do not need to consider extensions that were installed before the + // most recent extension found that provides the requested preference. + if (extension_install_time < winners_install_time) + continue; + + DictionaryValue* preferences = GetExtensionControlledPrefs(*ext_id); + Value *value = NULL; + if (preferences && preferences->GetWithoutPathExpansion(key, &value)) { + // This extension is more recent than the last one providing this pref. + winner = value; + winners_install_time = extension_install_time; + } + } + + return winner; +} + +void ExtensionPrefs::UpdatePrefStore( + const ExtensionPrefs::PrefKeySet& pref_keys) { + for (PrefKeySet::const_iterator i = pref_keys.begin(); + i != pref_keys.end(); ++i) { + UpdatePrefStore(*i); + } +} + +void ExtensionPrefs::UpdatePrefStore(const std::string& pref_key) { + if (pref_store_ == NULL) + return; + const Value* winning_pref_value = + GetWinningExtensionControlledPrefValue(pref_key); + + if (winning_pref_value) + pref_store_->SetExtensionPref(pref_key, winning_pref_value->DeepCopy()); + else + pref_store_->RemoveExtensionPref(pref_key); +} + +void ExtensionPrefs::SetExtensionControlledPref(const std::string& extension_id, + const std::string& pref_key, + Value* value) { + scoped_ptr<Value> scoped_value(value); + DCHECK(pref_service()->FindPreference(pref_key.c_str())) + << "Extension controlled preference key " << pref_key + << " not registered."; + DictionaryValue* extension_preferences = + GetExtensionControlledPrefs(extension_id); + + if (extension_preferences == NULL) { // May be pruned when writing to disk. + DictionaryValue* extension = GetExtensionPref(extension_id); + if (extension == NULL) { + LOG(ERROR) << "Extension preference for " << extension_id << " undefined"; + return; + } + extension_preferences = new DictionaryValue; + extension->Set(kPrefPreferences, extension_preferences); + } + + Value* oldValue = NULL; + extension_preferences->GetWithoutPathExpansion(pref_key, &oldValue); + bool modified = !Value::Equals(oldValue, scoped_value.get()); + if (!modified) + return; + + if (scoped_value.get() == NULL) + extension_preferences->RemoveWithoutPathExpansion(pref_key, NULL); + else + extension_preferences->SetWithoutPathExpansion(pref_key, + scoped_value.release()); + pref_service()->ScheduleSavePersistentPrefs(); + + UpdatePrefStore(pref_key); +} + +void ExtensionPrefs::GetExtensionControlledPrefKeys( + const std::string& extension_id, PrefKeySet *out) const { + DCHECK(out != NULL); + DictionaryValue* ext_prefs = GetExtensionControlledPrefs(extension_id); + if (ext_prefs) { + for (DictionaryValue::key_iterator i = ext_prefs->begin_keys(); + i != ext_prefs->end_keys(); ++i) { + out->insert(*i); + } + } +} + // static void ExtensionPrefs::RegisterUserPrefs(PrefService* prefs) { prefs->RegisterDictionaryPref(kExtensionsPref); diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h index 6245eda..8c8be82 100644 --- a/chrome/browser/extensions/extension_prefs.h +++ b/chrome/browser/extensions/extension_prefs.h @@ -16,9 +16,23 @@ #include "chrome/common/extensions/extension.h" #include "googleurl/src/gurl.h" +class ExtensionPrefStore; + // Class for managing global and per-extension preferences. -// This class is instantiated by ExtensionsService, so it should be accessed -// from there. +// +// This class distinguishes the following kinds of preferences: +// - global preferences: +// internal state for the extension system in general, not associated +// with an individual extension, such as lastUpdateTime. +// - per-extension preferences: +// meta-preferences describing properties of the extension like +// installation time, whether the extension is enabled, etc. +// - extension controlled preferences: +// browser preferences that an extension controls. For example, an +// extension could use the proxy API to specify the browser's proxy +// preference. Extension-controlled preferences are stored in +// PrefValueStore::extension_prefs(), which this class populates and +// maintains as the underlying extensions change. class ExtensionPrefs { public: // Key name for a preference that keeps track of per-extension settings. This @@ -28,6 +42,12 @@ class ExtensionPrefs { typedef std::vector<linked_ptr<ExtensionInfo> > ExtensionsInfo; + // Vector containing identifiers for preferences. + typedef std::set<std::string> PrefKeySet; + + // Vector containing identifiers for extensions. + typedef std::vector<std::string> ExtensionIdSet; + // This enum is used for the launch type the user wants to use for an // application. // Do not remove items or re-order this enum as it is used in preferences @@ -39,7 +59,9 @@ class ExtensionPrefs { LAUNCH_WINDOW }; - explicit ExtensionPrefs(PrefService* prefs, const FilePath& root_dir_); + explicit ExtensionPrefs(PrefService* prefs, + const FilePath& root_dir, + ExtensionPrefStore* extension_pref_store); ~ExtensionPrefs(); // Returns a copy of the Extensions prefs. @@ -47,8 +69,9 @@ class ExtensionPrefs { // aware of the internal structure of the preferences. DictionaryValue* CopyCurrentExtensions(); - // Populate |killed_ids| with extension ids that have been killed. - void GetKilledExtensionIds(std::set<std::string>* killed_ids); + // Returns true if the specified extension has an entry in prefs + // and its killbit is on. + bool IsExtensionKilled(const std::string& id); // Get the order that toolstrip URLs appear in the shelf. typedef std::vector<GURL> URLList; @@ -74,11 +97,14 @@ class ExtensionPrefs { bool external_uninstall); // Returns the state (enabled/disabled) of the given extension. - Extension::State GetExtensionState(const std::string& extension_id); + Extension::State GetExtensionState(const std::string& extension_id) const; // Called to change the extension's state when it is enabled/disabled. void SetExtensionState(const Extension* extension, Extension::State); + // Returns all installed and enabled extensions + void GetEnabledExtensions(ExtensionIdSet* out) const; + // Getter and setter for browser action visibility. bool GetBrowserActionVisibility(const Extension* extension); void SetBrowserActionVisibility(const Extension* extension, bool visible); @@ -232,11 +258,23 @@ class ExtensionPrefs { const std::string& data); std::string GetUpdateUrlData(const std::string& extension_id); + // Sets a preference value that is controlled by the extension. In other + // words, this is not a pref value *about* the extension but something + // global the extension wants to override. + void SetExtensionControlledPref(const std::string& extension_id, + const std::string& pref_key, + Value* value); + static void RegisterUserPrefs(PrefService* prefs); // The underlying PrefService. PrefService* pref_service() const { return prefs_; } + protected: + // For unit testing. Enables injecting an artificial clock that is used + // to query the current time, when an extension is installed. + virtual base::Time GetCurrentTime() const; + private: // Converts absolute paths in the pref to paths relative to the // install_directory_. @@ -296,6 +334,11 @@ class ExtensionPrefs { // Same as above, but returns NULL if it doesn't exist. DictionaryValue* GetExtensionPref(const std::string& id) const; + // Returns the dictionary of preferences controlled by the specified extension + // or NULL if unknown. All entries in the dictionary contain non-expanded + // paths. + DictionaryValue* GetExtensionControlledPrefs(const std::string& id) const; + // Serializes the data and schedules a persistent save via the |PrefService|. // Additionally fires a PREF_CHANGED notification with the top-level // |kExtensionsPref| path set. @@ -313,12 +356,44 @@ class ExtensionPrefs { base::Time LastPingDayImpl(const DictionaryValue* dictionary) const; void SetLastPingDayImpl(const base::Time& time, DictionaryValue* dictionary); + // Helper method to acquire the installation time of an extension. + base::Time GetInstallTime(const std::string& extension_id) const; + + // Fix missing preference entries in the extensions that are were introduced + // in a later Chrome version. + void FixMissingPrefs(const ExtensionIdSet& extension_ids); + + // Installs the persistent extension preferences into |prefs_|'s extension + // pref store. + void InitPrefStore(); + + // Returns the extension controlled preference value of the extension that was + // installed most recently. + const Value* GetWinningExtensionControlledPrefValue( + const std::string& key) const; + + // Executes UpdatePrefStore for all |pref_keys|. + void UpdatePrefStore(const PrefKeySet& pref_keys); + + // Finds the most recently installed extension that defines a preference + // for |pref_key|, then stores its value in the PrefValueStore's extension + // pref store and sends notifications to observers in case the value changed. + void UpdatePrefStore(const std::string& pref_key); + + // Retrieves a list of preference keys that the specified extension + // intends to manage. Keys are always appended, |out| is not cleared. + void GetExtensionControlledPrefKeys(const std::string& extension_id, + PrefKeySet *out) const; + // The pref service specific to this set of extension prefs. PrefService* prefs_; // Base extensions install directory. FilePath install_directory_; + // Used to manipulate extension preferences. + ExtensionPrefStore* pref_store_; + // The URLs of all of the toolstrips. URLList shelf_order_; diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc index d6dcc23..6b59740 100644 --- a/chrome/browser/extensions/extension_prefs_unittest.cc +++ b/chrome/browser/extensions/extension_prefs_unittest.cc @@ -8,17 +8,31 @@ #include "base/stl_util-inl.h" #include "base/string_number_conversions.h" #include "base/stringprintf.h" -#include "chrome/browser/browser_thread.h" #include "chrome/browser/extensions/extension_prefs.h" #include "chrome/browser/extensions/test_extension_prefs.h" +#include "chrome/browser/prefs/pref_change_registrar.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/notification_details.h" +#include "chrome/common/notification_observer_mock.h" +#include "chrome/common/notification_source.h" #include "testing/gtest/include/gtest/gtest.h" using base::Time; using base::TimeDelta; +const char kPref1[] = "path1.subpath"; +const char kPref2[] = "path2"; +const char kPref3[] = "path3"; +const char kPref4[] = "path4"; + +// Default values in case an extension pref value is not overridden. +const char kDefaultPref1[] = "default pref 1"; +const char kDefaultPref2[] = "default pref 2"; +const char kDefaultPref3[] = "default pref 3"; +const char kDefaultPref4[] = "default pref 4"; + static void AddPattern(ExtensionExtent* extent, const std::string& pattern) { int schemes = URLPattern::SCHEME_ALL; extent->AddPattern(URLPattern(schemes, pattern)); @@ -55,7 +69,11 @@ class ExtensionPrefsTest : public testing::Test { // things don't break after any ExtensionPrefs startup work. virtual void Verify() = 0; + // This function is called to Register preference default values. + virtual void RegisterPreferences() {} + virtual void SetUp() { + RegisterPreferences(); Initialize(); } @@ -64,6 +82,7 @@ class ExtensionPrefsTest : public testing::Test { // Reset ExtensionPrefs, and re-verify. prefs_.RecreateExtensionPrefs(); + RegisterPreferences(); Verify(); } @@ -527,3 +546,349 @@ class ExtensionPrefsAppLaunchIndex : public ExtensionPrefsTest { scoped_refptr<Extension> extension_; }; TEST_F(ExtensionPrefsAppLaunchIndex, ExtensionPrefsAppLaunchIndex) {} + +namespace keys = extension_manifest_keys; + +class ExtensionPrefsPreferencesBase : public ExtensionPrefsTest { + public: + ExtensionPrefsPreferencesBase() + : ExtensionPrefsTest(), + ext1_(NULL), + ext2_(NULL), + ext3_(NULL), + installed() { + DictionaryValue simple_dict; + std::string error; + + simple_dict.SetString(keys::kVersion, "1.0.0.0"); + simple_dict.SetString(keys::kName, "unused"); + + ext1_scoped_ = Extension::Create( + prefs_.temp_dir().AppendASCII("ext1_"), Extension::INVALID, + simple_dict, false, &error); + ext2_scoped_ = Extension::Create( + prefs_.temp_dir().AppendASCII("ext2_"), Extension::INVALID, + simple_dict, false, &error); + ext3_scoped_ = Extension::Create( + prefs_.temp_dir().AppendASCII("ext3_"), Extension::INVALID, + simple_dict, false, &error); + + ext1_ = ext1_scoped_.get(); + ext2_ = ext2_scoped_.get(); + ext3_ = ext3_scoped_.get(); + + for (size_t i = 0; i < arraysize(installed); ++i) + installed[i] = false; + } + + void RegisterPreferences() { + prefs()->pref_service()->RegisterStringPref(kPref1, kDefaultPref1); + prefs()->pref_service()->RegisterStringPref(kPref2, kDefaultPref2); + prefs()->pref_service()->RegisterStringPref(kPref3, kDefaultPref3); + prefs()->pref_service()->RegisterStringPref(kPref4, kDefaultPref4); + } + + void InstallExtControlledPref(Extension *ext, + const std::string& key, + Value* val) { + // Install extension the first time a preference is set for it. + Extension* extensions[] = {ext1_, ext2_, ext3_}; + for (int i = 0; i < 3; ++i) { + if (ext == extensions[i] && !installed[i]) { + prefs()->OnExtensionInstalled(ext, Extension::ENABLED, true); + installed[i] = true; + break; + } + } + + prefs()->SetExtensionControlledPref(ext->id(), key, val); + } + + void UninstallExtension(const std::string& extension_id) { + prefs()->OnExtensionUninstalled(extension_id, Extension::INTERNAL, false); + } + + // Weak references, for convenience. + Extension* ext1_; + Extension* ext2_; + Extension* ext3_; + + // Flags indicating whether each of the extensions has been installed, yet. + bool installed[3]; + + private: + scoped_refptr<Extension> ext1_scoped_; + scoped_refptr<Extension> ext2_scoped_; + scoped_refptr<Extension> ext3_scoped_; +}; + +class ExtensionPrefsInstallOneExtension + : public ExtensionPrefsPreferencesBase { + virtual void Initialize() { + InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1")); + } + virtual void Verify() { + std::string actual = prefs()->pref_service()->GetString(kPref1); + EXPECT_EQ("val1", actual); + } +}; +TEST_F(ExtensionPrefsInstallOneExtension, ExtensionPrefsInstallOneExtension) {} + +// Make sure the last-installed extension wins for each preference. +class ExtensionPrefsInstallOverwrittenExtensions + : public ExtensionPrefsPreferencesBase { + virtual void Initialize() { + InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1")); + InstallExtControlledPref(ext2_, kPref1, Value::CreateStringValue("val2")); + InstallExtControlledPref(ext3_, kPref1, Value::CreateStringValue("val3")); + + InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val4")); + InstallExtControlledPref(ext2_, kPref2, Value::CreateStringValue("val5")); + + InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val6")); + InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val7")); + InstallExtControlledPref(ext1_, kPref3, Value::CreateStringValue("val8")); + } + virtual void Verify() { + std::string actual; + actual = prefs()->pref_service()->GetString(kPref1); + EXPECT_EQ("val3", actual); + actual = prefs()->pref_service()->GetString(kPref2); + EXPECT_EQ("val5", actual); + actual = prefs()->pref_service()->GetString(kPref3); + EXPECT_EQ("val8", actual); + } +}; +TEST_F(ExtensionPrefsInstallOverwrittenExtensions, + ExtensionPrefsInstallOverwrittenExtensions) {} + +// Make sure the last-installed extension wins even if other extensions set +// the same or different preferences later. +class ExtensionPrefsInstallInterleavedExtensions + : public ExtensionPrefsPreferencesBase { + virtual void Initialize() { + InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1")); + InstallExtControlledPref(ext2_, kPref2, Value::CreateStringValue("val2")); + InstallExtControlledPref(ext3_, kPref3, Value::CreateStringValue("val3")); + + InstallExtControlledPref(ext3_, kPref3, Value::CreateStringValue("val4")); + InstallExtControlledPref(ext2_, kPref3, Value::CreateStringValue("val5")); + InstallExtControlledPref(ext1_, kPref3, Value::CreateStringValue("val6")); + + InstallExtControlledPref(ext3_, kPref1, Value::CreateStringValue("val7")); + } + virtual void Verify() { + std::string actual; + actual = prefs()->pref_service()->GetString(kPref1); + EXPECT_EQ("val7", actual); + actual = prefs()->pref_service()->GetString(kPref2); + EXPECT_EQ("val2", actual); + actual = prefs()->pref_service()->GetString(kPref3); + EXPECT_EQ("val4", actual); + } +}; +TEST_F(ExtensionPrefsInstallInterleavedExtensions, + ExtensionPrefsInstallInterleavedExtensions) {} + +class ExtensionPrefsUninstallOnlyExtension + : public ExtensionPrefsPreferencesBase { + virtual void Initialize() { + InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1")); + InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val2")); + + UninstallExtension(ext1_->id()); + } + virtual void Verify() { + std::string actual; + actual = prefs()->pref_service()->GetString(kPref1); + EXPECT_EQ(kDefaultPref1, actual); + actual = prefs()->pref_service()->GetString(kPref2); + EXPECT_EQ(kDefaultPref2, actual); + } +}; +TEST_F(ExtensionPrefsUninstallOnlyExtension, + ExtensionPrefsUninstallOnlyExtension) {} + +// Tests uninstalling an extension that wasn't winning for any preferences. +class ExtensionPrefsUninstallIrrelevantExtension + : public ExtensionPrefsPreferencesBase { + virtual void Initialize() { + InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1")); + InstallExtControlledPref(ext2_, kPref1, Value::CreateStringValue("val2")); + + InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val3")); + InstallExtControlledPref(ext2_, kPref2, Value::CreateStringValue("val4")); + + UninstallExtension(ext1_->id()); + } + virtual void Verify() { + std::string actual; + actual = prefs()->pref_service()->GetString(kPref1); + EXPECT_EQ("val2", actual); + actual = prefs()->pref_service()->GetString(kPref2); + EXPECT_EQ("val4", actual); + } +}; +TEST_F(ExtensionPrefsUninstallIrrelevantExtension, + ExtensionPrefsUninstallIrrelevantExtension) {} + +// Tests uninstalling an extension that was winning for all preferences. +class ExtensionPrefsUninstallExtensionFromTop + : public ExtensionPrefsPreferencesBase { + virtual void Initialize() { + InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1")); + InstallExtControlledPref(ext2_, kPref1, Value::CreateStringValue("val2")); + InstallExtControlledPref(ext3_, kPref1, Value::CreateStringValue("val3")); + + InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val4")); + InstallExtControlledPref(ext3_, kPref2, Value::CreateStringValue("val5")); + + UninstallExtension(ext3_->id()); + } + virtual void Verify() { + std::string actual; + actual = prefs()->pref_service()->GetString(kPref1); + EXPECT_EQ("val2", actual); + actual = prefs()->pref_service()->GetString(kPref2); + EXPECT_EQ("val4", actual); + } +}; +TEST_F(ExtensionPrefsUninstallExtensionFromTop, + ExtensionPrefsUninstallExtensionFromTop) {} + +// Tests uninstalling an extension that was winning for only some preferences. +class ExtensionPrefsUninstallExtensionFromMiddle + : public ExtensionPrefsPreferencesBase { + virtual void Initialize() { + InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1")); + InstallExtControlledPref(ext2_, kPref1, Value::CreateStringValue("val2")); + InstallExtControlledPref(ext3_, kPref1, Value::CreateStringValue("val3")); + + InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val4")); + InstallExtControlledPref(ext2_, kPref2, Value::CreateStringValue("val5")); + + InstallExtControlledPref(ext1_, kPref3, Value::CreateStringValue("val6")); + + InstallExtControlledPref(ext2_, kPref4, Value::CreateStringValue("val7")); + + UninstallExtension(ext2_->id()); + } + virtual void Verify() { + std::string actual; + actual = prefs()->pref_service()->GetString(kPref1); + EXPECT_EQ("val3", actual); + actual = prefs()->pref_service()->GetString(kPref2); + EXPECT_EQ("val4", actual); + actual = prefs()->pref_service()->GetString(kPref3); + EXPECT_EQ("val6", actual); + actual = prefs()->pref_service()->GetString(kPref4); + EXPECT_EQ(kDefaultPref4, actual); + } +}; +TEST_F(ExtensionPrefsUninstallExtensionFromMiddle, + ExtensionPrefsUninstallExtensionFromMiddle) {} + +// Tests triggering of notifications to registered observers +class ExtensionPrefsNotifyWhenNeeded + : public ExtensionPrefsPreferencesBase { + virtual void Initialize() { + using testing::_; + using testing::Mock; + using testing::StrEq; + + scoped_ptr<NotificationObserverMock> observer( + new NotificationObserverMock()); + PrefChangeRegistrar registrar; + registrar.Init(prefs()->pref_service()); + registrar.Add(kPref1, observer.get()); + + EXPECT_CALL(*observer, Observe(_, _, _)); + InstallExtControlledPref(ext1_, kPref1, + Value::CreateStringValue("https://www.chromium.org")); + Mock::VerifyAndClearExpectations(observer.get()); + + EXPECT_CALL(*observer, Observe(_, _, _)).Times(0); + InstallExtControlledPref(ext1_, kPref1, + Value::CreateStringValue("https://www.chromium.org")); + Mock::VerifyAndClearExpectations(observer.get()); + + EXPECT_CALL(*observer, Observe(_, _, _)).Times(2); + InstallExtControlledPref(ext1_, kPref1, + Value::CreateStringValue("chrome://newtab")); + + UninstallExtension(ext1_->id()); + registrar.Remove(kPref1, observer.get()); + } + virtual void Verify() { + std::string actual = prefs()->pref_service()->GetString(kPref1); + EXPECT_EQ(kDefaultPref1, actual); + } +}; +TEST_F(ExtensionPrefsNotifyWhenNeeded, + ExtensionPrefsNotifyWhenNeeded) {} + +// Tests disabling an extension +class ExtensionPrefsDisableExt + : public ExtensionPrefsPreferencesBase { + virtual void Initialize() { + InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1")); + std::string actual = prefs()->pref_service()->GetString(kPref1); + EXPECT_EQ("val1", actual); + prefs()->SetExtensionState(ext1_, Extension::DISABLED); + } + virtual void Verify() { + std::string actual = prefs()->pref_service()->GetString(kPref1); + EXPECT_EQ(kDefaultPref1, actual); + } +}; +TEST_F(ExtensionPrefsDisableExt, ExtensionPrefsDisableExt) {} + +// Tests disabling and reenabling an extension +class ExtensionPrefsReenableExt + : public ExtensionPrefsPreferencesBase { + virtual void Initialize() { + InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1")); + prefs()->SetExtensionState(ext1_, Extension::DISABLED); + prefs()->SetExtensionState(ext1_, Extension::ENABLED); + } + virtual void Verify() { + std::string actual = prefs()->pref_service()->GetString(kPref1); + EXPECT_EQ("val1", actual); + } +}; +TEST_F(ExtensionPrefsDisableExt, ExtensionPrefsReenableExt) {} + +// Mock class to test whether objects are deleted correctly. +class MockStringValue : public StringValue { + public: + explicit MockStringValue(const std::string& in_value) + : StringValue(in_value) { + } + virtual ~MockStringValue() { + Die(); + } + MOCK_METHOD0(Die, void()); +}; + +class ExtensionPrefsSetExtensionControlledPref + : public ExtensionPrefsPreferencesBase { + public: + virtual void Initialize() { + MockStringValue* v1 = new MockStringValue("https://www.chromium.org"); + MockStringValue* v2 = new MockStringValue("https://www.chromium.org"); + // Ownership is taken, value shall not be deleted. + EXPECT_CALL(*v1, Die()).Times(0); + InstallExtControlledPref(ext1_, kPref1, v1); + testing::Mock::VerifyAndClearExpectations(v1); + // Make sure there is no memory leak and both values are deleted. + EXPECT_CALL(*v2, Die()).Times(1); + EXPECT_CALL(*v1, Die()).Times(1); + InstallExtControlledPref(ext1_, kPref1, v2); + prefs_.RecreateExtensionPrefs(); + } + + virtual void Verify() { + } +}; +TEST_F(ExtensionPrefsSetExtensionControlledPref, + ExtensionPrefsSetExtensionControlledPref) {} diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc index c273033..03e868d 100644 --- a/chrome/browser/extensions/extension_process_manager.cc +++ b/chrome/browser/extensions/extension_process_manager.cc @@ -10,8 +10,8 @@ #include "chrome/browser/extensions/extension_host_mac.h" #endif #include "chrome/browser/extensions/extension_host.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/site_instance.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/tab_contents/tab_contents.h" @@ -135,8 +135,8 @@ ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url, ViewType::Type view_type) { // A NULL browser may only be given for pop-up views. DCHECK(browser || (!browser && view_type == ViewType::EXTENSION_POPUP)); - ExtensionsService* service = - browsing_instance_->profile()->GetExtensionsService(); + ExtensionService* service = + browsing_instance_->profile()->GetExtensionService(); if (service) { const Extension* extension = service->GetExtensionByURL(url); if (extension) @@ -226,8 +226,8 @@ void ExtensionProcessManager::RegisterExtensionProcess( DCHECK(it == process_ids_.end()); process_ids_[extension_id] = process_id; - ExtensionsService* extension_service = - browsing_instance_->profile()->GetExtensionsService(); + ExtensionService* extension_service = + browsing_instance_->profile()->GetExtensionService(); std::vector<std::string> page_action_ids; const Extension* extension = @@ -281,13 +281,13 @@ void ExtensionProcessManager::Observe(NotificationType type, switch (type.value) { case NotificationType::EXTENSIONS_READY: { CreateBackgroundHosts(this, - Source<Profile>(source).ptr()->GetExtensionsService()->extensions()); + Source<Profile>(source).ptr()->GetExtensionService()->extensions()); break; } case NotificationType::EXTENSION_LOADED: { - ExtensionsService* service = - Source<Profile>(source).ptr()->GetExtensionsService(); + ExtensionService* service = + Source<Profile>(source).ptr()->GetExtensionService(); if (service->is_ready()) { const Extension* extension = Details<const Extension>(details).ptr(); ::CreateBackgroundHost(this, extension); @@ -296,7 +296,8 @@ void ExtensionProcessManager::Observe(NotificationType type, } case NotificationType::EXTENSION_UNLOADED: { - const Extension* extension = Details<const Extension>(details).ptr(); + const Extension* extension = + Details<UnloadedExtensionInfo>(details)->extension; for (ExtensionHostSet::iterator iter = background_hosts_.begin(); iter != background_hosts_.end(); ++iter) { ExtensionHost* host = *iter; @@ -427,8 +428,8 @@ RenderProcessHost* IncognitoExtensionProcessManager::GetExtensionProcess( const Extension* IncognitoExtensionProcessManager::GetExtensionOrAppByURL( const GURL& url) { - ExtensionsService* service = - browsing_instance_->profile()->GetExtensionsService(); + ExtensionService* service = + browsing_instance_->profile()->GetExtensionService(); if (!service) return NULL; return (url.SchemeIs(chrome::kExtensionScheme)) ? @@ -437,8 +438,8 @@ const Extension* IncognitoExtensionProcessManager::GetExtensionOrAppByURL( bool IncognitoExtensionProcessManager::IsIncognitoEnabled( const Extension* extension) { - ExtensionsService* service = - browsing_instance_->profile()->GetExtensionsService(); + ExtensionService* service = + browsing_instance_->profile()->GetExtensionService(); return service && service->IsIncognitoEnabled(extension); } @@ -456,8 +457,8 @@ void IncognitoExtensionProcessManager::Observe( // On Chrome OS, a login screen is implemented as a browser. // This browser has no extension service. In this case, // service will be NULL. - ExtensionsService* service = - browsing_instance_->profile()->GetExtensionsService(); + ExtensionService* service = + browsing_instance_->profile()->GetExtensionService(); if (service && service->is_ready()) CreateBackgroundHosts(this, service->extensions()); } diff --git a/chrome/browser/extensions/extension_processes_api.cc b/chrome/browser/extensions/extension_processes_api.cc index 99b72e8..5edc2f0 100644 --- a/chrome/browser/extensions/extension_processes_api.cc +++ b/chrome/browser/extensions/extension_processes_api.cc @@ -16,13 +16,12 @@ #include "chrome/browser/extensions/extension_processes_api_constants.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/extensions/extension_tabs_module_constants.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents_wrapper.h" #include "chrome/browser/task_manager/task_manager.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/extensions/extension_error_utils.h" -#include "chrome/common/notification_service.h" #include "chrome/common/notification_type.h" namespace keys = extension_processes_api_constants; diff --git a/chrome/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc index edf937b..e95f18d 100644 --- a/chrome/browser/extensions/extension_protocols.cc +++ b/chrome/browser/extensions/extension_protocols.cc @@ -32,15 +32,15 @@ namespace { -class URLRequestResourceBundleJob : public URLRequestSimpleJob { +class URLRequestResourceBundleJob : public net::URLRequestSimpleJob { public: - explicit URLRequestResourceBundleJob(URLRequest* request, + explicit URLRequestResourceBundleJob(net::URLRequest* request, const FilePath& filename, int resource_id) - : URLRequestSimpleJob(request), + : net::URLRequestSimpleJob(request), filename_(filename), resource_id_(resource_id) { } - // URLRequestSimpleJob method. + // Overridden from URLRequestSimpleJob: virtual bool GetData(std::string* mime_type, std::string* charset, std::string* data) const { @@ -67,7 +67,7 @@ class URLRequestResourceBundleJob : public URLRequestSimpleJob { }; // Returns true if an chrome-extension:// resource should be allowed to load. -bool AllowExtensionResourceLoad(URLRequest* request, +bool AllowExtensionResourceLoad(net::URLRequest* request, ChromeURLRequestContext* context, const std::string& scheme) { const ResourceDispatcherHostRequestInfo* info = @@ -142,16 +142,17 @@ bool AllowExtensionResourceLoad(URLRequest* request, } // namespace -// Factory registered with URLRequest to create URLRequestJobs for extension:// -// URLs. -static URLRequestJob* CreateExtensionURLRequestJob(URLRequest* request, - const std::string& scheme) { +// Factory registered with net::URLRequest to create URLRequestJobs for +// extension:// URLs. +static net::URLRequestJob* CreateExtensionURLRequestJob( + net::URLRequest* request, + const std::string& scheme) { ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>(request->context()); // TODO(mpcomplete): better error code. if (!AllowExtensionResourceLoad(request, context, scheme)) - return new URLRequestErrorJob(request, net::ERR_ADDRESS_UNREACHABLE); + return new net::URLRequestErrorJob(request, net::ERR_ADDRESS_UNREACHABLE); // chrome-extension://extension-id/resource/path.js const std::string& extension_id = request->url().host(); @@ -198,13 +199,14 @@ static URLRequestJob* CreateExtensionURLRequestJob(URLRequest* request, base::ThreadRestrictions::ScopedAllowIO allow_io; resource_file_path = resource.GetFilePath(); } - return new URLRequestFileJob(request, resource_file_path); + return new net::URLRequestFileJob(request, resource_file_path); } -// Factory registered with URLRequest to create URLRequestJobs for +// Factory registered with net::URLRequest to create URLRequestJobs for // chrome-user-script:/ URLs. -static URLRequestJob* CreateUserScriptURLRequestJob(URLRequest* request, - const std::string& scheme) { +static net::URLRequestJob* CreateUserScriptURLRequestJob( + net::URLRequest* request, + const std::string& scheme) { ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>(request->context()); @@ -214,12 +216,12 @@ static URLRequestJob* CreateUserScriptURLRequestJob(URLRequest* request, ExtensionResource resource(request->url().host(), directory_path, extension_file_util::ExtensionURLToRelativeFilePath(request->url())); - return new URLRequestFileJob(request, resource.GetFilePath()); + return new net::URLRequestFileJob(request, resource.GetFilePath()); } void RegisterExtensionProtocols() { - URLRequest::RegisterProtocolFactory(chrome::kExtensionScheme, - &CreateExtensionURLRequestJob); - URLRequest::RegisterProtocolFactory(chrome::kUserScriptScheme, - &CreateUserScriptURLRequestJob); + net::URLRequest::RegisterProtocolFactory(chrome::kExtensionScheme, + &CreateExtensionURLRequestJob); + net::URLRequest::RegisterProtocolFactory(chrome::kUserScriptScheme, + &CreateUserScriptURLRequestJob); } diff --git a/chrome/browser/extensions/extension_proxy_api.cc b/chrome/browser/extensions/extension_proxy_api.cc index 030b711..d71c055 100644 --- a/chrome/browser/extensions/extension_proxy_api.cc +++ b/chrome/browser/extensions/extension_proxy_api.cc @@ -7,8 +7,9 @@ #include "base/string_util.h" #include "base/stringprintf.h" #include "base/values.h" -#include "chrome/browser/extensions/extension_pref_store.h" -#include "chrome/common/notification_service.h" +#include "chrome/browser/prefs/proxy_prefs.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/common/pref_names.h" namespace { @@ -53,8 +54,8 @@ bool UseCustomProxySettingsFunction::RunImpl() { DictionaryValue* proxy_config; EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &proxy_config)); - bool auto_detect = false; - proxy_config->GetBoolean("autoDetect", &auto_detect); + std::string proxy_mode; + proxy_config->GetString("mode", &proxy_mode); DictionaryValue* pac_dict = NULL; proxy_config->GetDictionary("pacScript", &pac_dict); @@ -62,7 +63,9 @@ bool UseCustomProxySettingsFunction::RunImpl() { DictionaryValue* proxy_rules = NULL; proxy_config->GetDictionary("rules", &proxy_rules); - return ApplyAutoDetect(auto_detect) && + // TODO(battre,gfeher): Make sure all the preferences get always + // overwritten. + return ApplyMode(proxy_mode) && ApplyPacScript(pac_dict) && ApplyProxyRules(proxy_rules); } @@ -75,13 +78,19 @@ bool UseCustomProxySettingsFunction::GetProxyServer( return true; } -bool UseCustomProxySettingsFunction::ApplyAutoDetect(bool auto_detect) { - // We take control of the auto-detect preference even if none was specified, - // so that all proxy preferences are controlled by the same extension (if not - // by a higher-priority source). - SendNotification(prefs::kProxyAutoDetect, - Value::CreateBooleanValue(auto_detect)); - return true; +bool UseCustomProxySettingsFunction::ApplyMode(const std::string& mode) { + // We take control of the mode preference even if none was specified, so that + // all proxy preferences are controlled by the same extension (if not by a + // higher-priority source). + bool result = true; + ProxyPrefs::ProxyMode mode_enum; + if (!ProxyPrefs::StringToProxyMode(mode, &mode_enum)) { + mode_enum = ProxyPrefs::MODE_SYSTEM; + LOG(WARNING) << "Invalid mode for proxy settings: " << mode; + result = false; + } + ApplyPreference(prefs::kProxyMode, Value::CreateIntegerValue(mode_enum)); + return result; } bool UseCustomProxySettingsFunction::ApplyPacScript(DictionaryValue* pac_dict) { @@ -92,14 +101,16 @@ bool UseCustomProxySettingsFunction::ApplyPacScript(DictionaryValue* pac_dict) { // We take control of the PAC preference even if none was specified, so that // all proxy preferences are controlled by the same extension (if not by a // higher-priority source). - SendNotification(prefs::kProxyPacUrl, Value::CreateStringValue(pac_url)); + ApplyPreference(prefs::kProxyPacUrl, Value::CreateStringValue(pac_url)); return true; } bool UseCustomProxySettingsFunction::ApplyProxyRules( DictionaryValue* proxy_rules) { - if (!proxy_rules) + if (!proxy_rules) { + ApplyPreference(prefs::kProxyServer, Value::CreateStringValue("")); return true; + } // Local data into which the parameters will be parsed. has_proxy describes // whether a setting was found for the scheme; proxy_dict holds the @@ -153,17 +164,12 @@ bool UseCustomProxySettingsFunction::ApplyProxyRules( } } - SendNotification(prefs::kProxyServer, Value::CreateStringValue(proxy_pref)); + ApplyPreference(prefs::kProxyServer, Value::CreateStringValue(proxy_pref)); return true; } -void UseCustomProxySettingsFunction::SendNotification(const char* pref_path, - Value* pref_value) { - ExtensionPrefStore::ExtensionPrefDetails details = - std::make_pair(GetExtension(), std::make_pair(pref_path, pref_value)); - - NotificationService::current()->Notify( - NotificationType::EXTENSION_PREF_CHANGED, - Source<Profile>(profile_), - Details<ExtensionPrefStore::ExtensionPrefDetails>(&details)); +void UseCustomProxySettingsFunction::ApplyPreference(const char* pref_path, + Value* pref_value) { + profile()->GetExtensionService()->extension_prefs() + ->SetExtensionControlledPref(extension_id(), pref_path, pref_value); } diff --git a/chrome/browser/extensions/extension_proxy_api.h b/chrome/browser/extensions/extension_proxy_api.h index 95be304..d645c44 100644 --- a/chrome/browser/extensions/extension_proxy_api.h +++ b/chrome/browser/extensions/extension_proxy_api.h @@ -33,14 +33,12 @@ class UseCustomProxySettingsFunction : public SyncExtensionFunction { bool GetProxyServer(const DictionaryValue* dict, ProxyServer* proxy_server); - bool ApplyAutoDetect(bool auto_detect); + bool ApplyMode(const std::string& mode); bool ApplyPacScript(DictionaryValue* pac_dict); bool ApplyProxyRules(DictionaryValue* proxy_rules); - // Sends a notification that the given pref would like to change to the - // indicated pref_value. This is mainly useful so the ExtensionPrefStore can - // apply the requested change. - void SendNotification(const char* pref_path, Value* pref_value); + // Takes ownership of |pref_value|. + void ApplyPreference(const char* pref_path, Value* pref_value); }; #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_PROXY_API_H_ diff --git a/chrome/browser/extensions/extension_proxy_apitest.cc b/chrome/browser/extensions/extension_proxy_apitest.cc index 7f83407..5537f32 100644 --- a/chrome/browser/extensions/extension_proxy_apitest.cc +++ b/chrome/browser/extensions/extension_proxy_apitest.cc @@ -4,13 +4,46 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/prefs/proxy_prefs.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/pref_names.h" -// Tests auto-detect and PAC proxy settings. +// Tests direct connection settings. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyDirectSettings) { + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableExperimentalExtensionApis); + + ASSERT_TRUE(RunExtensionTest("proxy/direct")) << message_; + const Extension* extension = GetSingleLoadedExtension(); + ASSERT_TRUE(extension); + + PrefService* pref_service = browser()->profile()->GetPrefs(); + + const PrefService::Preference* pref = + pref_service->FindPreference(prefs::kProxyMode); + ASSERT_TRUE(pref != NULL); + ASSERT_TRUE(pref->IsExtensionControlled()); + int mode = pref_service->GetInteger(prefs::kProxyMode); + EXPECT_EQ(ProxyPrefs::MODE_DIRECT, mode); + + // Other proxy prefs should also be set, so they're all controlled from one + // place. + pref = pref_service->FindPreference(prefs::kProxyPacUrl); + ASSERT_TRUE(pref != NULL); + EXPECT_TRUE(pref->IsExtensionControlled()); + EXPECT_EQ("", pref_service->GetString(prefs::kProxyPacUrl)); + + // No manual proxy prefs were set. + pref = pref_service->FindPreference(prefs::kProxyServer); + ASSERT_TRUE(pref != NULL); + EXPECT_TRUE(pref->IsExtensionControlled()); + EXPECT_EQ("", pref_service->GetString(prefs::kProxyServer)); +} + +// Tests auto-detect settings. IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyAutoSettings) { CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableExperimentalExtensionApis); @@ -22,11 +55,37 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyAutoSettings) { PrefService* pref_service = browser()->profile()->GetPrefs(); const PrefService::Preference* pref = - pref_service->FindPreference(prefs::kProxyAutoDetect); + pref_service->FindPreference(prefs::kProxyMode); + ASSERT_TRUE(pref != NULL); + ASSERT_TRUE(pref->IsExtensionControlled()); + int mode = pref_service->GetInteger(prefs::kProxyMode); + EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT, mode); + + // Other proxy prefs should also be set, so they're all controlled from one + // place. + pref = pref_service->FindPreference(prefs::kProxyPacUrl); + ASSERT_TRUE(pref != NULL); + EXPECT_TRUE(pref->IsExtensionControlled()); + EXPECT_EQ("", pref_service->GetString(prefs::kProxyPacUrl)); +} + +// Tests PAC proxy settings. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyPacScript) { + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableExperimentalExtensionApis); + + ASSERT_TRUE(RunExtensionTest("proxy/pac")) << message_; + const Extension* extension = GetSingleLoadedExtension(); + ASSERT_TRUE(extension); + + PrefService* pref_service = browser()->profile()->GetPrefs(); + + const PrefService::Preference* pref = + pref_service->FindPreference(prefs::kProxyMode); ASSERT_TRUE(pref != NULL); ASSERT_TRUE(pref->IsExtensionControlled()); - bool auto_detect = pref_service->GetBoolean(prefs::kProxyAutoDetect); - EXPECT_TRUE(auto_detect); + int mode = pref_service->GetInteger(prefs::kProxyMode); + EXPECT_EQ(ProxyPrefs::MODE_PAC_SCRIPT, mode); pref = pref_service->FindPreference(prefs::kProxyPacUrl); ASSERT_TRUE(pref != NULL); @@ -37,11 +96,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyAutoSettings) { // No manual proxy prefs were set. pref = pref_service->FindPreference(prefs::kProxyServer); ASSERT_TRUE(pref != NULL); - EXPECT_TRUE(pref->IsDefaultValue()); + EXPECT_TRUE(pref->IsExtensionControlled()); + EXPECT_EQ("", pref_service->GetString(prefs::kProxyServer)); } // Tests setting a single proxy to cover all schemes. -IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyManualSingle) { +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyFixedSingle) { CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableExperimentalExtensionApis); @@ -64,19 +124,53 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyManualSingle) { // Other proxy prefs should also be set, so they're all controlled from one // place. - pref = pref_service->FindPreference(prefs::kProxyAutoDetect); + pref = pref_service->FindPreference(prefs::kProxyMode); + ASSERT_TRUE(pref != NULL); + EXPECT_TRUE(pref->IsExtensionControlled()); + EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS, + pref_service->GetInteger(prefs::kProxyMode)); + + pref = pref_service->FindPreference(prefs::kProxyPacUrl); ASSERT_TRUE(pref != NULL); EXPECT_TRUE(pref->IsExtensionControlled()); - EXPECT_FALSE(pref_service->GetBoolean(prefs::kProxyAutoDetect)); + EXPECT_EQ("", pref_service->GetString(prefs::kProxyPacUrl)); +} + +// Tests setting to use the system's proxy settings. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxySystem) { + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableExperimentalExtensionApis); + + ASSERT_TRUE(RunExtensionTest("proxy/system")) << message_; + const Extension* extension = GetSingleLoadedExtension(); + ASSERT_TRUE(extension); + + PrefService* pref_service = browser()->profile()->GetPrefs(); + + // There should be no values superseding the extension-set proxy in this test. + const PrefService::Preference* pref = + pref_service->FindPreference(prefs::kProxyMode); + ASSERT_TRUE(pref != NULL); + ASSERT_TRUE(pref->IsExtensionControlled()); + int proxy_server_mode = pref_service->GetInteger(prefs::kProxyMode); + EXPECT_EQ(ProxyPrefs::MODE_SYSTEM, proxy_server_mode); + // Other proxy prefs should also be set, so they're all controlled from one + // place. pref = pref_service->FindPreference(prefs::kProxyPacUrl); ASSERT_TRUE(pref != NULL); EXPECT_TRUE(pref->IsExtensionControlled()); EXPECT_EQ("", pref_service->GetString(prefs::kProxyPacUrl)); + + // No manual proxy prefs were set. + pref = pref_service->FindPreference(prefs::kProxyServer); + ASSERT_TRUE(pref != NULL); + EXPECT_TRUE(pref->IsExtensionControlled()); + EXPECT_EQ("", pref_service->GetString(prefs::kProxyServer)); } // Tests setting separate proxies for each scheme. -IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyManualIndividual) { +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyFixedIndividual) { CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableExperimentalExtensionApis); @@ -100,10 +194,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyManualIndividual) { // Other proxy prefs should also be set, so they're all controlled from one // place. - pref = pref_service->FindPreference(prefs::kProxyAutoDetect); + pref = pref_service->FindPreference(prefs::kProxyMode); ASSERT_TRUE(pref != NULL); EXPECT_TRUE(pref->IsExtensionControlled()); - EXPECT_FALSE(pref_service->GetBoolean(prefs::kProxyAutoDetect)); + EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS, + pref_service->GetInteger(prefs::kProxyMode)); pref = pref_service->FindPreference(prefs::kProxyPacUrl); ASSERT_TRUE(pref != NULL); diff --git a/chrome/browser/extensions/extension_rlz_apitest.cc b/chrome/browser/extensions/extension_rlz_apitest.cc index 10bfba6..efb275a 100644 --- a/chrome/browser/extensions/extension_rlz_apitest.cc +++ b/chrome/browser/extensions/extension_rlz_apitest.cc @@ -5,7 +5,6 @@ #include <map> #include "base/win/registry.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/extension_function.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_apitest.h" diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extension_service.cc index 6842a84..bb24e1e 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include <algorithm> @@ -47,10 +47,8 @@ #include "chrome/browser/extensions/external_pref_extension_provider.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url_model.h" -#include "chrome/browser/sync/glue/extension_sync_traits.h" -#include "chrome/browser/sync/glue/extension_util.h" #include "chrome/common/child_process_logging.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" @@ -146,14 +144,14 @@ void GetExplicitOriginsInExtent(const Extension* extension, PendingExtensionInfo::PendingExtensionInfo( const GURL& update_url, - PendingExtensionInfo::ExpectedCrxType expected_crx_type, + ShouldInstallExtensionPredicate should_install_extension, bool is_from_sync, bool install_silently, bool enable_on_install, bool enable_incognito_on_install, Extension::Location location) : update_url(update_url), - expected_crx_type(expected_crx_type), + should_install_extension(should_install_extension), is_from_sync(is_from_sync), install_silently(install_silently), enable_on_install(enable_on_install), @@ -162,7 +160,7 @@ PendingExtensionInfo::PendingExtensionInfo( PendingExtensionInfo::PendingExtensionInfo() : update_url(), - expected_crx_type(PendingExtensionInfo::UNKNOWN), + should_install_extension(NULL), is_from_sync(true), install_silently(false), enable_on_install(false), @@ -170,27 +168,27 @@ PendingExtensionInfo::PendingExtensionInfo() install_source(Extension::INVALID) {} -ExtensionsService::ExtensionRuntimeData::ExtensionRuntimeData() +ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData() : background_page_ready(false), being_upgraded(false) { } -ExtensionsService::ExtensionRuntimeData::~ExtensionRuntimeData() { +ExtensionService::ExtensionRuntimeData::~ExtensionRuntimeData() { } -// ExtensionsService. +// ExtensionService. -const char* ExtensionsService::kInstallDirectoryName = "Extensions"; -const char* ExtensionsService::kCurrentVersionFileName = "Current Version"; +const char* ExtensionService::kInstallDirectoryName = "Extensions"; +const char* ExtensionService::kCurrentVersionFileName = "Current Version"; -// Implements IO for the ExtensionsService. +// Implements IO for the ExtensionService. -class ExtensionsServiceBackend - : public base::RefCountedThreadSafe<ExtensionsServiceBackend>, +class ExtensionServiceBackend + : public base::RefCountedThreadSafe<ExtensionServiceBackend>, public ExternalExtensionProvider::Visitor { public: // |install_directory| is a path where to look for extensions to load. - ExtensionsServiceBackend(PrefService* prefs, + ExtensionServiceBackend(PrefService* prefs, const FilePath& install_directory); // Loads a single extension from |path| where |path| is the top directory of @@ -200,17 +198,16 @@ class ExtensionsServiceBackend // TODO(erikkay): It might be useful to be able to load a packed extension // (presumably into memory) without installing it. void LoadSingleExtension(const FilePath &path, - scoped_refptr<ExtensionsService> frontend); + scoped_refptr<ExtensionService> frontend); // Check externally updated extensions for updates and install if necessary. // Errors are reported through ExtensionErrorReporter. Succcess is not // reported. - void CheckForExternalUpdates(const std::set<std::string>& ids_to_ignore, - scoped_refptr<ExtensionsService> frontend); + void CheckForExternalUpdates(scoped_refptr<ExtensionService> frontend); // For the extension in |version_path| with |id|, check to see if it's an // externally managed extension. If so, tell the frontend to uninstall it. - void CheckExternalUninstall(scoped_refptr<ExtensionsService> frontend, + void CheckExternalUninstall(scoped_refptr<ExtensionService> frontend, const std::string& id); // Clear all ExternalExtensionProviders. @@ -234,9 +231,9 @@ class ExtensionsServiceBackend scoped_refptr<RefCountedList> forcelist); private: - friend class base::RefCountedThreadSafe<ExtensionsServiceBackend>; + friend class base::RefCountedThreadSafe<ExtensionServiceBackend>; - virtual ~ExtensionsServiceBackend(); + virtual ~ExtensionServiceBackend(); // Finish installing the extension in |crx_path| after it has been unpacked to // |unpacked_path|. If |expected_id| is not empty, it's verified against the @@ -256,7 +253,7 @@ class ExtensionsServiceBackend // This is a naked pointer which is set by each entry point. // The entry point is responsible for ensuring lifetime. - ExtensionsService* frontend_; + ExtensionService* frontend_; // The top-level extensions directory being installed to. FilePath install_directory_; @@ -278,10 +275,10 @@ class ExtensionsServiceBackend // if an update check is needed to install pending extensions. bool external_extension_added_; - DISALLOW_COPY_AND_ASSIGN(ExtensionsServiceBackend); + DISALLOW_COPY_AND_ASSIGN(ExtensionServiceBackend); }; -ExtensionsServiceBackend::ExtensionsServiceBackend( +ExtensionServiceBackend::ExtensionServiceBackend( PrefService* prefs, const FilePath& install_directory) : frontend_(NULL), @@ -303,17 +300,16 @@ ExtensionsServiceBackend::ExtensionsServiceBackend( // variable so that UpdateExternalPolicyExtensionProvider can access it and // update its extension list later. external_policy_extension_provider_.reset( - new ExternalPolicyExtensionProvider()); - external_policy_extension_provider_->SetPreferences( - prefs->GetList(prefs::kExtensionInstallForceList)); + new ExternalPolicyExtensionProvider( + prefs->GetList(prefs::kExtensionInstallForceList))); external_extension_providers_.push_back(external_policy_extension_provider_); } -ExtensionsServiceBackend::~ExtensionsServiceBackend() { +ExtensionServiceBackend::~ExtensionServiceBackend() { } -void ExtensionsServiceBackend::LoadSingleExtension( - const FilePath& path_in, scoped_refptr<ExtensionsService> frontend) { +void ExtensionServiceBackend::LoadSingleExtension( + const FilePath& path_in, scoped_refptr<ExtensionService> frontend) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); frontend_ = frontend; @@ -341,18 +337,18 @@ void ExtensionsServiceBackend::LoadSingleExtension( BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod(frontend_, - &ExtensionsService::OnExtensionInstalled, + &ExtensionService::OnExtensionInstalled, extension)); } -void ExtensionsServiceBackend::ReportExtensionLoadError( +void ExtensionServiceBackend::ReportExtensionLoadError( const FilePath& extension_path, const std::string &error) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod( frontend_, - &ExtensionsService::ReportExtensionLoadError, extension_path, + &ExtensionService::ReportExtensionLoadError, extension_path, error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_)); } @@ -362,9 +358,8 @@ void ExtensionsServiceBackend::ReportExtensionLoadError( // (and also, on Windows, in the registry) and this code will periodically // check that location for a .crx file, which it will then install locally if // a new version is available. -void ExtensionsServiceBackend::CheckForExternalUpdates( - const std::set<std::string>& ids_to_ignore, - scoped_refptr<ExtensionsService> frontend) { +void ExtensionServiceBackend::CheckForExternalUpdates( + scoped_refptr<ExtensionService> frontend) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); // Note that this installation is intentionally silent (since it didn't @@ -382,7 +377,7 @@ void ExtensionsServiceBackend::CheckForExternalUpdates( for (i = external_extension_providers_.begin(); i != external_extension_providers_.end(); ++i) { ExternalExtensionProvider* provider = i->get(); - provider->VisitRegisteredExtension(this, ids_to_ignore); + provider->VisitRegisteredExtension(this); } if (external_extension_added_ && frontend->updater()) { @@ -393,8 +388,8 @@ void ExtensionsServiceBackend::CheckForExternalUpdates( } } -void ExtensionsServiceBackend::CheckExternalUninstall( - scoped_refptr<ExtensionsService> frontend, const std::string& id) { +void ExtensionServiceBackend::CheckExternalUninstall( + scoped_refptr<ExtensionService> frontend, const std::string& id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); // Check if the providers know about this extension. @@ -409,27 +404,27 @@ void ExtensionsServiceBackend::CheckExternalUninstall( BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod( - frontend.get(), &ExtensionsService::UninstallExtension, id, true)); + frontend.get(), &ExtensionService::UninstallExtension, id, true)); } -void ExtensionsServiceBackend::UpdateExternalPolicyExtensionProvider( +void ExtensionServiceBackend::UpdateExternalPolicyExtensionProvider( scoped_refptr<RefCountedList> forcelist) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); external_policy_extension_provider_->SetPreferences(forcelist->Get()); } -void ExtensionsServiceBackend::ClearProvidersForTesting() { +void ExtensionServiceBackend::ClearProvidersForTesting() { external_extension_providers_.clear(); } -void ExtensionsServiceBackend::AddProviderForTesting( +void ExtensionServiceBackend::AddProviderForTesting( ExternalExtensionProvider* test_provider) { DCHECK(test_provider); external_extension_providers_.push_back( linked_ptr<ExternalExtensionProvider>(test_provider)); } -void ExtensionsServiceBackend::OnExternalExtensionFileFound( +void ExtensionServiceBackend::OnExternalExtensionFileFound( const std::string& id, const Version* version, const FilePath& path, Extension::Location location) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); @@ -438,11 +433,11 @@ void ExtensionsServiceBackend::OnExternalExtensionFileFound( BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod( - frontend_, &ExtensionsService::OnExternalExtensionFileFound, id, + frontend_, &ExtensionService::OnExternalExtensionFileFound, id, version->GetString(), path, location)); } -void ExtensionsServiceBackend::OnExternalExtensionUpdateUrlFound( +void ExtensionServiceBackend::OnExternalExtensionUpdateUrlFound( const std::string& id, const GURL& update_url, Extension::Location location) { @@ -457,12 +452,12 @@ void ExtensionsServiceBackend::OnExternalExtensionUpdateUrlFound( BrowserThread::UI, FROM_HERE, NewRunnableMethod( frontend_, - &ExtensionsService::AddPendingExtensionFromExternalUpdateUrl, + &ExtensionService::AddPendingExtensionFromExternalUpdateUrl, id, update_url, location)); external_extension_added_ |= true; } -bool ExtensionsService::IsDownloadFromGallery(const GURL& download_url, +bool ExtensionService::IsDownloadFromGallery(const GURL& download_url, const GURL& referrer_url) { // Special-case the themes mini-gallery. // TODO(erikkay) When that gallery goes away, remove this code. @@ -511,15 +506,25 @@ bool ExtensionsService::IsDownloadFromGallery(const GURL& download_url, return (referrer_valid && download_valid); } -bool ExtensionsService::IsDownloadFromMiniGallery(const GURL& download_url) { +bool ExtensionService::IsDownloadFromMiniGallery(const GURL& download_url) { return StartsWithASCII(download_url.spec(), extension_urls::kMiniGalleryDownloadPrefix, false); // case_sensitive } +bool ExtensionService::IsInstalledApp(const GURL& url) { + // Check for hosted app. + if (GetExtensionByWebExtent(url) != NULL) + return true; + + // Check for packaged app. + const Extension* extension = GetExtensionByURL(url); + return extension != NULL && extension->is_app(); +} + // static -bool ExtensionsService::UninstallExtensionHelper( - ExtensionsService* extensions_service, +bool ExtensionService::UninstallExtensionHelper( + ExtensionService* extensions_service, const std::string& extension_id) { DCHECK(extensions_service); @@ -536,20 +541,19 @@ bool ExtensionsService::UninstallExtensionHelper( return true; } -ExtensionsService::ExtensionsService(Profile* profile, +ExtensionService::ExtensionService(Profile* profile, const CommandLine* command_line, const FilePath& install_directory, + ExtensionPrefs* extension_prefs, bool autoupdate_enabled) : profile_(profile), - extension_prefs_(new ExtensionPrefs(profile->GetPrefs(), - install_directory)), + extension_prefs_(extension_prefs), install_directory_(install_directory), extensions_enabled_(true), show_extensions_prompts_(true), ready_(false), ALLOW_THIS_IN_INITIALIZER_LIST(toolbar_model_(this)), - default_apps_(profile->GetPrefs(), - g_browser_process->GetApplicationLocale()), + default_apps_(profile->GetPrefs()), event_routers_initialized_(false) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -580,7 +584,7 @@ ExtensionsService::ExtensionsService(Profile* profile, update_frequency); } - backend_ = new ExtensionsServiceBackend(profile->GetPrefs(), + backend_ = new ExtensionServiceBackend(profile->GetPrefs(), install_directory_); // Use monochrome icons for Omnibox icons. @@ -590,7 +594,23 @@ ExtensionsService::ExtensionsService(Profile* profile, 0, kOmniboxIconPaddingRight)); } -ExtensionsService::~ExtensionsService() { +const ExtensionList* ExtensionService::extensions() const { + return &extensions_; +} + +const ExtensionList* ExtensionService::disabled_extensions() const { + return &disabled_extensions_; +} + +const PendingExtensionMap& ExtensionService::pending_extensions() const { + return pending_extensions_; +} + +bool ExtensionService::HasInstalledExtensions() { + return !(extensions_.empty() && disabled_extensions_.empty()); +} + +ExtensionService::~ExtensionService() { DCHECK(!profile_); // Profile should have told us it's going away. UnloadAllExtensions(); if (updater_.get()) { @@ -598,14 +618,14 @@ ExtensionsService::~ExtensionsService() { } } -void ExtensionsService::InitEventRouters() { +void ExtensionService::InitEventRouters() { if (event_routers_initialized_) return; ExtensionHistoryEventRouter::GetInstance()->ObserveProfile(profile_); ExtensionAccessibilityEventRouter::GetInstance()->ObserveProfile(profile_); ExtensionBrowserEventRouter::GetInstance()->Init(profile_); - ExtensionBookmarkEventRouter::GetSingleton()->Observe( + ExtensionBookmarkEventRouter::GetInstance()->Observe( profile_->GetBookmarkModel()); ExtensionCookiesEventRouter::GetInstance()->Init(); ExtensionManagementEventRouter::GetInstance()->Init(); @@ -614,7 +634,12 @@ void ExtensionsService::InitEventRouters() { event_routers_initialized_ = true; } -void ExtensionsService::Init() { +const Extension* ExtensionService::GetExtensionById(const std::string& id, + bool include_disabled) { + return GetExtensionByIdInternal(id, true, include_disabled); +} + +void ExtensionService::Init() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(!ready_); // Can't redo init. @@ -634,7 +659,7 @@ void ExtensionsService::Init() { GarbageCollectExtensions(); } -void ExtensionsService::InstallExtension(const FilePath& extension_path) { +void ExtensionService::InstallExtension(const FilePath& extension_path) { scoped_refptr<CrxInstaller> installer( new CrxInstaller(this, // frontend NULL)); // no client (silent install) @@ -650,7 +675,7 @@ namespace { } } // namespace -void ExtensionsService::UpdateExtension(const std::string& id, +void ExtensionService::UpdateExtension(const std::string& id, const FilePath& extension_path, const GURL& download_url) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -689,9 +714,9 @@ void ExtensionsService::UpdateExtension(const std::string& id, installer->InstallCrx(extension_path); } -void ExtensionsService::AddPendingExtensionFromSync( +void ExtensionService::AddPendingExtensionFromSync( const std::string& id, const GURL& update_url, - PendingExtensionInfo::ExpectedCrxType expected_crx_type, + ShouldInstallExtensionPredicate should_install_extension, bool install_silently, bool enable_on_install, bool enable_incognito_on_install) { if (GetExtensionByIdInternal(id, true, true)) { @@ -700,22 +725,29 @@ void ExtensionsService::AddPendingExtensionFromSync( return; } - AddPendingExtensionInternal(id, update_url, expected_crx_type, true, + AddPendingExtensionInternal(id, update_url, should_install_extension, true, install_silently, enable_on_install, enable_incognito_on_install, Extension::INTERNAL); } -void ExtensionsService::AddPendingExtensionFromExternalUpdateUrl( +namespace { + +bool AlwaysInstall(const Extension& extension) { + return true; +} + +} // namespace + +void ExtensionService::AddPendingExtensionFromExternalUpdateUrl( const std::string& id, const GURL& update_url, Extension::Location location) { - // Add the extension to this list of extensions to update. - const PendingExtensionInfo::ExpectedCrxType kExpectedCrxType = - PendingExtensionInfo::UNKNOWN; const bool kIsFromSync = false; const bool kInstallSilently = true; const bool kEnableOnInstall = true; const bool kEnableIncognitoOnInstall = false; + if (extension_prefs_->IsExtensionKilled(id)) + return; if (GetExtensionByIdInternal(id, true, true)) { LOG(DFATAL) << "Trying to add extension " << id @@ -723,17 +755,25 @@ void ExtensionsService::AddPendingExtensionFromExternalUpdateUrl( return; } - AddPendingExtensionInternal(id, update_url, kExpectedCrxType, kIsFromSync, - kInstallSilently, kEnableOnInstall, - kEnableIncognitoOnInstall, + AddPendingExtensionInternal(id, update_url, &AlwaysInstall, + kIsFromSync, kInstallSilently, + kEnableOnInstall, kEnableIncognitoOnInstall, location); } -void ExtensionsService::AddPendingExtensionFromDefaultAppList( +namespace { + +bool IsApp(const Extension& extension) { + return extension.is_app(); +} + +} // namespace + +// TODO(akalin): Change DefaultAppList to DefaultExtensionList and +// remove the IsApp() check. + +void ExtensionService::AddPendingExtensionFromDefaultAppList( const std::string& id) { - // Add the extension to this list of extensions to update. - const PendingExtensionInfo::ExpectedCrxType kExpectedCrxType = - PendingExtensionInfo::APP; const bool kIsFromSync = false; const bool kInstallSilently = true; const bool kEnableOnInstall = true; @@ -744,15 +784,15 @@ void ExtensionsService::AddPendingExtensionFromDefaultAppList( if (GetExtensionByIdInternal(id, true, true)) return; - AddPendingExtensionInternal(id, GURL(), kExpectedCrxType, kIsFromSync, - kInstallSilently, kEnableOnInstall, - kEnableIncognitoOnInstall, + AddPendingExtensionInternal(id, GURL(), &IsApp, + kIsFromSync, kInstallSilently, + kEnableOnInstall, kEnableIncognitoOnInstall, Extension::INTERNAL); } -void ExtensionsService::AddPendingExtensionInternal( +void ExtensionService::AddPendingExtensionInternal( const std::string& id, const GURL& update_url, - PendingExtensionInfo::ExpectedCrxType expected_crx_type, + ShouldInstallExtensionPredicate should_install_extension, bool is_from_sync, bool install_silently, bool enable_on_install, bool enable_incognito_on_install, Extension::Location install_source) { @@ -776,14 +816,13 @@ void ExtensionsService::AddPendingExtensionInternal( return; } - pending_extensions_[id] = - PendingExtensionInfo(update_url, expected_crx_type, is_from_sync, - install_silently, enable_on_install, + PendingExtensionInfo(update_url, should_install_extension, + is_from_sync, install_silently, enable_on_install, enable_incognito_on_install, install_source); } -void ExtensionsService::ReloadExtension(const std::string& extension_id) { +void ExtensionService::ReloadExtension(const std::string& extension_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); FilePath path; const Extension* current_extension = GetExtensionById(extension_id, false); @@ -826,7 +865,7 @@ void ExtensionsService::ReloadExtension(const std::string& extension_id) { } } -void ExtensionsService::UninstallExtension(const std::string& extension_id, +void ExtensionService::UninstallExtension(const std::string& extension_id, bool external_uninstall) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -843,7 +882,7 @@ void ExtensionsService::UninstallExtension(const std::string& extension_id, UninstalledExtensionInfo uninstalled_extension_info(*extension); UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType", - extension->GetHistogramType(), 100); + extension->GetType(), 100); // Also copy the extension identifier since the reference might have been // obtained via Extension::id(). @@ -854,7 +893,7 @@ void ExtensionsService::UninstallExtension(const std::string& extension_id, // Unload before doing more cleanup to ensure that nothing is hanging on to // any of these resources. - UnloadExtension(extension_id); + UnloadExtension(extension_id, UnloadedExtensionInfo::UNINSTALL); extension_prefs_->OnExtensionUninstalled(extension_id_copy, location, external_uninstall); @@ -878,13 +917,13 @@ void ExtensionsService::UninstallExtension(const std::string& extension_id, Details<UninstalledExtensionInfo>(&uninstalled_extension_info)); } -void ExtensionsService::ClearExtensionData(const GURL& extension_url) { +void ExtensionService::ClearExtensionData(const GURL& extension_url) { scoped_refptr<ExtensionDataDeleter> deleter( new ExtensionDataDeleter(profile_, extension_url)); deleter->StartDeleting(); } -void ExtensionsService::EnableExtension(const std::string& extension_id) { +void ExtensionService::EnableExtension(const std::string& extension_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); const Extension* extension = @@ -911,7 +950,7 @@ void ExtensionsService::EnableExtension(const std::string& extension_id) { UpdateActiveExtensionsInCrashReporter(); } -void ExtensionsService::DisableExtension(const std::string& extension_id) { +void ExtensionService::DisableExtension(const std::string& extension_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); const Extension* extension = @@ -932,11 +971,11 @@ void ExtensionsService::DisableExtension(const std::string& extension_id) { ExtensionDOMUI::UnregisterChromeURLOverrides(profile_, extension->GetChromeURLOverrides()); - NotifyExtensionUnloaded(extension); + NotifyExtensionUnloaded(extension, UnloadedExtensionInfo::DISABLE); UpdateActiveExtensionsInCrashReporter(); } -void ExtensionsService::GrantPermissions(const Extension* extension) { +void ExtensionService::GrantPermissions(const Extension* extension) { CHECK(extension); // We only maintain the granted permissions prefs for INTERNAL extensions. @@ -949,7 +988,7 @@ void ExtensionsService::GrantPermissions(const Extension* extension) { effective_hosts); } -void ExtensionsService::GrantPermissionsAndEnableExtension( +void ExtensionService::GrantPermissionsAndEnableExtension( const Extension* extension) { CHECK(extension); GrantPermissions(extension); @@ -957,16 +996,16 @@ void ExtensionsService::GrantPermissionsAndEnableExtension( EnableExtension(extension->id()); } -void ExtensionsService::LoadExtension(const FilePath& extension_path) { +void ExtensionService::LoadExtension(const FilePath& extension_path) { BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableMethod( backend_.get(), - &ExtensionsServiceBackend::LoadSingleExtension, - extension_path, scoped_refptr<ExtensionsService>(this))); + &ExtensionServiceBackend::LoadSingleExtension, + extension_path, scoped_refptr<ExtensionService>(this))); } -void ExtensionsService::LoadComponentExtensions() { +void ExtensionService::LoadComponentExtensions() { for (RegisteredComponentExtensions::iterator it = component_extension_manifests_.begin(); it != component_extension_manifests_.end(); ++it) { @@ -993,7 +1032,7 @@ void ExtensionsService::LoadComponentExtensions() { } } -void ExtensionsService::LoadAllExtensions() { +void ExtensionService::LoadAllExtensions() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); base::TimeTicks start_time = base::TimeTicks::Now(); @@ -1072,7 +1111,7 @@ void ExtensionsService::LoadAllExtensions() { ExtensionList::iterator ex; for (ex = extensions_.begin(); ex != extensions_.end(); ++ex) { Extension::Location location = (*ex)->location(); - Extension::HistogramType type = (*ex)->GetHistogramType(); + Extension::Type type = (*ex)->GetType(); if ((*ex)->is_app()) { UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation", location, 100); @@ -1134,7 +1173,7 @@ void ExtensionsService::LoadAllExtensions() { browser_action_count); } -void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info, +void ExtensionService::LoadInstalledExtension(const ExtensionInfo& info, bool write_to_prefs) { std::string error; scoped_refptr<const Extension> extension(NULL); @@ -1167,13 +1206,13 @@ void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info, BrowserThread::FILE, FROM_HERE, NewRunnableMethod( backend_.get(), - &ExtensionsServiceBackend::CheckExternalUninstall, - scoped_refptr<ExtensionsService>(this), + &ExtensionServiceBackend::CheckExternalUninstall, + scoped_refptr<ExtensionService>(this), info.extension_id)); } } -void ExtensionsService::NotifyExtensionLoaded(const Extension* extension) { +void ExtensionService::NotifyExtensionLoaded(const Extension* extension) { // The ChromeURLRequestContexts need to be first to know that the extension // was loaded, otherwise a race can arise where a renderer that is created // for the extension may try to load an extension URL with an extension id @@ -1199,11 +1238,13 @@ void ExtensionsService::NotifyExtensionLoaded(const Extension* extension) { Details<const Extension>(extension)); } -void ExtensionsService::NotifyExtensionUnloaded(const Extension* extension) { +void ExtensionService::NotifyExtensionUnloaded( + const Extension* extension, UnloadedExtensionInfo::Reason reason) { + UnloadedExtensionInfo details(extension, reason); NotificationService::current()->Notify( NotificationType::EXTENSION_UNLOADED, Source<Profile>(profile_), - Details<const Extension>(extension)); + Details<UnloadedExtensionInfo>(&details)); if (profile_) { profile_->UnregisterExtensionWithRequestContexts(extension); @@ -1219,7 +1260,7 @@ void ExtensionsService::NotifyExtensionUnloaded(const Extension* extension) { } } -void ExtensionsService::GrantProtectedStorage(const Extension* extension) { +void ExtensionService::GrantProtectedStorage(const Extension* extension) { DCHECK(extension->is_app()) << "Only Apps are allowed protected storage."; std::vector<GURL> origins; GetExplicitOriginsInExtent(extension, &origins); @@ -1227,7 +1268,7 @@ void ExtensionsService::GrantProtectedStorage(const Extension* extension) { ++protected_storage_map_[origins[i]]; } -void ExtensionsService::RevokeProtectedStorage(const Extension* extension) { +void ExtensionService::RevokeProtectedStorage(const Extension* extension) { DCHECK(extension->is_app()) << "Attempting to revoke protected storage from " << " a non-app extension."; std::vector<GURL> origins; @@ -1240,7 +1281,7 @@ void ExtensionsService::RevokeProtectedStorage(const Extension* extension) { } } -void ExtensionsService::GrantUnlimitedStorage(const Extension* extension) { +void ExtensionService::GrantUnlimitedStorage(const Extension* extension) { DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission)); std::vector<GURL> origins; GetExplicitOriginsInExtent(extension, &origins); @@ -1269,13 +1310,13 @@ void ExtensionsService::GrantUnlimitedStorage(const Extension* extension) { BrowserThread::IO, FROM_HERE, NewRunnableMethod( profile_->GetFileSystemContext(), - &BrowserFileSystemContext::SetOriginQuotaUnlimited, + &fileapi::SandboxedFileSystemContext::SetOriginQuotaUnlimited, origin)); } } } -void ExtensionsService::RevokeUnlimitedStorage(const Extension* extension) { +void ExtensionService::RevokeUnlimitedStorage(const Extension* extension) { DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission)); std::vector<GURL> origins; GetExplicitOriginsInExtent(extension, &origins); @@ -1304,13 +1345,13 @@ void ExtensionsService::RevokeUnlimitedStorage(const Extension* extension) { BrowserThread::IO, FROM_HERE, NewRunnableMethod( profile_->GetFileSystemContext(), - &BrowserFileSystemContext::ResetOriginQuotaUnlimited, + &fileapi::SandboxedFileSystemContext::ResetOriginQuotaUnlimited, origin)); } } } -void ExtensionsService::UpdateExtensionBlacklist( +void ExtensionService::UpdateExtensionBlacklist( const std::vector<std::string>& blacklist) { // Use this set to indicate if an extension in the blacklist has been used. std::set<std::string> blacklist_set; @@ -1333,17 +1374,21 @@ void ExtensionsService::UpdateExtensionBlacklist( // UnloadExtension will change the extensions_ list. So, we should // call it outside the iterator loop. for (unsigned int i = 0; i < to_be_removed.size(); ++i) { - UnloadExtension(to_be_removed[i]); + UnloadExtension(to_be_removed[i], UnloadedExtensionInfo::DISABLE); } } -void ExtensionsService::DestroyingProfile() { +void ExtensionService::DestroyingProfile() { pref_change_registrar_.RemoveAll(); profile_ = NULL; toolbar_model_.DestroyingProfile(); } -void ExtensionsService::CheckAdminBlacklist() { +ExtensionPrefs* ExtensionService::extension_prefs() { + return extension_prefs_; +} + +void ExtensionService::CheckAdminBlacklist() { std::vector<std::string> to_be_removed; // Loop through extensions list, unload installed extensions. for (ExtensionList::const_iterator iter = extensions_.begin(); @@ -1356,10 +1401,10 @@ void ExtensionsService::CheckAdminBlacklist() { // UnloadExtension will change the extensions_ list. So, we should // call it outside the iterator loop. for (unsigned int i = 0; i < to_be_removed.size(); ++i) - UnloadExtension(to_be_removed[i]); + UnloadExtension(to_be_removed[i], UnloadedExtensionInfo::DISABLE); } -bool ExtensionsService::IsIncognitoEnabled(const Extension* extension) { +bool ExtensionService::IsIncognitoEnabled(const Extension* extension) { // If this is a component extension we always allow it to work in incognito // mode. if (extension->location() == Extension::COMPONENT) @@ -1369,7 +1414,7 @@ bool ExtensionsService::IsIncognitoEnabled(const Extension* extension) { return extension_prefs_->IsIncognitoEnabled(extension->id()); } -void ExtensionsService::SetIsIncognitoEnabled(const Extension* extension, +void ExtensionService::SetIsIncognitoEnabled(const Extension* extension, bool enabled) { extension_prefs_->SetIsIncognitoEnabled(extension->id(), enabled); @@ -1378,25 +1423,25 @@ void ExtensionsService::SetIsIncognitoEnabled(const Extension* extension, bool is_enabled = std::find(extensions_.begin(), extensions_.end(), extension) != extensions_.end(); if (is_enabled) { - NotifyExtensionUnloaded(extension); + NotifyExtensionUnloaded(extension, UnloadedExtensionInfo::DISABLE); NotifyExtensionLoaded(extension); } } -bool ExtensionsService::CanCrossIncognito(const Extension* extension) { +bool ExtensionService::CanCrossIncognito(const Extension* extension) { // We allow the extension to see events and data from another profile iff it // uses "spanning" behavior and it has incognito access. "split" mode // extensions only see events for a matching profile. return IsIncognitoEnabled(extension) && !extension->incognito_split_mode(); } -bool ExtensionsService::AllowFileAccess(const Extension* extension) { +bool ExtensionService::AllowFileAccess(const Extension* extension) { return (CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableExtensionsFileAccessCheck) || extension_prefs_->AllowFileAccess(extension->id())); } -void ExtensionsService::SetAllowFileAccess(const Extension* extension, +void ExtensionService::SetAllowFileAccess(const Extension* extension, bool allow) { extension_prefs_->SetAllowFileAccess(extension->id(), allow); NotificationService::current()->Notify( @@ -1405,29 +1450,24 @@ void ExtensionsService::SetAllowFileAccess(const Extension* extension, Details<const Extension>(extension)); } -bool ExtensionsService::GetBrowserActionVisibility(const Extension* extension) { +bool ExtensionService::GetBrowserActionVisibility(const Extension* extension) { return extension_prefs_->GetBrowserActionVisibility(extension); } -void ExtensionsService::SetBrowserActionVisibility(const Extension* extension, +void ExtensionService::SetBrowserActionVisibility(const Extension* extension, bool visible) { extension_prefs_->SetBrowserActionVisibility(extension, visible); } -void ExtensionsService::CheckForExternalUpdates() { - // This installs or updates externally provided extensions. - // TODO(aa): Why pass this list into the provider, why not just filter it - // later? - std::set<std::string> killed_extensions; - extension_prefs_->GetKilledExtensionIds(&killed_extensions); +void ExtensionService::CheckForExternalUpdates() { BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableMethod( - backend_.get(), &ExtensionsServiceBackend::CheckForExternalUpdates, - killed_extensions, scoped_refptr<ExtensionsService>(this))); + backend_.get(), &ExtensionServiceBackend::CheckForExternalUpdates, + scoped_refptr<ExtensionService>(this))); } -void ExtensionsService::UpdateExternalPolicyExtensionProvider() { +void ExtensionService::UpdateExternalPolicyExtensionProvider() { const ListValue* list_pref = profile_->GetPrefs()->GetList(prefs::kExtensionInstallForceList); ListValue* list_copy = NULL; @@ -1437,12 +1477,14 @@ void ExtensionsService::UpdateExternalPolicyExtensionProvider() { BrowserThread::FILE, FROM_HERE, NewRunnableMethod( backend_.get(), - &ExtensionsServiceBackend::UpdateExternalPolicyExtensionProvider, + &ExtensionServiceBackend::UpdateExternalPolicyExtensionProvider, scoped_refptr<RefCountedList>( new RefCountedList(list_copy)))); } -void ExtensionsService::UnloadExtension(const std::string& extension_id) { +void ExtensionService::UnloadExtension( + const std::string& extension_id, + UnloadedExtensionInfo::Reason reason) { // Make sure the extension gets deleted after we return from this function. scoped_refptr<const Extension> extension( GetExtensionByIdInternal(extension_id, true, true)); @@ -1469,11 +1511,13 @@ void ExtensionsService::UnloadExtension(const std::string& extension_id) { disabled_extensions_.end(), extension.get()); if (iter != disabled_extensions_.end()) { + UnloadedExtensionInfo details(extension, reason); + details.already_disabled = true; disabled_extensions_.erase(iter); NotificationService::current()->Notify( - NotificationType::EXTENSION_UNLOADED_DISABLED, + NotificationType::EXTENSION_UNLOADED, Source<Profile>(profile_), - Details<const Extension>(extension.get())); + Details<UnloadedExtensionInfo>(&details)); return; } @@ -1482,11 +1526,11 @@ void ExtensionsService::UnloadExtension(const std::string& extension_id) { // Remove the extension from our list. extensions_.erase(iter); - NotifyExtensionUnloaded(extension.get()); + NotifyExtensionUnloaded(extension.get(), reason); UpdateActiveExtensionsInCrashReporter(); } -void ExtensionsService::UnloadAllExtensions() { +void ExtensionService::UnloadAllExtensions() { extensions_.clear(); disabled_extensions_.clear(); extension_runtime_data_.clear(); @@ -1496,13 +1540,13 @@ void ExtensionsService::UnloadAllExtensions() { // or uninstalled, and UnloadAll is just part of shutdown. } -void ExtensionsService::ReloadExtensions() { +void ExtensionService::ReloadExtensions() { UnloadAllExtensions(); LoadAllExtensions(); } -void ExtensionsService::GarbageCollectExtensions() { - if (extension_prefs_->pref_service()->read_only()) +void ExtensionService::GarbageCollectExtensions() { + if (extension_prefs_->pref_service()->ReadOnly()) return; scoped_ptr<ExtensionPrefs::ExtensionsInfo> info( @@ -1526,7 +1570,7 @@ void ExtensionsService::GarbageCollectExtensions() { } } -void ExtensionsService::OnLoadedInstalledExtensions() { +void ExtensionService::OnLoadedInstalledExtensions() { if (updater_.get()) { updater_->Start(); } @@ -1538,7 +1582,7 @@ void ExtensionsService::OnLoadedInstalledExtensions() { NotificationService::NoDetails()); } -void ExtensionsService::OnExtensionLoaded(const Extension* extension) { +void ExtensionService::OnExtensionLoaded(const Extension* extension) { // Ensure extension is deleted unless we transfer ownership. scoped_refptr<const Extension> scoped_extension(extension); @@ -1598,7 +1642,7 @@ void ExtensionsService::OnExtensionLoaded(const Extension* extension) { } } -void ExtensionsService::DisableIfPrivilegeIncrease(const Extension* extension) { +void ExtensionService::DisableIfPrivilegeIncrease(const Extension* extension) { // We keep track of all permissions the user has granted each extension. // This allows extensions to gracefully support backwards compatibility // by including unknown permissions in their manifests. When the user @@ -1654,8 +1698,10 @@ void ExtensionsService::DisableIfPrivilegeIncrease(const Extension* extension) { } if (is_extension_upgrade) { - // CrxInstaller should have guaranteed that we aren't downgrading. - CHECK(extension->version()->CompareTo(*(old->version())) >= 0); + // Other than for unpacked extensions, CrxInstaller should have guaranteed + // that we aren't downgrading. + if (extension->location() != Extension::LOAD) + CHECK(extension->version()->CompareTo(*(old->version())) >= 0); // Extensions get upgraded if the privileges are allowed to increase or // the privileges haven't increased. @@ -1666,7 +1712,7 @@ void ExtensionsService::DisableIfPrivilegeIncrease(const Extension* extension) { // To upgrade an extension in place, unload the old one and // then load the new one. - UnloadExtension(old->id()); + UnloadExtension(old->id(), UnloadedExtensionInfo::UPDATE); old = NULL; } @@ -1678,7 +1724,7 @@ void ExtensionsService::DisableIfPrivilegeIncrease(const Extension* extension) { } } -void ExtensionsService::UpdateActiveExtensionsInCrashReporter() { +void ExtensionService::UpdateActiveExtensionsInCrashReporter() { std::set<std::string> extension_ids; for (size_t i = 0; i < extensions_.size(); ++i) { if (!extensions_[i]->is_theme() && @@ -1689,7 +1735,7 @@ void ExtensionsService::UpdateActiveExtensionsInCrashReporter() { child_process_logging::SetActiveExtensions(extension_ids); } -void ExtensionsService::OnExtensionInstalled(const Extension* extension) { +void ExtensionService::OnExtensionInstalled(const Extension* extension) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // Ensure extension is deleted unless we transfer ownership. @@ -1700,25 +1746,17 @@ void ExtensionsService::OnExtensionInstalled(const Extension* extension) { pending_extensions_.find(extension->id()); if (it != pending_extensions_.end()) { PendingExtensionInfo pending_extension_info = it->second; - PendingExtensionInfo::ExpectedCrxType expected_crx_type = - pending_extension_info.expected_crx_type; - bool is_from_sync = pending_extension_info.is_from_sync; pending_extensions_.erase(it); it = pending_extensions_.end(); - // Set initial state from pending extension data. - PendingExtensionInfo::ExpectedCrxType actual_crx_type = - PendingExtensionInfo::EXTENSION; - if (extension->is_app()) - actual_crx_type = PendingExtensionInfo::APP; - else if (extension->is_theme()) - actual_crx_type = PendingExtensionInfo::THEME; - - if (expected_crx_type != PendingExtensionInfo::UNKNOWN && - expected_crx_type != actual_crx_type) { + if (!pending_extension_info.should_install_extension(*extension)) { LOG(WARNING) - << "Not installing pending extension " << extension->id() - << " with is_theme = " << extension->is_theme(); + << "should_install_extension (" + << pending_extension_info.should_install_extension + << ") returned false for " << extension->id() + << " of type " << extension->GetType() + << " and update URL " << extension->update_url().spec() + << "; not installing"; // Delete the extension directory since we're not going to // load it. BrowserThread::PostTask( @@ -1727,55 +1765,6 @@ void ExtensionsService::OnExtensionInstalled(const Extension* extension) { return; } - // If |extension| is not syncable, and was installed via sync, disallow - // the instanation. - // - // Themes are always allowed. Because they contain no active code, they - // are less of a risk than extensions. - // - // If |is_from_sync| is false, then the install was not initiated by sync, - // and this check should pass. Extensions that were installed from an - // update URL in external_extensions.json are an example. They are not - // syncable, because the user did not make an explicit choice to install - // them. However, they were installed through the update mechanism, so - // control must pass into this function. - // - // TODO(akalin): When we do apps sync, we have to work with its - // traits, too. - const browser_sync::ExtensionSyncTraits extension_sync_traits = - browser_sync::GetExtensionSyncTraits(); - const browser_sync::ExtensionSyncTraits app_sync_traits = - browser_sync::GetAppSyncTraits(); - // If an extension is a theme, we bypass the valid/syncable check - // as themes are harmless. - if (!extension->is_theme() && is_from_sync && - !browser_sync::IsExtensionValidAndSyncable( - *extension, extension_sync_traits.allowed_extension_types) && - !browser_sync::IsExtensionValidAndSyncable( - *extension, app_sync_traits.allowed_extension_types)) { - // We're an extension installed via sync that is unsyncable, - // i.e. we may have been syncable previously. We block these - // installs. We'll have to update the clause above if we decide - // to sync other extension-like things, like apps or user - // scripts. - // - // Note that this creates a small window where a user who tries - // to download/install an extension that is simultaneously - // installed via sync (and blocked) will find his download - // blocked. - // - // TODO(akalin): Remove this check once we've put in UI to - // approve synced extensions. - LOG(WARNING) - << "Not installing invalid or unsyncable extension " - << extension->id(); - // Delete the extension directory since we're not going to - // load it. - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableFunction(&DeleteFileHelper, extension->path(), true)); - return; - } if (extension->is_theme()) { DCHECK(pending_extension_info.enable_on_install); initial_state = Extension::ENABLED; @@ -1800,7 +1789,7 @@ void ExtensionsService::OnExtensionInstalled(const Extension* extension) { } UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType", - extension->GetHistogramType(), 100); + extension->GetType(), 100); ShownSectionsHandler::OnExtensionInstalled(profile_->GetPrefs(), extension); extension_prefs_->OnExtensionInstalled( extension, initial_state, initial_enable_incognito); @@ -1834,7 +1823,7 @@ void ExtensionsService::OnExtensionInstalled(const Extension* extension) { OnExtensionLoaded(scoped_extension); } -const Extension* ExtensionsService::GetExtensionByIdInternal( +const Extension* ExtensionService::GetExtensionByIdInternal( const std::string& id, bool include_enabled, bool include_disabled) { std::string lowercase_id = StringToLowerASCII(id); if (include_enabled) { @@ -1854,16 +1843,16 @@ const Extension* ExtensionsService::GetExtensionByIdInternal( return NULL; } -const Extension* ExtensionsService::GetWebStoreApp() { +const Extension* ExtensionService::GetWebStoreApp() { return GetExtensionById(extension_misc::kWebStoreAppId, false); } -const Extension* ExtensionsService::GetExtensionByURL(const GURL& url) { +const Extension* ExtensionService::GetExtensionByURL(const GURL& url) { return url.scheme() != chrome::kExtensionScheme ? NULL : GetExtensionById(url.host(), false); } -const Extension* ExtensionsService::GetExtensionByWebExtent(const GURL& url) { +const Extension* ExtensionService::GetExtensionByWebExtent(const GURL& url) { for (size_t i = 0; i < extensions_.size(); ++i) { if (extensions_[i]->web_extent().ContainsURL(url)) return extensions_[i]; @@ -1871,7 +1860,7 @@ const Extension* ExtensionsService::GetExtensionByWebExtent(const GURL& url) { return NULL; } -bool ExtensionsService::ExtensionBindingsAllowed(const GURL& url) { +bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) { // Allow bindings for all packaged extension. if (GetExtensionByURL(url)) return true; @@ -1881,7 +1870,7 @@ bool ExtensionsService::ExtensionBindingsAllowed(const GURL& url) { return (extension && extension->location() == Extension::COMPONENT); } -const Extension* ExtensionsService::GetExtensionByOverlappingWebExtent( +const Extension* ExtensionService::GetExtensionByOverlappingWebExtent( const ExtensionExtent& extent) { for (size_t i = 0; i < extensions_.size(); ++i) { if (extensions_[i]->web_extent().OverlapsWith(extent)) @@ -1891,38 +1880,40 @@ const Extension* ExtensionsService::GetExtensionByOverlappingWebExtent( return NULL; } -const SkBitmap& ExtensionsService::GetOmniboxIcon( +const SkBitmap& ExtensionService::GetOmniboxIcon( const std::string& extension_id) { return omnibox_icon_manager_.GetIcon(extension_id); } -const SkBitmap& ExtensionsService::GetOmniboxPopupIcon( +const SkBitmap& ExtensionService::GetOmniboxPopupIcon( const std::string& extension_id) { return omnibox_popup_icon_manager_.GetIcon(extension_id); } -void ExtensionsService::ClearProvidersForTesting() { +void ExtensionService::ClearProvidersForTesting() { BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableMethod( - backend_.get(), &ExtensionsServiceBackend::ClearProvidersForTesting)); + backend_.get(), &ExtensionServiceBackend::ClearProvidersForTesting)); } -void ExtensionsService::AddProviderForTesting( +void ExtensionService::AddProviderForTesting( ExternalExtensionProvider* test_provider) { BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableMethod( - backend_.get(), &ExtensionsServiceBackend::AddProviderForTesting, + backend_.get(), &ExtensionServiceBackend::AddProviderForTesting, test_provider)); } -void ExtensionsService::OnExternalExtensionFileFound( +void ExtensionService::OnExternalExtensionFileFound( const std::string& id, const std::string& version, const FilePath& path, Extension::Location location) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (extension_prefs_->IsExtensionKilled(id)) + return; // Before even bothering to unpack, check and see if we already have this // version. This is important because these extensions are going to get @@ -1944,6 +1935,20 @@ void ExtensionsService::OnExternalExtensionFileFound( } } + GURL update_url = GURL(); + bool is_from_sync = false; + bool install_silently = true; + bool enable_on_install = true; + bool enable_incognito_on_install = false; + pending_extensions_[id] = PendingExtensionInfo( + update_url, + &AlwaysInstall, + is_from_sync, + install_silently, + enable_on_install, + enable_incognito_on_install, + location); + scoped_refptr<CrxInstaller> installer( new CrxInstaller(this, // frontend NULL)); // no client (silent install) @@ -1952,7 +1957,7 @@ void ExtensionsService::OnExternalExtensionFileFound( installer->InstallCrx(path); } -void ExtensionsService::ReportExtensionLoadError( +void ExtensionService::ReportExtensionLoadError( const FilePath& extension_path, const std::string &error, NotificationType type, @@ -1970,7 +1975,7 @@ void ExtensionsService::ReportExtensionLoadError( ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy); } -void ExtensionsService::DidCreateRenderViewForBackgroundPage( +void ExtensionService::DidCreateRenderViewForBackgroundPage( ExtensionHost* host) { OrphanedDevTools::iterator iter = orphaned_dev_tools_.find(host->extension()->id()); @@ -1982,7 +1987,7 @@ void ExtensionsService::DidCreateRenderViewForBackgroundPage( orphaned_dev_tools_.erase(iter); } -void ExtensionsService::Observe(NotificationType type, +void ExtensionService::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { switch (type.value) { @@ -1997,8 +2002,10 @@ void ExtensionsService::Observe(NotificationType type, // We do it in a PostTask so that other handlers of this notification will // still have access to the Extension and ExtensionHost. MessageLoop::current()->PostTask(FROM_HERE, - NewRunnableMethod(this, &ExtensionsService::UnloadExtension, - host->extension()->id())); + NewRunnableMethod(this, + &ExtensionService::UnloadExtension, + host->extension()->id(), + UnloadedExtensionInfo::DISABLE)); break; } @@ -2024,11 +2031,11 @@ void ExtensionsService::Observe(NotificationType type, } } -bool ExtensionsService::HasApps() const { +bool ExtensionService::HasApps() const { return !GetAppIds().empty(); } -ExtensionIdSet ExtensionsService::GetAppIds() const { +ExtensionIdSet ExtensionService::GetAppIds() const { ExtensionIdSet result; for (ExtensionList::const_iterator it = extensions_.begin(); it != extensions_.end(); ++it) { @@ -2039,12 +2046,12 @@ ExtensionIdSet ExtensionsService::GetAppIds() const { return result; } -bool ExtensionsService::IsBackgroundPageReady(const Extension* extension) { +bool ExtensionService::IsBackgroundPageReady(const Extension* extension) { return (extension->background_url().is_empty() || extension_runtime_data_[extension->id()].background_page_ready); } -void ExtensionsService::SetBackgroundPageReady(const Extension* extension) { +void ExtensionService::SetBackgroundPageReady(const Extension* extension) { DCHECK(!extension->background_url().is_empty()); extension_runtime_data_[extension->id()].background_page_ready = true; NotificationService::current()->Notify( @@ -2053,15 +2060,15 @@ void ExtensionsService::SetBackgroundPageReady(const Extension* extension) { NotificationService::NoDetails()); } -bool ExtensionsService::IsBeingUpgraded(const Extension* extension) { +bool ExtensionService::IsBeingUpgraded(const Extension* extension) { return extension_runtime_data_[extension->id()].being_upgraded; } -void ExtensionsService::SetBeingUpgraded(const Extension* extension, +void ExtensionService::SetBeingUpgraded(const Extension* extension, bool value) { extension_runtime_data_[extension->id()].being_upgraded = value; } -PropertyBag* ExtensionsService::GetPropertyBag(const Extension* extension) { +PropertyBag* ExtensionService::GetPropertyBag(const Extension* extension) { return &extension_runtime_data_[extension->id()].property_bag; } diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extension_service.h index c831039..9e4206c 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extension_service.h @@ -2,12 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_ -#define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_ +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_ #pragma once #include <map> -#include <set> #include <string> #include <vector> @@ -35,41 +34,36 @@ #include "chrome/common/extensions/extension.h" #include "chrome/common/property_bag.h" -class ExtensionsServiceBackend; +class ExtensionServiceBackend; class ExtensionToolbarModel; class ExtensionUpdater; class GURL; -class PrefService; class Profile; class Version; +typedef bool (*ShouldInstallExtensionPredicate)(const Extension&); + // A pending extension is an extension that hasn't been installed yet // and is intended to be installed in the next auto-update cycle. The // update URL of a pending extension may be blank, in which case a // default one is assumed. struct PendingExtensionInfo { - // TODO(skerner): Consider merging ExpectedCrxType with - // browser_sync::ExtensionType. - enum ExpectedCrxType { - UNKNOWN, // Sometimes we don't know the type of a pending item. An - // update URL from external_extensions.json is one such case. - APP, - THEME, - EXTENSION - }; - - PendingExtensionInfo(const GURL& update_url, - ExpectedCrxType expected_crx_type, - bool is_from_sync, - bool install_silently, - bool enable_on_install, - bool enable_incognito_on_install, - Extension::Location install_source); + PendingExtensionInfo( + const GURL& update_url, + ShouldInstallExtensionPredicate should_install_extension, + bool is_from_sync, + bool install_silently, + bool enable_on_install, + bool enable_incognito_on_install, + Extension::Location install_source); PendingExtensionInfo(); GURL update_url; - ExpectedCrxType expected_crx_type; + // When the extension is about to be installed, this function is + // called. If this function returns true, the install proceeds. If + // this function returns false, the install is aborted. + ShouldInstallExtensionPredicate should_install_extension; bool is_from_sync; // This update check was initiated from sync. bool install_silently; bool enable_on_install; @@ -82,7 +76,7 @@ struct PendingExtensionInfo { typedef std::map<std::string, PendingExtensionInfo> PendingExtensionMap; // This is an interface class to encapsulate the dependencies that -// ExtensionUpdater has on ExtensionsService. This allows easy mocking. +// ExtensionUpdater has on ExtensionService. This allows easy mocking. class ExtensionUpdateService { public: virtual ~ExtensionUpdateService() {} @@ -101,8 +95,8 @@ class ExtensionUpdateService { }; // Manages installed and running Chromium extensions. -class ExtensionsService - : public base::RefCountedThreadSafe<ExtensionsService, +class ExtensionService + : public base::RefCountedThreadSafe<ExtensionService, BrowserThread::DeleteOnUIThread>, public ExtensionUpdateService, public NotificationObserver { @@ -116,7 +110,7 @@ class ExtensionsService } // The extension's manifest. This is required for component extensions so - // that ExtensionsService doesn't need to go to disk to load them. + // that ExtensionService doesn't need to go to disk to load them. std::string manifest; // Directory where the extension is stored. @@ -143,26 +137,28 @@ class ExtensionsService // Used to test if we need to show the "Loading" dialog for themes. static bool IsDownloadFromMiniGallery(const GURL& download_url); + // Returns whether the URL is from either a hosted or packaged app. + bool IsInstalledApp(const GURL& url); + // Attempts to uninstall an extension from a given ExtensionService. Returns // true iff the target extension exists. - static bool UninstallExtensionHelper(ExtensionsService* extensions_service, + static bool UninstallExtensionHelper(ExtensionService* extensions_service, const std::string& extension_id); - ExtensionsService(Profile* profile, + // Constructor stores pointers to |profile| and |extension_prefs| but + // ownership remains at caller. + ExtensionService(Profile* profile, const CommandLine* command_line, const FilePath& install_directory, + ExtensionPrefs* extension_prefs, bool autoupdate_enabled); // Gets the list of currently installed extensions. - virtual const ExtensionList* extensions() const { return &extensions_; } - virtual const ExtensionList* disabled_extensions() const { - return &disabled_extensions_; - } + virtual const ExtensionList* extensions() const; + virtual const ExtensionList* disabled_extensions() const; // Gets the set of pending extensions. - virtual const PendingExtensionMap& pending_extensions() const { - return pending_extensions_; - } + virtual const PendingExtensionMap& pending_extensions() const; // Registers an extension to be loaded as a component extension. void register_component_extension(const ComponentExtensionInfo& info) { @@ -170,9 +166,7 @@ class ExtensionsService } // Returns true if any extensions are installed. - virtual bool HasInstalledExtensions() { - return !(extensions_.empty() && disabled_extensions_.empty()); - } + virtual bool HasInstalledExtensions(); const FilePath& install_directory() const { return install_directory_; } @@ -215,10 +209,8 @@ class ExtensionsService void InitEventRouters(); // Look up an extension by ID. - const Extension* GetExtensionById(const std::string& id, - bool include_disabled) { - return GetExtensionByIdInternal(id, true, include_disabled); - } + virtual const Extension* GetExtensionById(const std::string& id, + bool include_disabled); // Install the extension file at |extension_path|. Will install as an // update if an older version is already installed. @@ -246,7 +238,7 @@ class ExtensionsService // pre-enabled permissions. void AddPendingExtensionFromSync( const std::string& id, const GURL& update_url, - const PendingExtensionInfo::ExpectedCrxType expected_crx_type, + ShouldInstallExtensionPredicate should_install_extension, bool install_silently, bool enable_on_install, bool enable_incognito_on_install); @@ -310,7 +302,8 @@ class ExtensionsService void UpdateExternalPolicyExtensionProvider(); // Unload the specified extension. - void UnloadExtension(const std::string& extension_id); + void UnloadExtension(const std::string& extension_id, + UnloadedExtensionInfo::Reason reason); // Unload all extensions. This is currently only called on shutdown, and // does not send notifications. @@ -402,7 +395,7 @@ class ExtensionsService // it. void DestroyingProfile(); - ExtensionPrefs* extension_prefs() { return extension_prefs_.get(); } + virtual ExtensionPrefs* extension_prefs(); // Whether the extension service is ready. // TODO(skerner): Get rid of this method. crbug.com/63756 @@ -422,7 +415,7 @@ class ExtensionsService } // Notify the frontend that there was an error loading an extension. - // This method is public because ExtensionsServiceBackend can post to here. + // This method is public because ExtensionServiceBackend can post to here. void ReportExtensionLoadError(const FilePath& extension_path, const std::string& error, NotificationType type, @@ -445,7 +438,7 @@ class ExtensionsService private: friend class BrowserThread; - friend class DeleteTask<ExtensionsService>; + friend class DeleteTask<ExtensionService>; // Contains Extension data that can change during the life of the process, // but does not persist across restarts. @@ -464,7 +457,7 @@ class ExtensionsService }; typedef std::map<std::string, ExtensionRuntimeData> ExtensionRuntimeDataMap; - virtual ~ExtensionsService(); + virtual ~ExtensionService(); // Clear all persistent data that may have been stored by the extension. void ClearExtensionData(const GURL& extension_url); @@ -475,11 +468,11 @@ class ExtensionsService bool include_enabled, bool include_disabled); - // Like AddPendingExtension() but assumes an extension with the same - // id is not already installed. + // Like AddPendingExtension*() functions above, but assumes an + // extension with the same id is not already installed. void AddPendingExtensionInternal( const std::string& id, const GURL& update_url, - PendingExtensionInfo::ExpectedCrxType crx_type, + ShouldInstallExtensionPredicate should_install_extension, bool is_from_sync, bool install_silently, bool enable_on_install, bool enable_incognito_on_install, Extension::Location install_source); @@ -488,7 +481,8 @@ class ExtensionsService void NotifyExtensionLoaded(const Extension* extension); // Handles sending notification that |extension| was unloaded. - void NotifyExtensionUnloaded(const Extension* extension); + void NotifyExtensionUnloaded(const Extension* extension, + UnloadedExtensionInfo::Reason reason); // Helper that updates the active extension list used for crash reporting. void UpdateActiveExtensionsInCrashReporter(); @@ -502,11 +496,11 @@ class ExtensionsService void GrantUnlimitedStorage(const Extension* extension); void RevokeUnlimitedStorage(const Extension* extension); - // The profile this ExtensionsService is part of. + // The profile this ExtensionService is part of. Profile* profile_; - // Preferences for the owning profile. - scoped_ptr<ExtensionPrefs> extension_prefs_; + // Preferences for the owning profile (weak reference). + ExtensionPrefs* extension_prefs_; // The current list of installed extensions. ExtensionList extensions_; @@ -530,7 +524,7 @@ class ExtensionsService bool show_extensions_prompts_; // The backend that will do IO on behalf of this instance. - scoped_refptr<ExtensionsServiceBackend> backend_; + scoped_refptr<ExtensionServiceBackend> backend_; // Used by dispatchers to limit API quota for individual extensions. ExtensionsQuotaService quota_service_; @@ -595,13 +589,13 @@ class ExtensionsService // Flag to make sure event routers are only initialized once. bool event_routers_initialized_; - FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest, + FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, UpdatePendingExtensionAlreadyInstalled); - FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest, + FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, InstallAppsWithUnlimtedStorage); - FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest, + FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, InstallAppsAndCheckStorageProtection); - DISALLOW_COPY_AND_ASSIGN(ExtensionsService); + DISALLOW_COPY_AND_ASSIGN(ExtensionService); }; -#endif // CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_ +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_ diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index e6c4e3a..7f052b6 100644 --- a/chrome/browser/extensions/extensions_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/extensions/extensions_service_unittest.h" +#include "chrome/browser/extensions/extension_service_unittest.h" #include <algorithm> +#include <set> #include <vector> #include "base/basictypes.h" @@ -23,18 +24,19 @@ #include "base/version.h" #include "chrome/browser/appcache/chrome_appcache_service.h" #include "chrome/browser/browser_thread.h" -#include "chrome/browser/file_system/browser_file_system_context.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_creator.h" #include "chrome/browser/extensions/extension_error_reporter.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/external_extension_provider.h" #include "chrome/browser/extensions/external_pref_extension_provider.h" #include "chrome/browser/extensions/pack_extension_job.cc" +#include "chrome/browser/file_system/browser_file_system_helper.h" #include "chrome/browser/in_process_webkit/dom_storage_context.h" #include "chrome/browser/in_process_webkit/webkit_context.h" #include "chrome/browser/prefs/browser_prefs.h" -#include "chrome/browser/prefs/pref_value_store.h" +#include "chrome/browser/prefs/pref_service_mock_builder.h" +#include "chrome/browser/prefs/scoped_pref_update.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" @@ -140,13 +142,10 @@ class MockExtensionProvider : public ExternalExtensionProvider { } // ExternalExtensionProvider implementation: - virtual void VisitRegisteredExtension( - Visitor* visitor, const std::set<std::string>& ids_to_ignore) const { + virtual void VisitRegisteredExtension(Visitor* visitor) const { visit_count_++; for (DataMap::const_iterator i = extension_map_.begin(); i != extension_map_.end(); ++i) { - if (ids_to_ignore.find(i->first) != ids_to_ignore.end()) - continue; scoped_ptr<Version> version; version.reset(Version::GetVersionFromString(i->second.first)); @@ -198,8 +197,7 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor { MockProviderVisitor() : ids_found_(0) { } - int Visit(const std::string& json_data, - const std::set<std::string>& ignore_list) { + int Visit(const std::string& json_data) { // Give the test json file to the provider for parsing. provider_.reset(new ExternalPrefExtensionProvider()); provider_->SetPreferencesForTesting(json_data); @@ -220,9 +218,8 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor { // Reset our counter. ids_found_ = 0; - // Ask the provider to look up all extensions (and return the ones - // found (that are not on the ignore list). - provider_->VisitRegisteredExtension(this, ignore_list); + // Ask the provider to look up all extensions and return them. + provider_->VisitRegisteredExtension(this); return ids_found_; } @@ -302,10 +299,10 @@ class ExtensionTestingProfile : public TestingProfile { ExtensionTestingProfile() : service_(NULL) { } - void set_extensions_service(ExtensionsService* service) { + void set_extensions_service(ExtensionService* service) { service_ = service; } - virtual ExtensionsService* GetExtensionsService() { return service_; } + virtual ExtensionService* GetExtensionService() { return service_; } virtual ChromeAppCacheService* GetAppCacheService() { if (!appcache_service_) { @@ -320,21 +317,21 @@ class ExtensionTestingProfile : public TestingProfile { return appcache_service_; } - virtual BrowserFileSystemContext* GetFileSystemContext() { - if (!browser_file_system_context_) - browser_file_system_context_ = new BrowserFileSystemContext( + virtual fileapi::SandboxedFileSystemContext* GetFileSystemContext() { + if (!file_system_context_) + file_system_context_ = CreateFileSystemContext( GetPath(), IsOffTheRecord()); - return browser_file_system_context_; + return file_system_context_; } private: - ExtensionsService* service_; + ExtensionService* service_; scoped_refptr<ChromeAppCacheService> appcache_service_; - scoped_refptr<BrowserFileSystemContext> browser_file_system_context_; + scoped_refptr<fileapi::SandboxedFileSystemContext> file_system_context_; }; // Our message loop may be used in tests which require it to be an IO loop. -ExtensionsServiceTestBase::ExtensionsServiceTestBase() +ExtensionServiceTestBase::ExtensionServiceTestBase() : total_successes_(0), loop_(MessageLoop::TYPE_IO), ui_thread_(BrowserThread::UI, &loop_), @@ -344,8 +341,8 @@ ExtensionsServiceTestBase::ExtensionsServiceTestBase() io_thread_(BrowserThread::IO, &loop_) { } -ExtensionsServiceTestBase::~ExtensionsServiceTestBase() { - // Drop our reference to ExtensionsService and TestingProfile, so that they +ExtensionServiceTestBase::~ExtensionServiceTestBase() { + // Drop our reference to ExtensionService and TestingProfile, so that they // can be destroyed while BrowserThreads and MessageLoop are still around // (they are used in the destruction process). service_ = NULL; @@ -353,19 +350,19 @@ ExtensionsServiceTestBase::~ExtensionsServiceTestBase() { MessageLoop::current()->RunAllPending(); } -void ExtensionsServiceTestBase::InitializeExtensionsService( +void ExtensionServiceTestBase::InitializeExtensionService( const FilePath& pref_file, const FilePath& extensions_install_dir) { ExtensionTestingProfile* profile = new ExtensionTestingProfile(); - // Create a preference service that only contains user defined - // preference values. - PrefService* prefs = PrefService::CreateUserPrefService(pref_file); + // Create a PrefService that only contains user defined preference values. + PrefService* prefs = + PrefServiceMockBuilder().WithUserFilePrefs(pref_file).Create(); Profile::RegisterUserPrefs(prefs); browser::RegisterUserPrefs(prefs); profile->SetPrefService(prefs); profile_.reset(profile); - service_ = profile->CreateExtensionsService( + service_ = profile->CreateExtensionService( CommandLine::ForCurrentProcess(), extensions_install_dir); service_->set_extensions_enabled(true); @@ -382,7 +379,7 @@ void ExtensionsServiceTestBase::InitializeExtensionsService( total_successes_ = 0; } -void ExtensionsServiceTestBase::InitializeInstalledExtensionsService( +void ExtensionServiceTestBase::InitializeInstalledExtensionService( const FilePath& prefs_file, const FilePath& source_install_dir) { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); FilePath path_ = temp_dir_.path(); @@ -396,10 +393,10 @@ void ExtensionsServiceTestBase::InitializeInstalledExtensionsService( file_util::Delete(extensions_install_dir_, true); file_util::CopyDirectory(source_install_dir, extensions_install_dir_, true); - InitializeExtensionsService(temp_prefs, extensions_install_dir_); + InitializeExtensionService(temp_prefs, extensions_install_dir_); } -void ExtensionsServiceTestBase::InitializeEmptyExtensionsService() { +void ExtensionServiceTestBase::InitializeEmptyExtensionService() { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); FilePath path_ = temp_dir_.path(); path_ = path_.Append(FILE_PATH_LITERAL("TestingExtensionsPath")); @@ -411,22 +408,22 @@ void ExtensionsServiceTestBase::InitializeEmptyExtensionsService() { file_util::Delete(extensions_install_dir_, true); file_util::CreateDirectory(extensions_install_dir_); - InitializeExtensionsService(prefs_filename, extensions_install_dir_); + InitializeExtensionService(prefs_filename, extensions_install_dir_); } // static -void ExtensionsServiceTestBase::SetUpTestCase() { +void ExtensionServiceTestBase::SetUpTestCase() { ExtensionErrorReporter::Init(false); // no noisy errors } -void ExtensionsServiceTestBase::SetUp() { +void ExtensionServiceTestBase::SetUp() { ExtensionErrorReporter::GetInstance()->ClearErrors(); } -class ExtensionsServiceTest - : public ExtensionsServiceTestBase, public NotificationObserver { +class ExtensionServiceTest + : public ExtensionServiceTestBase, public NotificationObserver { public: - ExtensionsServiceTest() : installed_(NULL) { + ExtensionServiceTest() : installed_(NULL) { registrar_.Add(this, NotificationType::EXTENSION_LOADED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, @@ -451,7 +448,8 @@ class ExtensionsServiceTest } case NotificationType::EXTENSION_UNLOADED: { - const Extension* e = Details<const Extension>(details).ptr(); + const Extension* e = + Details<UnloadedExtensionInfo>(details)->extension; unloaded_id_ = e->id(); ExtensionList::iterator i = std::find(loaded_.begin(), loaded_.end(), e); @@ -820,7 +818,7 @@ void PackExtensionTestClient::OnPackFailure(const std::string& error_message) { } // Test loading good extensions from the profile directory. -TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) { +TEST_F(ExtensionServiceTest, LoadAllExtensionsFromDirectorySuccess) { // Initialize the test dir with a good Preferences/extensions. FilePath source_install_dir; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); @@ -831,7 +829,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) { FilePath pref_path = source_install_dir .DirName() .AppendASCII("Preferences"); - InitializeInstalledExtensionsService(pref_path, source_install_dir); + InitializeInstalledExtensionService(pref_path, source_install_dir); service_->Init(); @@ -924,7 +922,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) { }; // Test loading bad extensions from the profile directory. -TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectoryFail) { +TEST_F(ExtensionServiceTest, LoadAllExtensionsFromDirectoryFail) { // Initialize the test dir with a bad Preferences/extensions. FilePath source_install_dir; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); @@ -936,7 +934,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectoryFail) { .DirName() .AppendASCII("Preferences"); - InitializeInstalledExtensionsService(pref_path, source_install_dir); + InitializeInstalledExtensionService(pref_path, source_install_dir); service_->Init(); loop_.RunAllPending(); @@ -963,7 +961,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectoryFail) { // Test that partially deleted extensions are cleaned up during startup // Test loading bad extensions from the profile directory. -TEST_F(ExtensionsServiceTest, CleanupOnStartup) { +TEST_F(ExtensionServiceTest, CleanupOnStartup) { FilePath source_install_dir; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); source_install_dir = source_install_dir @@ -974,7 +972,7 @@ TEST_F(ExtensionsServiceTest, CleanupOnStartup) { .DirName() .AppendASCII("Preferences"); - InitializeInstalledExtensionsService(pref_path, source_install_dir); + InitializeInstalledExtensionService(pref_path, source_install_dir); // Simulate that one of them got partially deleted by clearing its pref. DictionaryValue* dict = @@ -1003,8 +1001,8 @@ TEST_F(ExtensionsServiceTest, CleanupOnStartup) { // Test installing extensions. This test tries to install few extensions using // crx files. If you need to change those crx files, feel free to repackage // them, throw away the key used and change the id's above. -TEST_F(ExtensionsServiceTest, InstallExtension) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, InstallExtension) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); @@ -1062,11 +1060,57 @@ TEST_F(ExtensionsServiceTest, InstallExtension) { // TODO(erikkay): add tests for upgrade cases. } +// Test the handling of killed extensions. +TEST_F(ExtensionServiceTest, KilledExtensions) { + InitializeEmptyExtensionService(); + + FilePath extensions_path; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); + extensions_path = extensions_path.AppendASCII("extensions"); + FilePath path = extensions_path.AppendASCII("good.crx"); + set_extensions_enabled(true); + + // Install an external extension. + service_->OnExternalExtensionFileFound(good_crx, "1.0.0.0", + path, Extension::EXTERNAL_PREF); + loop_.RunAllPending(); + ASSERT_TRUE(NULL != service_->GetExtensionById(good_crx, false)); + + // Uninstall it and check that its killbit gets set. + service_->UninstallExtension(good_crx, false); + loop_.RunAllPending(); + ValidateIntegerPref(good_crx, "location", Extension::KILLBIT); + + // Try to re-install it externally. This should fail because of the killbit. + service_->OnExternalExtensionFileFound(good_crx, "1.0.0.0", + path, Extension::EXTERNAL_PREF); + loop_.RunAllPending(); + ASSERT_TRUE(NULL == service_->GetExtensionById(good_crx, false)); + ValidateIntegerPref(good_crx, "location", Extension::KILLBIT); + + // Repeat the same thing with a newer version of the extension. + path = extensions_path.AppendASCII("good2.crx"); + service_->OnExternalExtensionFileFound(good_crx, "1.0.0.1", + path, Extension::EXTERNAL_PREF); + loop_.RunAllPending(); + ASSERT_TRUE(NULL == service_->GetExtensionById(good_crx, false)); + ValidateIntegerPref(good_crx, "location", Extension::KILLBIT); + + // Try adding the same extension from an external update URL. + service_->AddPendingExtensionFromExternalUpdateUrl( + good_crx, + GURL("http:://fake.update/url"), + Extension::EXTERNAL_PREF_DOWNLOAD); + const PendingExtensionMap& pending_extensions = + service_->pending_extensions(); + ASSERT_TRUE(pending_extensions.find(good_crx) == pending_extensions.end()); +} + // Install a user script (they get converted automatically to an extension) -TEST_F(ExtensionsServiceTest, InstallUserScript) { +TEST_F(ExtensionServiceTest, InstallUserScript) { // The details of script conversion are tested elsewhere, this just tests - // integration with ExtensionsService. - InitializeEmptyExtensionsService(); + // integration with ExtensionService. + InitializeEmptyExtensionService(); FilePath path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); @@ -1096,8 +1140,8 @@ TEST_F(ExtensionsServiceTest, InstallUserScript) { // This tests that the granted permissions preferences are correctly set when // installing an extension. -TEST_F(ExtensionsServiceTest, GrantedPermissions) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, GrantedPermissions) { + InitializeEmptyExtensionService(); FilePath path; FilePath pem_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); @@ -1155,8 +1199,8 @@ TEST_F(ExtensionsServiceTest, GrantedPermissions) { // Tests that the granted permissions full_access bit gets set correctly when // an extension contains an NPAPI plugin. Don't run this test on Chrome OS // since they don't support plugins. -TEST_F(ExtensionsServiceTest, GrantedFullAccessPermissions) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, GrantedFullAccessPermissions) { + InitializeEmptyExtensionService(); FilePath path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); @@ -1191,8 +1235,8 @@ TEST_F(ExtensionsServiceTest, GrantedFullAccessPermissions) { // Tests that the extension is disabled when permissions are missing from // the extension's granted permissions preferences. (This simulates updating // the browser to a version which recognizes more permissions). -TEST_F(ExtensionsServiceTest, GrantedAPIAndHostPermissions) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) { + InitializeEmptyExtensionService(); FilePath path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); @@ -1321,8 +1365,8 @@ TEST_F(ExtensionsServiceTest, GrantedAPIAndHostPermissions) { } // Test Packaging and installing an extension. -TEST_F(ExtensionsServiceTest, PackExtension) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, PackExtension) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1369,8 +1413,8 @@ TEST_F(ExtensionsServiceTest, PackExtension) { } // Test Packaging and installing an extension whose name contains punctuation. -TEST_F(ExtensionsServiceTest, PackPunctuatedExtension) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, PackPunctuatedExtension) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1448,8 +1492,8 @@ TEST_F(ExtensionsServiceTest, PackPunctuatedExtension) { // > openssl pkcs8 -topk8 -nocrypt -in privkey.pem -out privkey_asn1.pem // The privkey.pem is a PrivateKey, and the pcks8 -topk8 creates a // PrivateKeyInfo ASN.1 structure, we our RSAPrivateKey expects. -TEST_F(ExtensionsServiceTest, PackExtensionOpenSSLKey) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, PackExtensionOpenSSLKey) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1475,8 +1519,8 @@ TEST_F(ExtensionsServiceTest, PackExtensionOpenSSLKey) { InstallExtension(crx_path, true); } -TEST_F(ExtensionsServiceTest, InstallTheme) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, InstallTheme) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1511,9 +1555,9 @@ TEST_F(ExtensionsServiceTest, InstallTheme) { ValidatePrefKeyCount(pref_count); } -TEST_F(ExtensionsServiceTest, LoadLocalizedTheme) { +TEST_F(ExtensionServiceTest, LoadLocalizedTheme) { // Load. - InitializeEmptyExtensionsService(); + InitializeEmptyExtensionService(); FilePath extension_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extension_path)); extension_path = extension_path @@ -1529,8 +1573,8 @@ TEST_F(ExtensionsServiceTest, LoadLocalizedTheme) { EXPECT_EQ("description", service_->extensions()->at(0)->description()); } -TEST_F(ExtensionsServiceTest, InstallLocalizedTheme) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, InstallLocalizedTheme) { + InitializeEmptyExtensionService(); FilePath theme_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &theme_path)); theme_path = theme_path @@ -1545,8 +1589,8 @@ TEST_F(ExtensionsServiceTest, InstallLocalizedTheme) { EXPECT_EQ("description", service_->extensions()->at(0)->description()); } -TEST_F(ExtensionsServiceTest, InstallApps) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, InstallApps) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1569,8 +1613,8 @@ TEST_F(ExtensionsServiceTest, InstallApps) { ValidatePrefKeyCount(pref_count); } -TEST_F(ExtensionsServiceTest, InstallAppsWithUnlimtedStorage) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) { + InitializeEmptyExtensionService(); EXPECT_TRUE(service_->extensions()->empty()); EXPECT_TRUE(service_->unlimited_storage_map_.empty()); @@ -1629,8 +1673,8 @@ TEST_F(ExtensionsServiceTest, InstallAppsWithUnlimtedStorage) { EXPECT_TRUE(service_->unlimited_storage_map_.empty()); } -TEST_F(ExtensionsServiceTest, InstallAppsAndCheckStorageProtection) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, InstallAppsAndCheckStorageProtection) { + InitializeEmptyExtensionService(); EXPECT_TRUE(service_->extensions()->empty()); EXPECT_TRUE(service_->protected_storage_map_.empty()); @@ -1673,8 +1717,8 @@ TEST_F(ExtensionsServiceTest, InstallAppsAndCheckStorageProtection) { } // Test that when an extension version is reinstalled, nothing happens. -TEST_F(ExtensionsServiceTest, Reinstall) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, Reinstall) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1708,8 +1752,8 @@ TEST_F(ExtensionsServiceTest, Reinstall) { } // Test upgrading a signed extension. -TEST_F(ExtensionsServiceTest, UpgradeSignedGood) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpgradeSignedGood) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1735,8 +1779,8 @@ TEST_F(ExtensionsServiceTest, UpgradeSignedGood) { } // Test upgrading a signed extension with a bad signature. -TEST_F(ExtensionsServiceTest, UpgradeSignedBad) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpgradeSignedBad) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1762,8 +1806,8 @@ TEST_F(ExtensionsServiceTest, UpgradeSignedBad) { } // Test a normal update via the UpdateExtension API -TEST_F(ExtensionsServiceTest, UpdateExtension) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdateExtension) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1781,8 +1825,8 @@ TEST_F(ExtensionsServiceTest, UpdateExtension) { } // Test updating a not-already-installed extension - this should fail -TEST_F(ExtensionsServiceTest, UpdateNotInstalledExtension) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdateNotInstalledExtension) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1797,8 +1841,8 @@ TEST_F(ExtensionsServiceTest, UpdateNotInstalledExtension) { } // Makes sure you can't downgrade an extension via UpdateExtension -TEST_F(ExtensionsServiceTest, UpdateWillNotDowngrade) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdateWillNotDowngrade) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1817,8 +1861,8 @@ TEST_F(ExtensionsServiceTest, UpdateWillNotDowngrade) { } // Make sure calling update with an identical version does nothing -TEST_F(ExtensionsServiceTest, UpdateToSameVersionIsNoop) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdateToSameVersionIsNoop) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1832,8 +1876,8 @@ TEST_F(ExtensionsServiceTest, UpdateToSameVersionIsNoop) { } // Tests that updating an extension does not clobber old state. -TEST_F(ExtensionsServiceTest, UpdateExtensionPreservesState) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdateExtensionPreservesState) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1859,8 +1903,8 @@ TEST_F(ExtensionsServiceTest, UpdateExtensionPreservesState) { } // Tests that updating preserves extension location. -TEST_F(ExtensionsServiceTest, UpdateExtensionPreservesLocation) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdateExtensionPreservesLocation) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -1883,36 +1927,83 @@ TEST_F(ExtensionsServiceTest, UpdateExtensionPreservesLocation) { EXPECT_EQ(good2->location(), Extension::EXTERNAL_PREF); } +// Makes sure that LOAD extension types can downgrade. +TEST_F(ExtensionServiceTest, LoadExtensionsCanDowngrade) { + InitializeEmptyExtensionService(); + + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + + // We'll write the extension manifest dynamically to a temporary path + // to make it easier to change the version number. + FilePath extension_path = temp.path(); + FilePath manifest_path = extension_path.Append(Extension::kManifestFilename); + ASSERT_FALSE(file_util::PathExists(manifest_path)); + + // Start with version 2.0. + DictionaryValue manifest; + manifest.SetString("version", "2.0"); + manifest.SetString("name", "LOAD Downgrade Test"); + + JSONFileValueSerializer serializer(manifest_path); + ASSERT_TRUE(serializer.Serialize(manifest)); + + service_->LoadExtension(extension_path); + loop_.RunAllPending(); + + EXPECT_EQ(0u, GetErrors().size()); + ASSERT_EQ(1u, loaded_.size()); + EXPECT_EQ(Extension::LOAD, loaded_[0]->location()); + EXPECT_EQ(1u, service_->extensions()->size()); + EXPECT_EQ("2.0", loaded_[0]->VersionString()); + + // Now set the version number to 1.0, reload the extensions and verify that + // the downgrade was accepted. + manifest.SetString("version", "1.0"); + ASSERT_TRUE(serializer.Serialize(manifest)); + + service_->LoadExtension(extension_path); + loop_.RunAllPending(); + + EXPECT_EQ(0u, GetErrors().size()); + ASSERT_EQ(1u, loaded_.size()); + EXPECT_EQ(Extension::LOAD, loaded_[0]->location()); + EXPECT_EQ(1u, service_->extensions()->size()); + EXPECT_EQ("1.0", loaded_[0]->VersionString()); +} + +namespace { + +bool IsExtension(const Extension& extension) { + return extension.GetType() == Extension::TYPE_EXTENSION; +} + +} // namespace + // Test adding a pending extension. -TEST_F(ExtensionsServiceTest, AddPendingExtension) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, AddPendingExtensionFromSync) { + InitializeEmptyExtensionService(); const std::string kFakeId("fake-id"); const GURL kFakeUpdateURL("http:://fake.update/url"); - const PendingExtensionInfo::ExpectedCrxType kFakeExpectedCrxType = - PendingExtensionInfo::EXTENSION; const bool kFakeInstallSilently(true); const Extension::State kFakeInitialState(Extension::ENABLED); const bool kFakeInitialIncognitoEnabled(false); service_->AddPendingExtensionFromSync( - kFakeId, kFakeUpdateURL, kFakeExpectedCrxType, kFakeInstallSilently, - kFakeInitialState, kFakeInitialIncognitoEnabled); + kFakeId, kFakeUpdateURL, &IsExtension, + kFakeInstallSilently, kFakeInitialState, kFakeInitialIncognitoEnabled); PendingExtensionMap::const_iterator it = service_->pending_extensions().find(kFakeId); ASSERT_TRUE(it != service_->pending_extensions().end()); EXPECT_EQ(kFakeUpdateURL, it->second.update_url); - EXPECT_EQ(kFakeExpectedCrxType, it->second.expected_crx_type); + EXPECT_EQ(&IsExtension, it->second.should_install_extension); EXPECT_EQ(kFakeInstallSilently, it->second.install_silently); } namespace { const char kGoodId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; const char kGoodUpdateURL[] = "http://good.update/url"; -const PendingExtensionInfo::ExpectedCrxType kCrxTypeTheme = - PendingExtensionInfo::THEME; -const PendingExtensionInfo::ExpectedCrxType kCrxTypeExtension = - PendingExtensionInfo::EXTENSION; const bool kGoodIsFromSync = true; const bool kGoodInstallSilently = true; const Extension::State kGoodInitialState = Extension::DISABLED; @@ -1920,10 +2011,10 @@ const bool kGoodInitialIncognitoEnabled = true; } // namespace // Test updating a pending extension. -TEST_F(ExtensionsServiceTest, UpdatePendingExtension) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdatePendingExtension) { + InitializeEmptyExtensionService(); service_->AddPendingExtensionFromSync( - kGoodId, GURL(kGoodUpdateURL), kCrxTypeExtension, + kGoodId, GURL(kGoodUpdateURL), &IsExtension, kGoodInstallSilently, kGoodInitialState, kGoodInitialIncognitoEnabled); EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId)); @@ -1947,11 +2038,19 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExtension) { service_->IsIncognitoEnabled(extension)); } +namespace { + +bool IsTheme(const Extension& extension) { + return extension.is_theme(); +} + +} // namespace + // Test updating a pending theme. -TEST_F(ExtensionsServiceTest, UpdatePendingTheme) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdatePendingTheme) { + InitializeEmptyExtensionService(); service_->AddPendingExtensionFromSync( - theme_crx, GURL(), PendingExtensionInfo::THEME, + theme_crx, GURL(), &IsTheme, false, Extension::ENABLED, false); EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx)); @@ -1974,8 +2073,8 @@ TEST_F(ExtensionsServiceTest, UpdatePendingTheme) { // Test updating a pending CRX as if the source is an external extension // with an update URL. In this case we don't know if the CRX is a theme // or not. -TEST_F(ExtensionsServiceTest, UpdatePendingExternalCrx) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdatePendingExternalCrx) { + InitializeEmptyExtensionService(); service_->AddPendingExtensionFromExternalUpdateUrl( theme_crx, GURL(), Extension::EXTERNAL_PREF_DOWNLOAD); @@ -2000,12 +2099,12 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExternalCrx) { // Test updating a pending CRX as if the source is an external extension // with an update URL. The external update should overwrite a sync update, // but a sync update should not overwrite a non-sync update. -TEST_F(ExtensionsServiceTest, UpdatePendingExternalCrxWinsOverSync) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdatePendingExternalCrxWinsOverSync) { + InitializeEmptyExtensionService(); // Add a crx to be installed from the update mechanism. service_->AddPendingExtensionFromSync( - kGoodId, GURL(kGoodUpdateURL), kCrxTypeExtension, + kGoodId, GURL(kGoodUpdateURL), &IsExtension, kGoodInstallSilently, kGoodInitialState, kGoodInitialIncognitoEnabled); @@ -2026,7 +2125,7 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExternalCrxWinsOverSync) { // Add a crx to be installed from the update mechanism. service_->AddPendingExtensionFromSync( - kGoodId, GURL(kGoodUpdateURL), kCrxTypeExtension, + kGoodId, GURL(kGoodUpdateURL), &IsExtension, kGoodInstallSilently, kGoodInitialState, kGoodInitialIncognitoEnabled); @@ -2038,11 +2137,10 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExternalCrxWinsOverSync) { // Updating a theme should fail if the updater is explicitly told that // the CRX is not a theme. -TEST_F(ExtensionsServiceTest, UpdatePendingCrxThemeMismatch) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdatePendingCrxThemeMismatch) { + InitializeEmptyExtensionService(); service_->AddPendingExtensionFromSync( - theme_crx, GURL(), - PendingExtensionInfo::EXTENSION, + theme_crx, GURL(), &IsExtension, true, Extension::ENABLED, false); EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx)); @@ -2063,13 +2161,13 @@ TEST_F(ExtensionsServiceTest, UpdatePendingCrxThemeMismatch) { // we can mock out ExtensionInstallUI and inject our version into // UpdateExtension(). -// Test updating a pending extension with wrong is_theme. -TEST_F(ExtensionsServiceTest, UpdatePendingExtensionWrongIsTheme) { - InitializeEmptyExtensionsService(); +// Test updating a pending extension which fails the should-install test. +TEST_F(ExtensionServiceTest, UpdatePendingExtensionFailedShouldInstallTest) { + InitializeEmptyExtensionService(); // Add pending extension with a flipped is_theme. service_->AddPendingExtensionFromSync( - kGoodId, GURL(kGoodUpdateURL), - kCrxTypeTheme, kGoodInstallSilently, kGoodInitialState, + kGoodId, GURL(kGoodUpdateURL), &IsTheme, + kGoodInstallSilently, kGoodInitialState, kGoodInitialIncognitoEnabled); EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId)); @@ -2089,8 +2187,8 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExtensionWrongIsTheme) { // unsyncable extensions are blocked. // Test updating a pending extension for one that is not pending. -TEST_F(ExtensionsServiceTest, UpdatePendingExtensionNotPending) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdatePendingExtensionNotPending) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); @@ -2103,8 +2201,8 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExtensionNotPending) { // Test updating a pending extension for one that is already // installed. -TEST_F(ExtensionsServiceTest, UpdatePendingExtensionAlreadyInstalled) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UpdatePendingExtensionAlreadyInstalled) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); @@ -2119,8 +2217,7 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExtensionAlreadyInstalled) { // Use AddPendingExtensionInternal() as AddPendingExtension() would // balk. service_->AddPendingExtensionInternal( - good->id(), good->update_url(), - PendingExtensionInfo::EXTENSION, + good->id(), good->update_url(), &IsExtension, kGoodIsFromSync, kGoodInstallSilently, kGoodInitialState, kGoodInitialIncognitoEnabled, Extension::INTERNAL); UpdateExtension(good->id(), path, INSTALLED); @@ -2129,8 +2226,8 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExtensionAlreadyInstalled) { } // Test pref settings for blacklist and unblacklist extensions. -TEST_F(ExtensionsServiceTest, SetUnsetBlacklistInPrefs) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, SetUnsetBlacklistInPrefs) { + InitializeEmptyExtensionService(); std::vector<std::string> blacklist; blacklist.push_back(good0); blacklist.push_back("invalid_id"); // an invalid id @@ -2158,8 +2255,8 @@ TEST_F(ExtensionsServiceTest, SetUnsetBlacklistInPrefs) { } // Unload installed extension from blacklist. -TEST_F(ExtensionsServiceTest, UnloadBlacklistedExtension) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UnloadBlacklistedExtension) { + InitializeEmptyExtensionService(); FilePath extensions_path; EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -2191,8 +2288,8 @@ TEST_F(ExtensionsServiceTest, UnloadBlacklistedExtension) { } // Unload installed extension from blacklist. -TEST_F(ExtensionsServiceTest, BlacklistedExtensionWillNotInstall) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, BlacklistedExtensionWillNotInstall) { + InitializeEmptyExtensionService(); std::vector<std::string> blacklist; blacklist.push_back(good_crx); service_->UpdateExtensionBlacklist(blacklist); @@ -2215,7 +2312,7 @@ TEST_F(ExtensionsServiceTest, BlacklistedExtensionWillNotInstall) { // Test loading extensions from the profile directory, except // blacklisted ones. -TEST_F(ExtensionsServiceTest, WillNotLoadBlacklistedExtensionsFromDirectory) { +TEST_F(ExtensionServiceTest, WillNotLoadBlacklistedExtensionsFromDirectory) { // Initialize the test dir with a good Preferences/extensions. FilePath source_install_dir; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); @@ -2226,7 +2323,7 @@ TEST_F(ExtensionsServiceTest, WillNotLoadBlacklistedExtensionsFromDirectory) { FilePath pref_path = source_install_dir .DirName() .AppendASCII("Preferences"); - InitializeInstalledExtensionsService(pref_path, source_install_dir); + InitializeInstalledExtensionService(pref_path, source_install_dir); // Blacklist good1. std::vector<std::string> blacklist; @@ -2255,7 +2352,7 @@ TEST_F(ExtensionsServiceTest, WillNotLoadBlacklistedExtensionsFromDirectory) { #if defined(OS_CHROMEOS) // Test loading extensions from the profile directory, except // ones with a plugin. -TEST_F(ExtensionsServiceTest, WillNotLoadPluginExtensionsFromDirectory) { +TEST_F(ExtensionServiceTest, WillNotLoadPluginExtensionsFromDirectory) { // Initialize the test dir with a good Preferences/extensions. FilePath source_install_dir; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); @@ -2266,7 +2363,7 @@ TEST_F(ExtensionsServiceTest, WillNotLoadPluginExtensionsFromDirectory) { FilePath pref_path = source_install_dir .DirName() .AppendASCII("Preferences"); - InitializeInstalledExtensionsService(pref_path, source_install_dir); + InitializeInstalledExtensionService(pref_path, source_install_dir); // good1 contains a plugin. // Load extensions. @@ -2286,13 +2383,13 @@ TEST_F(ExtensionsServiceTest, WillNotLoadPluginExtensionsFromDirectory) { #endif // Will not install extension blacklisted by policy. -TEST_F(ExtensionsServiceTest, BlacklistedByPolicyWillNotInstall) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, BlacklistedByPolicyWillNotInstall) { + InitializeEmptyExtensionService(); ListValue* whitelist = - profile_->GetPrefs()->GetMutableList("extensions.install.allowlist"); + profile_->GetPrefs()->GetMutableList(prefs::kExtensionInstallAllowList); ListValue* blacklist = - profile_->GetPrefs()->GetMutableList("extensions.install.denylist"); + profile_->GetPrefs()->GetMutableList(prefs::kExtensionInstallDenyList); ASSERT_TRUE(whitelist != NULL && blacklist != NULL); // Blacklist everything. @@ -2317,8 +2414,8 @@ TEST_F(ExtensionsServiceTest, BlacklistedByPolicyWillNotInstall) { } // Extension blacklisted by policy get unloaded after installing. -TEST_F(ExtensionsServiceTest, BlacklistedByPolicyRemovedIfRunning) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, BlacklistedByPolicyRemovedIfRunning) { + InitializeEmptyExtensionService(); // Install good_crx. FilePath extensions_path; @@ -2329,18 +2426,17 @@ TEST_F(ExtensionsServiceTest, BlacklistedByPolicyRemovedIfRunning) { loop_.RunAllPending(); EXPECT_EQ(1u, service_->extensions()->size()); - PrefService* prefs = profile_->GetPrefs(); - ListValue* blacklist = - prefs->GetMutableList("extensions.install.denylist"); - ASSERT_TRUE(blacklist != NULL); - - // Blacklist this extension. - blacklist->Append(Value::CreateStringValue(good_crx)); - prefs->ScheduleSavePersistentPrefs(); - - // Programmatically appending to the prefs doesn't seem to notify the - // observers... :/ - prefs->pref_notifier()->FireObservers("extensions.install.denylist"); + { // Scope for pref update notification. + PrefService* prefs = profile_->GetPrefs(); + ScopedPrefUpdate pref_update(prefs, prefs::kExtensionInstallDenyList); + ListValue* blacklist = + prefs->GetMutableList(prefs::kExtensionInstallDenyList); + ASSERT_TRUE(blacklist != NULL); + + // Blacklist this extension. + blacklist->Append(Value::CreateStringValue(good_crx)); + prefs->ScheduleSavePersistentPrefs(); + } // Extension should not be running now. loop_.RunAllPending(); @@ -2348,8 +2444,8 @@ TEST_F(ExtensionsServiceTest, BlacklistedByPolicyRemovedIfRunning) { } // Tests disabling extensions -TEST_F(ExtensionsServiceTest, DisableExtension) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, DisableExtension) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -2374,8 +2470,8 @@ TEST_F(ExtensionsServiceTest, DisableExtension) { } // Tests disabling all extensions (simulating --disable-extensions flag). -TEST_F(ExtensionsServiceTest, DisableAllExtensions) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, DisableAllExtensions) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); @@ -2412,8 +2508,8 @@ TEST_F(ExtensionsServiceTest, DisableAllExtensions) { } // Tests reloading extensions -TEST_F(ExtensionsServiceTest, ReloadExtensions) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, ReloadExtensions) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -2450,8 +2546,8 @@ TEST_F(ExtensionsServiceTest, ReloadExtensions) { } // Tests uninstalling normal extensions -TEST_F(ExtensionsServiceTest, UninstallExtension) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UninstallExtension) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -2488,8 +2584,8 @@ TEST_F(ExtensionsServiceTest, UninstallExtension) { } // Tests the uninstaller helper. -TEST_F(ExtensionsServiceTest, UninstallExtensionHelper) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, UninstallExtensionHelper) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -2503,7 +2599,7 @@ TEST_F(ExtensionsServiceTest, UninstallExtensionHelper) { FilePath extension_path = extensions_install_dir_.AppendASCII(extension_id); EXPECT_TRUE(file_util::PathExists(extension_path)); - bool result = ExtensionsService::UninstallExtensionHelper(service_, + bool result = ExtensionService::UninstallExtensionHelper(service_, extension_id); total_successes_ = 0; @@ -2524,13 +2620,13 @@ TEST_F(ExtensionsServiceTest, UninstallExtensionHelper) { // Attempt to uninstall again. This should fail as we just removed the // extension. - result = ExtensionsService::UninstallExtensionHelper(service_, extension_id); + result = ExtensionService::UninstallExtensionHelper(service_, extension_id); EXPECT_FALSE(result); } // Verifies extension state is removed upon uninstall -TEST_F(ExtensionsServiceTest, ClearExtensionData) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, ClearExtensionData) { + InitializeEmptyExtensionService(); // Load a test extension. FilePath path; @@ -2550,8 +2646,7 @@ TEST_F(ExtensionsServiceTest, ClearExtensionData) { ASSERT_TRUE(cookie_monster); net::CookieOptions options; cookie_monster->SetCookieWithOptions(ext_url, "dummy=value", options); - net::CookieMonster::CookieList list = - cookie_monster->GetAllCookiesForURL(ext_url); + net::CookieList list = cookie_monster->GetAllCookiesForURL(ext_url); EXPECT_EQ(1U, list.size()); // Open a database. @@ -2607,8 +2702,8 @@ TEST_F(ExtensionsServiceTest, ClearExtensionData) { } // Tests loading single extensions (like --load-extension) -TEST_F(ExtensionsServiceTest, LoadExtension) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, LoadExtension) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); extensions_path = extensions_path.AppendASCII("extensions"); @@ -2650,8 +2745,8 @@ TEST_F(ExtensionsServiceTest, LoadExtension) { // Tests that we generate IDs when they are not specified in the manifest for // --load-extension. -TEST_F(ExtensionsServiceTest, GenerateID) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, GenerateID) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); @@ -2676,7 +2771,7 @@ TEST_F(ExtensionsServiceTest, GenerateID) { ASSERT_EQ(previous_id, loaded_[0]->id()); } -void ExtensionsServiceTest::TestExternalProvider( +void ExtensionServiceTest::TestExternalProvider( MockExtensionProvider* provider, Extension::Location location) { // Verify that starting with no providers loads no extensions. service_->Init(); @@ -2806,9 +2901,9 @@ void ExtensionsServiceTest::TestExternalProvider( // Tests the external installation feature #if defined(OS_WIN) -TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) { +TEST_F(ExtensionServiceTest, ExternalInstallRegistry) { // This should all work, even when normal extension installation is disabled. - InitializeEmptyExtensionsService(); + InitializeEmptyExtensionService(); set_extensions_enabled(false); // Now add providers. Extension system takes ownership of the objects. @@ -2819,8 +2914,8 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) { } #endif -TEST_F(ExtensionsServiceTest, ExternalInstallPref) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, ExternalInstallPref) { + InitializeEmptyExtensionService(); // Now add providers. Extension system takes ownership of the objects. MockExtensionProvider* pref_provider = @@ -2830,9 +2925,9 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) { TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF); } -TEST_F(ExtensionsServiceTest, ExternalInstallPrefUpdateUrl) { +TEST_F(ExtensionServiceTest, ExternalInstallPrefUpdateUrl) { // This should all work, even when normal extension installation is disabled. - InitializeEmptyExtensionsService(); + InitializeEmptyExtensionService(); set_extensions_enabled(false); // TODO(skerner): The mock provider is not a good model of a provider @@ -2850,7 +2945,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPrefUpdateUrl) { // Tests that external extensions get uninstalled when the external extension // providers can't account for them. -TEST_F(ExtensionsServiceTest, ExternalUninstall) { +TEST_F(ExtensionServiceTest, ExternalUninstall) { // Start the extensions service with one external extension already installed. FilePath source_install_dir; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); @@ -2863,7 +2958,7 @@ TEST_F(ExtensionsServiceTest, ExternalUninstall) { .AppendASCII("PreferencesExternal"); // This initializes the extensions service with no ExternalExtensionProviders. - InitializeInstalledExtensionsService(pref_path, source_install_dir); + InitializeInstalledExtensionService(pref_path, source_install_dir); set_extensions_enabled(false); service_->Init(); @@ -2881,8 +2976,8 @@ TEST_F(ExtensionsServiceTest, ExternalUninstall) { ASSERT_EQ(0u, loaded_.size()); } -TEST_F(ExtensionsServiceTest, ExternalPrefProvider) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, ExternalPrefProvider) { + InitializeEmptyExtensionService(); std::string json_data = "{" " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {" @@ -2899,14 +2994,6 @@ TEST_F(ExtensionsServiceTest, ExternalPrefProvider) { "}"; MockProviderVisitor visitor; - std::set<std::string> ignore_list; - EXPECT_EQ(3, visitor.Visit(json_data, ignore_list)); - ignore_list.insert("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); - EXPECT_EQ(2, visitor.Visit(json_data, ignore_list)); - ignore_list.insert("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); - EXPECT_EQ(1, visitor.Visit(json_data, ignore_list)); - ignore_list.insert("cccccccccccccccccccccccccccccccc"); - EXPECT_EQ(0, visitor.Visit(json_data, ignore_list)); // Simulate an external_extensions.json file that contains seven invalid // extensions: @@ -2950,12 +3037,11 @@ TEST_F(ExtensionsServiceTest, ExternalPrefProvider) { " \"external_version\": \"1.0\"" " }" "}"; - ignore_list.clear(); - EXPECT_EQ(1, visitor.Visit(json_data, ignore_list)); + EXPECT_EQ(1, visitor.Visit(json_data)); } // Test loading good extensions from the profile directory. -TEST_F(ExtensionsServiceTest, LoadAndRelocalizeExtensions) { +TEST_F(ExtensionServiceTest, LoadAndRelocalizeExtensions) { // Initialize the test dir with a good Preferences/extensions. FilePath source_install_dir; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); @@ -2963,7 +3049,7 @@ TEST_F(ExtensionsServiceTest, LoadAndRelocalizeExtensions) { .AppendASCII("extensions") .AppendASCII("l10n"); FilePath pref_path = source_install_dir.AppendASCII("Preferences"); - InitializeInstalledExtensionsService(pref_path, source_install_dir); + InitializeInstalledExtensionService(pref_path, source_install_dir); service_->Init(); loop_.RunAllPending(); @@ -3013,25 +3099,25 @@ class ExtensionsReadyRecorder : public NotificationObserver { }; // Test that we get enabled/disabled correctly for all the pref/command-line -// combinations. We don't want to derive from the ExtensionsServiceTest class -// for this test, so we use ExtensionsServiceTestSimple. +// combinations. We don't want to derive from the ExtensionServiceTest class +// for this test, so we use ExtensionServiceTestSimple. // // Also tests that we always fire EXTENSIONS_READY, no matter whether we are // enabled or not. -TEST(ExtensionsServiceTestSimple, Enabledness) { +TEST(ExtensionServiceTestSimple, Enabledness) { ExtensionsReadyRecorder recorder; scoped_ptr<TestingProfile> profile(new TestingProfile()); MessageLoop loop; BrowserThread ui_thread(BrowserThread::UI, &loop); BrowserThread file_thread(BrowserThread::FILE, &loop); scoped_ptr<CommandLine> command_line; - scoped_refptr<ExtensionsService> service; + scoped_refptr<ExtensionService> service; FilePath install_dir = profile->GetPath() - .AppendASCII(ExtensionsService::kInstallDirectoryName); + .AppendASCII(ExtensionService::kInstallDirectoryName); // By default, we are enabled. command_line.reset(new CommandLine(CommandLine::NO_PROGRAM)); - service = profile->CreateExtensionsService(command_line.get(), + service = profile->CreateExtensionService(command_line.get(), install_dir); EXPECT_TRUE(service->extensions_enabled()); service->Init(); @@ -3042,7 +3128,7 @@ TEST(ExtensionsServiceTestSimple, Enabledness) { recorder.set_ready(false); profile.reset(new TestingProfile()); command_line->AppendSwitch(switches::kDisableExtensions); - service = profile->CreateExtensionsService(command_line.get(), + service = profile->CreateExtensionService(command_line.get(), install_dir); EXPECT_FALSE(service->extensions_enabled()); service->Init(); @@ -3052,7 +3138,7 @@ TEST(ExtensionsServiceTestSimple, Enabledness) { recorder.set_ready(false); profile.reset(new TestingProfile()); profile->GetPrefs()->SetBoolean(prefs::kDisableExtensions, true); - service = profile->CreateExtensionsService(command_line.get(), + service = profile->CreateExtensionService(command_line.get(), install_dir); EXPECT_FALSE(service->extensions_enabled()); service->Init(); @@ -3063,7 +3149,7 @@ TEST(ExtensionsServiceTestSimple, Enabledness) { profile.reset(new TestingProfile()); profile->GetPrefs()->SetBoolean(prefs::kDisableExtensions, true); command_line.reset(new CommandLine(CommandLine::NO_PROGRAM)); - service = profile->CreateExtensionsService(command_line.get(), + service = profile->CreateExtensionService(command_line.get(), install_dir); EXPECT_FALSE(service->extensions_enabled()); service->Init(); @@ -3076,8 +3162,8 @@ TEST(ExtensionsServiceTestSimple, Enabledness) { } // Test loading extensions that require limited and unlimited storage quotas. -TEST_F(ExtensionsServiceTest, StorageQuota) { - InitializeEmptyExtensionsService(); +TEST_F(ExtensionServiceTest, StorageQuota) { + InitializeEmptyExtensionService(); FilePath extensions_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); @@ -3135,9 +3221,9 @@ TEST_F(ExtensionsServiceTest, StorageQuota) { EXPECT_EQ(kint64max, unlimited_quota); } -// Tests ExtensionsService::register_component_extension(). -TEST_F(ExtensionsServiceTest, ComponentExtensions) { - InitializeEmptyExtensionsService(); +// Tests ExtensionService::register_component_extension(). +TEST_F(ExtensionServiceTest, ComponentExtensions) { + InitializeEmptyExtensionService(); // Component extensions should work even when extensions are disabled. set_extensions_enabled(false); @@ -3155,7 +3241,7 @@ TEST_F(ExtensionsServiceTest, ComponentExtensions) { path.Append(Extension::kManifestFilename), &manifest)); service_->register_component_extension( - ExtensionsService::ComponentExtensionInfo(manifest, path)); + ExtensionService::ComponentExtensionInfo(manifest, path)); service_->Init(); // Note that we do not pump messages -- the extension should be loaded diff --git a/chrome/browser/extensions/extensions_service_unittest.h b/chrome/browser/extensions/extension_service_unittest.h index f38cc34..8ca7b28 100644 --- a/chrome/browser/extensions/extensions_service_unittest.h +++ b/chrome/browser/extensions/extension_service_unittest.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_UNITTEST_H_ -#define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_UNITTEST_H_ +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_UNITTEST_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_UNITTEST_H_ #pragma once #include "base/file_path.h" @@ -12,21 +12,21 @@ #include "base/scoped_ptr.h" #include "base/scoped_temp_dir.h" #include "chrome/browser/browser_thread.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "testing/gtest/include/gtest/gtest.h" -class ExtensionsServiceTestBase : public testing::Test { +class ExtensionServiceTestBase : public testing::Test { public: - ExtensionsServiceTestBase(); - ~ExtensionsServiceTestBase(); + ExtensionServiceTestBase(); + ~ExtensionServiceTestBase(); - virtual void InitializeExtensionsService( + virtual void InitializeExtensionService( const FilePath& pref_file, const FilePath& extensions_install_dir); - virtual void InitializeInstalledExtensionsService( + virtual void InitializeInstalledExtensionService( const FilePath& prefs_file, const FilePath& source_install_dir); - virtual void InitializeEmptyExtensionsService(); + virtual void InitializeEmptyExtensionService(); static void SetUpTestCase(); @@ -40,7 +40,7 @@ class ExtensionsServiceTestBase : public testing::Test { ScopedTempDir temp_dir_; scoped_ptr<Profile> profile_; FilePath extensions_install_dir_; - scoped_refptr<ExtensionsService> service_; + scoped_refptr<ExtensionService> service_; size_t total_successes_; MessageLoop loop_; BrowserThread ui_thread_; @@ -50,4 +50,4 @@ class ExtensionsServiceTestBase : public testing::Test { BrowserThread io_thread_; }; -#endif // CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_UNITTEST_H_ +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_UNITTEST_H_ diff --git a/chrome/browser/extensions/extension_sidebar_api.cc b/chrome/browser/extensions/extension_sidebar_api.cc index 5495a8e..bd32d5a 100644 --- a/chrome/browser/extensions/extension_sidebar_api.cc +++ b/chrome/browser/extensions/extension_sidebar_api.cc @@ -10,13 +10,13 @@ #include "base/string16.h" #include "base/values.h" #include "chrome/browser/extensions/extension_event_router.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/sidebar/sidebar_container.h" #include "chrome/browser/sidebar/sidebar_manager.h" #include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents_wrapper.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_error_utils.h" diff --git a/chrome/browser/extensions/extension_startup_browsertest.cc b/chrome/browser/extensions/extension_startup_browsertest.cc index 97cc84d..25bad91 100644 --- a/chrome/browser/extensions/extension_startup_browsertest.cc +++ b/chrome/browser/extensions/extension_startup_browsertest.cc @@ -8,9 +8,9 @@ #include "base/file_path.h" #include "base/file_util.h" #include "base/path_service.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/user_script_master.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_paths.h" @@ -18,7 +18,6 @@ #include "chrome/common/notification_details.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" -#include "chrome/common/notification_service.h" #include "chrome/common/notification_type.h" #include "chrome/test/in_process_browser_test.h" #include "chrome/test/ui_test_utils.h" @@ -85,7 +84,7 @@ class ExtensionStartupTestBase : public InProcessBrowserTest { void WaitForServicesToStart(int num_expected_extensions, bool expect_extensions_enabled) { - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); // Count the number of non-component extensions. int found_extensions = 0; @@ -168,7 +167,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, Test) { IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, MAYBE_NoFileAccess) { WaitForServicesToStart(num_expected_extensions_, true); - ExtensionsService* service = browser()->profile()->GetExtensionsService(); + ExtensionService* service = browser()->profile()->GetExtensionService(); for (size_t i = 0; i < service->extensions()->size(); ++i) { if (service->extensions()->at(i)->location() == Extension::COMPONENT) continue; diff --git a/chrome/browser/extensions/extension_tabs_apitest.cc b/chrome/browser/extensions/extension_tabs_apitest.cc index 6ec3e6c..b736777 100644 --- a/chrome/browser/extensions/extension_tabs_apitest.cc +++ b/chrome/browser/extensions/extension_tabs_apitest.cc @@ -5,7 +5,7 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/pref_names.h" diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc index 169cfff..b58e07c 100644 --- a/chrome/browser/extensions/extension_tabs_module.cc +++ b/chrome/browser/extensions/extension_tabs_module.cc @@ -4,6 +4,9 @@ #include "chrome/browser/extensions/extension_tabs_module.h" +#include <algorithm> +#include <vector> + #include "base/base64.h" #include "base/string_number_conversions.h" #include "base/string_util.h" @@ -15,21 +18,22 @@ #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_infobar_delegate.h" #include "chrome/browser/extensions/extension_tabs_module_constants.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/backing_store.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/tab_contents_view.h" #include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents_wrapper.h" #include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_navigator.h" -#include "chrome/browser/window_sizer.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" +#include "chrome/browser/ui/window_sizer.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_error_utils.h" +#include "chrome/common/notification_service.h" #include "chrome/common/url_constants.h" #include "gfx/codec/jpeg_codec.h" #include "gfx/codec/png_codec.h" @@ -310,6 +314,7 @@ bool GetAllWindowsFunction::RunImpl() { bool CreateWindowFunction::RunImpl() { DictionaryValue* args = NULL; std::vector<GURL> urls; + TabContentsWrapper* contents = NULL; if (HasOptionalArgument(0)) EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); @@ -349,6 +354,29 @@ bool CreateWindowFunction::RunImpl() { } } + // Look for optional tab id. + if (args) { + int tab_id; + if (args->HasKey(keys::kTabIdKey)) { + EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kTabIdKey, &tab_id)); + + // Find the tab and detach it from the original window. + Browser* source_browser = NULL; + TabStripModel* source_tab_strip = NULL; + int tab_index = -1; + if (!GetTabById(tab_id, profile(), include_incognito(), + &source_browser, &source_tab_strip, &contents, + &tab_index, &error_)) + return false; + contents = source_tab_strip->DetachTabContentsAt(tab_index); + if (!contents) { + error_ = ExtensionErrorUtils::FormatErrorMessage( + keys::kTabNotFoundError, base::IntToString(tab_id)); + return false; + } + } + } + // Try to position the new browser relative its originating browser window. gfx::Rect window_bounds; bool maximized; @@ -428,8 +456,13 @@ bool CreateWindowFunction::RunImpl() { Browser* new_window = Browser::CreateForType(window_type, window_profile); for (std::vector<GURL>::iterator i = urls.begin(); i != urls.end(); ++i) new_window->AddSelectedTabWithURL(*i, PageTransition::LINK); - if (urls.size() == 0) + if (contents) { + TabStripModel* target_tab_strip = new_window->tabstrip_model(); + target_tab_strip->InsertTabContentsAt(urls.size(), contents, + TabStripModel::ADD_NONE); + } else if (urls.size() == 0) { new_window->NewTab(); + } new_window->SelectNumberedTab(0); if (window_type & Browser::TYPE_POPUP) new_window->window()->SetBounds(popup_bounds); @@ -517,6 +550,13 @@ bool RemoveWindowFunction::RunImpl() { if (!browser) return false; + // Don't let the extension remove the window if the user is dragging tabs + // in that window. + if (!browser->IsTabStripEditable()) { + error_ = keys::kTabStripNotEditableError; + return false; + } + browser->CloseWindow(); return true; @@ -815,8 +855,9 @@ bool MoveTabFunction::RunImpl() { &tab_index, &error_)) return false; - if (source_browser->type() != Browser::TYPE_NORMAL) { - error_ = keys::kCanOnlyMoveTabsWithinNormalWindowsError; + // Don't let the extension move the tab if the user is dragging tabs. + if (!source_browser->IsTabStripEditable()) { + error_ = keys::kTabStripNotEditableError; return false; } @@ -830,6 +871,11 @@ bool MoveTabFunction::RunImpl() { if (!target_browser) return false; + if (!target_browser->IsTabStripEditable()) { + error_ = keys::kTabStripNotEditableError; + return false; + } + if (target_browser->type() != Browser::TYPE_NORMAL) { error_ = keys::kCanOnlyMoveTabsWithinNormalWindowsError; return false; @@ -889,6 +935,12 @@ bool RemoveTabFunction::RunImpl() { &browser, NULL, &contents, NULL, &error_)) return false; + // Don't let the extension remove a tab if the user is dragging tabs around. + if (!browser->IsTabStripEditable()) { + error_ = keys::kTabStripNotEditableError; + return false; + } + // Close the tab in this convoluted way, since there's a chance that the tab // is being dragged, or we're in some other nested event loop. This code path // should ensure that the tab is safely closed under such circumstances, diff --git a/chrome/browser/extensions/extension_tabs_module.h b/chrome/browser/extensions/extension_tabs_module.h index 4307c90..7125867 100644 --- a/chrome/browser/extensions/extension_tabs_module.h +++ b/chrome/browser/extensions/extension_tabs_module.h @@ -9,7 +9,6 @@ #include <string> #include "chrome/browser/extensions/extension_function.h" -#include "chrome/common/notification_service.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" diff --git a/chrome/browser/extensions/extension_tabs_module_constants.cc b/chrome/browser/extensions/extension_tabs_module_constants.cc index 6405783..6ea521f 100644 --- a/chrome/browser/extensions/extension_tabs_module_constants.cc +++ b/chrome/browser/extensions/extension_tabs_module_constants.cc @@ -58,6 +58,8 @@ const char kNoCurrentWindowError[] = "No current window"; const char kNoLastFocusedWindowError[] = "No last-focused window"; const char kWindowNotFoundError[] = "No window with id: *."; const char kTabNotFoundError[] = "No tab with id: *."; +const char kTabStripNotEditableError[] = + "Tabs cannot be edited right now (user may be dragging a tab)."; const char kNoSelectedTabError[] = "No selected tab"; const char kInvalidUrlError[] = "Invalid url: \"*\"."; const char kInternalVisibleTabCaptureError[] = diff --git a/chrome/browser/extensions/extension_tabs_module_constants.h b/chrome/browser/extensions/extension_tabs_module_constants.h index 89c1cd3..4ac09de 100644 --- a/chrome/browser/extensions/extension_tabs_module_constants.h +++ b/chrome/browser/extensions/extension_tabs_module_constants.h @@ -61,6 +61,7 @@ extern const char kNoCurrentWindowError[]; extern const char kNoLastFocusedWindowError[]; extern const char kWindowNotFoundError[]; extern const char kTabNotFoundError[]; +extern const char kTabStripNotEditableError[]; extern const char kNoSelectedTabError[]; extern const char kInvalidUrlError[]; extern const char kInternalVisibleTabCaptureError[]; diff --git a/chrome/browser/extensions/extension_test_api.cc b/chrome/browser/extensions/extension_test_api.cc index eb50391..83800b0 100644 --- a/chrome/browser/extensions/extension_test_api.cc +++ b/chrome/browser/extensions/extension_test_api.cc @@ -6,9 +6,10 @@ #include <string> -#include "chrome/browser/extensions/extensions_service.h" +#include "base/singleton.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extensions_quota_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/notification_service.h" @@ -55,7 +56,7 @@ bool ExtensionTestLogFunction::RunImpl() { ExtensionTestQuotaResetFunction::~ExtensionTestQuotaResetFunction() {} bool ExtensionTestQuotaResetFunction::RunImpl() { - ExtensionsService* service = profile()->GetExtensionsService(); + ExtensionService* service = profile()->GetExtensionService(); ExtensionsQuotaService* quota = service->quota_service(); quota->Purge(); quota->violators_.clear(); @@ -93,17 +94,23 @@ void ExtensionTestSendMessageFunction::Reply(const std::string& message) { // static void ExtensionTestGetConfigFunction::set_test_config_state( DictionaryValue* value) { - TestConfigState* test_config_state = Singleton<TestConfigState>::get(); + TestConfigState* test_config_state = TestConfigState::GetInstance(); test_config_state->set_config_state(value); } ExtensionTestGetConfigFunction::TestConfigState::TestConfigState() : config_state_(NULL) {} +// static +ExtensionTestGetConfigFunction::TestConfigState* +ExtensionTestGetConfigFunction::TestConfigState::GetInstance() { + return Singleton<TestConfigState>::get(); +} + ExtensionTestGetConfigFunction::~ExtensionTestGetConfigFunction() {} bool ExtensionTestGetConfigFunction::RunImpl() { - TestConfigState* test_config_state = Singleton<TestConfigState>::get(); + TestConfigState* test_config_state = TestConfigState::GetInstance(); if (!test_config_state->config_state()) { error_ = kNoTestConfigDataError; diff --git a/chrome/browser/extensions/extension_test_api.h b/chrome/browser/extensions/extension_test_api.h index 27b55dc..1a0baa0 100644 --- a/chrome/browser/extensions/extension_test_api.h +++ b/chrome/browser/extensions/extension_test_api.h @@ -6,10 +6,11 @@ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_API_H_ #pragma once -#include "base/singleton.h" #include "base/values.h" #include "chrome/browser/extensions/extension_function.h" +template <typename T> struct DefaultSingletonTraits; + class ExtensionTestPassFunction : public SyncExtensionFunction { ~ExtensionTestPassFunction(); virtual bool RunImpl(); @@ -65,6 +66,8 @@ class ExtensionTestGetConfigFunction : public SyncExtensionFunction { // state, owned by the test code. class TestConfigState { public: + static TestConfigState* GetInstance(); + void set_config_state(DictionaryValue* config_state) { config_state_ = config_state; } diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/extensions/extension_toolbar_model.cc index 973dba8..3979cbf 100644 --- a/chrome/browser/extensions/extension_toolbar_model.cc +++ b/chrome/browser/extensions/extension_toolbar_model.cc @@ -5,14 +5,14 @@ #include "chrome/browser/extensions/extension_toolbar_model.h" #include "chrome/browser/extensions/extension_prefs.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/notification_service.h" #include "chrome/common/pref_names.h" -ExtensionToolbarModel::ExtensionToolbarModel(ExtensionsService* service) +ExtensionToolbarModel::ExtensionToolbarModel(ExtensionService* service) : service_(service), prefs_(service->profile()->GetPrefs()), extensions_initialized_(false) { @@ -22,8 +22,6 @@ ExtensionToolbarModel::ExtensionToolbarModel(ExtensionsService* service) Source<Profile>(service_->profile())); registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, Source<Profile>(service_->profile())); - registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, - Source<Profile>(service_->profile())); registrar_.Add(this, NotificationType::EXTENSIONS_READY, Source<Profile>(service_->profile())); registrar_.Add(this, @@ -96,7 +94,12 @@ void ExtensionToolbarModel::Observe(NotificationType type, if (!service_->is_ready()) return; - const Extension* extension = Details<const Extension>(details).ptr(); + const Extension* extension = NULL; + if (type == NotificationType::EXTENSION_UNLOADED) { + extension = Details<UnloadedExtensionInfo>(details)->extension; + } else { + extension = Details<const Extension>(details).ptr(); + } if (type == NotificationType::EXTENSION_LOADED) { // We don't want to add the same extension twice. It may have already been // added by EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED below, if the user @@ -105,9 +108,9 @@ void ExtensionToolbarModel::Observe(NotificationType type, if (toolitems_[i].get() == extension) return; // Already exists. } - AddExtension(extension); - } else if (type == NotificationType::EXTENSION_UNLOADED || - type == NotificationType::EXTENSION_UNLOADED_DISABLED) { + if (service_->GetBrowserActionVisibility(extension)) + AddExtension(extension); + } else if (type == NotificationType::EXTENSION_UNLOADED) { RemoveExtension(extension); } else if (type == NotificationType::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED) { @@ -160,7 +163,7 @@ void ExtensionToolbarModel::RemoveExtension(const Extension* extension) { } // Combine the currently enabled extensions that have browser actions (which -// we get from the ExtensionsService) with the ordering we get from the +// we get from the ExtensionService) with the ordering we get from the // pref service. For robustness we use a somewhat inefficient process: // 1. Create a vector of extensions sorted by their pref values. This vector may // have holes. diff --git a/chrome/browser/extensions/extension_toolbar_model.h b/chrome/browser/extensions/extension_toolbar_model.h index 37c3a08..f782c05 100644 --- a/chrome/browser/extensions/extension_toolbar_model.h +++ b/chrome/browser/extensions/extension_toolbar_model.h @@ -11,13 +11,13 @@ #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" -class ExtensionsService; +class ExtensionService; class PrefService; // Model for the browser actions toolbar. class ExtensionToolbarModel : public NotificationObserver { public: - explicit ExtensionToolbarModel(ExtensionsService* service); + explicit ExtensionToolbarModel(ExtensionService* service); ~ExtensionToolbarModel(); // Notifies the toolbar model that the Profile that suplied its @@ -96,8 +96,8 @@ class ExtensionToolbarModel : public NotificationObserver { void AddExtension(const Extension* extension); void RemoveExtension(const Extension* extension); - // Our ExtensionsService, guaranteed to outlive us. - ExtensionsService* service_; + // Our ExtensionService, guaranteed to outlive us. + ExtensionService* service_; PrefService* prefs_; diff --git a/chrome/browser/extensions/extension_toolbar_model_browsertest.cc b/chrome/browser/extensions/extension_toolbar_model_browsertest.cc index 755ac01..951f424 100644 --- a/chrome/browser/extensions/extension_toolbar_model_browsertest.cc +++ b/chrome/browser/extensions/extension_toolbar_model_browsertest.cc @@ -3,16 +3,16 @@ // found in the LICENSE file. #include "chrome/browser/extensions/extension_browsertest.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_toolbar_model.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/in_process_browser_test.h" // An InProcessBrowserTest for testing the ExtensionToolbarModel. // TODO(erikkay) It's unfortunate that this needs to be an in-proc browser test. -// It would be nice to refactor things so that ExtensionsService could run +// It would be nice to refactor things so that ExtensionService could run // without so much of the browser in place. class ExtensionToolbarModelTest : public ExtensionBrowserTest, public ExtensionToolbarModel::Observer { @@ -27,7 +27,7 @@ class ExtensionToolbarModelTest : public ExtensionBrowserTest, virtual Browser* CreateBrowser(Profile* profile) { Browser* b = InProcessBrowserTest::CreateBrowser(profile); - ExtensionsService* service = b->profile()->GetExtensionsService(); + ExtensionService* service = b->profile()->GetExtensionService(); model_ = service->toolbar_model(); model_->AddObserver(this); return b; diff --git a/chrome/browser/extensions/extension_tts_api.cc b/chrome/browser/extensions/extension_tts_api.cc index 1654b07..c618db3 100644 --- a/chrome/browser/extensions/extension_tts_api.cc +++ b/chrome/browser/extensions/extension_tts_api.cc @@ -2,22 +2,116 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/extensions/extension_tts_api.h" - #include <string> +#include <vector> #include "base/float_util.h" +#include "base/json/json_writer.h" #include "base/message_loop.h" #include "base/values.h" +#include "chrome/browser/extensions/extension_event_router.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_tts_api.h" +#include "chrome/browser/profiles/profile.h" namespace util = extension_tts_api_util; namespace { -const char kCrosLibraryNotLoadedError[] = - "Cros shared library not loaded."; +const char kSpeechInterruptedError[] = "Utterance interrupted."; +const char kSpeechRemovedFromQueueError[] = "Utterance removed from queue."; const int kSpeechCheckDelayIntervalMs = 100; }; +namespace events { +const char kOnSpeak[] = "experimental.tts.onSpeak"; +const char kOnStop[] = "experimental.tts.onStop"; +}; // namespace events + +// +// ExtensionTtsPlatformImpl +// + +std::string ExtensionTtsPlatformImpl::error() { + return error_; +} + +void ExtensionTtsPlatformImpl::clear_error() { + error_ = std::string(); +} + +void ExtensionTtsPlatformImpl::set_error(const std::string& error) { + error_ = error; +} + +// +// Utterance +// + +// static +int Utterance::next_utterance_id_ = 0; + +Utterance::Utterance(Profile* profile, + const std::string& text, + DictionaryValue* options, + Task* completion_task) + : profile_(profile), + id_(next_utterance_id_++), + text_(text), + rate_(-1.0), + pitch_(-1.0), + volume_(-1.0), + can_enqueue_(false), + completion_task_(completion_task) { + if (!options) { + // Use all default options. + options_.reset(new DictionaryValue()); + return; + } + + options_.reset(options->DeepCopy()); + + if (options->HasKey(util::kVoiceNameKey)) + options->GetString(util::kVoiceNameKey, &voice_name_); + + if (options->HasKey(util::kLocaleKey)) + options->GetString(util::kLocaleKey, &locale_); + + if (options->HasKey(util::kGenderKey)) + options->GetString(util::kGenderKey, &gender_); + + if (util::ReadNumberByKey(options, util::kRateKey, &rate_)) { + if (!base::IsFinite(rate_) || rate_ < 0.0 || rate_ > 1.0) + rate_ = -1.0; + } + + if (util::ReadNumberByKey(options, util::kPitchKey, &pitch_)) { + if (!base::IsFinite(pitch_) || pitch_ < 0.0 || pitch_ > 1.0) + pitch_ = -1.0; + } + + if (util::ReadNumberByKey(options, util::kVolumeKey, &volume_)) { + if (!base::IsFinite(volume_) || volume_ < 0.0 || volume_ > 1.0) + volume_ = -1.0; + } + + if (options->HasKey(util::kEnqueueKey)) + options->GetBoolean(util::kEnqueueKey, &can_enqueue_); +} + +Utterance::~Utterance() { + DCHECK_EQ(completion_task_, static_cast<Task *>(NULL)); +} + +void Utterance::FinishAndDestroy() { + completion_task_->Run(); + completion_task_ = NULL; + delete this; +} + +// +// ExtensionTtsController +// + // static ExtensionTtsController* ExtensionTtsController::GetInstance() { return Singleton<ExtensionTtsController>::get(); @@ -29,9 +123,13 @@ ExtensionTtsController::ExtensionTtsController() platform_impl_(NULL) { } -void ExtensionTtsController::SpeakOrEnqueue( - Utterance* utterance, bool can_enqueue) { - if (IsSpeaking() && can_enqueue) { +ExtensionTtsController::~ExtensionTtsController() { + FinishCurrentUtterance(); + ClearUtteranceQueue(); +} + +void ExtensionTtsController::SpeakOrEnqueue(Utterance* utterance) { + if (IsSpeaking() && utterance->can_enqueue()) { utterance_queue_.push(utterance); } else { Stop(); @@ -39,59 +137,167 @@ void ExtensionTtsController::SpeakOrEnqueue( } } +std::string ExtensionTtsController::GetMatchingExtensionId( + Utterance* utterance) { + ExtensionService* service = utterance->profile()->GetExtensionService(); + DCHECK(service); + ExtensionEventRouter* event_router = + utterance->profile()->GetExtensionEventRouter(); + DCHECK(event_router); + + const ExtensionList* extensions = service->extensions(); + ExtensionList::const_iterator iter; + for (iter = extensions->begin(); iter != extensions->end(); ++iter) { + const Extension* extension = *iter; + + if (!event_router->ExtensionHasEventListener( + extension->id(), events::kOnSpeak) || + !event_router->ExtensionHasEventListener( + extension->id(), events::kOnStop)) { + continue; + } + + const std::vector<Extension::TtsVoice>& tts_voices = + extension->tts_voices(); + for (size_t i = 0; i < tts_voices.size(); ++i) { + const Extension::TtsVoice& voice = tts_voices[i]; + if (!voice.voice_name.empty() && + !utterance->voice_name().empty() && + voice.voice_name != utterance->voice_name()) { + continue; + } + if (!voice.locale.empty() && + !utterance->locale().empty() && + voice.locale != utterance->locale()) { + continue; + } + if (!voice.gender.empty() && + !utterance->gender().empty() && + voice.gender != utterance->gender()) { + continue; + } + + return extension->id(); + } + } + + return std::string(); +} + void ExtensionTtsController::SpeakNow(Utterance* utterance) { + std::string extension_id = GetMatchingExtensionId(utterance); + if (!extension_id.empty()) { + current_utterance_ = utterance; + utterance->set_extension_id(extension_id); + + ListValue args; + args.Set(0, Value::CreateStringValue(utterance->text())); + + // Pass through all options to the speech engine, except for + // "enqueue", which the speech engine doesn't need to handle. + DictionaryValue* options = static_cast<DictionaryValue*>( + utterance->options()->DeepCopy()); + if (options->HasKey(util::kEnqueueKey)) + options->Remove(util::kEnqueueKey, NULL); + + args.Set(1, options); + args.Set(2, Value::CreateIntegerValue(utterance->id())); + std::string json_args; + base::JSONWriter::Write(&args, false, &json_args); + + utterance->profile()->GetExtensionEventRouter()->DispatchEventToExtension( + extension_id, + events::kOnSpeak, + json_args, + utterance->profile(), + GURL()); + + return; + } + GetPlatformImpl()->clear_error(); bool success = GetPlatformImpl()->Speak( - utterance->text, - utterance->language, - utterance->gender, - utterance->rate, - utterance->pitch, - utterance->volume); + utterance->text(), + utterance->locale(), + utterance->gender(), + utterance->rate(), + utterance->pitch(), + utterance->volume()); if (!success) { - utterance->error = GetPlatformImpl()->error(); - utterance->failure_task->Run(); - delete utterance->success_task; - delete utterance; + utterance->set_error(GetPlatformImpl()->error()); + utterance->FinishAndDestroy(); return; } current_utterance_ = utterance; - // Post a task to check if this utterance has completed after a delay. - MessageLoop::current()->PostDelayedTask( - FROM_HERE, method_factory_.NewRunnableMethod( - &ExtensionTtsController::CheckSpeechStatus), - kSpeechCheckDelayIntervalMs); + // Check to see if it's still speaking; finish the utterance if not and + // start polling if so. Checking immediately helps to avoid flaky unit + // tests by forcing them to set expectations for IsSpeaking. + CheckSpeechStatus(); } void ExtensionTtsController::Stop() { - GetPlatformImpl()->clear_error(); - GetPlatformImpl()->StopSpeaking(); + if (current_utterance_ && !current_utterance_->extension_id().empty()) { + current_utterance_->profile()->GetExtensionEventRouter()-> + DispatchEventToExtension( + current_utterance_->extension_id(), + events::kOnStop, + "[]", + current_utterance_->profile(), + GURL()); + } else { + GetPlatformImpl()->clear_error(); + GetPlatformImpl()->StopSpeaking(); + } + if (current_utterance_) + current_utterance_->set_error(kSpeechInterruptedError); FinishCurrentUtterance(); ClearUtteranceQueue(); } +void ExtensionTtsController::OnSpeechFinished( + int request_id, std::string error_message) { + // We may sometimes receive completion callbacks "late", after we've + // already finished the utterance (for example because another utterance + // interrupted or we got a call to Stop). It's also possible that a buggy + // extension has called this more than once. In either case it's safe to + // just ignore this call. + if (!current_utterance_ || request_id != current_utterance_->id()) + return; + + current_utterance_->set_error(error_message); + FinishCurrentUtterance(); + SpeakNextUtterance(); +} + bool ExtensionTtsController::IsSpeaking() const { return current_utterance_ != NULL; } void ExtensionTtsController::FinishCurrentUtterance() { if (current_utterance_) { - current_utterance_->success_task->Run(); - delete current_utterance_->failure_task; - delete current_utterance_; + current_utterance_->FinishAndDestroy(); current_utterance_ = NULL; } } +void ExtensionTtsController::SpeakNextUtterance() { + // Start speaking the next utterance in the queue. Keep trying in case + // one fails but there are still more in the queue to try. + while (!utterance_queue_.empty() && !current_utterance_) { + Utterance* utterance = utterance_queue_.front(); + utterance_queue_.pop(); + SpeakNow(utterance); + } +} + void ExtensionTtsController::ClearUtteranceQueue() { while (!utterance_queue_.empty()) { Utterance* utterance = utterance_queue_.front(); utterance_queue_.pop(); - utterance->success_task->Run(); - delete utterance->failure_task; - delete utterance; + utterance->set_error(kSpeechRemovedFromQueueError); + utterance->FinishAndDestroy(); } } @@ -99,21 +305,19 @@ void ExtensionTtsController::CheckSpeechStatus() { if (!current_utterance_) return; + if (!current_utterance_->extension_id().empty()) + return; + if (GetPlatformImpl()->IsSpeaking() == false) { FinishCurrentUtterance(); - - // Start speaking the next utterance in the queue. Keep trying in case - // one fails but there are still more in the queue to try. - while (!utterance_queue_.empty() && !current_utterance_) { - Utterance* utterance = utterance_queue_.front(); - utterance_queue_.pop(); - SpeakNow(utterance); - } + SpeakNextUtterance(); } // If we're still speaking something (either the prevoius utterance or // a new utterance), keep calling this method after another delay. - if (current_utterance_) { + // TODO(dmazzoni): get rid of this as soon as all platform implementations + // provide completion callbacks rather than only supporting polling. + if (current_utterance_ && current_utterance_->extension_id().empty()) { MessageLoop::current()->PostDelayedTask( FROM_HERE, method_factory_.NewRunnableMethod( &ExtensionTtsController::CheckSpeechStatus), @@ -137,67 +341,25 @@ ExtensionTtsPlatformImpl* ExtensionTtsController::GetPlatformImpl() { // bool ExtensionTtsSpeakFunction::RunImpl() { - utterance_ = new ExtensionTtsController::Utterance(); - bool can_enqueue = false; - - DictionaryValue* speak_options = NULL; - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &utterance_->text)); - - if (args_->GetDictionary(1, &speak_options)) { - if (speak_options->HasKey(util::kLanguageNameKey)) { - speak_options->GetString(util::kLanguageNameKey, &utterance_->language); - } - - if (speak_options->HasKey(util::kGenderKey)) { - speak_options->GetString(util::kGenderKey, &utterance_->gender); - } - - if (speak_options->HasKey(util::kEnqueueKey)) { - speak_options->GetBoolean(util::kEnqueueKey, &can_enqueue); - } - - if (util::ReadNumberByKey( - speak_options, util::kRateKey, &utterance_->rate)) { - if (!base::IsFinite(utterance_->rate) || - utterance_->rate < 0.0 || - utterance_->rate > 1.0) { - utterance_->rate = -1.0; - } - } - - if (util::ReadNumberByKey( - speak_options, util::kPitchKey, &utterance_->pitch)) { - if (!base::IsFinite(utterance_->pitch) || - utterance_->pitch < 0.0 || - utterance_->pitch > 1.0) { - utterance_->pitch = -1.0; - } - } - - if (util::ReadNumberByKey( - speak_options, util::kVolumeKey, &utterance_->volume)) { - if (!base::IsFinite(utterance_->volume) || - utterance_->volume < 0.0 || - utterance_->volume > 1.0) { - utterance_->volume = -1.0; - } - } - } + std::string text; + EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &text)); + DictionaryValue* options = NULL; + if (args_->GetSize() >= 2) + EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options)); + Task* completion_task = NewRunnableMethod( + this, &ExtensionTtsSpeakFunction::SpeechFinished); + utterance_ = new Utterance(profile(), text, options, completion_task); AddRef(); // Balanced in SpeechFinished(). - utterance_->success_task = NewRunnableMethod( - this, &ExtensionTtsSpeakFunction::SpeechFinished, true); - utterance_->failure_task = NewRunnableMethod( - this, &ExtensionTtsSpeakFunction::SpeechFinished, false); - ExtensionTtsController::GetInstance()->SpeakOrEnqueue( - utterance_, can_enqueue); + ExtensionTtsController::GetInstance()->SpeakOrEnqueue(utterance_); return true; } -void ExtensionTtsSpeakFunction::SpeechFinished(bool success) { - error_ = utterance_->error; +void ExtensionTtsSpeakFunction::SpeechFinished() { + error_ = utterance_->error(); + bool success = error_.empty(); SendResponse(success); - Release(); // Balanced in Speak(). + Release(); // Balanced in RunImpl(). } bool ExtensionTtsStopSpeakingFunction::RunImpl() { @@ -210,3 +372,15 @@ bool ExtensionTtsIsSpeakingFunction::RunImpl() { ExtensionTtsController::GetInstance()->IsSpeaking())); return true; } + +bool ExtensionTtsSpeakCompletedFunction::RunImpl() { + int request_id; + std::string error_message; + EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &request_id)); + if (args_->GetSize() >= 2) + EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &error_message)); + ExtensionTtsController::GetInstance()->OnSpeechFinished( + request_id, error_message); + + return true; +} diff --git a/chrome/browser/extensions/extension_tts_api.h b/chrome/browser/extensions/extension_tts_api.h index 0eedcc2..9f7da37 100644 --- a/chrome/browser/extensions/extension_tts_api.h +++ b/chrome/browser/extensions/extension_tts_api.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_H_ #include <queue> +#include <string> #include "base/singleton.h" #include "base/task.h" @@ -19,7 +20,7 @@ class ExtensionTtsPlatformImpl { // Speak the given utterance with the given parameters if possible, // and return true on success. Utterance will always be nonempty. - // If the user does not specify the other values, language and gender + // If the user does not specify the other values, then locale and gender // will be empty strings, and rate, pitch, and volume will be -1.0. // // The ExtensionTtsController will only try to speak one utterance at @@ -28,7 +29,7 @@ class ExtensionTtsPlatformImpl { // returns false before calling Speak again. virtual bool Speak( const std::string& utterance, - const std::string& language, + const std::string& locale, const std::string& gender, double rate, double pitch, @@ -40,9 +41,9 @@ class ExtensionTtsPlatformImpl { // Return true if the synthesis engine is currently speaking. virtual bool IsSpeaking() = 0; - virtual std::string error() { return error_; } - virtual void clear_error() { error_ = std::string(); } - virtual void set_error(const std::string& error) { error_ = error; } + virtual std::string error(); + virtual void clear_error(); + virtual void set_error(const std::string& error); protected: ExtensionTtsPlatformImpl() {} @@ -53,51 +54,108 @@ class ExtensionTtsPlatformImpl { DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImpl); }; +// One speech utterance. +class Utterance { + public: + // Construct an utterance given a profile, the text to speak, + // the options passed to tts.speak, and a completion task to call + // when the utterance is done speaking. + Utterance(Profile* profile, + const std::string& text, + DictionaryValue* options, + Task* completion_task); + ~Utterance(); + + // Calls the completion task and then destroys itself. + void FinishAndDestroy(); + + void set_error(const std::string& error) { error_ = error; } + void set_extension_id(const std::string& extension_id) { + extension_id_ = extension_id; + } + + // Accessors + Profile* profile() { return profile_; } + const std::string& extension_id() { return extension_id_; } + int id() { return id_; } + const std::string& text() { return text_; } + const Value* options() { return options_.get(); } + const std::string& voice_name() { return voice_name_; } + const std::string& locale() { return locale_; } + const std::string& gender() { return gender_; } + double rate() { return rate_; } + double pitch() { return pitch_; } + double volume() { return volume_; } + bool can_enqueue() { return can_enqueue_; } + const std::string& error() { return error_; } + + private: + // The profile that initiated this utterance. + Profile* profile_; + + // The extension ID of the extension providing TTS for this utterance, or + // empty if native TTS is being used. + std::string extension_id_; + + // The unique ID of this utterance, used to associate callback functions + // with utterances. + int id_; + + // The id of the next utterance, so we can associate requests with + // responses. + static int next_utterance_id_; + + // The text to speak. + std::string text_; + + // The full options arg passed to tts.speak, which may include fields + // other than the ones we explicitly parse, below. + scoped_ptr<Value> options_; + + // The parsed options. + std::string voice_name_; + std::string locale_; + std::string gender_; + double rate_; + double pitch_; + double volume_; + bool can_enqueue_; + + // The error string to pass to the completion task. Will be empty if + // no error occurred. + std::string error_; + + // The method to call when this utterance has completed speaking. + Task* completion_task_; +}; + // Singleton class that manages text-to-speech. class ExtensionTtsController { public: // Get the single instance of this class. static ExtensionTtsController* GetInstance(); - struct Utterance { - Utterance() - : rate(-1.0), - pitch(-1.0), - volume(-1.0), - success_task(NULL), - failure_task(NULL) { - } - - std::string text; - std::string language; - std::string gender; - double rate; - double pitch; - double volume; - - Task* success_task; - Task* failure_task; - - std::string error; - }; - // Returns true if we're currently speaking an utterance. bool IsSpeaking() const; - // Speak the given utterance. If |can_enqueue| is true and another - // utterance is in progress, adds it to the end of the queue. Otherwise, - // interrupts any current utterance and speaks this one immediately. - void SpeakOrEnqueue(Utterance* utterance, bool can_enqueue); + // Speak the given utterance. If the utterance's can_enqueue flag is true + // and another utterance is in progress, adds it to the end of the queue. + // Otherwise, interrupts any current utterance and speaks this one + // immediately. + void SpeakOrEnqueue(Utterance* utterance); // Stop all utterances and flush the queue. void Stop(); + // Called when an extension finishes speaking an utterance. + void OnSpeechFinished(int request_id, std::string error_message); + // For unit testing. void SetPlatformImpl(ExtensionTtsPlatformImpl* platform_impl); private: ExtensionTtsController(); - virtual ~ExtensionTtsController() {} + virtual ~ExtensionTtsController(); // Get the platform TTS implementation (or injected mock). ExtensionTtsPlatformImpl* GetPlatformImpl(); @@ -117,6 +175,14 @@ class ExtensionTtsController { // Finalize and delete the current utterance. void FinishCurrentUtterance(); + // Start speaking the next utterance in the queue. + void SpeakNextUtterance(); + + // Return the id string of the first extension with tts_voices in its + // manifest that matches the speech parameters of this utterance, + // or the empty string if none is found. + std::string GetMatchingExtensionId(Utterance* utterance); + ScopedRunnableMethodFactory<ExtensionTtsController> method_factory_; friend struct DefaultSingletonTraits<ExtensionTtsController>; @@ -141,8 +207,8 @@ class ExtensionTtsSpeakFunction : public AsyncExtensionFunction { private: ~ExtensionTtsSpeakFunction() {} virtual bool RunImpl(); - void SpeechFinished(bool success); - ExtensionTtsController::Utterance* utterance_; + void SpeechFinished(); + Utterance* utterance_; DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.speak") }; @@ -160,4 +226,11 @@ class ExtensionTtsIsSpeakingFunction : public SyncExtensionFunction { DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.isSpeaking") }; +class ExtensionTtsSpeakCompletedFunction : public SyncExtensionFunction { + private: + ~ExtensionTtsSpeakCompletedFunction() {} + virtual bool RunImpl(); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.speakCompleted") +}; + #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_H_ diff --git a/chrome/browser/extensions/extension_tts_api_chromeos.cc b/chrome/browser/extensions/extension_tts_api_chromeos.cc index a183612..4e6ce65 100644 --- a/chrome/browser/extensions/extension_tts_api_chromeos.cc +++ b/chrome/browser/extensions/extension_tts_api_chromeos.cc @@ -21,7 +21,7 @@ class ExtensionTtsPlatformImplChromeOs : public ExtensionTtsPlatformImpl { public: virtual bool Speak( const std::string& utterance, - const std::string& language, + const std::string& locale, const std::string& gender, double rate, double pitch, @@ -38,6 +38,10 @@ class ExtensionTtsPlatformImplChromeOs : public ExtensionTtsPlatformImpl { ExtensionTtsPlatformImplChromeOs() {} virtual ~ExtensionTtsPlatformImplChromeOs() {} + void AppendSpeakOption(std::string key, + std::string value, + std::string* options); + friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplChromeOs>; DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplChromeOs); @@ -50,7 +54,7 @@ ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() { bool ExtensionTtsPlatformImplChromeOs::Speak( const std::string& utterance, - const std::string& language, + const std::string& locale, const std::string& gender, double rate, double pitch, @@ -63,31 +67,41 @@ bool ExtensionTtsPlatformImplChromeOs::Speak( std::string options; - if (!language.empty()) { - util::AppendSpeakOption( - std::string(util::kNameKey), language, &options); + if (!locale.empty()) { + AppendSpeakOption( + chromeos::SpeechSynthesisLibrary::kSpeechPropertyLocale, + locale, + &options); } if (!gender.empty()) { - util::AppendSpeakOption( - std::string(util::kGenderKey), gender, &options); + AppendSpeakOption( + chromeos::SpeechSynthesisLibrary::kSpeechPropertyGender, + gender, + &options); } if (rate >= 0.0) { - util::AppendSpeakOption( - std::string(util::kRateKey), DoubleToString(rate * 5), &options); + AppendSpeakOption( + chromeos::SpeechSynthesisLibrary::kSpeechPropertyRate, + DoubleToString(rate * 5), + &options); } if (pitch >= 0.0) { // The TTS service allows a range of 0 to 2 for speech pitch. - util::AppendSpeakOption( - std::string(util::kPitchKey), DoubleToString(pitch * 2), &options); + AppendSpeakOption( + chromeos::SpeechSynthesisLibrary::kSpeechPropertyPitch, + DoubleToString(pitch * 2), + &options); } if (volume >= 0.0) { // The TTS service allows a range of 0 to 5 for speech volume. - util::AppendSpeakOption( - std::string(util::kVolumeKey), DoubleToString(volume * 5), &options); + AppendSpeakOption( + chromeos::SpeechSynthesisLibrary::kSpeechPropertyVolume, + DoubleToString(volume * 5), + &options); } if (!options.empty()) { @@ -118,6 +132,17 @@ bool ExtensionTtsPlatformImplChromeOs::IsSpeaking() { return false; } +void ExtensionTtsPlatformImplChromeOs::AppendSpeakOption( + std::string key, + std::string value, + std::string* options) { + *options += + key + + chromeos::SpeechSynthesisLibrary::kSpeechPropertyEquals + + value + + chromeos::SpeechSynthesisLibrary::kSpeechPropertyDelimiter; +} + // static ExtensionTtsPlatformImplChromeOs* ExtensionTtsPlatformImplChromeOs::GetInstance() { diff --git a/chrome/browser/extensions/extension_tts_api_util.cc b/chrome/browser/extensions/extension_tts_api_util.cc index ac5d53b..b3ef18c 100644 --- a/chrome/browser/extensions/extension_tts_api_util.cc +++ b/chrome/browser/extensions/extension_tts_api_util.cc @@ -6,6 +6,14 @@ namespace extension_tts_api_util { +const char kVoiceNameKey[] = "voiceName"; +const char kLocaleKey[] = "locale"; +const char kGenderKey[] = "gender"; +const char kRateKey[] = "rate"; +const char kPitchKey[] = "pitch"; +const char kVolumeKey[] = "volume"; +const char kEnqueueKey[] = "enqueue"; + // Static. bool ReadNumberByKey(DictionaryValue* dict, const char* key, @@ -28,11 +36,4 @@ bool ReadNumberByKey(DictionaryValue* dict, return true; } -// Static. -void AppendSpeakOption(std::string key, - std::string value, - std::string* options) { - *options += key + kEqualStr + value + kDelimiter; -} - } // namespace extension_tts_api_util. diff --git a/chrome/browser/extensions/extension_tts_api_util.h b/chrome/browser/extensions/extension_tts_api_util.h index cf0d702..9d13e75 100644 --- a/chrome/browser/extensions/extension_tts_api_util.h +++ b/chrome/browser/extensions/extension_tts_api_util.h @@ -11,23 +11,17 @@ namespace extension_tts_api_util { -const char kNameKey[] = "name"; -const char kLanguageNameKey[] = "languageName"; -const char kGenderKey[] = "gender"; -const char kRateKey[] = "rate"; -const char kPitchKey[] = "pitch"; -const char kVolumeKey[] = "volume"; -const char kEnqueueKey[] = "enqueue"; -const char kEqualStr[] = "="; -const char kDelimiter[] = ";"; +extern const char kVoiceNameKey[]; +extern const char kLocaleKey[]; +extern const char kGenderKey[]; +extern const char kRateKey[]; +extern const char kPitchKey[]; +extern const char kVolumeKey[]; +extern const char kEnqueueKey[]; bool ReadNumberByKey(DictionaryValue* dict, const char* key, double* ret_value); -void AppendSpeakOption(std::string key, - std::string value, - std::string* options); - } // namespace extension_tts_api_util. #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_UTIL_H_ diff --git a/chrome/browser/extensions/extension_tts_apitest.cc b/chrome/browser/extensions/extension_tts_apitest.cc index 6f37404..f7ed0d8 100644 --- a/chrome/browser/extensions/extension_tts_apitest.cc +++ b/chrome/browser/extensions/extension_tts_apitest.cc @@ -16,6 +16,7 @@ #include "chrome/browser/chromeos/cros/cros_mock.h" #endif +using ::testing::AnyNumber; using ::testing::CreateFunctor; using ::testing::DoAll; using ::testing::InSequence; @@ -28,7 +29,7 @@ class MockExtensionTtsPlatformImpl : public ExtensionTtsPlatformImpl { public: MOCK_METHOD6(Speak, bool(const std::string& utterance, - const std::string& language, + const std::string& locale, const std::string& gender, double rate, double pitch, @@ -83,11 +84,20 @@ IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakKeepsSpeakingTwice) { } IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakInterrupt) { + // One utterances starts speaking, and then a second interrupts. InSequence s; EXPECT_CALL(mock_platform_impl_, StopSpeaking()) .WillOnce(Return(true)); EXPECT_CALL(mock_platform_impl_, Speak("text 1", _, _, _, _, _)) .WillOnce(Return(true)); + + // Ensure that the first utterance keeps going until it's interrupted. + EXPECT_CALL(mock_platform_impl_, IsSpeaking()) + .Times(AnyNumber()) + .WillRepeatedly(Return(true)); + + // Expect the second utterance and allow it to continue for two calls to + // IsSpeaking and then finish successfully. EXPECT_CALL(mock_platform_impl_, StopSpeaking()) .WillOnce(Return(true)); EXPECT_CALL(mock_platform_impl_, Speak("text 2", _, _, _, _, _)) @@ -107,6 +117,14 @@ IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakQueueInterrupt) { .WillOnce(Return(true)); EXPECT_CALL(mock_platform_impl_, Speak("text 1", _, _, _, _, _)) .WillOnce(Return(true)); + + // Ensure that the first utterance keeps going until it's interrupted. + EXPECT_CALL(mock_platform_impl_, IsSpeaking()) + .Times(AnyNumber()) + .WillRepeatedly(Return(true)); + + // Expect the third utterance and allow it to continue for two calls to + // IsSpeaking and then finish successfully. EXPECT_CALL(mock_platform_impl_, StopSpeaking()) .WillOnce(Return(true)); EXPECT_CALL(mock_platform_impl_, Speak("text 3", _, _, _, _, _)) @@ -145,12 +163,16 @@ IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakError) { .WillOnce(Return(true)); EXPECT_CALL(mock_platform_impl_, IsSpeaking()) .WillOnce(Return(false)); + EXPECT_CALL(mock_platform_impl_, StopSpeaking()) + .WillOnce(Return(true)); EXPECT_CALL(mock_platform_impl_, Speak(_, _, _, _, _, _)) .WillOnce(DoAll( InvokeWithoutArgs( CreateFunctor(&mock_platform_impl_, &MockExtensionTtsPlatformImpl::SetErrorToEpicFail)), Return(false))); + EXPECT_CALL(mock_platform_impl_, StopSpeaking()) + .WillOnce(Return(true)); EXPECT_CALL(mock_platform_impl_, Speak(_, _, _, _, _, _)) .WillOnce(Return(true)); EXPECT_CALL(mock_platform_impl_, IsSpeaking()) @@ -158,6 +180,25 @@ IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakError) { ASSERT_TRUE(RunExtensionTest("tts/speak_error")) << message_; } +IN_PROC_BROWSER_TEST_F(TtsApiTest, Provide) { + EXPECT_CALL(mock_platform_impl_, StopSpeaking()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(mock_platform_impl_, IsSpeaking()) + .WillRepeatedly(Return(false)); + + { + InSequence s; + EXPECT_CALL(mock_platform_impl_, Speak("native speech", _, _, _, _, _)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_platform_impl_, Speak("native speech 2", _, _, _, _, _)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_platform_impl_, Speak("native speech 3", _, _, _, _, _)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(RunExtensionTest("tts/provide")) << message_; +} + #if defined(OS_CHROMEOS) IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TtsChromeOs) { CommandLine::ForCurrentProcess()->AppendSwitch( diff --git a/chrome/browser/extensions/extension_uitest.cc b/chrome/browser/extensions/extension_uitest.cc index bc25d75..845696e 100644 --- a/chrome/browser/extensions/extension_uitest.cc +++ b/chrome/browser/extensions/extension_uitest.cc @@ -126,15 +126,15 @@ TEST_F(ExtensionTestSimpleApiCall, FLAKY_RunTest) { namespace keys = extension_automation_constants; ASSERT_THAT(mock_, testing::NotNull()); - EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1); - EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _, _)) + EXPECT_CALL(*mock_, OnDidNavigate(_)).Times(1); + EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); std::string message_received; EXPECT_CALL(*mock_, OnForwardMessageToExternalHost( - _, _, keys::kAutomationOrigin, keys::kAutomationRequestTarget)) + _, keys::kAutomationOrigin, keys::kAutomationRequestTarget)) .WillOnce(DoAll( - SaveArg<1>(&message_received), + SaveArg<0>(&message_received), InvokeWithoutArgs( CreateFunctor(&loop_, &TimedMessageLoopRunner::Quit)))); @@ -277,15 +277,15 @@ TEST_F(ExtensionTestRoundtripApiCall, FLAKY_RunTest) { namespace keys = extension_automation_constants; ASSERT_THAT(mock_, testing::NotNull()); - EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1); - EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _, _)) + EXPECT_CALL(*mock_, OnDidNavigate(_)).Times(1); + EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); - EXPECT_CALL(*mock_, OnLoad(_, _)).Times(testing::AnyNumber()); + EXPECT_CALL(*mock_, OnLoad(_)).Times(testing::AnyNumber()); EXPECT_CALL(*mock_, OnForwardMessageToExternalHost( - _, _, keys::kAutomationOrigin, keys::kAutomationRequestTarget)) + _, keys::kAutomationOrigin, keys::kAutomationRequestTarget)) .Times(2) - .WillRepeatedly(WithArgs<1>(Invoke( + .WillRepeatedly(WithArgs<0>(Invoke( CreateFunctor(this, &ExtensionTestRoundtripApiCall::CheckAndSendResponse)))); @@ -465,14 +465,14 @@ TEST_F(ExtensionTestBrowserEvents, FLAKY_RunTest) { namespace keys = extension_automation_constants; ASSERT_THAT(mock_, testing::NotNull()); - EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1); - EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _, _)) + EXPECT_CALL(*mock_, OnDidNavigate(_)).Times(1); + EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); - EXPECT_CALL(*mock_, OnLoad(_, _)).Times(testing::AnyNumber()); + EXPECT_CALL(*mock_, OnLoad(_)).Times(testing::AnyNumber()); EXPECT_CALL(*mock_, OnForwardMessageToExternalHost( - _, _, keys::kAutomationOrigin, _)) - .WillRepeatedly(WithArgs<1, 3>(Invoke( + _, keys::kAutomationOrigin, _)) + .WillRepeatedly(WithArgs<0, 2>(Invoke( CreateFunctor(this, &ExtensionTestBrowserEvents::HandleMessageFromChrome)))); diff --git a/chrome/browser/extensions/extension_updater.cc b/chrome/browser/extensions/extension_updater.cc index 15e26aa..63374ac 100644 --- a/chrome/browser/extensions/extension_updater.cc +++ b/chrome/browser/extensions/extension_updater.cc @@ -21,9 +21,9 @@ #include "base/version.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/extension_error_reporter.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/utility_process_host.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_version_info.h" @@ -190,8 +190,7 @@ void ManifestFetchesBuilder::AddExtension(const Extension& extension) { AddExtensionData(extension.location(), extension.id(), *extension.version(), - (extension.is_theme() ? PendingExtensionInfo::THEME - : PendingExtensionInfo::EXTENSION), + extension.GetType(), extension.update_url(), update_url_data); } @@ -204,17 +203,20 @@ void ManifestFetchesBuilder::AddPendingExtension( scoped_ptr<Version> version( Version::GetVersionFromString("0.0.0.0")); - AddExtensionData(info.install_source, id, *version, - info.expected_crx_type, info.update_url, ""); + AddExtensionData( + info.install_source, id, *version, + Extension::TYPE_UNKNOWN, info.update_url, ""); } void ManifestFetchesBuilder::ReportStats() const { - UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtensions", - url_stats_.google_url_count + - url_stats_.other_url_count - - url_stats_.theme_count); + UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtension", + url_stats_.extension_count); UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckTheme", url_stats_.theme_count); + UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckApp", + url_stats_.app_count); + UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckPending", + url_stats_.pending_count); UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckGoogleUrl", url_stats_.google_url_count); UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckOtherUrl", @@ -239,7 +241,7 @@ void ManifestFetchesBuilder::AddExtensionData( Extension::Location location, const std::string& id, const Version& version, - PendingExtensionInfo::ExpectedCrxType crx_type, + Extension::Type extension_type, GURL update_url, const std::string& update_url_data) { @@ -272,8 +274,21 @@ void ManifestFetchesBuilder::AddExtensionData( url_stats_.other_url_count++; } - if (crx_type == PendingExtensionInfo::THEME) { - url_stats_.theme_count++; + switch (extension_type) { + case Extension::TYPE_THEME: + ++url_stats_.theme_count; + break; + case Extension::TYPE_EXTENSION: + case Extension::TYPE_USER_SCRIPT: + ++url_stats_.extension_count; + break; + case Extension::TYPE_HOSTED_APP: + case Extension::TYPE_PACKAGED_APP: + ++url_stats_.app_count; + case Extension::TYPE_UNKNOWN: + default: + ++url_stats_.pending_count; + break; } DCHECK(!update_url.is_empty()); @@ -637,7 +652,7 @@ void ExtensionUpdater::OnCRXFetchComplete(const GURL& url, ProcessBlacklist(data); } else { // Successfully fetched - now write crx to a file so we can have the - // ExtensionsService install it. + // ExtensionService install it. BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableMethod( @@ -669,7 +684,7 @@ void ExtensionUpdater::OnCRXFileWritten(const std::string& id, // This can be called after we've been stopped. if (!alive_) return; - // The ExtensionsService is now responsible for cleaning up the temp file + // The ExtensionService is now responsible for cleaning up the temp file // at |path|. service_->UpdateExtension(id, path, download_url); } @@ -701,7 +716,7 @@ void ExtensionUpdater::TimerFired() { // If the user has overridden the update frequency, don't bother reporting // this. - if (frequency_seconds_ == ExtensionsService::kDefaultUpdateFrequencySeconds) { + if (frequency_seconds_ == ExtensionService::kDefaultUpdateFrequencySeconds) { Time last = Time::FromInternalValue(prefs_->GetInt64( kLastExtensionsUpdateCheck)); if (last.ToInternalValue() != 0) { @@ -734,7 +749,10 @@ void ExtensionUpdater::CheckNow() { service_->pending_extensions(); for (PendingExtensionMap::const_iterator iter = pending_extensions.begin(); iter != pending_extensions.end(); ++iter) { - fetches_builder.AddPendingExtension(iter->first, iter->second); + Extension::Location location = iter->second.install_source; + if (location != Extension::EXTERNAL_PREF && + location != Extension::EXTERNAL_REGISTRY) + fetches_builder.AddPendingExtension(iter->first, iter->second); } fetches_builder.ReportStats(); diff --git a/chrome/browser/extensions/extension_updater.h b/chrome/browser/extensions/extension_updater.h index 041dba0..d9e6a3e 100644 --- a/chrome/browser/extensions/extension_updater.h +++ b/chrome/browser/extensions/extension_updater.h @@ -19,7 +19,7 @@ #include "base/task.h" #include "base/time.h" #include "base/timer.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/common/extensions/update_manifest.h" #include "chrome/common/net/url_fetcher.h" #include "googleurl/src/gurl.h" @@ -104,15 +104,19 @@ class ManifestFetchesBuilder { : no_url_count(0), google_url_count(0), other_url_count(0), - theme_count(0) {} + extension_count(0), + theme_count(0), + app_count(0), + pending_count(0) {} - int no_url_count, google_url_count, other_url_count, theme_count; + int no_url_count, google_url_count, other_url_count; + int extension_count, theme_count, app_count, pending_count; }; void AddExtensionData(Extension::Location location, const std::string& id, const Version& version, - PendingExtensionInfo::ExpectedCrxType crx_type, + Extension::Type extension_type, GURL update_url, const std::string& update_url_data); ExtensionUpdateService* service_; diff --git a/chrome/browser/extensions/extension_updater_unittest.cc b/chrome/browser/extensions/extension_updater_unittest.cc index b85d5d8..d501de6 100644 --- a/chrome/browser/extensions/extension_updater_unittest.cc +++ b/chrome/browser/extensions/extension_updater_unittest.cc @@ -16,7 +16,7 @@ #include "chrome/browser/browser_thread.h" #include "chrome/browser/extensions/extension_error_reporter.h" #include "chrome/browser/extensions/extension_updater.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/test_extension_prefs.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/common/extensions/extension.h" @@ -124,22 +124,34 @@ std::string GenerateId(std::string input) { return result; } +bool ShouldInstallExtensionsOnly(const Extension& extension) { + return extension.GetType() == Extension::TYPE_EXTENSION; +} + +bool ShouldInstallThemesOnly(const Extension& extension) { + return extension.is_theme(); +} + +bool ShouldAlwaysInstall(const Extension& extension) { + return true; +} + // Creates test pending extensions and inserts them into list. The // name and version are all based on their index. void CreateTestPendingExtensions(int count, const GURL& update_url, PendingExtensionMap* pending_extensions) { - PendingExtensionInfo::ExpectedCrxType crx_type; for (int i = 1; i <= count; i++) { - crx_type = ((i % 2) ? PendingExtensionInfo::EXTENSION - : PendingExtensionInfo::THEME); + ShouldInstallExtensionPredicate should_install_extension = + (i % 2 == 0) ? &ShouldInstallThemesOnly : + &ShouldInstallExtensionsOnly; const bool kIsFromSync = true; const bool kInstallSilently = true; const Extension::State kInitialState = Extension::ENABLED; const bool kInitialIncognitoEnabled = false; std::string id = GenerateId(base::StringPrintf("extension%i", i)); (*pending_extensions)[id] = - PendingExtensionInfo(update_url, crx_type, kIsFromSync, - kInstallSilently, kInitialState, + PendingExtensionInfo(update_url, should_install_extension, + kIsFromSync, kInstallSilently, kInitialState, kInitialIncognitoEnabled, Extension::INTERNAL); } } @@ -636,15 +648,13 @@ class ExtensionUpdaterTest : public testing::Test { updater->FetchUpdatedExtension(id, test_url, hash, version->GetString()); if (pending) { - const PendingExtensionInfo::ExpectedCrxType kExpectedCrxType = - PendingExtensionInfo::EXTENSION; const bool kIsFromSync = true; const bool kInstallSilently = true; const Extension::State kInitialState = Extension::ENABLED; const bool kInitialIncognitoEnabled = false; PendingExtensionMap pending_extensions; pending_extensions[id] = - PendingExtensionInfo(test_url, kExpectedCrxType, kIsFromSync, + PendingExtensionInfo(test_url, &ShouldAlwaysInstall, kIsFromSync, kInstallSilently, kInitialState, kInitialIncognitoEnabled, Extension::INTERNAL); service.set_pending_extensions(pending_extensions); @@ -985,14 +995,14 @@ TEST(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) { // Extensions with invalid update URLs should be rejected. builder.AddPendingExtension( GenerateId("foo"), PendingExtensionInfo(GURL("http:google.com:foo"), - PendingExtensionInfo::EXTENSION, + &ShouldInstallExtensionsOnly, false, false, true, false, Extension::INTERNAL)); EXPECT_TRUE(builder.GetFetches().empty()); // Extensions with empty IDs should be rejected. builder.AddPendingExtension( - "", PendingExtensionInfo(GURL(), PendingExtensionInfo::EXTENSION, + "", PendingExtensionInfo(GURL(), &ShouldInstallExtensionsOnly, false, false, true, false, Extension::INTERNAL)); EXPECT_TRUE(builder.GetFetches().empty()); @@ -1004,7 +1014,7 @@ TEST(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) { // filled in. builder.AddPendingExtension( GenerateId("foo"), PendingExtensionInfo(GURL(), - PendingExtensionInfo::EXTENSION, + &ShouldInstallExtensionsOnly, false, false, true, false, Extension::INTERNAL)); std::vector<ManifestFetchData*> fetches = builder.GetFetches(); diff --git a/chrome/browser/extensions/extension_webglbackground_apitest.cc b/chrome/browser/extensions/extension_webglbackground_apitest.cc new file mode 100644 index 0000000..9e7701c --- /dev/null +++ b/chrome/browser/extensions/extension_webglbackground_apitest.cc @@ -0,0 +1,9 @@ +// Copyright (c) 2010 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/extension_apitest.h" + +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebGLBackground) { + ASSERT_TRUE(RunExtensionTest("webglbackground")) << message_; +} diff --git a/chrome/browser/extensions/extension_webnavigation_api.cc b/chrome/browser/extensions/extension_webnavigation_api.cc index 9a3e4ab..2e3a1ca 100644 --- a/chrome/browser/extensions/extension_webnavigation_api.cc +++ b/chrome/browser/extensions/extension_webnavigation_api.cc @@ -12,12 +12,11 @@ #include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/extensions/extension_webnavigation_api_constants.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/navigation_controller.h" #include "chrome/browser/tab_contents/provisional_load_details.h" #include "chrome/common/notification_type.h" #include "chrome/common/notification_service.h" -#include "chrome/common/url_constants.h" #include "net/base/net_errors.h" namespace keys = extension_webnavigation_api_constants; @@ -37,34 +36,35 @@ double MilliSecondsFromTime(const base::Time& time) { } // namespace + FrameNavigationState::FrameNavigationState() { } FrameNavigationState::~FrameNavigationState() { } -bool FrameNavigationState::CanSendEvents(long long frame_id) const { +bool FrameNavigationState::CanSendEvents(int64 frame_id) const { FrameIdToStateMap::const_iterator frame_state = frame_state_map_.find(frame_id); return frame_state != frame_state_map_.end() && !frame_state->second.error_occurred; } -void FrameNavigationState::TrackFrame(long long frame_id, +void FrameNavigationState::TrackFrame(int64 frame_id, const GURL& url, bool is_main_frame, + bool is_error_page, const TabContents* tab_contents) { if (is_main_frame) RemoveTabContentsState(tab_contents); - tab_contents_map_.insert( - TabContentsToFrameIdMap::value_type(tab_contents, frame_id)); + tab_contents_map_.insert(std::make_pair(tab_contents, frame_id)); FrameState& frame_state = frame_state_map_[frame_id]; - frame_state.error_occurred = (url.spec() == chrome::kUnreachableWebDataURL); + frame_state.error_occurred = is_error_page; frame_state.url = url; frame_state.is_main_frame = is_main_frame; } -GURL FrameNavigationState::GetUrl(long long frame_id) const { +GURL FrameNavigationState::GetUrl(int64 frame_id) const { FrameIdToStateMap::const_iterator frame_state = frame_state_map_.find(frame_id); if (frame_state == frame_state_map_.end()) { @@ -74,7 +74,7 @@ GURL FrameNavigationState::GetUrl(long long frame_id) const { return frame_state->second.url; } -bool FrameNavigationState::IsMainFrame(long long frame_id) const { +bool FrameNavigationState::IsMainFrame(int64 frame_id) const { FrameIdToStateMap::const_iterator frame_state = frame_state_map_.find(frame_id); if (frame_state == frame_state_map_.end()) { @@ -84,7 +84,7 @@ bool FrameNavigationState::IsMainFrame(long long frame_id) const { return frame_state->second.is_main_frame; } -void FrameNavigationState::ErrorOccurredInFrame(long long frame_id) { +void FrameNavigationState::ErrorOccurredInFrame(int64 frame_id) { DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end()); frame_state_map_[frame_id].error_occurred = true; } @@ -93,7 +93,7 @@ void FrameNavigationState::RemoveTabContentsState( const TabContents* tab_contents) { typedef TabContentsToFrameIdMap::iterator FrameIdIterator; std::pair<FrameIdIterator, FrameIdIterator> frame_ids = - tab_contents_map_.equal_range(tab_contents); + tab_contents_map_.equal_range(tab_contents); for (FrameIdIterator frame_id = frame_ids.first; frame_id != frame_ids.second; ++frame_id) { frame_state_map_.erase(frame_id->second); @@ -149,19 +149,18 @@ void ExtensionWebNavigationEventRouter::Observe( case NotificationType::FRAME_DOM_CONTENT_LOADED: FrameDomContentLoaded( Source<NavigationController>(source).ptr(), - *Details<long long>(details).ptr()); + *Details<int64>(details).ptr()); break; case NotificationType::FRAME_DID_FINISH_LOAD: FrameDidFinishLoad( Source<NavigationController>(source).ptr(), - *Details<long long>(details).ptr()); + *Details<int64>(details).ptr()); break; case NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR: FailProvisionalLoadWithError( Source<NavigationController>(source).ptr(), Details<ProvisionalLoadDetails>(details).ptr()); break; - case NotificationType::TAB_CONTENTS_DESTROYED: navigation_state_.RemoveTabContentsState( Source<TabContents>(source).ptr()); @@ -177,6 +176,7 @@ void ExtensionWebNavigationEventRouter::FrameProvisionalLoadStart( navigation_state_.TrackFrame(details->frame_id(), details->url(), details->main_frame(), + details->is_error_page(), controller->tab_contents()); if (!navigation_state_.CanSendEvents(details->frame_id())) return; @@ -184,8 +184,7 @@ void ExtensionWebNavigationEventRouter::FrameProvisionalLoadStart( DictionaryValue* dict = new DictionaryValue(); dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(controller->tab_contents())); - dict->SetString(keys::kUrlKey, - details->url().spec()); + dict->SetString(keys::kUrlKey, details->url().spec()); dict->SetInteger(keys::kFrameIdKey, GetFrameId(details)); dict->SetInteger(keys::kRequestIdKey, 0); dict->SetReal(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now())); @@ -205,8 +204,7 @@ void ExtensionWebNavigationEventRouter::FrameProvisionalLoadCommitted( DictionaryValue* dict = new DictionaryValue(); dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(controller->tab_contents())); - dict->SetString(keys::kUrlKey, - details->url().spec()); + dict->SetString(keys::kUrlKey, details->url().spec()); dict->SetInteger(keys::kFrameIdKey, GetFrameId(details)); dict->SetString(keys::kTransitionTypeKey, PageTransition::CoreTransitionString( @@ -223,7 +221,8 @@ void ExtensionWebNavigationEventRouter::FrameProvisionalLoadCommitted( } void ExtensionWebNavigationEventRouter::FrameDomContentLoaded( - NavigationController* controller, long long frame_id) { + NavigationController* controller, + int64 frame_id) { if (!navigation_state_.CanSendEvents(frame_id)) return; ListValue args; @@ -231,8 +230,8 @@ void ExtensionWebNavigationEventRouter::FrameDomContentLoaded( dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(controller->tab_contents())); dict->SetString(keys::kUrlKey, navigation_state_.GetUrl(frame_id).spec()); - dict->SetInteger(keys::kFrameIdKey, navigation_state_.IsMainFrame(frame_id) ? - 0 : static_cast<int>(frame_id)); + dict->SetInteger(keys::kFrameIdKey, + navigation_state_.IsMainFrame(frame_id) ? 0 : static_cast<int>(frame_id)); dict->SetReal(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now())); args.Append(dict); @@ -242,7 +241,8 @@ void ExtensionWebNavigationEventRouter::FrameDomContentLoaded( } void ExtensionWebNavigationEventRouter::FrameDidFinishLoad( - NavigationController* controller, long long frame_id) { + NavigationController* controller, + int64 frame_id) { if (!navigation_state_.CanSendEvents(frame_id)) return; ListValue args; @@ -250,8 +250,8 @@ void ExtensionWebNavigationEventRouter::FrameDidFinishLoad( dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(controller->tab_contents())); dict->SetString(keys::kUrlKey, navigation_state_.GetUrl(frame_id).spec()); - dict->SetInteger(keys::kFrameIdKey, navigation_state_.IsMainFrame(frame_id) ? - 0 : static_cast<int>(frame_id)); + dict->SetInteger(keys::kFrameIdKey, + navigation_state_.IsMainFrame(frame_id) ? 0 : static_cast<int>(frame_id)); dict->SetReal(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now())); args.Append(dict); @@ -269,8 +269,7 @@ void ExtensionWebNavigationEventRouter::FailProvisionalLoadWithError( DictionaryValue* dict = new DictionaryValue(); dict->SetInteger(keys::kTabIdKey, ExtensionTabUtil::GetTabId(controller->tab_contents())); - dict->SetString(keys::kUrlKey, - details->url().spec()); + dict->SetString(keys::kUrlKey, details->url().spec()); dict->SetInteger(keys::kFrameIdKey, GetFrameId(details)); dict->SetString(keys::kErrorKey, std::string(net::ErrorToString(details->error_code()))); diff --git a/chrome/browser/extensions/extension_webnavigation_api.h b/chrome/browser/extensions/extension_webnavigation_api.h index b595aca..0f5948e 100644 --- a/chrome/browser/extensions/extension_webnavigation_api.h +++ b/chrome/browser/extensions/extension_webnavigation_api.h @@ -22,43 +22,45 @@ class NavigationController; class ProvisionalLoadDetails; class TabContents; -// Tracks which frames are in an error state, and no navigation events should -// be sent for. +// Tracks the navigation state of all frames currently known to the +// webNavigation API. It is mainly used to track in which frames an error +// occurred so no further events for this frame are being sent. class FrameNavigationState { public: FrameNavigationState(); ~FrameNavigationState(); // True if navigation events for the given frame can be sent. - bool CanSendEvents(long long frame_id) const; + bool CanSendEvents(int64 frame_id) const; // Starts to track a frame given by its |frame_id| showing the URL |url| in // a |tab_contents|. - void TrackFrame(long long frame_id, + void TrackFrame(int64 frame_id, const GURL& url, bool is_main_frame, + bool is_error_page, const TabContents* tab_contents); // Returns the URL corresponding to a tracked frame given by its |frame_id|. - GURL GetUrl(long long frame_id) const; + GURL GetUrl(int64 frame_id) const; // True if the frame given by its |frame_id| is the main frame of its tab. - bool IsMainFrame(long long frame_id) const; + bool IsMainFrame(int64 frame_id) const; // Marks a frame as in an error state. - void ErrorOccurredInFrame(long long frame_id); + void ErrorOccurredInFrame(int64 frame_id); // Removes state associated with this tab contents and all of its frames. void RemoveTabContentsState(const TabContents* tab_contents); private: - typedef std::multimap<const TabContents*, long long> TabContentsToFrameIdMap; + typedef std::multimap<const TabContents*, int64> TabContentsToFrameIdMap; struct FrameState { bool error_occurred; // True if an error has occurred in this frame. bool is_main_frame; // True if this is a main frame. GURL url; // URL of this frame. }; - typedef std::map<long long, FrameState> FrameIdToStateMap; + typedef std::map<int64, FrameState> FrameIdToStateMap; // Tracks which frames belong to a given tab contents object. TabContentsToFrameIdMap tab_contents_map_; @@ -69,13 +71,16 @@ class FrameNavigationState { DISALLOW_COPY_AND_ASSIGN(FrameNavigationState); }; + // Observes navigation notifications and routes them as events to the extension // system. class ExtensionWebNavigationEventRouter : public NotificationObserver { public: - // Single instance of the event router. + // Returns the singleton instance of the event router. static ExtensionWebNavigationEventRouter* GetInstance(); + // Invoked by the extensions service once the extension system is fully set + // up and can start dispatching events to extensions. void Init(); private: @@ -104,11 +109,11 @@ class ExtensionWebNavigationEventRouter : public NotificationObserver { // Handler for the FRAME_DOM_CONTENT_LOADED event. The method takes the frame // ID and constructs a suitable JSON formatted extension event from it. void FrameDomContentLoaded(NavigationController* controller, - long long frame_id); + int64 frame_id); // Handler for the FRAME_DID_FINISH_LOAD event. The method takes the frame // ID and constructs a suitable JSON formatted extension event from it. - void FrameDidFinishLoad(NavigationController* controller, long long frame_id); + void FrameDidFinishLoad(NavigationController* controller, int64 frame_id); // Handler for the FAIL_PROVISIONAL_LOAD_WITH_ERROR event. The method takes // the details of such an event and constructs a suitable JSON formatted @@ -116,7 +121,7 @@ class ExtensionWebNavigationEventRouter : public NotificationObserver { void FailProvisionalLoadWithError(NavigationController* controller, ProvisionalLoadDetails* details); - // This method dispatches events to the extension message service. + // Dispatches events to the extension message service. void DispatchEvent(Profile* context, const char* event_name, const std::string& json_args); diff --git a/chrome/browser/extensions/extension_webnavigation_apitest.cc b/chrome/browser/extensions/extension_webnavigation_apitest.cc index b27887b..8e833b0 100644 --- a/chrome/browser/extensions/extension_webnavigation_apitest.cc +++ b/chrome/browser/extensions/extension_webnavigation_apitest.cc @@ -6,6 +6,7 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/common/chrome_switches.h" + IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigation) { CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableExperimentalExtensionApis); diff --git a/chrome/browser/extensions/extension_webnavigation_unittest.cc b/chrome/browser/extensions/extension_webnavigation_unittest.cc index 5ac378e..cfeada0 100644 --- a/chrome/browser/extensions/extension_webnavigation_unittest.cc +++ b/chrome/browser/extensions/extension_webnavigation_unittest.cc @@ -8,13 +8,12 @@ #include "testing/gtest/include/gtest/gtest.h" #include "base/values.h" -#include "chrome/browser/browser_thread.h" #include "chrome/browser/extensions/extension_webnavigation_api.h" #include "chrome/browser/renderer_host/test/test_render_view_host.h" #include "chrome/browser/tab_contents/test_tab_contents.h" -#include "chrome/common/url_constants.h" #include "chrome/test/testing_profile.h" + class FrameNavigationStateTest : public RenderViewHostTestHarness { }; @@ -22,19 +21,19 @@ class FrameNavigationStateTest : public RenderViewHostTestHarness { // goes away. TEST_F(FrameNavigationStateTest, TrackFrame) { FrameNavigationState navigation_state; - const long long frame_id1 = 23; - const long long frame_id2 = 42; + const int64 frame_id1 = 23; + const int64 frame_id2 = 42; const GURL url1("http://www.google.com/"); const GURL url2("http://mail.google.com/"); // Create a main frame. EXPECT_FALSE(navigation_state.CanSendEvents(frame_id1)); - navigation_state.TrackFrame(frame_id1, url1, true, contents()); + navigation_state.TrackFrame(frame_id1, url1, true, false, contents()); EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1)); // Add a sub frame. EXPECT_FALSE(navigation_state.CanSendEvents(frame_id2)); - navigation_state.TrackFrame(frame_id2, url2, false, contents()); + navigation_state.TrackFrame(frame_id2, url2, false, false, contents()); EXPECT_TRUE(navigation_state.CanSendEvents(frame_id2)); // Check frame state. @@ -54,23 +53,22 @@ TEST_F(FrameNavigationStateTest, TrackFrame) { // before a new navigation happened in this frame. TEST_F(FrameNavigationStateTest, ErrorState) { FrameNavigationState navigation_state; - const long long frame_id = 42; + const int64 frame_id = 42; const GURL url("http://www.google.com/"); - navigation_state.TrackFrame(frame_id, url, true, contents()); + navigation_state.TrackFrame(frame_id, url, true, false, contents()); EXPECT_TRUE(navigation_state.CanSendEvents(frame_id)); // After an error occurred, no further events should be sent. navigation_state.ErrorOccurredInFrame(frame_id); EXPECT_FALSE(navigation_state.CanSendEvents(frame_id)); - // Navigations to the "unreachable web data" URL should be ignored. - navigation_state.TrackFrame( - frame_id, GURL(chrome::kUnreachableWebDataURL), true, contents()); + // Navigations to a network error page should be ignored. + navigation_state.TrackFrame(frame_id, GURL(), true, true, contents()); EXPECT_FALSE(navigation_state.CanSendEvents(frame_id)); // However, when the frame navigates again, it should send events again. - navigation_state.TrackFrame(frame_id, url, true, contents()); + navigation_state.TrackFrame(frame_id, url, true, false, contents()); EXPECT_TRUE(navigation_state.CanSendEvents(frame_id)); } @@ -78,12 +76,12 @@ TEST_F(FrameNavigationStateTest, ErrorState) { // before a new navigation happened in this frame. TEST_F(FrameNavigationStateTest, ErrorStateFrame) { FrameNavigationState navigation_state; - const long long frame_id1 = 23; - const long long frame_id2 = 42; + const int64 frame_id1 = 23; + const int64 frame_id2 = 42; const GURL url("http://www.google.com/"); - navigation_state.TrackFrame(frame_id1, url, true, contents()); - navigation_state.TrackFrame(frame_id2, url, false, contents()); + navigation_state.TrackFrame(frame_id1, url, true, false, contents()); + navigation_state.TrackFrame(frame_id2, url, false, false, contents()); EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1)); EXPECT_TRUE(navigation_state.CanSendEvents(frame_id2)); @@ -92,14 +90,13 @@ TEST_F(FrameNavigationStateTest, ErrorStateFrame) { EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1)); EXPECT_FALSE(navigation_state.CanSendEvents(frame_id2)); - // Navigations to the "unreachable web data" URL should be ignored. - navigation_state.TrackFrame( - frame_id2, GURL(chrome::kUnreachableWebDataURL), false, contents()); + // Navigations to a network error page should be ignored. + navigation_state.TrackFrame(frame_id2, GURL(), false, true, contents()); EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1)); EXPECT_FALSE(navigation_state.CanSendEvents(frame_id2)); // However, when the frame navigates again, it should send events again. - navigation_state.TrackFrame(frame_id2, url, false, contents()); + navigation_state.TrackFrame(frame_id2, url, false, false, contents()); EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1)); EXPECT_TRUE(navigation_state.CanSendEvents(frame_id2)); } diff --git a/chrome/browser/extensions/extension_webstore_private_api.cc b/chrome/browser/extensions/extension_webstore_private_api.cc index 468ae14..32b7c65 100644 --- a/chrome/browser/extensions/extension_webstore_private_api.cc +++ b/chrome/browser/extensions/extension_webstore_private_api.cc @@ -13,16 +13,17 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_prefs.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/net/gaia/token_service.h" -#include "chrome/browser/profile_manager.h" +#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_error_utils.h" #include "chrome/common/net/gaia/gaia_constants.h" -#include "chrome/common/notification_service.h" +#include "chrome/common/notification_details.h" +#include "chrome/common/notification_source.h" #include "chrome/common/notification_type.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" @@ -58,7 +59,7 @@ BrowserSignin* GetBrowserSignin(Profile* profile) { } bool IsWebStoreURL(Profile* profile, const GURL& url) { - ExtensionsService* service = profile->GetExtensionsService(); + ExtensionService* service = profile->GetExtensionService(); const Extension* store = service->GetWebStoreApp(); if (!store) { NOTREACHED(); @@ -185,7 +186,7 @@ bool GetBrowserLoginFunction::RunImpl() { bool GetStoreLoginFunction::RunImpl() { if (!IsWebStoreURL(profile_, source_url())) return false; - ExtensionsService* service = profile_->GetExtensionsService(); + ExtensionService* service = profile_->GetExtensionService(); ExtensionPrefs* prefs = service->extension_prefs(); std::string login; if (prefs->GetWebStoreLogin(&login)) { @@ -201,7 +202,7 @@ bool SetStoreLoginFunction::RunImpl() { return false; std::string login; EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &login)); - ExtensionsService* service = profile_->GetExtensionsService(); + ExtensionService* service = profile_->GetExtensionService(); ExtensionPrefs* prefs = service->extension_prefs(); prefs->SetWebStoreLogin(login); return true; diff --git a/chrome/browser/extensions/extension_webstore_private_browsertest.cc b/chrome/browser/extensions/extension_webstore_private_browsertest.cc index 01b8e45..3ed1383 100644 --- a/chrome/browser/extensions/extension_webstore_private_browsertest.cc +++ b/chrome/browser/extensions/extension_webstore_private_browsertest.cc @@ -10,7 +10,7 @@ #include "chrome/browser/extensions/extension_test_message_listener.h" #include "chrome/browser/extensions/extension_webstore_private_api.h" #include "chrome/browser/net/gaia/token_service.h" -#include "chrome/browser/profile_manager.h" +#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/chrome_switches.h" diff --git a/chrome/browser/extensions/extensions_startup.cc b/chrome/browser/extensions/extensions_startup.cc index 9faeac6..8e0b855 100644 --- a/chrome/browser/extensions/extensions_startup.cc +++ b/chrome/browser/extensions/extensions_startup.cc @@ -7,49 +7,31 @@ #include "base/string_util.h" #include "base/stringprintf.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/extensions/pack_extension_job.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_switches.h" #if defined(OS_WIN) #include "app/win_util.h" #endif -namespace extensions_startup { +ExtensionsStartupUtil::ExtensionsStartupUtil() : pack_job_succeeded_(false) {} -class PackExtensionLogger : public PackExtensionJob::Client { - public: - PackExtensionLogger() : process_startup_(false) {} - virtual void OnPackSuccess(const FilePath& crx_path, - const FilePath& output_private_key_path); - virtual void OnPackFailure(const std::string& error_message); - - private: - // We need to track if this extension packing job was created on process - // startup or not so we know if we should Quit() the message loop after - // packaging the extension. - bool process_startup_; - void ShowPackExtensionMessage(const std::wstring& caption, - const std::wstring& message); - - DISALLOW_COPY_AND_ASSIGN(PackExtensionLogger); -}; - -void PackExtensionLogger::OnPackSuccess( +void ExtensionsStartupUtil::OnPackSuccess( const FilePath& crx_path, const FilePath& output_private_key_path) { + pack_job_succeeded_ = true; ShowPackExtensionMessage(L"Extension Packaging Success", PackExtensionJob::StandardSuccessMessage( crx_path, output_private_key_path)); } -void PackExtensionLogger::OnPackFailure(const std::string& error_message) { +void ExtensionsStartupUtil::OnPackFailure(const std::string& error_message) { ShowPackExtensionMessage(L"Extension Packaging Error", UTF8ToWide(error_message)); } -void PackExtensionLogger::ShowPackExtensionMessage( +void ExtensionsStartupUtil::ShowPackExtensionMessage( const std::wstring& caption, const std::wstring& message) { #if defined(OS_WIN) @@ -62,62 +44,49 @@ void PackExtensionLogger::ShowPackExtensionMessage( out_text.append("\n"); base::StringPrintf("%s", out_text.c_str()); #endif - - // We got the notification and processed it; we don't expect any further tasks - // to be posted to the current thread, so we should stop blocking and exit. - // This call to |Quit()| matches the call to |Run()| in - // |ProcessCmdLineImpl()|. - MessageLoop::current()->Quit(); } -bool HandlePackExtension(const CommandLine& cmd_line) { - if (cmd_line.HasSwitch(switches::kPackExtension)) { - // Input Paths. - FilePath src_dir = cmd_line.GetSwitchValuePath( - switches::kPackExtension); - FilePath private_key_path; - if (cmd_line.HasSwitch(switches::kPackExtensionKey)) { - private_key_path = cmd_line.GetSwitchValuePath( - switches::kPackExtensionKey); - } - - // Launch a job to perform the packing on the file thread. - PackExtensionLogger pack_client; - scoped_refptr<PackExtensionJob> pack_job( - new PackExtensionJob(&pack_client, src_dir, private_key_path)); - pack_job->Start(); - - // The job will post a notification task to the current thread's message - // loop when it is finished. We manually run the loop here so that we - // block and catch the notification. Otherwise, the process would exit; - // in particular, this would mean that |pack_client| would be destroyed - // and we wouldn't be able to report success or failure back to the user. - // This call to |Run()| is matched by a call to |Quit()| in the - // |PackExtensionLogger|'s notification handling code. - MessageLoop::current()->Run(); +bool ExtensionsStartupUtil::PackExtension(const CommandLine& cmd_line) { + if (!cmd_line.HasSwitch(switches::kPackExtension)) + return false; - return true; + // Input Paths. + FilePath src_dir = cmd_line.GetSwitchValuePath(switches::kPackExtension); + FilePath private_key_path; + if (cmd_line.HasSwitch(switches::kPackExtensionKey)) { + private_key_path = cmd_line.GetSwitchValuePath(switches::kPackExtensionKey); } - return false; + // Launch a job to perform the packing on the file thread. + pack_job_ = new PackExtensionJob(this, src_dir, private_key_path); + pack_job_->set_asynchronous(false); + pack_job_->Start(); + + return pack_job_succeeded_; } -bool HandleUninstallExtension(const CommandLine& cmd_line, Profile* profile) { +bool ExtensionsStartupUtil::UninstallExtension(const CommandLine& cmd_line, + Profile* profile) { DCHECK(profile); - if (cmd_line.HasSwitch(switches::kUninstallExtension)) { - ExtensionsService* extensions_service = profile->GetExtensionsService(); - if (extensions_service) { - std::string extension_id = cmd_line.GetSwitchValueASCII( - switches::kUninstallExtension); - if (ExtensionsService::UninstallExtensionHelper(extensions_service, - extension_id)) { - return true; - } - } + if (!cmd_line.HasSwitch(switches::kUninstallExtension)) + return false; + + ExtensionService* extension_service = profile->GetExtensionService(); + if (!extension_service) + return false; + + std::string extension_id = cmd_line.GetSwitchValueASCII( + switches::kUninstallExtension); + if (ExtensionService::UninstallExtensionHelper(extension_service, + extension_id)) { + return true; } return false; } -} // namespace extensions_startup +ExtensionsStartupUtil::~ExtensionsStartupUtil() { + if (pack_job_.get()) + pack_job_->ClearClient(); +} diff --git a/chrome/browser/extensions/extensions_startup.h b/chrome/browser/extensions/extensions_startup.h index 85622de..2dee7d3 100644 --- a/chrome/browser/extensions/extensions_startup.h +++ b/chrome/browser/extensions/extensions_startup.h @@ -6,19 +6,38 @@ #define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_STARTUP_H_ #pragma once +#include "base/scoped_ptr.h" +#include "chrome/browser/extensions/pack_extension_job.h" + class CommandLine; class Profile; // Initialization helpers for various Extension startup actions. -namespace extensions_startup { -// Handle --pack-extension flag from the |cmd_line| by packing the specified -// extension. Returns false if the pack job could not be started. -bool HandlePackExtension(const CommandLine& cmd_line); - -// Handle --uninstall-extension flag from the |cmd_line| by uninstalling the -// specified extension from |profile|. Returns false if the uninstall job -// could not be started. -bool HandleUninstallExtension(const CommandLine& cmd_line, Profile* profile); -} // namespace extensions_startup +class ExtensionsStartupUtil : public PackExtensionJob::Client { + public: + ExtensionsStartupUtil(); + virtual ~ExtensionsStartupUtil(); + + virtual void OnPackSuccess(const FilePath& crx_path, + const FilePath& output_private_key_path); + virtual void OnPackFailure(const std::string& error_message); + + // Handle --pack-extension flag from the |cmd_line| by packing the specified + // extension. Returns false if the pack job failed. + bool PackExtension(const CommandLine& cmd_line); + + // Handle --uninstall-extension flag from the |cmd_line| by uninstalling the + // specified extension from |profile|. Returns false if the uninstall job + // could not be started. + bool UninstallExtension(const CommandLine& cmd_line, Profile* profile); + + private: + void ShowPackExtensionMessage(const std::wstring& caption, + const std::wstring& message); + scoped_refptr<PackExtensionJob> pack_job_; + bool pack_job_succeeded_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionsStartupUtil); +}; #endif // CHROME_BROWSER_EXTENSIONS_EXTENSIONS_STARTUP_H_ diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc index 0078f0e..5d3a05d 100644 --- a/chrome/browser/extensions/extensions_ui.cc +++ b/chrome/browser/extensions/extensions_ui.cc @@ -4,6 +4,8 @@ #include "chrome/browser/extensions/extensions_ui.h" +#include <algorithm> + #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "base/base64.h" @@ -16,7 +18,6 @@ #include "base/thread.h" #include "base/version.h" #include "chrome/browser/browser_list.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/debugger/devtools_manager.h" #include "chrome/browser/debugger/devtools_toggle_action.h" #include "chrome/browser/extensions/crx_installer.h" @@ -25,11 +26,11 @@ #include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_message_service.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_updater.h" #include "chrome/browser/google/google_util.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_widget_host.h" #include "chrome/browser/renderer_host/render_view_host.h" @@ -190,6 +191,9 @@ void ExtensionsUIHTMLSource::StartDataRequest(const std::string& path, SendResponse(request_id, html_bytes); } +std::string ExtensionsUIHTMLSource::GetMimeType(const std::string&) const { + return "text/html"; +} //////////////////////////////////////////////////////////////////////////////// // @@ -289,7 +293,7 @@ void ExtensionsDOMHandler::IconLoader::ReportResultOnUIThread( // /////////////////////////////////////////////////////////////////////////////// -ExtensionsDOMHandler::ExtensionsDOMHandler(ExtensionsService* extension_service) +ExtensionsDOMHandler::ExtensionsDOMHandler(ExtensionService* extension_service) : extensions_service_(extension_service), ignore_notifications_(false), deleting_rvh_(NULL) { @@ -387,8 +391,6 @@ void ExtensionsDOMHandler::OnIconsLoaded(DictionaryValue* json) { NotificationService::AllSources()); registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, NotificationService::AllSources()); - registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, - NotificationService::AllSources()); registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED, @@ -675,6 +677,11 @@ void ExtensionsDOMHandler::FileSelected(const FilePath& path, int index, dom_ui_->CallJavascriptFunction(L"window.handleFilePathSelected", results); } +void ExtensionsDOMHandler::MultiFilesSelected( + const std::vector<FilePath>& files, void* params) { + NOTREACHED(); +} + void ExtensionsDOMHandler::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { @@ -702,7 +709,6 @@ void ExtensionsDOMHandler::Observe(NotificationType type, case NotificationType::EXTENSION_LOADED: case NotificationType::EXTENSION_PROCESS_CREATED: case NotificationType::EXTENSION_UNLOADED: - case NotificationType::EXTENSION_UNLOADED_DISABLED: case NotificationType::EXTENSION_UPDATE_DISABLED: case NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED: case NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED: @@ -784,7 +790,7 @@ static bool ExtensionWantsFileAccess(const Extension* extension) { // Static DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue( - ExtensionsService* service, const Extension* extension, + ExtensionService* service, const Extension* extension, const std::vector<ExtensionPage>& pages, bool enabled) { DictionaryValue* extension_data = new DictionaryValue(); @@ -929,8 +935,8 @@ ExtensionsDOMHandler::~ExtensionsDOMHandler() { // ExtensionsDOMHandler, public: ----------------------------------------------- ExtensionsUI::ExtensionsUI(TabContents* contents) : DOMUI(contents) { - ExtensionsService *exstension_service = - GetProfile()->GetOriginalProfile()->GetExtensionsService(); + ExtensionService *exstension_service = + GetProfile()->GetOriginalProfile()->GetExtensionService(); ExtensionsDOMHandler* handler = new ExtensionsDOMHandler(exstension_service); AddMessageHandler(handler); @@ -942,7 +948,7 @@ ExtensionsUI::ExtensionsUI(TabContents* contents) : DOMUI(contents) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod( - Singleton<ChromeURLDataManager>::get(), + ChromeURLDataManager::GetInstance(), &ChromeURLDataManager::AddDataSource, make_scoped_refptr(html_source))); } diff --git a/chrome/browser/extensions/extensions_ui.h b/chrome/browser/extensions/extensions_ui.h index 54ec298..b7a9b69 100644 --- a/chrome/browser/extensions/extensions_ui.h +++ b/chrome/browser/extensions/extensions_ui.h @@ -22,7 +22,7 @@ class DictionaryValue; class Extension; -class ExtensionsService; +class ExtensionService; class FilePath; class ListValue; class PrefService; @@ -51,9 +51,7 @@ class ExtensionsUIHTMLSource : public ChromeURLDataManager::DataSource { virtual void StartDataRequest(const std::string& path, bool is_off_the_record, int request_id); - virtual std::string GetMimeType(const std::string&) const { - return "text/html"; - } + virtual std::string GetMimeType(const std::string&) const; private: ~ExtensionsUIHTMLSource() {} @@ -104,7 +102,7 @@ class ExtensionsDOMHandler ExtensionsDOMHandler* handler_; }; - explicit ExtensionsDOMHandler(ExtensionsService* extension_service); + explicit ExtensionsDOMHandler(ExtensionService* extension_service); virtual ~ExtensionsDOMHandler(); // DOMMessageHandler implementation. @@ -113,7 +111,7 @@ class ExtensionsDOMHandler // Extension Detail JSON Struct for page. (static for ease of testing). // Note: service can be NULL in unit tests. static DictionaryValue* CreateExtensionDetailValue( - ExtensionsService* service, + ExtensionService* service, const Extension* extension, const std::vector<ExtensionPage>& pages, bool enabled); @@ -190,9 +188,7 @@ class ExtensionsDOMHandler virtual void FileSelected(const FilePath& path, int index, void* params); virtual void MultiFilesSelected( - const std::vector<FilePath>& files, void* params) { - NOTREACHED(); - } + const std::vector<FilePath>& files, void* params); virtual void FileSelectionCanceled(void* params) {} // NotificationObserver @@ -227,7 +223,7 @@ class ExtensionsDOMHandler ExtensionInstallUI* GetExtensionInstallUI(); // Our model. - scoped_refptr<ExtensionsService> extensions_service_; + scoped_refptr<ExtensionService> extensions_service_; // Used to pick the directory when loading an extension. scoped_refptr<SelectFileDialog> load_extension_dialog_; diff --git a/chrome/browser/extensions/external_extension_provider.h b/chrome/browser/extensions/external_extension_provider.h index 1d040bd..5bcce1d 100644 --- a/chrome/browser/extensions/external_extension_provider.h +++ b/chrome/browser/extensions/external_extension_provider.h @@ -6,9 +6,6 @@ #define CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_H_ #pragma once -#include <set> -#include <string> - #include "chrome/common/extensions/extension.h" class FilePath; @@ -44,8 +41,7 @@ class ExternalExtensionProvider { // Enumerate registered extension, calling OnExternalExtensionFound on // the |visitor| object for each registered extension found. |ids_to_ignore| // contains a list of extension ids that should not result in a call back. - virtual void VisitRegisteredExtension( - Visitor* visitor, const std::set<std::string>& ids_to_ignore) const = 0; + virtual void VisitRegisteredExtension(Visitor* visitor) const = 0; // Test if this provider has an extension with id |id| registered. virtual bool HasExtension(const std::string& id) const = 0; diff --git a/chrome/browser/extensions/external_policy_extension_provider.cc b/chrome/browser/extensions/external_policy_extension_provider.cc index d482bb3..5e87379 100644 --- a/chrome/browser/extensions/external_policy_extension_provider.cc +++ b/chrome/browser/extensions/external_policy_extension_provider.cc @@ -4,8 +4,10 @@ #include "chrome/browser/extensions/external_policy_extension_provider.h" +#include "base/logging.h" #include "base/values.h" #include "chrome/common/pref_names.h" +#include "chrome/browser/browser_thread.h" #include "chrome/browser/extensions/stateful_external_extension_provider.h" #include "chrome/browser/prefs/pref_service.h" @@ -29,16 +31,27 @@ bool CheckExtension(std::string id, std::string update_url) { } -ExternalPolicyExtensionProvider::ExternalPolicyExtensionProvider() - : StatefulExternalExtensionProvider(Extension::INVALID, - Extension::EXTERNAL_POLICY_DOWNLOAD) { +ExternalPolicyExtensionProvider::ExternalPolicyExtensionProvider( + const ListValue* forcelist) + : StatefulExternalExtensionProvider( + Extension::INVALID, + Extension::EXTERNAL_POLICY_DOWNLOAD) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ProcessPreferences(forcelist); } ExternalPolicyExtensionProvider::~ExternalPolicyExtensionProvider() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); } void ExternalPolicyExtensionProvider::SetPreferences( const ListValue* forcelist) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + ProcessPreferences(forcelist); +} + +void ExternalPolicyExtensionProvider::ProcessPreferences( + const ListValue* forcelist) { DictionaryValue* result = new DictionaryValue(); if (forcelist != NULL) { std::string extension_desc; @@ -59,5 +72,5 @@ void ExternalPolicyExtensionProvider::SetPreferences( } } } - prefs_.reset(result); + set_prefs(result); } diff --git a/chrome/browser/extensions/external_policy_extension_provider.h b/chrome/browser/extensions/external_policy_extension_provider.h index bb4cc7d..9c36960 100644 --- a/chrome/browser/extensions/external_policy_extension_provider.h +++ b/chrome/browser/extensions/external_policy_extension_provider.h @@ -14,11 +14,14 @@ class PrefService; // A specialization of the ExternalExtensionProvider that uses // prefs::kExtensionInstallForceList to look up which external extensions are -// registered. +// registered. The value of this preference is received via the constructor and +// via |SetPreferences| in case of run-time updates. +// Instances of this class are expected to be created and destroyed on the UI +// thread and they are expecting public method calls from the FILE thread. class ExternalPolicyExtensionProvider : public StatefulExternalExtensionProvider { public: - explicit ExternalPolicyExtensionProvider(); + explicit ExternalPolicyExtensionProvider(const ListValue* forcelist); virtual ~ExternalPolicyExtensionProvider(); // Set the internal list of extensions based on |forcelist|. @@ -28,6 +31,9 @@ class ExternalPolicyExtensionProvider private: friend class MockExternalPolicyExtensionProviderVisitor; + // Set the internal list of extensions based on |forcelist|. + // Does not take ownership of |forcelist|. + void ProcessPreferences(const ListValue* forcelist); }; #endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_POLICY_EXTENSION_PROVIDER_H_ diff --git a/chrome/browser/extensions/external_policy_extension_provider_unittest.cc b/chrome/browser/extensions/external_policy_extension_provider_unittest.cc index 4fb5117..cd5a3df 100644 --- a/chrome/browser/extensions/external_policy_extension_provider_unittest.cc +++ b/chrome/browser/extensions/external_policy_extension_provider_unittest.cc @@ -7,11 +7,26 @@ #include "base/logging.h" #include "base/values.h" #include "base/version.h" +#include "chrome/browser/browser_thread.h" #include "chrome/browser/extensions/external_policy_extension_provider.h" #include "chrome/common/extensions/extension.h" #include "testing/gtest/include/gtest/gtest.h" class ExternalPolicyExtensionProviderTest : public testing::Test { + public: + ExternalPolicyExtensionProviderTest() + : loop_(MessageLoop::TYPE_IO), + ui_thread_(BrowserThread::UI, &loop_), + file_thread_(BrowserThread::FILE, &loop_) { + } + + virtual ~ExternalPolicyExtensionProviderTest() { + } + + private: + MessageLoop loop_; + BrowserThread ui_thread_; + BrowserThread file_thread_; }; class MockExternalPolicyExtensionProviderVisitor @@ -25,14 +40,12 @@ class MockExternalPolicyExtensionProviderVisitor void Visit(ListValue* policy_forcelist, ListValue* policy_validlist, const std::set<std::string>& ignore_list) { - provider_.reset(new ExternalPolicyExtensionProvider()); - // Give the list extensions to the provider. - provider_->SetPreferences(policy_forcelist); + provider_.reset(new ExternalPolicyExtensionProvider(policy_forcelist)); // Extensions will be removed from this list as they visited, // so it should be emptied by the end. remaining_extensions = policy_validlist; - provider_->VisitRegisteredExtension(this, ignore_list); + provider_->VisitRegisteredExtension(this); EXPECT_EQ(0u, remaining_extensions->GetSize()); } diff --git a/chrome/browser/extensions/external_pref_extension_provider.cc b/chrome/browser/extensions/external_pref_extension_provider.cc index 7580388..7ea5f4a 100644 --- a/chrome/browser/extensions/external_pref_extension_provider.cc +++ b/chrome/browser/extensions/external_pref_extension_provider.cc @@ -9,12 +9,14 @@ #include "base/file_util.h" #include "base/logging.h" #include "base/path_service.h" +#include "chrome/browser/browser_thread.h" #include "chrome/browser/extensions/stateful_external_extension_provider.h" #include "chrome/common/json_value_serializer.h" ExternalPrefExtensionProvider::ExternalPrefExtensionProvider() : StatefulExternalExtensionProvider(Extension::EXTERNAL_PREF, Extension::EXTERNAL_PREF_DOWNLOAD) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); FilePath json_file; PathService::Get(app::DIR_EXTERNAL_EXTENSIONS, &json_file); json_file = json_file.Append(FILE_PATH_LITERAL("external_extensions.json")); @@ -23,11 +25,12 @@ ExternalPrefExtensionProvider::ExternalPrefExtensionProvider() JSONFileValueSerializer serializer(json_file); SetPreferences(&serializer); } else { - prefs_.reset(new DictionaryValue()); + set_prefs(new DictionaryValue()); } } ExternalPrefExtensionProvider::~ExternalPrefExtensionProvider() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); } void ExternalPrefExtensionProvider::SetPreferencesForTesting( @@ -50,5 +53,5 @@ void ExternalPrefExtensionProvider::SetPreferences( dictionary.reset(static_cast<DictionaryValue*>(extensions)); } } - prefs_.reset(dictionary.release()); + set_prefs(dictionary.release()); } diff --git a/chrome/browser/extensions/external_pref_extension_provider.h b/chrome/browser/extensions/external_pref_extension_provider.h index 8b9eb0b..b74be39 100644 --- a/chrome/browser/extensions/external_pref_extension_provider.h +++ b/chrome/browser/extensions/external_pref_extension_provider.h @@ -10,6 +10,8 @@ // A specialization of the ExternalExtensionProvider that uses a json file to // look up which external extensions are registered. +// Instances of this class are expected to be created and destroyed on the UI +// thread and they are expecting public method calls from the FILE thread. class ExternalPrefExtensionProvider : public StatefulExternalExtensionProvider { public: explicit ExternalPrefExtensionProvider(); diff --git a/chrome/browser/extensions/external_registry_extension_provider_win.cc b/chrome/browser/extensions/external_registry_extension_provider_win.cc index 00bea09..16b107f 100644 --- a/chrome/browser/extensions/external_registry_extension_provider_win.cc +++ b/chrome/browser/extensions/external_registry_extension_provider_win.cc @@ -41,7 +41,7 @@ ExternalRegistryExtensionProvider::~ExternalRegistryExtensionProvider() { } void ExternalRegistryExtensionProvider::VisitRegisteredExtension( - Visitor* visitor, const std::set<std::string>& ids_to_ignore) const { + Visitor* visitor) const { base::win::RegistryKeyIterator iterator( kRegRoot, ASCIIToWide(kRegistryExtensions).c_str()); while (iterator.Valid()) { @@ -56,13 +56,10 @@ void ExternalRegistryExtensionProvider::VisitRegisteredExtension( if (key.ReadValue(kRegistryExtensionVersion, &extension_version)) { std::string id = WideToASCII(iterator.Name()); StringToLowerASCII(&id); - if (ids_to_ignore.find(id) != ids_to_ignore.end()) { - ++iterator; - continue; - } scoped_ptr<Version> version; - version.reset(Version::GetVersionFromString(extension_version)); + version.reset(Version::GetVersionFromString( + WideToASCII(extension_version))); if (!version.get()) { LOG(ERROR) << "Invalid version value " << extension_version << " for key " << key_path; @@ -107,8 +104,10 @@ bool ExternalRegistryExtensionProvider::GetExtensionDetails( if (!key.ReadValue(kRegistryExtensionVersion, &extension_version)) return false; - if (version) - version->reset(Version::GetVersionFromString(extension_version)); + if (version) { + version->reset(Version::GetVersionFromString( + WideToASCII(extension_version))); + } if (location) *location = Extension::EXTERNAL_REGISTRY; diff --git a/chrome/browser/extensions/external_registry_extension_provider_win.h b/chrome/browser/extensions/external_registry_extension_provider_win.h index bb60106..34899ae 100644 --- a/chrome/browser/extensions/external_registry_extension_provider_win.h +++ b/chrome/browser/extensions/external_registry_extension_provider_win.h @@ -6,9 +6,6 @@ #define CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_PROVIDER_WIN_H_ #pragma once -#include <set> -#include <string> - #include "chrome/browser/extensions/external_extension_provider.h" class Version; @@ -21,8 +18,7 @@ class ExternalRegistryExtensionProvider : public ExternalExtensionProvider { virtual ~ExternalRegistryExtensionProvider(); // ExternalExtensionProvider implementation: - virtual void VisitRegisteredExtension( - Visitor* visitor, const std::set<std::string>& ids_to_ignore) const; + virtual void VisitRegisteredExtension(Visitor* visitor) const; virtual bool HasExtension(const std::string& id) const; diff --git a/chrome/browser/extensions/fragment_navigation_apitest.cc b/chrome/browser/extensions/fragment_navigation_apitest.cc index 68ca622..8d931a8 100644 --- a/chrome/browser/extensions/fragment_navigation_apitest.cc +++ b/chrome/browser/extensions/fragment_navigation_apitest.cc @@ -11,7 +11,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptFragmentNavigation) { ASSERT_TRUE(RunExtensionTest(extension_name)) << message_; } -IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ExecuteScriptFragmentNavigation) { +// Crashy, http://crbug.com/67774. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, + DISABLED_ExecuteScriptFragmentNavigation) { ASSERT_TRUE(StartTestServer()); const char* extension_name = "executescript/fragment"; ASSERT_TRUE(RunExtensionTest(extension_name)) << message_; diff --git a/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc b/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc index d3fc1c0..cd2f123 100644 --- a/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc +++ b/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc @@ -4,7 +4,7 @@ #include "chrome/browser/extensions/gtk_theme_installed_infobar_delegate.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" GtkThemeInstalledInfoBarDelegate::GtkThemeInstalledInfoBarDelegate( TabContents* tab_contents, diff --git a/chrome/browser/extensions/image_loading_tracker.cc b/chrome/browser/extensions/image_loading_tracker.cc index 496c3ad..873dcaa 100644 --- a/chrome/browser/extensions/image_loading_tracker.cc +++ b/chrome/browser/extensions/image_loading_tracker.cc @@ -123,8 +123,6 @@ ImageLoadingTracker::ImageLoadingTracker(Observer* observer) next_id_(0) { registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, NotificationService::AllSources()); - registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, - NotificationService::AllSources()); } ImageLoadingTracker::~ImageLoadingTracker() { @@ -184,10 +182,10 @@ void ImageLoadingTracker::OnImageLoaded( void ImageLoadingTracker::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { - DCHECK(type == NotificationType::EXTENSION_UNLOADED || - type == NotificationType::EXTENSION_UNLOADED_DISABLED); + DCHECK(type == NotificationType::EXTENSION_UNLOADED); - const Extension* extension = Details<const Extension>(details).ptr(); + const Extension* extension = + Details<UnloadedExtensionInfo>(details)->extension; // Remove all entries in the load_map_ referencing the extension. This ensures // we don't attempt to cache the image when the load completes. diff --git a/chrome/browser/extensions/image_loading_tracker_unittest.cc b/chrome/browser/extensions/image_loading_tracker_unittest.cc index 57b5268..4c9734f 100644 --- a/chrome/browser/extensions/image_loading_tracker_unittest.cc +++ b/chrome/browser/extensions/image_loading_tracker_unittest.cc @@ -160,10 +160,12 @@ TEST_F(ImageLoadingTrackerTest, DeleteExtensionWhileWaitingForCache) { EXPECT_EQ(0, image_loaded_count()); // Send out notification the extension was uninstalled. + UnloadedExtensionInfo details(extension.get(), + UnloadedExtensionInfo::UNINSTALL); NotificationService::current()->Notify( NotificationType::EXTENSION_UNLOADED, NotificationService::AllSources(), - Details<const Extension>(extension.get())); + Details<UnloadedExtensionInfo>(&details)); // Chuck the extension, that way if anyone tries to access it we should crash // or get valgrind errors. diff --git a/chrome/browser/extensions/notifications_apitest.cc b/chrome/browser/extensions/notifications_apitest.cc index 6a80635..7e2a34d 100644 --- a/chrome/browser/extensions/notifications_apitest.cc +++ b/chrome/browser/extensions/notifications_apitest.cc @@ -5,17 +5,11 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/notifications/desktop_notification_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" -// Fails and hoses bot, http://crbug.com/50060. // Flaky, http://crbug.com/42314. -#if defined(OS_MACOSX) -#define MAYBE_Notifications DISABLED_Notifications -#else -#define MAYBE_Notifications FLAKY_Notifications -#endif -IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Notifications) { +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_Notifications) { #if defined(OS_LINUX) && defined(TOOLKIT_VIEWS) // Notifications not supported on linux/views yet. #else diff --git a/chrome/browser/extensions/pack_extension_job.cc b/chrome/browser/extensions/pack_extension_job.cc index 5f64025..327d7c4 100644 --- a/chrome/browser/extensions/pack_extension_job.cc +++ b/chrome/browser/extensions/pack_extension_job.cc @@ -15,15 +15,19 @@ PackExtensionJob::PackExtensionJob(Client* client, const FilePath& root_directory, const FilePath& key_file) - : client_(client), key_file_(key_file) { + : client_(client), key_file_(key_file), asynchronous_(true) { root_directory_ = root_directory.StripTrailingSeparators(); CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_)); } void PackExtensionJob::Start() { - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod(this, &PackExtensionJob::RunOnFileThread)); + if (asynchronous_) { + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod(this, &PackExtensionJob::Run)); + } else { + Run(); + } } void PackExtensionJob::ClearClient() { @@ -32,7 +36,7 @@ void PackExtensionJob::ClearClient() { PackExtensionJob::~PackExtensionJob() {} -void PackExtensionJob::RunOnFileThread() { +void PackExtensionJob::Run() { crx_file_out_ = FilePath(root_directory_.value() + chrome::kExtensionFileExtension); @@ -44,16 +48,24 @@ void PackExtensionJob::RunOnFileThread() { // returns. See bug 20734. ExtensionCreator creator; if (creator.Run(root_directory_, crx_file_out_, key_file_, key_file_out_)) { - BrowserThread::PostTask( - client_thread_id_, FROM_HERE, - NewRunnableMethod(this, - &PackExtensionJob::ReportSuccessOnClientThread)); + if (asynchronous_) { + BrowserThread::PostTask( + client_thread_id_, FROM_HERE, + NewRunnableMethod(this, + &PackExtensionJob::ReportSuccessOnClientThread)); + } else { + ReportSuccessOnClientThread(); + } } else { - BrowserThread::PostTask( - client_thread_id_, FROM_HERE, - NewRunnableMethod( - this, &PackExtensionJob::ReportFailureOnClientThread, - creator.error_message())); + if (asynchronous_) { + BrowserThread::PostTask( + client_thread_id_, FROM_HERE, + NewRunnableMethod( + this, &PackExtensionJob::ReportFailureOnClientThread, + creator.error_message())); + } else { + ReportFailureOnClientThread(creator.error_message()); + } } } diff --git a/chrome/browser/extensions/pack_extension_job.h b/chrome/browser/extensions/pack_extension_job.h index ecd3d68..e26687a 100644 --- a/chrome/browser/extensions/pack_extension_job.h +++ b/chrome/browser/extensions/pack_extension_job.h @@ -33,8 +33,7 @@ class PackExtensionJob : public base::RefCountedThreadSafe<PackExtensionJob> { const FilePath& root_directory, const FilePath& key_file); - // Starts the packing thread job. See http://crbug.com/27944 for more details - // on why this function is needed. + // Starts the packing job. void Start(); // The client should call this when it is destroyed to prevent @@ -45,12 +44,15 @@ class PackExtensionJob : public base::RefCountedThreadSafe<PackExtensionJob> { static std::wstring StandardSuccessMessage(const FilePath& crx_file, const FilePath& key_file); + void set_asynchronous(bool async) { asynchronous_ = async; } + private: friend class base::RefCountedThreadSafe<PackExtensionJob>; virtual ~PackExtensionJob(); - void RunOnFileThread(); + // If |asynchronous_| is false, this is run on whichever thread calls it. + void Run(); void ReportSuccessOnClientThread(); void ReportFailureOnClientThread(const std::string& error); @@ -60,6 +62,7 @@ class PackExtensionJob : public base::RefCountedThreadSafe<PackExtensionJob> { FilePath key_file_; FilePath crx_file_out_; FilePath key_file_out_; + bool asynchronous_; DISALLOW_COPY_AND_ASSIGN(PackExtensionJob); }; diff --git a/chrome/browser/extensions/page_action_apitest.cc b/chrome/browser/extensions/page_action_apitest.cc index dede04b..504f909 100644 --- a/chrome/browser/extensions/page_action_apitest.cc +++ b/chrome/browser/extensions/page_action_apitest.cc @@ -5,12 +5,12 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/location_bar.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/omnibox/location_bar.h" #include "chrome/common/extensions/extension_action.h" #include "chrome/common/extensions/extension.h" #include "chrome/test/ui_test_utils.h" diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.cc b/chrome/browser/extensions/sandboxed_extension_unpacker.cc index faf236b..9d7e45b 100644 --- a/chrome/browser/extensions/sandboxed_extension_unpacker.cc +++ b/chrome/browser/extensions/sandboxed_extension_unpacker.cc @@ -6,6 +6,7 @@ #include <set> +#include "app/l10n_util.h" #include "base/base64.h" #include "base/crypto/signature_verifier.h" #include "base/file_util.h" @@ -15,7 +16,7 @@ #include "base/task.h" #include "base/utf_string_conversions.h" // TODO(viettrungluu): delete me. #include "chrome/browser/browser_thread.h" -#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/renderer_host/resource_dispatcher_host.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" @@ -25,6 +26,7 @@ #include "chrome/common/extensions/extension_unpacker.h" #include "chrome/common/json_value_serializer.h" #include "gfx/codec/png_codec.h" +#include "grit/generated_resources.h" #include "third_party/skia/include/core/SkBitmap.h" const char SandboxedExtensionUnpacker::kExtensionHeaderMagic[] = "Cr24"; @@ -46,7 +48,10 @@ void SandboxedExtensionUnpacker::Start() { // Create a temporary directory to work in. if (!temp_dir_.CreateUniqueTempDirUnderPath(temp_path_)) { - ReportFailure("Could not create temporary directory."); + // Could not create temporary directory. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY"))); return; } @@ -61,7 +66,10 @@ void SandboxedExtensionUnpacker::Start() { // Copy the crx file into our working directory. FilePath temp_crx_path = temp_dir_.path().Append(crx_path_.BaseName()); if (!file_util::CopyFile(crx_path_, temp_crx_path)) { - ReportFailure("Failed to copy extension file to temporary directory."); + // Failed to copy extension file to temporary directory. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY"))); return; } @@ -81,21 +89,7 @@ void SandboxedExtensionUnpacker::Start() { if (!file_util::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) { LOG(ERROR) << "Could not get the normalized path of " << temp_crx_path.value(); -#if defined (OS_WIN) - // On windows, it is possible to mount a disk without the root of that - // disk having a drive letter. The sandbox does not support this. - // See crbug/49530 . - ReportFailure( - "Can not unpack extension. To safely unpack an extension, " - "there must be a path to your profile directory that starts " - "with a drive letter and does not contain a junction, mount " - "point, or symlink. No such path exists for your profile."); -#else - ReportFailure( - "Can not unpack extension. To safely unpack an extension, " - "there must be a path to your profile directory that does " - "not contain a symlink. No such path exists for your profile."); -#endif + ReportFailure(l10n_util::GetStringUTF8(IDS_EXTENSION_UNPACK_FAILED)); return; } @@ -153,7 +147,9 @@ void SandboxedExtensionUnpacker::OnUnpackExtensionSucceeded( if (!extension_l10n_util::LocalizeExtension(extension_root_, final_manifest.get(), &error)) { - ReportFailure(error); + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, + ASCIIToUTF16(error))); return; } @@ -178,21 +174,29 @@ void SandboxedExtensionUnpacker::OnUnpackExtensionFailed( const std::string& error) { DCHECK(BrowserThread::CurrentlyOn(thread_identifier_)); got_response_ = true; - ReportFailure(error); + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, + ASCIIToUTF16(error))); } -void SandboxedExtensionUnpacker::OnProcessCrashed() { +void SandboxedExtensionUnpacker::OnProcessCrashed(int exit_code) { // Don't report crashes if they happen after we got a response. if (got_response_) return; - ReportFailure("Utility process crashed while trying to install."); + // Utility process crashed while trying to install. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL"))); } bool SandboxedExtensionUnpacker::ValidateSignature() { ScopedStdioHandle file(file_util::OpenFile(crx_path_, "rb")); if (!file.get()) { - ReportFailure("Could not open crx file for reading"); + // Could not open crx file for reading + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_CODE, + ASCIIToUTF16("CRX_FILE_NOT_READABLE"))); return false; } @@ -207,29 +211,47 @@ bool SandboxedExtensionUnpacker::ValidateSignature() { len = fread(&header, 1, sizeof(ExtensionHeader), file.get()); if (len < sizeof(ExtensionHeader)) { - ReportFailure("Invalid crx header"); + // Invalid crx header + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_CODE, + ASCIIToUTF16("CRX_HEADER_INVALID"))); return false; } if (strncmp(kExtensionHeaderMagic, header.magic, sizeof(header.magic))) { - ReportFailure("Bad magic number"); + // Bad magic number + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_CODE, + ASCIIToUTF16("CRX_MAGIC_NUMBER_INVALID"))); return false; } if (header.version != kCurrentVersion) { - ReportFailure("Bad version number"); + // Bad version numer + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_CODE, + ASCIIToUTF16("CRX_VERSION_NUMBER_INVALID"))); return false; } if (header.key_size > kMaxPublicKeySize || header.signature_size > kMaxSignatureSize) { - ReportFailure("Excessively large key or signature"); + // Excessively large key or signature + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_CODE, + ASCIIToUTF16("CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE"))); return false; } if (header.key_size == 0) { - ReportFailure("Key length is zero"); + // Key length is zero + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_CODE, + ASCIIToUTF16("CRX_ZERO_KEY_LENGTH"))); return false; } if (header.signature_size == 0) { - ReportFailure("Signature length is zero"); + // Signature length is zero + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_CODE, + ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH"))); return false; } @@ -237,7 +259,10 @@ bool SandboxedExtensionUnpacker::ValidateSignature() { key.resize(header.key_size); len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); if (len < header.key_size) { - ReportFailure("Invalid public key"); + // Invalid public key + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_CODE, + ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID"))); return false; } @@ -246,7 +271,10 @@ bool SandboxedExtensionUnpacker::ValidateSignature() { len = fread(&signature.front(), sizeof(uint8), header.signature_size, file.get()); if (len < header.signature_size) { - ReportFailure("Invalid signature"); + // Invalid signature + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_CODE, + ASCIIToUTF16("CRX_SIGNATURE_INVALID"))); return false; } @@ -257,9 +285,11 @@ bool SandboxedExtensionUnpacker::ValidateSignature() { signature.size(), &key.front(), key.size())) { - ReportFailure("Signature verification initialization failed. " - "This is most likely caused by a public key in " - "the wrong format (should encode algorithm)."); + // Signature verification initialization failed. This is most likely + // caused by a public key in the wrong format (should encode algorithm). + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_CODE, + ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED"))); return false; } @@ -268,7 +298,10 @@ bool SandboxedExtensionUnpacker::ValidateSignature() { verifier.VerifyUpdate(buf, len); if (!verifier.VerifyFinal()) { - ReportFailure("Signature verification failed"); + // Signature verification failed + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_ERROR_CODE, + ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED"))); return false; } @@ -300,7 +333,10 @@ DictionaryValue* SandboxedExtensionUnpacker::RewriteManifestFile( JSONStringValueSerializer serializer(&manifest_json); serializer.set_pretty_print(true); if (!serializer.Serialize(*final_manifest)) { - ReportFailure("Error serializing manifest.json."); + // Error serializing manifest.json. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON"))); return NULL; } @@ -308,7 +344,10 @@ DictionaryValue* SandboxedExtensionUnpacker::RewriteManifestFile( extension_root_.Append(Extension::kManifestFilename); if (!file_util::WriteFile(manifest_path, manifest_json.data(), manifest_json.size())) { - ReportFailure("Error saving manifest.json."); + // Error saving manifest.json. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON"))); return NULL; } @@ -318,7 +357,10 @@ DictionaryValue* SandboxedExtensionUnpacker::RewriteManifestFile( bool SandboxedExtensionUnpacker::RewriteImageFiles() { ExtensionUnpacker::DecodedImages images; if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) { - ReportFailure("Couldn't read image data from disk."); + // Couldn't read image data from disk. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("COULD_NOT_READ_IMAGE_DATA_FROM_DISK"))); return false; } @@ -327,7 +369,10 @@ bool SandboxedExtensionUnpacker::RewriteImageFiles() { // originals are gone for good. std::set<FilePath> image_paths = extension_->GetBrowserImages(); if (image_paths.size() != images.size()) { - ReportFailure("Decoded images don't match what's in the manifest."); + // Decoded images don't match what's in the manifest. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST"))); return false; } @@ -335,11 +380,17 @@ bool SandboxedExtensionUnpacker::RewriteImageFiles() { it != image_paths.end(); ++it) { FilePath path = *it; if (path.IsAbsolute() || path.ReferencesParent()) { - ReportFailure("Invalid path for browser image."); + // Invalid path for browser image. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE"))); return false; } if (!file_util::Delete(extension_root_.Append(path), false)) { - ReportFailure("Error removing old image file."); + // Error removing old image file. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("ERROR_REMOVING_OLD_IMAGE_FILE"))); return false; } } @@ -349,7 +400,10 @@ bool SandboxedExtensionUnpacker::RewriteImageFiles() { const SkBitmap& image = images[i].a; FilePath path_suffix = images[i].b; if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) { - ReportFailure("Invalid path for bitmap image."); + // Invalid path for bitmap image. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE"))); return false; } FilePath path = extension_root_.Append(path_suffix); @@ -359,7 +413,10 @@ bool SandboxedExtensionUnpacker::RewriteImageFiles() { // though they may originally be .jpg, etc. Figure something out. // http://code.google.com/p/chromium/issues/detail?id=12459 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) { - ReportFailure("Error re-encoding theme image."); + // Error re-encoding theme image. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("ERROR_RE_ENCODING_THEME_IMAGE"))); return false; } @@ -367,7 +424,10 @@ bool SandboxedExtensionUnpacker::RewriteImageFiles() { // so we can be sure the directory exists. const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]); if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) { - ReportFailure("Error saving theme image."); + // Error saving theme image. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE"))); return false; } } @@ -379,7 +439,10 @@ bool SandboxedExtensionUnpacker::RewriteCatalogFiles() { DictionaryValue catalogs; if (!ExtensionUnpacker::ReadMessageCatalogsFromFile(temp_dir_.path(), &catalogs)) { - ReportFailure("Could not read catalog data from disk."); + // Could not read catalog data from disk. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("COULD_NOT_READ_CATALOG_DATA_FROM_DISK"))); return false; } @@ -388,7 +451,10 @@ bool SandboxedExtensionUnpacker::RewriteCatalogFiles() { key_it != catalogs.end_keys(); ++key_it) { DictionaryValue* catalog; if (!catalogs.GetDictionaryWithoutPathExpansion(*key_it, &catalog)) { - ReportFailure("Invalid catalog data."); + // Invalid catalog data. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("INVALID_CATALOG_DATA"))); return false; } @@ -397,7 +463,10 @@ bool SandboxedExtensionUnpacker::RewriteCatalogFiles() { FilePath relative_path = FilePath::FromWStringHack(UTF8ToWide(*key_it)); relative_path = relative_path.Append(Extension::kMessagesFilename); if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) { - ReportFailure("Invalid path for catalog."); + // Invalid path for catalog. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("INVALID_PATH_FOR_CATALOG"))); return false; } FilePath path = extension_root_.Append(relative_path); @@ -406,7 +475,10 @@ bool SandboxedExtensionUnpacker::RewriteCatalogFiles() { JSONStringValueSerializer serializer(&catalog_json); serializer.set_pretty_print(true); if (!serializer.Serialize(*catalog)) { - ReportFailure("Error serializing catalog."); + // Error serializing catalog. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("ERROR_SERIALIZING_CATALOG"))); return false; } @@ -415,7 +487,10 @@ bool SandboxedExtensionUnpacker::RewriteCatalogFiles() { if (!file_util::WriteFile(path, catalog_json.c_str(), catalog_json.size())) { - ReportFailure("Error saving catalog."); + // Error saving catalog. + ReportFailure(l10n_util::GetStringFUTF8( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("ERROR_SAVING_CATALOG"))); return false; } } diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.h b/chrome/browser/extensions/sandboxed_extension_unpacker.h index 8438482..e47b26c 100644 --- a/chrome/browser/extensions/sandboxed_extension_unpacker.h +++ b/chrome/browser/extensions/sandboxed_extension_unpacker.h @@ -122,9 +122,9 @@ class SandboxedExtensionUnpacker : public UtilityProcessHost::Client { void StartProcessOnIOThread(const FilePath& temp_crx_path); // SandboxedExtensionUnpacker - void OnUnpackExtensionSucceeded(const DictionaryValue& manifest); - void OnUnpackExtensionFailed(const std::string& error_message); - void OnProcessCrashed(); + virtual void OnUnpackExtensionSucceeded(const DictionaryValue& manifest); + virtual void OnUnpackExtensionFailed(const std::string& error_message); + virtual void OnProcessCrashed(int exit_code); void ReportFailure(const std::string& message); void ReportSuccess(); diff --git a/chrome/browser/extensions/stateful_external_extension_provider.cc b/chrome/browser/extensions/stateful_external_extension_provider.cc index 63899da..fd1a42a 100644 --- a/chrome/browser/extensions/stateful_external_extension_provider.cc +++ b/chrome/browser/extensions/stateful_external_extension_provider.cc @@ -10,6 +10,7 @@ #include "base/path_service.h" #include "base/values.h" #include "base/version.h" +#include "chrome/browser/browser_thread.h" namespace { @@ -27,19 +28,20 @@ StatefulExternalExtensionProvider::StatefulExternalExtensionProvider( Extension::Location download_location) : crx_location_(crx_location), download_location_(download_location) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); } StatefulExternalExtensionProvider::~StatefulExternalExtensionProvider() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); } void StatefulExternalExtensionProvider::VisitRegisteredExtension( - Visitor* visitor, const std::set<std::string>& ids_to_ignore) const { + Visitor* visitor) const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + DCHECK(prefs_.get()); for (DictionaryValue::key_iterator i = prefs_->begin_keys(); i != prefs_->end_keys(); ++i) { const std::string& extension_id = *i; - if (ids_to_ignore.find(extension_id) != ids_to_ignore.end()) - continue; - DictionaryValue* extension; if (!prefs_->GetDictionaryWithoutPathExpansion(extension_id, &extension)) continue; @@ -123,12 +125,16 @@ void StatefulExternalExtensionProvider::VisitRegisteredExtension( bool StatefulExternalExtensionProvider::HasExtension( const std::string& id) const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + DCHECK(prefs_.get()); return prefs_->HasKey(id); } bool StatefulExternalExtensionProvider::GetExtensionDetails( const std::string& id, Extension::Location* location, scoped_ptr<Version>* version) const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + DCHECK(prefs_.get()); DictionaryValue* extension = NULL; if (!prefs_->GetDictionary(id, &extension)) return false; @@ -157,3 +163,7 @@ bool StatefulExternalExtensionProvider::GetExtensionDetails( return true; } + +void StatefulExternalExtensionProvider::set_prefs(DictionaryValue* prefs) { + prefs_.reset(prefs); +} diff --git a/chrome/browser/extensions/stateful_external_extension_provider.h b/chrome/browser/extensions/stateful_external_extension_provider.h index 506873d..2fd481c 100644 --- a/chrome/browser/extensions/stateful_external_extension_provider.h +++ b/chrome/browser/extensions/stateful_external_extension_provider.h @@ -6,9 +6,6 @@ #define CHROME_BROWSER_EXTENSIONS_STATEFUL_EXTERNAL_EXTENSION_PROVIDER_H_ #pragma once -#include <set> -#include <string> - #include "chrome/browser/extensions/external_extension_provider.h" class DictionaryValue; @@ -23,6 +20,8 @@ class Version; // This provider can provide external extensions from two sources: crx files // and udpate URLs. The locations that the provider will report for these // are specified at the constructor. +// Instances of this class are expected to be created and destroyed on the UI +// thread and they are expecting public method calls from the FILE thread. class StatefulExternalExtensionProvider : public ExternalExtensionProvider { public: // Initialize the location for external extensions originating from crx @@ -35,8 +34,7 @@ class StatefulExternalExtensionProvider : public ExternalExtensionProvider { virtual ~StatefulExternalExtensionProvider(); // ExternalExtensionProvider implementation: - virtual void VisitRegisteredExtension( - Visitor* visitor, const std::set<std::string>& ids_to_ignore) const; + virtual void VisitRegisteredExtension(Visitor* visitor) const; virtual bool HasExtension(const std::string& id) const; @@ -50,6 +48,12 @@ class StatefulExternalExtensionProvider : public ExternalExtensionProvider { // Location for external extensions that are provided by this provider from // update URLs. const Extension::Location download_location_; + + // Stores the dictionary of external extensions internally. Takes ownership + // of |prefs|. + void set_prefs(DictionaryValue* prefs); + + private: // Dictionary of the external extensions that are provided by this provider. scoped_ptr<DictionaryValue> prefs_; }; diff --git a/chrome/browser/extensions/test_extension_prefs.cc b/chrome/browser/extensions/test_extension_prefs.cc index 2cbb2d1..5b0ee7b 100644 --- a/chrome/browser/extensions/test_extension_prefs.cc +++ b/chrome/browser/extensions/test_extension_prefs.cc @@ -6,18 +6,46 @@ #include "base/file_util.h" #include "base/message_loop.h" +#include "base/message_loop_proxy.h" #include "base/scoped_ptr.h" #include "base/values.h" #include "chrome/browser/browser_thread.h" +#include "chrome/browser/extensions/extension_pref_store.h" #include "chrome/browser/extensions/extension_prefs.h" #include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/prefs/pref_service_mock_builder.h" #include "chrome/browser/prefs/pref_value_store.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/json_pref_store.h" #include "testing/gtest/include/gtest/gtest.h" -TestExtensionPrefs::TestExtensionPrefs() { +namespace { + +// Mock ExtensionPrefs class with artificial clock to guarantee that no two +// extensions get the same installation time stamp and we can reliably +// assert the installation order in the tests below. +class MockExtensionPrefs : public ExtensionPrefs { + public: + MockExtensionPrefs(PrefService* prefs, + const FilePath& root_dir_, + ExtensionPrefStore* pref_store) + : ExtensionPrefs(prefs, root_dir_, pref_store), + currentTime(base::Time::Now()) {} + ~MockExtensionPrefs() {} + + protected: + mutable base::Time currentTime; + + virtual base::Time GetCurrentTime() const { + currentTime += base::TimeDelta::FromSeconds(10); + return currentTime; + } +}; + +} // namespace + +TestExtensionPrefs::TestExtensionPrefs() : pref_service_(NULL) { EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); preferences_file_ = temp_dir_.path().AppendASCII("Preferences"); extensions_dir_ = temp_dir_.path().AppendASCII("Extensions"); @@ -29,6 +57,9 @@ TestExtensionPrefs::TestExtensionPrefs() { TestExtensionPrefs::~TestExtensionPrefs() {} void TestExtensionPrefs::RecreateExtensionPrefs() { + // We persist and reload the PrefService's PrefStores because this process + // deletes all empty dictionaries. The ExtensionPrefs implementation + // needs to be able to handle this situation. if (pref_service_.get()) { // The PrefService writes its persistent file on the file thread, so we // need to wait for any pending I/O to complete before creating a new @@ -39,10 +70,14 @@ void TestExtensionPrefs::RecreateExtensionPrefs() { file_loop.RunAllPending(); } - // Create a |PrefService| instance that contains only user defined values. - pref_service_.reset(PrefService::CreateUserPrefService(preferences_file_)); + ExtensionPrefStore* pref_store = new ExtensionPrefStore; + PrefServiceMockBuilder builder; + builder.WithUserFilePrefs(preferences_file_); + builder.WithExtensionPrefs(pref_store); + pref_service_.reset(builder.Create()); ExtensionPrefs::RegisterUserPrefs(pref_service_.get()); - prefs_.reset(new ExtensionPrefs(pref_service_.get(), temp_dir_.path())); + prefs_.reset(new MockExtensionPrefs(pref_service_.get(), temp_dir_.path(), + pref_store)); } scoped_refptr<Extension> TestExtensionPrefs::AddExtension(std::string name) { diff --git a/chrome/browser/extensions/test_extension_prefs.h b/chrome/browser/extensions/test_extension_prefs.h index cb723b2..3220d7a 100644 --- a/chrome/browser/extensions/test_extension_prefs.h +++ b/chrome/browser/extensions/test_extension_prefs.h @@ -16,7 +16,6 @@ class DictionaryValue; class ExtensionPrefs; class PrefService; - // This is a test class intended to make it easier to work with ExtensionPrefs // in tests. class TestExtensionPrefs { diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc index 088e732..5f47084 100644 --- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc +++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc @@ -9,8 +9,8 @@ #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/themes/browser_theme_provider.h" #include "chrome/common/extensions/extension.h" @@ -75,7 +75,7 @@ string16 ThemeInstalledInfoBarDelegate::GetButtonLabel( bool ThemeInstalledInfoBarDelegate::Cancel() { if (!previous_theme_id_.empty()) { - ExtensionsService* service = profile_->GetExtensionsService(); + ExtensionService* service = profile_->GetExtensionService(); if (service) { const Extension* previous_theme = service->GetExtensionById(previous_theme_id_, true); diff --git a/chrome/browser/extensions/user_script_listener.cc b/chrome/browser/extensions/user_script_listener.cc index c553b1f..43965f0 100644 --- a/chrome/browser/extensions/user_script_listener.cc +++ b/chrome/browser/extensions/user_script_listener.cc @@ -5,8 +5,8 @@ #include "chrome/browser/extensions/user_script_listener.h" #include "chrome/browser/browser_thread.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_host/global_request_id.h" #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" #include "chrome/common/extensions/extension.h" @@ -34,7 +34,7 @@ void UserScriptListener::ShutdownMainThread() { } bool UserScriptListener::ShouldDelayRequest( - URLRequest* request, + net::URLRequest* request, const ResourceDispatcherHostRequestInfo& request_info, const GlobalRequestID& request_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); @@ -136,14 +136,14 @@ void UserScriptListener::Observe(NotificationType type, case NotificationType::EXTENSION_UNLOADED: { const Extension* unloaded_extension = - Details<const Extension>(details).ptr(); + Details<UnloadedExtensionInfo>(details)->extension; if (unloaded_extension->content_scripts().empty()) return; // no patterns to delete for this extension. // Clear all our patterns and reregister all the still-loaded extensions. URLPatterns new_patterns; - ExtensionsService* service = - Source<Profile>(source).ptr()->GetExtensionsService(); + ExtensionService* service = + Source<Profile>(source).ptr()->GetExtensionService(); for (ExtensionList::const_iterator it = service->extensions()->begin(); it != service->extensions()->end(); ++it) { if (*it != unloaded_extension) diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc index ec13f9f..cd40fd5 100644 --- a/chrome/browser/extensions/user_script_listener_unittest.cc +++ b/chrome/browser/extensions/user_script_listener_unittest.cc @@ -4,7 +4,7 @@ #include "base/message_loop.h" #include "base/thread.h" -#include "chrome/browser/extensions/extensions_service_unittest.h" +#include "chrome/browser/extensions/extension_service_unittest.h" #include "chrome/browser/extensions/user_script_listener.h" #include "chrome/browser/renderer_host/global_request_id.h" #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" @@ -90,35 +90,35 @@ ResourceDispatcherHostRequestInfo* CreateRequestInfo(int request_id) { return new ResourceDispatcherHostRequestInfo( new DummyResourceHandler(), ChildProcessInfo::RENDER_PROCESS, 0, 0, request_id, "null", "null", ResourceType::MAIN_FRAME, - 0, false, false, -1, -1); + 0, false, false, false, -1, -1); } -// A simple test URLRequestJob. We don't care what it does, only that whether it -// starts and finishes. +// A simple test net::URLRequestJob. We don't care what it does, only that +// whether it starts and finishes. class SimpleTestJob : public URLRequestTestJob { public: - explicit SimpleTestJob(URLRequest* request) + explicit SimpleTestJob(net::URLRequest* request) : URLRequestTestJob(request, test_headers(), kTestData, true) {} private: ~SimpleTestJob() {} }; class UserScriptListenerTest - : public ExtensionsServiceTestBase, - public URLRequest::Interceptor { + : public ExtensionServiceTestBase, + public net::URLRequest::Interceptor { public: UserScriptListenerTest() { - URLRequest::RegisterRequestInterceptor(this); + net::URLRequest::RegisterRequestInterceptor(this); } ~UserScriptListenerTest() { - URLRequest::UnregisterRequestInterceptor(this); + net::URLRequest::UnregisterRequestInterceptor(this); } virtual void SetUp() { - ExtensionsServiceTestBase::SetUp(); + ExtensionServiceTestBase::SetUp(); - InitializeEmptyExtensionsService(); + InitializeEmptyExtensionService(); service_->Init(); MessageLoop::current()->RunAllPending(); @@ -135,13 +135,13 @@ class UserScriptListenerTest MessageLoop::current()->RunAllPending(); } - // URLRequest::Interceptor - virtual URLRequestJob* MaybeIntercept(URLRequest* request) { + // net::URLRequest::Interceptor + virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request) { return new SimpleTestJob(request); } protected: - TestURLRequest* StartTestRequest(URLRequest::Delegate* delegate, + TestURLRequest* StartTestRequest(net::URLRequest::Delegate* delegate, const std::string& url) { TestURLRequest* request = new TestURLRequest(GURL(url), delegate); scoped_ptr<ResourceDispatcherHostRequestInfo> rdh_info( @@ -164,7 +164,8 @@ class UserScriptListenerTest void UnloadTestExtension() { ASSERT_FALSE(service_->extensions()->empty()); - service_->UnloadExtension(service_->extensions()->at(0)->id()); + service_->UnloadExtension(service_->extensions()->at(0)->id(), + UnloadedExtensionInfo::DISABLE); } scoped_refptr<UserScriptListener> listener_; diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc index 1712bb6..2af102e 100644 --- a/chrome/browser/extensions/user_script_master.cc +++ b/chrome/browser/extensions/user_script_master.cc @@ -15,9 +15,8 @@ #include "base/string_util.h" #include "base/thread.h" #include "base/version.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_resource.h" #include "chrome/common/notification_service.h" @@ -340,9 +339,9 @@ void UserScriptMaster::Observe(NotificationType type, case NotificationType::EXTENSION_LOADED: { // Add any content scripts inside the extension. const Extension* extension = Details<const Extension>(details).ptr(); - bool incognito_enabled = profile_->GetExtensionsService()-> + bool incognito_enabled = profile_->GetExtensionService()-> IsIncognitoEnabled(extension); - bool allow_file_access = profile_->GetExtensionsService()-> + bool allow_file_access = profile_->GetExtensionService()-> AllowFileAccess(extension); const UserScriptList& scripts = extension->content_scripts(); for (UserScriptList::const_iterator iter = scripts.begin(); @@ -357,7 +356,8 @@ void UserScriptMaster::Observe(NotificationType type, } case NotificationType::EXTENSION_UNLOADED: { // Remove any content scripts. - const Extension* extension = Details<const Extension>(details).ptr(); + const Extension* extension = + Details<UnloadedExtensionInfo>(details)->extension; UserScriptList new_lone_scripts; for (UserScriptList::iterator iter = lone_scripts_.begin(); iter != lone_scripts_.end(); ++iter) { @@ -375,9 +375,9 @@ void UserScriptMaster::Observe(NotificationType type, case NotificationType::EXTENSION_USER_SCRIPTS_UPDATED: { const Extension* extension = Details<const Extension>(details).ptr(); UserScriptList new_lone_scripts; - bool incognito_enabled = profile_->GetExtensionsService()-> + bool incognito_enabled = profile_->GetExtensionService()-> IsIncognitoEnabled(extension); - bool allow_file_access = profile_->GetExtensionsService()-> + bool allow_file_access = profile_->GetExtensionService()-> AllowFileAccess(extension); for (UserScriptList::iterator iter = lone_scripts_.begin(); iter != lone_scripts_.end(); ++iter) { diff --git a/chrome/browser/extensions/window_open_apitest.cc b/chrome/browser/extensions/window_open_apitest.cc index 7fe20b9..567ccc7 100644 --- a/chrome/browser/extensions/window_open_apitest.cc +++ b/chrome/browser/extensions/window_open_apitest.cc @@ -4,14 +4,14 @@ #include "base/command_line.h" #include "chrome/browser/extensions/extension_apitest.h" -#include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/ui_test_utils.h" #include "net/base/mock_host_resolver.h" -IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpen) { +// Disabled, http://crbug.com/64899. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_WindowOpen) { CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableExperimentalExtensionApis); |