summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r--chrome/browser/extensions/alert_apitest.cc2
-rw-r--r--chrome/browser/extensions/app_background_page_apitest.cc64
-rw-r--r--chrome/browser/extensions/autoupdate_interceptor.cc8
-rw-r--r--chrome/browser/extensions/browser_action_apitest.cc14
-rw-r--r--chrome/browser/extensions/content_script_all_frames_apitest.cc4
-rw-r--r--chrome/browser/extensions/content_script_extension_process_apitest.cc5
-rw-r--r--chrome/browser/extensions/convert_user_script.cc13
-rw-r--r--chrome/browser/extensions/convert_user_script.h7
-rw-r--r--chrome/browser/extensions/convert_user_script_unittest.cc4
-rw-r--r--chrome/browser/extensions/crx_installer.cc44
-rw-r--r--chrome/browser/extensions/crx_installer.h11
-rw-r--r--chrome/browser/extensions/crx_installer_browsertest.cc77
-rw-r--r--chrome/browser/extensions/default_apps.cc2
-rw-r--r--chrome/browser/extensions/default_apps_unittest.cc6
-rw-r--r--chrome/browser/extensions/execute_code_in_tab_function.cc4
-rw-r--r--chrome/browser/extensions/execute_script_apitest.cc2
-rw-r--r--chrome/browser/extensions/extension_apitest.cc21
-rw-r--r--chrome/browser/extensions/extension_apitest.h2
-rw-r--r--chrome/browser/extensions/extension_browser_actions_api.cc2
-rw-r--r--chrome/browser/extensions/extension_browser_event_router.cc77
-rw-r--r--chrome/browser/extensions/extension_browser_event_router.h10
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc68
-rw-r--r--chrome/browser/extensions/extension_browsertests_misc.cc14
-rw-r--r--chrome/browser/extensions/extension_context_menu_api.cc31
-rw-r--r--chrome/browser/extensions/extension_context_menu_browsertest.cc79
-rw-r--r--chrome/browser/extensions/extension_context_menu_model.cc49
-rw-r--r--chrome/browser/extensions/extension_context_menu_model.h10
-rw-r--r--chrome/browser/extensions/extension_cookies_api.cc2
-rw-r--r--chrome/browser/extensions/extension_crash_recovery_browsertest.cc11
-rw-r--r--chrome/browser/extensions/extension_creator.cc2
-rw-r--r--chrome/browser/extensions/extension_disabled_infobar_delegate.cc14
-rw-r--r--chrome/browser/extensions/extension_disabled_infobar_delegate.h4
-rw-r--r--chrome/browser/extensions/extension_dom_ui.cc23
-rw-r--r--chrome/browser/extensions/extension_dom_ui.h6
-rw-r--r--chrome/browser/extensions/extension_error_reporter.h2
-rw-r--r--chrome/browser/extensions/extension_event_router.cc34
-rw-r--r--chrome/browser/extensions/extension_event_router.h7
-rw-r--r--chrome/browser/extensions/extension_function.cc2
-rw-r--r--chrome/browser/extensions/extension_function.h2
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc10
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.h2
-rw-r--r--chrome/browser/extensions/extension_host.cc87
-rw-r--r--chrome/browser/extensions/extension_host.h15
-rw-r--r--chrome/browser/extensions/extension_host_mac.h2
-rw-r--r--chrome/browser/extensions/extension_host_mac.mm3
-rw-r--r--chrome/browser/extensions/extension_icon_manager.cc2
-rw-r--r--chrome/browser/extensions/extension_icon_manager.h2
-rw-r--r--chrome/browser/extensions/extension_icon_manager_unittest.cc18
-rw-r--r--chrome/browser/extensions/extension_info_map.cc27
-rw-r--r--chrome/browser/extensions/extension_info_map.h9
-rw-r--r--chrome/browser/extensions/extension_info_map_unittest.cc89
-rw-r--r--chrome/browser/extensions/extension_infobar_apitest.cc3
-rw-r--r--chrome/browser/extensions/extension_infobar_delegate.cc4
-rw-r--r--chrome/browser/extensions/extension_infobar_delegate.h6
-rw-r--r--chrome/browser/extensions/extension_infobar_module.cc2
-rw-r--r--chrome/browser/extensions/extension_install_ui.cc14
-rw-r--r--chrome/browser/extensions/extension_install_ui.h18
-rw-r--r--chrome/browser/extensions/extension_install_ui_browsertest.cc2
-rw-r--r--chrome/browser/extensions/extension_management_api.cc22
-rw-r--r--chrome/browser/extensions/extension_management_api.h6
-rw-r--r--chrome/browser/extensions/extension_management_browsertest.cc7
-rw-r--r--chrome/browser/extensions/extension_menu_manager.cc45
-rw-r--r--chrome/browser/extensions/extension_menu_manager.h22
-rw-r--r--chrome/browser/extensions/extension_menu_manager_unittest.cc31
-rw-r--r--chrome/browser/extensions/extension_message_service.cc11
-rw-r--r--chrome/browser/extensions/extension_metrics_apitest.cc2
-rw-r--r--chrome/browser/extensions/extension_omnibox_api.cc2
-rw-r--r--chrome/browser/extensions/extension_omnibox_api.h2
-rw-r--r--chrome/browser/extensions/extension_omnibox_apitest.cc1
-rw-r--r--chrome/browser/extensions/extension_popup_apitest.cc3
-rw-r--r--chrome/browser/extensions/extension_pref_store.cc8
-rw-r--r--chrome/browser/extensions/extension_pref_store.h49
-rw-r--r--chrome/browser/extensions/extension_pref_store_unittest.cc29
-rw-r--r--chrome/browser/extensions/extension_prefs.cc9
-rw-r--r--chrome/browser/extensions/extension_prefs.h8
-rw-r--r--chrome/browser/extensions/extension_prefs_unittest.cc28
-rw-r--r--chrome/browser/extensions/extension_process_manager.cc50
-rw-r--r--chrome/browser/extensions/extension_process_manager.h13
-rw-r--r--chrome/browser/extensions/extension_protocols.cc3
-rw-r--r--chrome/browser/extensions/extension_proxy_apitest.cc6
-rw-r--r--chrome/browser/extensions/extension_rlz_module.cc21
-rw-r--r--chrome/browser/extensions/extension_sidebar_api.cc4
-rw-r--r--chrome/browser/extensions/extension_tabs_apitest.cc40
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc105
-rw-r--r--chrome/browser/extensions/extension_tabs_module.h5
-rw-r--r--chrome/browser/extensions/extension_tabs_module_constants.cc2
-rw-r--r--chrome/browser/extensions/extension_tabs_module_constants.h2
-rw-r--r--chrome/browser/extensions/extension_test_message_listener.cc2
-rw-r--r--chrome/browser/extensions/extension_test_message_listener.h2
-rw-r--r--chrome/browser/extensions/extension_toolbar_model.cc23
-rw-r--r--chrome/browser/extensions/extension_toolbar_model.h14
-rw-r--r--chrome/browser/extensions/extension_toolbar_model_browsertest.cc18
-rw-r--r--chrome/browser/extensions/extension_tts_api.cc196
-rw-r--r--chrome/browser/extensions/extension_tts_api.h96
-rw-r--r--chrome/browser/extensions/extension_tts_api_linux.cc2
-rw-r--r--chrome/browser/extensions/extension_tts_api_util.h1
-rw-r--r--chrome/browser/extensions/extension_tts_apitest.cc158
-rw-r--r--chrome/browser/extensions/extension_ui_unittest.cc8
-rw-r--r--chrome/browser/extensions/extension_uitest.cc1
-rw-r--r--chrome/browser/extensions/extension_updater.cc26
-rw-r--r--chrome/browser/extensions/extension_updater.h3
-rw-r--r--chrome/browser/extensions/extension_updater_unittest.cc65
-rw-r--r--chrome/browser/extensions/extension_webnavigation_api.cc139
-rw-r--r--chrome/browser/extensions/extension_webnavigation_api.h59
-rw-r--r--chrome/browser/extensions/extension_webnavigation_apitest.cc12
-rw-r--r--chrome/browser/extensions/extension_webnavigation_unittest.cc105
-rw-r--r--chrome/browser/extensions/extension_webstore_private_api.cc178
-rw-r--r--chrome/browser/extensions/extension_webstore_private_api.h33
-rw-r--r--chrome/browser/extensions/extension_webstore_private_browsertest.cc151
-rw-r--r--chrome/browser/extensions/extensions_service.cc375
-rw-r--r--chrome/browser/extensions/extensions_service.h85
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.cc174
-rw-r--r--chrome/browser/extensions/extensions_startup.cc4
-rw-r--r--chrome/browser/extensions/extensions_ui.cc29
-rw-r--r--chrome/browser/extensions/extensions_ui.h9
-rw-r--r--chrome/browser/extensions/external_extension_provider.h18
-rw-r--r--chrome/browser/extensions/external_policy_extension_provider.cc68
-rw-r--r--chrome/browser/extensions/external_policy_extension_provider.h35
-rw-r--r--chrome/browser/extensions/external_policy_extension_provider_unittest.cc113
-rw-r--r--chrome/browser/extensions/external_pref_extension_provider.cc110
-rw-r--r--chrome/browser/extensions/external_pref_extension_provider.h20
-rw-r--r--chrome/browser/extensions/external_registry_extension_provider_win.cc40
-rw-r--r--chrome/browser/extensions/external_registry_extension_provider_win.h7
-rw-r--r--chrome/browser/extensions/image_loading_tracker.cc4
-rw-r--r--chrome/browser/extensions/image_loading_tracker.h4
-rw-r--r--chrome/browser/extensions/image_loading_tracker_unittest.cc17
-rw-r--r--chrome/browser/extensions/page_action_apitest.cc10
-rw-r--r--chrome/browser/extensions/sandboxed_extension_unpacker.cc21
-rw-r--r--chrome/browser/extensions/sandboxed_extension_unpacker.h4
-rw-r--r--chrome/browser/extensions/sandboxed_extension_unpacker_unittest.cc15
-rw-r--r--chrome/browser/extensions/stateful_external_extension_provider.cc159
-rw-r--r--chrome/browser/extensions/stateful_external_extension_provider.h57
-rw-r--r--chrome/browser/extensions/test_extension_prefs.cc15
-rw-r--r--chrome/browser/extensions/test_extension_prefs.h6
-rw-r--r--chrome/browser/extensions/theme_installed_infobar_delegate.cc6
-rw-r--r--chrome/browser/extensions/theme_installed_infobar_delegate.h2
-rw-r--r--chrome/browser/extensions/user_script_listener.cc10
-rw-r--r--chrome/browser/extensions/user_script_listener.h2
-rw-r--r--chrome/browser/extensions/user_script_master.cc17
-rw-r--r--chrome/browser/extensions/window_open_apitest.cc8
140 files changed, 3137 insertions, 1189 deletions
diff --git a/chrome/browser/extensions/alert_apitest.cc b/chrome/browser/extensions/alert_apitest.cc
index 23e8fe8..8e70fdb 100644
--- a/chrome/browser/extensions/alert_apitest.cc
+++ b/chrome/browser/extensions/alert_apitest.cc
@@ -14,7 +14,7 @@
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, AlertBasic) {
ASSERT_TRUE(RunExtensionTest("alert")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ExtensionHost* host = browser()->profile()->GetExtensionProcessManager()->
GetBackgroundHostForExtension(extension);
ASSERT_TRUE(host);
diff --git a/chrome/browser/extensions/app_background_page_apitest.cc b/chrome/browser/extensions/app_background_page_apitest.cc
index d1e78d1..80d2218 100644
--- a/chrome/browser/extensions/app_background_page_apitest.cc
+++ b/chrome/browser/extensions/app_background_page_apitest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"
@@ -14,14 +15,53 @@ class AppBackgroundPageApiTest : public ExtensionApiTest {
ExtensionApiTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kDisablePopupBlocking);
}
+
+ bool CreateApp(const std::string& app_manifest,
+ FilePath* app_dir) {
+ if (!app_dir_.CreateUniqueTempDir()) {
+ LOG(ERROR) << "Unable to create a temporary directory.";
+ return false;
+ }
+ FilePath manifest_path = app_dir_.path().AppendASCII("manifest.json");
+ int bytes_written = file_util::WriteFile(manifest_path,
+ app_manifest.data(),
+ app_manifest.size());
+ if (bytes_written != static_cast<int>(app_manifest.size())) {
+ LOG(ERROR) << "Unable to write complete manifest to file. Return code="
+ << bytes_written;
+ return false;
+ }
+ *app_dir = app_dir_.path();
+ return true;
+ }
+
+ private:
+ ScopedTempDir app_dir_;
};
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, Basic) {
host_resolver()->AddRule("a.com", "127.0.0.1");
ASSERT_TRUE(StartTestServer());
- LoadExtension(test_data_dir_.AppendASCII(
- "app_background_page/app_has_permission"));
+ std::string app_manifest = StringPrintf(
+ "{"
+ " \"name\": \"App\","
+ " \"version\": \"0.1\","
+ " \"app\": {"
+ " \"urls\": ["
+ " \"http://a.com/\""
+ " ],"
+ " \"launch\": {"
+ " \"web_url\": \"http://a.com:%d/\""
+ " }"
+ " },"
+ " \"permissions\": [\"background\"]"
+ "}",
+ test_server()->host_port_pair().port());
+
+ FilePath app_dir;
+ ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
+ ASSERT_TRUE(LoadExtension(app_dir));
ASSERT_TRUE(RunExtensionTest("app_background_page/basic")) << message_;
}
@@ -29,8 +69,24 @@ IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, LacksPermission) {
host_resolver()->AddRule("a.com", "127.0.0.1");
ASSERT_TRUE(StartTestServer());
- LoadExtension(test_data_dir_.AppendASCII(
- "app_background_page/app_lacks_permission"));
+ std::string app_manifest = StringPrintf(
+ "{"
+ " \"name\": \"App\","
+ " \"version\": \"0.1\","
+ " \"app\": {"
+ " \"urls\": ["
+ " \"http://a.com/\""
+ " ],"
+ " \"launch\": {"
+ " \"web_url\": \"http://a.com:%d/\""
+ " }"
+ " }"
+ "}",
+ test_server()->host_port_pair().port());
+
+ FilePath app_dir;
+ ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
+ ASSERT_TRUE(LoadExtension(app_dir));
ASSERT_TRUE(RunExtensionTest("app_background_page/lacks_permission"))
<< message_;
}
diff --git a/chrome/browser/extensions/autoupdate_interceptor.cc b/chrome/browser/extensions/autoupdate_interceptor.cc
index 2acd0a0..ef0091f 100644
--- a/chrome/browser/extensions/autoupdate_interceptor.cc
+++ b/chrome/browser/extensions/autoupdate_interceptor.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/extensions/autoupdate_interceptor.h"
#include "base/file_util.h"
+#include "base/thread_restrictions.h"
#include "chrome/browser/browser_thread.h"
#include "net/url_request/url_request_test_job.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -40,6 +41,10 @@ URLRequestJob* AutoUpdateInterceptor::MaybeIntercept(URLRequest* request) {
return NULL;
}
+ // It's ok to do a blocking disk access on this thread; this class
+ // is just used for tests.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
// Search for this request's url, ignoring any query parameters.
GURL url = request->url();
if (url.has_query()) {
@@ -61,6 +66,9 @@ URLRequestJob* AutoUpdateInterceptor::MaybeIntercept(URLRequest* request) {
void AutoUpdateInterceptor::SetResponse(const std::string url,
const FilePath& path) {
EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // It's ok to do a blocking disk access on this thread; this class
+ // is just used for tests.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
GURL gurl(url);
EXPECT_EQ("http", gurl.scheme());
EXPECT_EQ("localhost", gurl.host());
diff --git a/chrome/browser/extensions/browser_action_apitest.cc b/chrome/browser/extensions/browser_action_apitest.cc
index 8b09783..5e76310 100644
--- a/chrome/browser/extensions/browser_action_apitest.cc
+++ b/chrome/browser/extensions/browser_action_apitest.cc
@@ -47,7 +47,7 @@ class BrowserActionApiTest : public ExtensionApiTest {
IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, Basic) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("browser_action/basics")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
// Test that there is a browser action in the toolbar.
@@ -87,7 +87,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, Basic) {
IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, DynamicBrowserAction) {
ASSERT_TRUE(RunExtensionTest("browser_action/no_icon")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
// Test that there is a browser action in the toolbar and that it has no icon.
@@ -117,7 +117,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, DynamicBrowserAction) {
IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, TabSpecificBrowserActionState) {
ASSERT_TRUE(RunExtensionTest("browser_action/tab_specific_state")) <<
message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
// Test that there is a browser action in the toolbar and that it has an icon.
@@ -147,7 +147,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BrowserActionPopup) {
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
"browser_action/popup")));
BrowserActionTestUtil actions_bar = GetBrowserActionsBar();
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
// The extension's popup's size grows by |growFactor| each click.
@@ -180,7 +180,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BrowserActionPopup) {
// a popup.
IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BrowserActionAddPopup) {
ASSERT_TRUE(RunExtensionTest("browser_action/add_popup")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
int tab_id = ExtensionTabUtil::GetTabId(browser()->GetSelectedTabContents());
@@ -235,7 +235,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BrowserActionAddPopup) {
IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BrowserActionRemovePopup) {
// Load the extension, which has a browser action with a default popup.
ASSERT_TRUE(RunExtensionTest("browser_action/remove_popup")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
int tab_id = ExtensionTabUtil::GetTabId(browser()->GetSelectedTabContents());
@@ -269,7 +269,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoBasic) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("browser_action/basics")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
// Test that there is a browser action in the toolbar.
diff --git a/chrome/browser/extensions/content_script_all_frames_apitest.cc b/chrome/browser/extensions/content_script_all_frames_apitest.cc
index fac6362..b465c42 100644
--- a/chrome/browser/extensions/content_script_all_frames_apitest.cc
+++ b/chrome/browser/extensions/content_script_all_frames_apitest.cc
@@ -5,11 +5,11 @@
#include "chrome/browser/extensions/extension_apitest.h"
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptAllFrames) {
- ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(StartTestServer());
ASSERT_TRUE(RunExtensionTest("content_scripts/all_frames")) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionIframe) {
- ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(StartTestServer());
ASSERT_TRUE(RunExtensionTest("content_scripts/extension_iframe")) << message_;
}
diff --git a/chrome/browser/extensions/content_script_extension_process_apitest.cc b/chrome/browser/extensions/content_script_extension_process_apitest.cc
index 46729d2..64574a0 100644
--- a/chrome/browser/extensions/content_script_extension_process_apitest.cc
+++ b/chrome/browser/extensions/content_script_extension_process_apitest.cc
@@ -10,6 +10,7 @@
#include "chrome/test/ui_test_utils.h"
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionProcess) {
- ASSERT_TRUE(test_server()->Start());
- ASSERT_TRUE(RunExtensionTest("content_scripts/extension_process")) << message_;
+ ASSERT_TRUE(StartTestServer());
+ ASSERT_TRUE(
+ RunExtensionTest("content_scripts/extension_process")) << message_;
}
diff --git a/chrome/browser/extensions/convert_user_script.cc b/chrome/browser/extensions/convert_user_script.cc
index d50bec1..89caec4 100644
--- a/chrome/browser/extensions/convert_user_script.cc
+++ b/chrome/browser/extensions/convert_user_script.cc
@@ -24,9 +24,9 @@
namespace keys = extension_manifest_keys;
-Extension* ConvertUserScriptToExtension(const FilePath& user_script_path,
- const GURL& original_url,
- std::string* error) {
+scoped_refptr<Extension> ConvertUserScriptToExtension(
+ const FilePath& user_script_path, const GURL& original_url,
+ std::string* error) {
std::string content;
if (!file_util::ReadFileToString(user_script_path, &content)) {
*error = "Could not read source file: " +
@@ -138,12 +138,13 @@ Extension* ConvertUserScriptToExtension(const FilePath& user_script_path,
return NULL;
}
- scoped_ptr<Extension> extension(new Extension(temp_dir.path()));
- if (!extension->InitFromValue(*root, false, error)) {
+ scoped_refptr<Extension> extension = Extension::Create(
+ temp_dir.path(), Extension::INTERNAL, *root, false, error);
+ if (!extension) {
NOTREACHED() << "Could not init extension " << *error;
return NULL;
}
temp_dir.Take(); // The caller takes ownership of the directory.
- return extension.release();
+ return extension;
}
diff --git a/chrome/browser/extensions/convert_user_script.h b/chrome/browser/extensions/convert_user_script.h
index d392c4d..d779de0 100644
--- a/chrome/browser/extensions/convert_user_script.h
+++ b/chrome/browser/extensions/convert_user_script.h
@@ -8,6 +8,8 @@
#include <string>
+#include "base/ref_counted.h"
+
class Extension;
class FilePath;
class GURL;
@@ -17,8 +19,7 @@ class GURL;
// should take ownership on success, or NULL and |error| on failure.
//
// NOTE: This function does file IO and should not be called on the UI thread.
-Extension* ConvertUserScriptToExtension(const FilePath& user_script,
- const GURL& original_url,
- std::string* error);
+scoped_refptr<Extension> ConvertUserScriptToExtension(
+ const FilePath& user_script, const GURL& original_url, std::string* error);
#endif // CHROME_BROWSER_EXTENSIONS_CONVERT_USER_SCRIPT_H_
diff --git a/chrome/browser/extensions/convert_user_script_unittest.cc b/chrome/browser/extensions/convert_user_script_unittest.cc
index 299fee7..a0e1b8b 100644
--- a/chrome/browser/extensions/convert_user_script_unittest.cc
+++ b/chrome/browser/extensions/convert_user_script_unittest.cc
@@ -21,7 +21,7 @@ TEST(ExtensionFromUserScript, Basic) {
.AppendASCII("user_script_basic.user.js");
std::string error;
- scoped_ptr<Extension> extension(ConvertUserScriptToExtension(
+ scoped_refptr<Extension> extension(ConvertUserScriptToExtension(
test_file, GURL("http://www.google.com/foo"), &error));
ASSERT_TRUE(extension.get());
@@ -61,7 +61,7 @@ TEST(ExtensionFromUserScript, NoMetdata) {
.AppendASCII("user_script_no_metadata.user.js");
std::string error;
- scoped_ptr<Extension> extension(ConvertUserScriptToExtension(
+ scoped_refptr<Extension> extension(ConvertUserScriptToExtension(
test_file, GURL("http://www.google.com/foo/bar.user.js?monkey"), &error));
ASSERT_TRUE(extension.get());
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 6f34b3c..b2c60e3 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/extensions/crx_installer.h"
+#include <list>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/file_util.h"
@@ -12,6 +14,7 @@
#include "base/singleton.h"
#include "base/stringprintf.h"
#include "base/task.h"
+#include "base/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "base/version.h"
#include "chrome/browser/browser_process.h"
@@ -45,7 +48,7 @@ struct WhitelistedInstallData {
std::list<std::string> ids;
};
-}
+} // namespace
// static
void CrxInstaller::SetWhitelistedInstallId(const std::string& id) {
@@ -55,6 +58,7 @@ void CrxInstaller::SetWhitelistedInstallId(const std::string& id) {
// static
bool CrxInstaller::ClearWhitelistedInstallId(const std::string& id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
std::list<std::string>& ids = Singleton<WhitelistedInstallData>::get()->ids;
std::list<std::string>::iterator iter = ids.begin();
for (; iter != ids.end(); ++iter) {
@@ -112,7 +116,12 @@ void CrxInstaller::InstallCrx(const FilePath& source_file) {
source_file_ = source_file;
FilePath user_data_temp_dir;
- CHECK(PathService::Get(chrome::DIR_USER_DATA_TEMP, &user_data_temp_dir));
+ {
+ // We shouldn't be doing disk IO on the UI thread.
+ // http://code.google.com/p/chromium/issues/detail?id=60634
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ CHECK(PathService::Get(chrome::DIR_USER_DATA_TEMP, &user_data_temp_dir));
+ }
scoped_refptr<SandboxedExtensionUnpacker> unpacker(
new SandboxedExtensionUnpacker(
@@ -141,8 +150,8 @@ void CrxInstaller::InstallUserScript(const FilePath& source_file,
void CrxInstaller::ConvertUserScriptOnFileThread() {
std::string error;
- Extension* extension = ConvertUserScriptToExtension(source_file_,
- original_url_, &error);
+ scoped_refptr<Extension> extension =
+ ConvertUserScriptToExtension(source_file_, original_url_, &error);
if (!extension) {
ReportFailureFromFileThread(error);
return;
@@ -151,7 +160,8 @@ void CrxInstaller::ConvertUserScriptOnFileThread() {
OnUnpackSuccess(extension->path(), extension->path(), extension);
}
-bool CrxInstaller::AllowInstall(Extension* extension, std::string* error) {
+bool CrxInstaller::AllowInstall(const Extension* extension,
+ std::string* error) {
DCHECK(error);
// We always allow themes and external installs.
@@ -233,11 +243,11 @@ void CrxInstaller::OnUnpackFailure(const std::string& error_message) {
void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir,
const FilePath& extension_dir,
- Extension* extension) {
+ const Extension* extension) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
// Note: We take ownership of |extension| and |temp_dir|.
- extension_.reset(extension);
+ extension_ = extension;
temp_dir_ = temp_dir;
// We don't have to delete the unpack dir explicity since it is a child of
@@ -263,8 +273,8 @@ void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir,
void CrxInstaller::ConfirmInstall() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (frontend_->extension_prefs()->IsExtensionBlacklisted(extension_->id())) {
- LOG(INFO) << "This extension: " << extension_->id()
- << " is blacklisted. Install failed.";
+ VLOG(1) << "This extension: " << extension_->id()
+ << " is blacklisted. Install failed.";
ReportFailureFromUIThread("This extension is blacklisted.");
return;
}
@@ -276,7 +286,7 @@ void CrxInstaller::ConfirmInstall() {
}
GURL overlapping_url;
- Extension* overlapping_extension =
+ const Extension* overlapping_extension =
frontend_->GetExtensionByOverlappingWebExtent(extension_->web_extent());
if (overlapping_extension) {
ReportFailureFromUIThread(l10n_util::GetStringFUTF8(
@@ -288,9 +298,11 @@ void CrxInstaller::ConfirmInstall() {
current_version_ =
frontend_->extension_prefs()->GetVersionString(extension_->id());
+ bool whitelisted = ClearWhitelistedInstallId(extension_->id()) &&
+ extension_->plugins().empty();
+
if (client_ &&
- (!allow_silent_install_ ||
- !ClearWhitelistedInstallId(extension_->id()))) {
+ (!allow_silent_install_ || !whitelisted)) {
AddRef(); // Balanced in Proceed() and Abort().
client_->ConfirmInstall(this, extension_.get());
} else {
@@ -351,8 +363,8 @@ void CrxInstaller::CompleteInstall() {
// TODO(aa): All paths to resources inside extensions should be created
// lazily and based on the Extension's root path at that moment.
std::string error;
- extension_.reset(extension_file_util::LoadExtension(
- version_dir, install_source_, true, &error));
+ extension_ = extension_file_util::LoadExtension(
+ version_dir, install_source_, true, &error);
DCHECK(error.empty());
ReportSuccessFromFileThread();
@@ -400,8 +412,8 @@ void CrxInstaller::ReportSuccessFromUIThread() {
// Tell the frontend about the installation and hand off ownership of
// extension_ to it.
- frontend_->OnExtensionInstalled(extension_.release(),
- allow_privilege_increase_);
+ frontend_->OnExtensionInstalled(extension_, allow_privilege_increase_);
+ extension_ = NULL;
// We're done. We don't post any more tasks to ourselves so we are deleted
// soon.
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index b1212a2..349b225 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -49,11 +49,12 @@ class CrxInstaller
// ExtensionFunction to a resulting download in the download manager, it's
// currently necessary. This is the |id| of an extension to be installed
// *by the web store only* which should not get the permissions install
- // prompt.
+ // prompt. This should only be called on the UI thread.
// crbug.com/54916
static void SetWhitelistedInstallId(const std::string& id);
- // Returns whether |id| was found and removed (was whitelisted).
+ // Returns whether |id| was found and removed (was whitelisted). This should
+ // only be called on the UI thread.
static bool ClearWhitelistedInstallId(const std::string& id);
// Constructor. Extensions will be unpacked to |install_directory|.
@@ -120,13 +121,13 @@ class CrxInstaller
// Called after OnUnpackSuccess as a last check to see whether the install
// should complete.
- bool AllowInstall(Extension* extension, std::string* error);
+ bool AllowInstall(const Extension* extension, std::string* error);
// SandboxedExtensionUnpackerClient
virtual void OnUnpackFailure(const std::string& error_message);
virtual void OnUnpackSuccess(const FilePath& temp_dir,
const FilePath& extension_dir,
- Extension* extension);
+ const Extension* extension);
// Runs on the UI thread. Confirms with the user (via ExtensionInstallUI) that
// it is OK to install this extension.
@@ -187,7 +188,7 @@ class CrxInstaller
// The extension we're installing. We own this and either pass it off to
// ExtensionsService on success, or delete it on failure.
- scoped_ptr<Extension> extension_;
+ scoped_refptr<const Extension> extension_;
// If non-empty, contains the current version of the extension we're
// installing (for upgrades).
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
new file mode 100644
index 0000000..535efc9
--- /dev/null
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -0,0 +1,77 @@
+// 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/browser.h"
+#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/test/ui_test_utils.h"
+
+namespace {
+
+class MockInstallUI : public ExtensionInstallUI {
+ public:
+ explicit MockInstallUI(Profile* profile) :
+ ExtensionInstallUI(profile), confirmation_requested_(false) {}
+
+ // Did the Delegate request confirmation?
+ bool confirmation_requested() { return confirmation_requested_; }
+
+ // Overriding some of the ExtensionInstallUI API.
+ void ConfirmInstall(Delegate* delegate, const Extension* extension) {
+ confirmation_requested_ = true;
+ delegate->InstallUIProceed();
+ }
+ void OnInstallSuccess(const Extension* extension) {
+ MessageLoopForUI::current()->Quit();
+ }
+ void OnInstallFailure(const std::string& error) {
+ ADD_FAILURE() << "insall failed";
+ MessageLoopForUI::current()->Quit();
+ }
+
+ private:
+ bool confirmation_requested_;
+};
+
+} // namespace
+
+class ExtensionCrxInstallerTest : public ExtensionBrowserTest {
+ public:
+ // Installs a crx from |crx_relpath| (a path relative to the extension test
+ // data dir) with expected id |id|. Returns whether a confirmation prompt
+ // happened or not.
+ bool DidWhitelistInstallPrompt(const std::string& crx_relpath,
+ const std::string& id) {
+ ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ MockInstallUI* mock_install_ui = new MockInstallUI(browser()->profile());
+
+ scoped_refptr<CrxInstaller> installer(
+ new CrxInstaller(service->install_directory(),
+ service,
+ mock_install_ui /* ownership transferred */));
+
+ installer->set_allow_silent_install(true);
+ CrxInstaller::SetWhitelistedInstallId(id);
+
+ FilePath crx_path = test_data_dir_.AppendASCII(crx_relpath);
+ installer->InstallCrx(crx_path);
+ ui_test_utils::RunMessageLoop();
+
+ return mock_install_ui->confirmation_requested();
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, Whitelisting) {
+ // A regular extension should give no prompt.
+ EXPECT_FALSE(DidWhitelistInstallPrompt("good.crx",
+ "ldnnhddmnhbkjipkidpdiheffobcpfmf"));
+#if !defined(OS_CHROMEOS)
+ // An extension with NPAPI should give a prompt.
+ EXPECT_TRUE(DidWhitelistInstallPrompt("uitest/plugins.crx",
+ "hdgllgikmikobbofgnabhfimcfoopgnd"));
+#endif // !defined(OS_CHROMEOS
+}
diff --git a/chrome/browser/extensions/default_apps.cc b/chrome/browser/extensions/default_apps.cc
index ad39a34..1dff210 100644
--- a/chrome/browser/extensions/default_apps.cc
+++ b/chrome/browser/extensions/default_apps.cc
@@ -19,10 +19,12 @@ void DefaultApps::RegisterUserPrefs(PrefService* prefs) {
DefaultApps::DefaultApps(PrefService* prefs)
: prefs_(prefs) {
+#if !defined(OS_CHROMEOS)
// gmail, calendar, docs
ids_.insert("pjkljhegncpnkpknbcohdijeoejaedia");
ids_.insert("ejjicmeblgpmajnghnpcppodonldlgfn");
ids_.insert("apdfllckaahabafndbhieahigkjlhalf");
+#endif // OS_CHROMEOS
}
DefaultApps::~DefaultApps() {}
diff --git a/chrome/browser/extensions/default_apps_unittest.cc b/chrome/browser/extensions/default_apps_unittest.cc
index 8037236..24a9d70 100644
--- a/chrome/browser/extensions/default_apps_unittest.cc
+++ b/chrome/browser/extensions/default_apps_unittest.cc
@@ -7,6 +7,8 @@
#include "chrome/test/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
+// TODO(dpolukhin): On Chrome OS all apps are installed via external extensions
+#if !defined(OS_CHROMEOS)
TEST(DefaultApps, Basics) {
TestingPrefService pref_service;
DefaultApps::RegisterUserPrefs(&pref_service);
@@ -59,6 +61,7 @@ TEST(DefaultApps, Basics) {
EXPECT_FALSE(default_apps.ShouldShowPromo(default_app_ids));
EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter());
}
+#endif // OS_CHROMEOS
TEST(DefaultApps, HidePromo) {
TestingPrefService pref_service;
@@ -97,6 +100,8 @@ TEST(DefaultApps, InstallingAnAppHidesPromo) {
EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter());
}
+// TODO(dpolukhin): On Chrome OS all apps are installed via external extensions
+#if !defined(OS_CHROMEOS)
TEST(DefaultApps, ManualAppInstalledWhileInstallingDefaultApps) {
// It is possible to have apps manually installed while the default apps are
// being installed. The network or server might be down, causing the default
@@ -131,3 +136,4 @@ TEST(DefaultApps, ManualAppInstalledWhileInstallingDefaultApps) {
EXPECT_FALSE(default_apps.ShouldShowPromo(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 b7bf999..8021e6c 100644
--- a/chrome/browser/extensions/execute_code_in_tab_function.cc
+++ b/chrome/browser/extensions/execute_code_in_tab_function.cc
@@ -78,7 +78,7 @@ bool ExecuteCodeInTabFunction::RunImpl() {
// NOTE: This can give the wrong answer due to race conditions, but it is OK,
// we check again in the renderer.
- Extension* extension = GetExtension();
+ const Extension* extension = GetExtension();
const std::vector<URLPattern> host_permissions =
extension->host_permissions();
if (!Extension::CanExecuteScriptOnPage(
@@ -158,7 +158,7 @@ bool ExecuteCodeInTabFunction::Execute(const std::string& code_string) {
return false;
}
- Extension* extension = GetExtension();
+ const Extension* extension = GetExtension();
if (!extension) {
SendResponse(false);
return false;
diff --git a/chrome/browser/extensions/execute_script_apitest.cc b/chrome/browser/extensions/execute_script_apitest.cc
index a450fe0..9edd0b6 100644
--- a/chrome/browser/extensions/execute_script_apitest.cc
+++ b/chrome/browser/extensions/execute_script_apitest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 20109 The Chromium Authors. All rights reserved.
+// 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.
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index d136b50..07668b3 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -13,10 +13,6 @@
#include "chrome/common/notification_registrar.h"
#include "chrome/test/ui_test_utils.h"
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/views/domui_menu_widget.h"
-#endif
-
namespace {
const char kTestServerPort[] = "testServer.port";
@@ -68,7 +64,7 @@ void ExtensionApiTest::ResultCatcher::Observe(
switch (type.value) {
case NotificationType::EXTENSION_TEST_PASSED:
- LOG(INFO) << "Got EXTENSION_TEST_PASSED notification.";
+ VLOG(1) << "Got EXTENSION_TEST_PASSED notification.";
results_.push_back(true);
messages_.push_back("");
if (waiting_)
@@ -76,7 +72,7 @@ void ExtensionApiTest::ResultCatcher::Observe(
break;
case NotificationType::EXTENSION_TEST_FAILED:
- LOG(INFO) << "Got EXTENSION_TEST_FAILED notification.";
+ VLOG(1) << "Got EXTENSION_TEST_FAILED notification.";
results_.push_back(false);
messages_.push_back(*(Details<std::string>(details).ptr()));
if (waiting_)
@@ -122,13 +118,6 @@ bool ExtensionApiTest::RunPageTest(const std::string& page_url) {
bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name,
const std::string& page_url,
bool enable_incognito) {
-#if defined(OS_CHROMEOS)
- // ChromeOS uses DOMUI for menu and creates a stand-by renderer to
- // improve 1st time response. This can confuse this test as the test
- // uses AllSources to listen to notifications, thus disabling the warmup
- // process for ExtensionAPITests.
- chromeos::DOMUIMenuWidget::DisableWarmUp();
-#endif
ResultCatcher catcher;
DCHECK(!std::string(extension_name).empty() || !page_url.empty()) <<
"extension_name and page_url cannot both be empty";
@@ -155,7 +144,7 @@ bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name,
"Relative page_url given with no extension_name";
ExtensionsService* service = browser()->profile()->GetExtensionsService();
- Extension* extension =
+ const Extension* extension =
service->GetExtensionById(last_loaded_extension_id_, false);
if (!extension)
return false;
@@ -176,7 +165,7 @@ bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name,
}
// Test that exactly one extension loaded.
-Extension* ExtensionApiTest::GetSingleLoadedExtension() {
+const Extension* ExtensionApiTest::GetSingleLoadedExtension() {
ExtensionsService* service = browser()->profile()->GetExtensionsService();
int found_extension_index = -1;
@@ -196,7 +185,7 @@ Extension* ExtensionApiTest::GetSingleLoadedExtension() {
found_extension_index = static_cast<int>(i);
}
- Extension* extension = service->extensions()->at(found_extension_index);
+ const Extension* extension = service->extensions()->at(found_extension_index);
if (!extension) {
message_ = "extension pointer is NULL.";
return NULL;
diff --git a/chrome/browser/extensions/extension_apitest.h b/chrome/browser/extensions/extension_apitest.h
index b0a0e01..b2079a6 100644
--- a/chrome/browser/extensions/extension_apitest.h
+++ b/chrome/browser/extensions/extension_apitest.h
@@ -94,7 +94,7 @@ class ExtensionApiTest : public ExtensionBrowserTest {
// Test that exactly one extension loaded. If so, return a pointer to
// the extension. If not, return NULL and set message_.
- Extension* GetSingleLoadedExtension();
+ const Extension* GetSingleLoadedExtension();
// All extensions tested by ExtensionApiTest are in the "api_test" dir.
virtual void SetUpCommandLine(CommandLine* command_line);
diff --git a/chrome/browser/extensions/extension_browser_actions_api.cc b/chrome/browser/extensions/extension_browser_actions_api.cc
index 1ce4dfe..1986d28 100644
--- a/chrome/browser/extensions/extension_browser_actions_api.cc
+++ b/chrome/browser/extensions/extension_browser_actions_api.cc
@@ -26,7 +26,7 @@ bool BrowserActionFunction::RunImpl() {
if (details_->HasKey("tabId"))
EXTENSION_FUNCTION_VALIDATE(details_->GetInteger("tabId", &tab_id_));
- Extension* extension = GetExtension();
+ const Extension* extension = GetExtension();
browser_action_ = extension->browser_action();
if (!browser_action_) {
error_ = kNoBrowserActionError;
diff --git a/chrome/browser/extensions/extension_browser_event_router.cc b/chrome/browser/extensions/extension_browser_event_router.cc
index ce58dc7..dcf9b9d 100644
--- a/chrome/browser/extensions/extension_browser_event_router.cc
+++ b/chrome/browser/extensions/extension_browser_event_router.cc
@@ -270,7 +270,7 @@ void ExtensionBrowserEventRouter::TabInsertedAt(TabContents* contents,
bool foreground) {
// If tab is new, send created event.
int tab_id = ExtensionTabUtil::GetTabId(contents);
- if (tab_entries_.find(tab_id) == tab_entries_.end()) {
+ if (!GetTabEntry(contents)) {
tab_entries_[tab_id] = TabEntry();
TabCreatedAt(contents, index, foreground);
@@ -295,14 +295,13 @@ void ExtensionBrowserEventRouter::TabInsertedAt(TabContents* contents,
void ExtensionBrowserEventRouter::TabDetachedAt(TabContents* contents,
int index) {
- int tab_id = ExtensionTabUtil::GetTabId(contents);
- if (tab_entries_.find(tab_id) == tab_entries_.end()) {
+ if (!GetTabEntry(contents)) {
// The tab was removed. Don't send detach event.
return;
}
ListValue args;
- args.Append(Value::CreateIntegerValue(tab_id));
+ args.Append(Value::CreateIntegerValue(ExtensionTabUtil::GetTabId(contents)));
DictionaryValue* object_args = new DictionaryValue();
object_args->Set(tab_keys::kOldWindowIdKey, Value::CreateIntegerValue(
@@ -384,36 +383,51 @@ void ExtensionBrowserEventRouter::TabMoved(TabContents* contents,
void ExtensionBrowserEventRouter::TabUpdated(TabContents* contents,
bool did_navigate) {
- int tab_id = ExtensionTabUtil::GetTabId(contents);
- std::map<int, TabEntry>::iterator i = tab_entries_.find(tab_id);
- DCHECK(tab_entries_.end() != i);
- TabEntry& entry = i->second;
-
+ TabEntry* entry = GetTabEntry(contents);
DictionaryValue* changed_properties = NULL;
+
+ DCHECK(entry);
+
if (did_navigate)
- changed_properties = entry.DidNavigate(contents);
+ changed_properties = entry->DidNavigate(contents);
else
- changed_properties = entry.UpdateLoadState(contents);
+ changed_properties = entry->UpdateLoadState(contents);
+
+ if (changed_properties)
+ DispatchTabUpdatedEvent(contents, changed_properties);
+}
- if (changed_properties) {
- // The state of the tab (as seen from the extension point of view) has
- // changed. Send a notification to the extension.
- ListValue args;
+void ExtensionBrowserEventRouter::DispatchTabUpdatedEvent(
+ TabContents* contents, DictionaryValue* changed_properties) {
+ DCHECK(changed_properties);
+ DCHECK(contents);
- // First arg: The id of the tab that changed.
- args.Append(Value::CreateIntegerValue(tab_id));
+ // The state of the tab (as seen from the extension point of view) has
+ // changed. Send a notification to the extension.
+ ListValue args;
- // Second arg: An object containing the changes to the tab state.
- args.Append(changed_properties);
+ // First arg: The id of the tab that changed.
+ args.Append(Value::CreateIntegerValue(ExtensionTabUtil::GetTabId(contents)));
- // Third arg: An object containing the state of the tab.
- args.Append(ExtensionTabUtil::CreateTabValue(contents));
+ // Second arg: An object containing the changes to the tab state.
+ args.Append(changed_properties);
- std::string json_args;
- base::JSONWriter::Write(&args, false, &json_args);
+ // Third arg: An object containing the state of the tab.
+ args.Append(ExtensionTabUtil::CreateTabValue(contents));
- DispatchEvent(contents->profile(), events::kOnTabUpdated, json_args);
- }
+ std::string json_args;
+ base::JSONWriter::Write(&args, false, &json_args);
+
+ DispatchEvent(contents->profile(), events::kOnTabUpdated, json_args);
+}
+
+ExtensionBrowserEventRouter::TabEntry* ExtensionBrowserEventRouter::GetTabEntry(
+ const TabContents* contents) {
+ int tab_id = ExtensionTabUtil::GetTabId(contents);
+ std::map<int, TabEntry>::iterator i = tab_entries_.find(tab_id);
+ if (tab_entries_.end() == i)
+ return NULL;
+ return &i->second;
}
void ExtensionBrowserEventRouter::Observe(NotificationType type,
@@ -455,6 +469,19 @@ void ExtensionBrowserEventRouter::TabReplacedAt(TabContents* old_contents,
RegisterForTabNotifications(new_contents);
}
+void ExtensionBrowserEventRouter::TabPinnedStateChanged(TabContents* contents,
+ int index) {
+ TabStripModel* tab_strip = NULL;
+ int tab_index;
+
+ if (ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index)) {
+ DictionaryValue* changed_properties = new DictionaryValue();
+ changed_properties->SetBoolean(tab_keys::kPinnedKey,
+ tab_strip->IsTabPinned(tab_index));
+ DispatchTabUpdatedEvent(contents, changed_properties);
+ }
+}
+
void ExtensionBrowserEventRouter::TabStripEmpty() {}
void ExtensionBrowserEventRouter::DispatchOldPageActionEvent(
diff --git a/chrome/browser/extensions/extension_browser_event_router.h b/chrome/browser/extensions/extension_browser_event_router.h
index bfd2205..a84749d 100644
--- a/chrome/browser/extensions/extension_browser_event_router.h
+++ b/chrome/browser/extensions/extension_browser_event_router.h
@@ -74,6 +74,7 @@ class ExtensionBrowserEventRouter : public TabStripModelObserver,
virtual void TabReplacedAt(TabContents* old_contents,
TabContents* new_contents,
int index);
+ virtual void TabPinnedStateChanged(TabContents* contents, int index);
virtual void TabStripEmpty();
// Page Action execute event.
@@ -100,6 +101,11 @@ class ExtensionBrowserEventRouter : public TabStripModelObserver,
// and Observe/NAV_ENTRY_COMMITTED.
void TabUpdated(TabContents* contents, bool did_navigate);
+ // Packages |changed_properties| as a tab updated event for the tab |contents|
+ // and dispatches the event to the extension.
+ void DispatchTabUpdatedEvent(TabContents* contents,
+ DictionaryValue* changed_properties);
+
// Called to dispatch a deprecated style page action click event that was
// registered like:
// chrome.pageActions["name"].addListener(function(actionId, info){})
@@ -164,6 +170,10 @@ class ExtensionBrowserEventRouter : public TabStripModelObserver,
GURL url_;
};
+ // Gets the TabEntry for the given |contents|. Returns TabEntry* if
+ // found, NULL if not.
+ TabEntry* GetTabEntry(const TabContents* contents);
+
std::map<int, TabEntry> tab_entries_;
// The currently focused window. We keep this so as to avoid sending multiple
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index aa5b46a..af8a6de 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -58,7 +58,6 @@ void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) {
bool ExtensionBrowserTest::LoadExtensionImpl(const FilePath& path,
bool incognito_enabled) {
ExtensionsService* service = browser()->profile()->GetExtensionsService();
- size_t num_before = service->extensions()->size();
{
NotificationRegistrar registrar;
registrar.Add(this, NotificationType::EXTENSION_LOADED,
@@ -66,15 +65,26 @@ bool ExtensionBrowserTest::LoadExtensionImpl(const FilePath& path,
service->LoadExtension(path);
ui_test_utils::RunMessageLoop();
}
- size_t num_after = service->extensions()->size();
- if (num_after != (num_before + 1))
+
+ // Find the extension by iterating backwards since it is likely last.
+ FilePath extension_path = path;
+ file_util::AbsolutePath(&extension_path);
+ const Extension* extension = NULL;
+ for (ExtensionList::const_reverse_iterator iter =
+ service->extensions()->rbegin();
+ iter != service->extensions()->rend(); ++iter) {
+ if ((*iter)->path() == extension_path) {
+ extension = *iter;
+ break;
+ }
+ }
+ if (!extension)
return false;
if (incognito_enabled) {
// Enable the incognito bit in the extension prefs. The call to
// OnExtensionInstalled ensures the other extension prefs are set up with
// the defaults.
- Extension* extension = service->extensions()->at(num_after - 1);
service->extension_prefs()->OnExtensionInstalled(
extension, Extension::ENABLED, false);
service->SetIsIncognitoEnabled(extension, true);
@@ -97,14 +107,15 @@ class MockAbortExtensionInstallUI : public ExtensionInstallUI {
MockAbortExtensionInstallUI() : ExtensionInstallUI(NULL) {}
// Simulate a user abort on an extension installation.
- virtual void ConfirmInstall(Delegate* delegate, Extension* extension) {
+ virtual void ConfirmInstall(Delegate* delegate, const Extension* extension) {
delegate->InstallUIAbort();
MessageLoopForUI::current()->Quit();
}
- virtual void ConfirmUninstall(Delegate* delegate, Extension* extension) {}
+ virtual void ConfirmUninstall(Delegate* delegate,
+ const Extension* extension) {}
- virtual void OnInstallSuccess(Extension* extension) {}
+ virtual void OnInstallSuccess(const Extension* extension) {}
virtual void OnInstallFailure(const std::string& error) {}
};
@@ -142,21 +153,19 @@ bool ExtensionBrowserTest::InstallOrUpdateExtension(const std::string& id,
size_t num_after = service->extensions()->size();
if (num_after != (num_before + expected_change)) {
- LOG(INFO) << "Num extensions before: "
- << base::IntToString(num_before) << " "
- << "num after: " << base::IntToString(num_after) << " "
- << "Installed extensions follow:";
+ VLOG(1) << "Num extensions before: " << base::IntToString(num_before)
+ << " num after: " << base::IntToString(num_after)
+ << " Installed extensions follow:";
for (size_t i = 0; i < service->extensions()->size(); ++i)
- LOG(INFO) << " " << service->extensions()->at(i)->id();
+ VLOG(1) << " " << (*service->extensions())[i]->id();
- LOG(INFO) << "Errors follow:";
+ VLOG(1) << "Errors follow:";
const std::vector<std::string>* errors =
ExtensionErrorReporter::GetInstance()->GetErrors();
for (std::vector<std::string>::const_iterator iter = errors->begin();
- iter != errors->end(); ++iter) {
- LOG(INFO) << *iter;
- }
+ iter != errors->end(); ++iter)
+ VLOG(1) << *iter;
return false;
}
@@ -280,48 +289,47 @@ void ExtensionBrowserTest::Observe(NotificationType type,
const NotificationDetails& details) {
switch (type.value) {
case NotificationType::EXTENSION_LOADED:
- last_loaded_extension_id_ = Details<Extension>(details).ptr()->id();
- LOG(INFO) << "Got EXTENSION_LOADED notification.";
+ last_loaded_extension_id_ = Details<const Extension>(details).ptr()->id();
+ VLOG(1) << "Got EXTENSION_LOADED notification.";
MessageLoopForUI::current()->Quit();
break;
case NotificationType::EXTENSION_UPDATE_DISABLED:
- LOG(INFO) << "Got EXTENSION_UPDATE_DISABLED notification.";
+ VLOG(1) << "Got EXTENSION_UPDATE_DISABLED notification.";
MessageLoopForUI::current()->Quit();
break;
case NotificationType::EXTENSION_HOST_DID_STOP_LOADING:
- LOG(INFO) << "Got EXTENSION_HOST_DID_STOP_LOADING notification.";
+ VLOG(1) << "Got EXTENSION_HOST_DID_STOP_LOADING notification.";
MessageLoopForUI::current()->Quit();
break;
case NotificationType::EXTENSION_INSTALLED:
- LOG(INFO) << "Got EXTENSION_INSTALLED notification.";
+ VLOG(1) << "Got EXTENSION_INSTALLED notification.";
++extension_installs_observed_;
MessageLoopForUI::current()->Quit();
break;
case NotificationType::EXTENSION_INSTALL_ERROR:
- LOG(INFO) << "Got EXTENSION_INSTALL_ERROR notification.";
+ VLOG(1) << "Got EXTENSION_INSTALL_ERROR notification.";
MessageLoopForUI::current()->Quit();
break;
case NotificationType::EXTENSION_PROCESS_CREATED:
- LOG(INFO) << "Got EXTENSION_PROCESS_CREATED notification.";
+ VLOG(1) << "Got EXTENSION_PROCESS_CREATED notification.";
MessageLoopForUI::current()->Quit();
break;
case NotificationType::EXTENSION_PROCESS_TERMINATED:
- LOG(INFO) << "Got EXTENSION_PROCESS_TERMINATED notification.";
+ VLOG(1) << "Got EXTENSION_PROCESS_TERMINATED notification.";
MessageLoopForUI::current()->Quit();
break;
case NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED: {
LocationBarTesting* location_bar =
browser()->window()->GetLocationBar()->GetLocationBarForTesting();
- LOG(INFO) << "Got EXTENSION_PAGE_ACTION_COUNT_CHANGED "
- << "notification. Number of page actions: "
- << location_bar->PageActionCount() << "";
+ VLOG(1) << "Got EXTENSION_PAGE_ACTION_COUNT_CHANGED notification. Number "
+ "of page actions: " << location_bar->PageActionCount();
if (location_bar->PageActionCount() ==
target_page_action_count_) {
target_page_action_count_ = -1;
@@ -333,9 +341,9 @@ void ExtensionBrowserTest::Observe(NotificationType type,
case NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED: {
LocationBarTesting* location_bar =
browser()->window()->GetLocationBar()->GetLocationBarForTesting();
- LOG(INFO) << "Got EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED "
- << "notification. Number of visible page actions: "
- << location_bar->PageActionVisibleCount();
+ VLOG(1) << "Got EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED notification. "
+ "Number of visible page actions: "
+ << location_bar->PageActionVisibleCount();
if (location_bar->PageActionVisibleCount() ==
target_visible_page_action_count_) {
target_visible_page_action_count_ = -1;
diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc
index 8338a52..3b1780d 100644
--- a/chrome/browser/extensions/extension_browsertests_misc.cc
+++ b/chrome/browser/extensions/extension_browsertests_misc.cc
@@ -260,13 +260,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageActionRefreshCrash) {
ASSERT_TRUE(LoadExtension(base_path.AppendASCII("ExtA")));
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
ASSERT_EQ(size_before + 1, service->extensions()->size());
- Extension* extensionA = service->extensions()->at(size_before);
+ const Extension* extensionA = service->extensions()->at(size_before);
// Load extension B.
ASSERT_TRUE(LoadExtension(base_path.AppendASCII("ExtB")));
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(2));
ASSERT_EQ(size_before + 2, service->extensions()->size());
- Extension* extensionB = service->extensions()->at(size_before + 1);
+ const Extension* extensionB = service->extensions()->at(size_before + 1);
ReloadExtension(extensionA->id());
// ExtensionA has changed, so refetch it.
@@ -306,7 +306,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationBrowserAction) {
ASSERT_TRUE(LoadExtension(extension_path));
ASSERT_EQ(size_before + 1, service->extensions()->size());
- Extension* extension = service->extensions()->at(size_before);
+ const Extension* extension = service->extensions()->at(size_before);
EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur: l10n browser action").c_str(),
extension->description().c_str());
@@ -335,7 +335,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationPageAction) {
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
ASSERT_EQ(size_before + 1, service->extensions()->size());
- Extension* extension = service->extensions()->at(size_before);
+ const Extension* extension = service->extensions()->at(size_before);
EXPECT_STREQ(WideToUTF8(L"Hreggvi\u00F0ur: l10n page action").c_str(),
extension->description().c_str());
@@ -422,7 +422,7 @@ void NavigateToFeedAndValidate(net::TestServer* server,
}
ExtensionsService* service = browser->profile()->GetExtensionsService();
- Extension* extension = service->extensions()->back();
+ const Extension* extension = service->extensions()->back();
std::string id = extension->id();
// Navigate to the subscribe page directly.
@@ -701,7 +701,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenNoPrivileges) {
#define MAYBE_PluginLoadUnload PluginLoadUnload
#elif defined(OS_LINUX)
// http://crbug.com/47598
-#define MAYBE_PluginLoadUnload FLAKY_PluginLoadUnload
+#define MAYBE_PluginLoadUnload DISABLED_PluginLoadUnload
#else
// TODO(mpcomplete): http://crbug.com/29900 need cross platform plugin support.
#define MAYBE_PluginLoadUnload DISABLED_PluginLoadUnload
@@ -778,7 +778,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_OptionsPage) {
ExtensionsService* service = browser()->profile()->GetExtensionsService();
const ExtensionList* extensions = service->extensions();
ASSERT_EQ(1u, extensions->size());
- Extension* extension = extensions->at(0);
+ const Extension* extension = extensions->at(0);
// Go to the chrome://extensions page and click the Options button.
ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIExtensionsURL));
diff --git a/chrome/browser/extensions/extension_context_menu_api.cc b/chrome/browser/extensions/extension_context_menu_api.cc
index 92e9ad4..a004b97 100644
--- a/chrome/browser/extensions/extension_context_menu_api.cc
+++ b/chrome/browser/extensions/extension_context_menu_api.cc
@@ -138,7 +138,7 @@ bool ExtensionContextMenuFunction::ParseURLPatterns(
return false;
URLPattern pattern(ExtensionMenuManager::kAllowedSchemes);
- if (!pattern.Parse(tmp)) {
+ if (URLPattern::PARSE_SUCCESS != pattern.Parse(tmp)) {
error_ = ExtensionErrorUtils::FormatErrorMessage(kInvalidURLPatternError,
tmp);
return false;
@@ -174,22 +174,21 @@ bool ExtensionContextMenuFunction::SetURLPatterns(
return true;
}
-
bool ExtensionContextMenuFunction::GetParent(
const DictionaryValue& properties,
const ExtensionMenuManager& manager,
ExtensionMenuItem** result) {
if (!properties.HasKey(kParentIdKey))
return true;
- ExtensionMenuItem::Id parent_id(extension_id(), 0);
+ ExtensionMenuItem::Id parent_id(profile(), extension_id(), 0);
if (properties.HasKey(kParentIdKey) &&
- !properties.GetInteger(kParentIdKey, &parent_id.second))
+ !properties.GetInteger(kParentIdKey, &parent_id.uid))
return false;
ExtensionMenuItem* parent = manager.GetItemById(parent_id);
if (!parent) {
error_ = "Cannot find menu item with id " +
- base::IntToString(parent_id.second);
+ base::IntToString(parent_id.uid);
return false;
}
if (parent->type() != ExtensionMenuItem::NORMAL) {
@@ -205,9 +204,9 @@ bool CreateContextMenuFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &properties));
EXTENSION_FUNCTION_VALIDATE(properties != NULL);
- ExtensionMenuItem::Id id(extension_id(), 0);
+ ExtensionMenuItem::Id id(profile(), extension_id(), 0);
EXTENSION_FUNCTION_VALIDATE(properties->GetInteger(kGeneratedIdKey,
- &id.second));
+ &id.uid));
std::string title;
if (properties->HasKey(kTitleKey) &&
!properties->GetString(kTitleKey, &title))
@@ -241,13 +240,13 @@ bool CreateContextMenuFunction::RunImpl() {
bool success = true;
if (properties->HasKey(kParentIdKey)) {
- ExtensionMenuItem::Id parent_id(extension_id(), 0);
+ ExtensionMenuItem::Id parent_id(profile(), extension_id(), 0);
EXTENSION_FUNCTION_VALIDATE(properties->GetInteger(kParentIdKey,
- &parent_id.second));
+ &parent_id.uid));
ExtensionMenuItem* parent = menu_manager->GetItemById(parent_id);
if (!parent) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
- kCannotFindItemError, base::IntToString(parent_id.second));
+ kCannotFindItemError, base::IntToString(parent_id.uid));
return false;
}
if (parent->type() != ExtensionMenuItem::NORMAL) {
@@ -266,15 +265,15 @@ bool CreateContextMenuFunction::RunImpl() {
}
bool UpdateContextMenuFunction::RunImpl() {
- ExtensionMenuItem::Id item_id(extension_id(), 0);
- EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &item_id.second));
+ ExtensionMenuItem::Id item_id(profile(), extension_id(), 0);
+ EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &item_id.uid));
ExtensionsService* service = profile()->GetExtensionsService();
ExtensionMenuManager* manager = service->menu_manager();
ExtensionMenuItem* item = manager->GetItemById(item_id);
if (!item || item->extension_id() != extension_id()) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
- kCannotFindItemError, base::IntToString(item_id.second));
+ kCannotFindItemError, base::IntToString(item_id.uid));
return false;
}
@@ -333,8 +332,8 @@ bool UpdateContextMenuFunction::RunImpl() {
}
bool RemoveContextMenuFunction::RunImpl() {
- ExtensionMenuItem::Id id(extension_id(), 0);
- EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &id.second));
+ ExtensionMenuItem::Id id(profile(), extension_id(), 0);
+ EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &id.uid));
ExtensionsService* service = profile()->GetExtensionsService();
ExtensionMenuManager* manager = service->menu_manager();
@@ -342,7 +341,7 @@ bool RemoveContextMenuFunction::RunImpl() {
// Ensure one extension can't remove another's menu items.
if (!item || item->extension_id() != extension_id()) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
- kCannotFindItemError, base::IntToString(id.second));
+ kCannotFindItemError, base::IntToString(id.uid));
return false;
}
diff --git a/chrome/browser/extensions/extension_context_menu_browsertest.cc b/chrome/browser/extensions/extension_context_menu_browsertest.cc
index 62221e1..da83124 100644
--- a/chrome/browser/extensions/extension_context_menu_browsertest.cc
+++ b/chrome/browser/extensions/extension_context_menu_browsertest.cc
@@ -3,8 +3,9 @@
// found in the LICENSE file.
#include "app/menus/menu_model.h"
-#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/browser.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"
@@ -122,9 +123,16 @@ class ExtensionContextMenuBrowserTest : public ExtensionBrowserTest {
return LoadExtension(extension_dir);
}
- TestRenderViewContextMenu* CreateMenu(const GURL& page_url,
+ bool LoadContextMenuExtensionIncognito(std::string subdirectory) {
+ FilePath extension_dir =
+ test_data_dir_.AppendASCII("context_menus").AppendASCII(subdirectory);
+ return LoadExtensionIncognito(extension_dir);
+ }
+
+ TestRenderViewContextMenu* CreateMenu(Browser* browser,
+ const GURL& page_url,
const GURL& link_url) {
- TabContents* tab_contents = browser()->GetSelectedTabContents();
+ TabContents* tab_contents = browser->GetSelectedTabContents();
WebContextMenuData data;
ContextMenuParams params(data);
params.page_url = page_url;
@@ -142,7 +150,7 @@ class ExtensionContextMenuBrowserTest : public ExtensionBrowserTest {
// Returns a pointer to the currently loaded extension with |name|, or null
// if not found.
- Extension* GetExtensionNamed(std::string name) {
+ const Extension* GetExtensionNamed(std::string name) {
const ExtensionList* extensions =
browser()->profile()->GetExtensionsService()->extensions();
ExtensionList::const_iterator i;
@@ -173,7 +181,8 @@ class ExtensionContextMenuBrowserTest : public ExtensionBrowserTest {
bool MenuHasItemWithLabel(const GURL& page_url,
const GURL& link_url,
const std::string& label) {
- scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(page_url, link_url));
+ scoped_ptr<TestRenderViewContextMenu> menu(
+ CreateMenu(browser(), page_url, link_url));
return menu->HasExtensionItemWithLabel(label);
}
};
@@ -190,7 +199,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Simple) {
GURL page_url("http://www.google.com");
// Create and build our test context menu.
- scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(page_url, GURL()));
+ scoped_ptr<TestRenderViewContextMenu> menu(
+ CreateMenu(browser(), page_url, GURL()));
// Look for the extension item in the menu, and execute it.
int command_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
@@ -249,7 +259,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, LongTitle) {
// Create a context menu, then find the item's label. It should be properly
// truncated.
GURL url("http://foo.com/");
- scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(url, GURL()));
+ scoped_ptr<TestRenderViewContextMenu> menu(
+ CreateMenu(browser(), url, GURL()));
string16 label;
ASSERT_TRUE(menu->GetItemLabel(item->id(), &label));
@@ -301,7 +312,7 @@ static void VerifyMenuForSeparatorsTest(const MenuModel& menu) {
IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Separators) {
// Load the extension.
ASSERT_TRUE(LoadContextMenuExtension("separators"));
- Extension* extension = GetExtensionNamed("Separators Test");
+ const Extension* extension = GetExtensionNamed("Separators Test");
ASSERT_TRUE(extension != NULL);
// Navigate to test1.html inside the extension, which should create a bunch
@@ -313,7 +324,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Separators) {
listener1.WaitUntilSatisfied();
GURL url("http://www.google.com/");
- scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(url, GURL()));
+ scoped_ptr<TestRenderViewContextMenu> menu(
+ CreateMenu(browser(), url, GURL()));
// The top-level item should be an "automagic parent" with the extension's
// name.
@@ -336,7 +348,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Separators) {
ui_test_utils::NavigateToURL(browser(),
GURL(extension->GetResourceURL("test2.html")));
listener2.WaitUntilSatisfied();
- menu.reset(CreateMenu(url, GURL()));
+ menu.reset(CreateMenu(browser(), url, GURL()));
ASSERT_TRUE(menu->GetMenuModelAndItemIndex(
IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, &model, &index));
EXPECT_EQ(UTF8ToUTF16("parent"), model->GetLabelAt(index));
@@ -368,3 +380,50 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, TargetURLs) {
non_google_url,
std::string("item1")));
}
+
+// Tests adding a simple context menu item.
+IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, IncognitoSplit) {
+ ExtensionTestMessageListener created("created item regular", false);
+ ExtensionTestMessageListener created_incognito("created item incognito",
+ false);
+
+ ExtensionTestMessageListener onclick("onclick fired regular", false);
+ ExtensionTestMessageListener onclick_incognito("onclick fired incognito",
+ false);
+
+ // Open an incognito window.
+ ui_test_utils::OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
+
+ ASSERT_TRUE(LoadContextMenuExtensionIncognito("incognito"));
+
+ // Wait for the extension's processes to tell us they've created an item.
+ ASSERT_TRUE(created.WaitUntilSatisfied());
+ ASSERT_TRUE(created_incognito.WaitUntilSatisfied());
+
+ GURL page_url("http://www.google.com");
+
+ // Create and build our test context menu.
+ Browser* browser_incognito = BrowserList::FindBrowserWithType(
+ browser()->profile()->GetOffTheRecordProfile(),
+ Browser::TYPE_NORMAL, false);
+ ASSERT_TRUE(browser_incognito);
+ scoped_ptr<TestRenderViewContextMenu> menu(
+ CreateMenu(browser(), page_url, GURL()));
+ scoped_ptr<TestRenderViewContextMenu> menu_incognito(
+ CreateMenu(browser_incognito, page_url, GURL()));
+
+ // Look for the extension item in the menu, and execute it.
+ int command_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
+ ASSERT_TRUE(menu->IsCommandIdEnabled(command_id));
+ menu->ExecuteCommand(command_id);
+
+ // Wait for the extension's script to tell us its onclick fired. Ensure
+ // that the incognito version doesn't fire until we explicitly click the
+ // incognito menu item.
+ ASSERT_TRUE(onclick.WaitUntilSatisfied());
+ EXPECT_FALSE(onclick_incognito.was_satisfied());
+
+ ASSERT_TRUE(menu_incognito->IsCommandIdEnabled(command_id));
+ menu_incognito->ExecuteCommand(command_id);
+ ASSERT_TRUE(onclick_incognito.WaitUntilSatisfied());
+}
diff --git a/chrome/browser/extensions/extension_context_menu_model.cc b/chrome/browser/extensions/extension_context_menu_model.cc
index 16ef321..404241e 100644
--- a/chrome/browser/extensions/extension_context_menu_model.cc
+++ b/chrome/browser/extensions/extension_context_menu_model.cc
@@ -28,11 +28,11 @@ enum MenuEntries {
};
ExtensionContextMenuModel::ExtensionContextMenuModel(
- Extension* extension,
+ const Extension* extension,
Browser* browser,
PopupDelegate* delegate)
: ALLOW_THIS_IN_INITIALIZER_LIST(SimpleMenuModel(this)),
- extension_(extension),
+ extension_id_(extension->id()),
browser_(browser),
profile_(browser->profile()),
delegate_(delegate) {
@@ -53,7 +53,13 @@ ExtensionContextMenuModel::~ExtensionContextMenuModel() {
}
void ExtensionContextMenuModel::InitCommonCommands() {
- AddItem(NAME, UTF8ToUTF16(extension_->name()));
+ const Extension* extension = GetExtension();
+
+ // The extension pointer should only be null if the extension was uninstalled,
+ // and since the menu just opened, it should still be installed.
+ DCHECK(extension);
+
+ AddItem(NAME, UTF8ToUTF16(extension->name()));
AddSeparator();
AddItemWithStringId(CONFIGURE, IDS_EXTENSIONS_OPTIONS);
AddItemWithStringId(DISABLE, IDS_EXTENSIONS_DISABLE);
@@ -67,14 +73,16 @@ bool ExtensionContextMenuModel::IsCommandIdChecked(int command_id) const {
}
bool ExtensionContextMenuModel::IsCommandIdEnabled(int command_id) const {
+ const Extension* extension = this->GetExtension();
+ if (!extension)
+ return false;
+
if (command_id == CONFIGURE) {
- return extension_->options_url().spec().length() > 0;
+ return extension->options_url().spec().length() > 0;
} else if (command_id == NAME) {
- // The NAME links to the gallery page, which only makes sense if Google is
- // hosting the extension. For other 3rd party extensions we don't have a
- // homepage url, so we just disable this menu item on those cases, at least
- // for now.
- return extension_->GalleryUrl().is_valid();
+ // The NAME links to the Homepage URL. If the extension doesn't have a
+ // homepage, we just disable this menu item.
+ return extension->GetHomepageURL().is_valid();
} else if (command_id == INSPECT_POPUP) {
TabContents* contents = browser_->GetSelectedTabContents();
if (!contents)
@@ -91,26 +99,30 @@ bool ExtensionContextMenuModel::GetAcceleratorForCommandId(
}
void ExtensionContextMenuModel::ExecuteCommand(int command_id) {
+ const Extension* extension = GetExtension();
+ if (!extension)
+ return;
+
switch (command_id) {
case NAME: {
- browser_->OpenURL(extension_->GalleryUrl(), GURL(),
+ browser_->OpenURL(extension->GetHomepageURL(), GURL(),
NEW_FOREGROUND_TAB, PageTransition::LINK);
break;
}
case CONFIGURE:
- DCHECK(!extension_->options_url().is_empty());
- profile_->GetExtensionProcessManager()->OpenOptionsPage(extension_,
+ DCHECK(!extension->options_url().is_empty());
+ profile_->GetExtensionProcessManager()->OpenOptionsPage(extension,
browser_);
break;
case DISABLE: {
ExtensionsService* extension_service = profile_->GetExtensionsService();
- extension_service->DisableExtension(extension_->id());
+ extension_service->DisableExtension(extension_id_);
break;
}
case UNINSTALL: {
AddRef(); // Balanced in InstallUIProceed and InstallUIAbort.
install_ui_.reset(new ExtensionInstallUI(profile_));
- install_ui_->ConfirmUninstall(this, extension_);
+ install_ui_->ConfirmUninstall(this, extension);
break;
}
case MANAGE: {
@@ -129,8 +141,8 @@ void ExtensionContextMenuModel::ExecuteCommand(int command_id) {
}
void ExtensionContextMenuModel::InstallUIProceed() {
- std::string id = extension_->id();
- profile_->GetExtensionsService()->UninstallExtension(id, false);
+ if (GetExtension())
+ profile_->GetExtensionsService()->UninstallExtension(extension_id_, false);
Release();
}
@@ -138,3 +150,8 @@ void ExtensionContextMenuModel::InstallUIProceed() {
void ExtensionContextMenuModel::InstallUIAbort() {
Release();
}
+
+const Extension* ExtensionContextMenuModel::GetExtension() const {
+ ExtensionsService* extension_service = profile_->GetExtensionsService();
+ return extension_service->GetExtensionById(extension_id_, false);
+}
diff --git a/chrome/browser/extensions/extension_context_menu_model.h b/chrome/browser/extensions/extension_context_menu_model.h
index 35af19d..89cf3f9 100644
--- a/chrome/browser/extensions/extension_context_menu_model.h
+++ b/chrome/browser/extensions/extension_context_menu_model.h
@@ -37,7 +37,7 @@ class ExtensionContextMenuModel
// prefs::kExtensionsUIDeveloperMode is enabled then a menu item
// will be shown for "Inspect Popup" which, when selected, will cause
// ShowPopupForDevToolsWindow() to be called on |delegate|.
- ExtensionContextMenuModel(Extension* extension,
+ ExtensionContextMenuModel(const Extension* extension,
Browser* browser,
PopupDelegate* delegate);
virtual ~ExtensionContextMenuModel();
@@ -56,8 +56,12 @@ class ExtensionContextMenuModel
private:
void InitCommonCommands();
- // The extension we are displaying the menu for.
- Extension* extension_;
+ // Gets the extension we are displaying the menu for. Returns NULL if the
+ // extension has been uninstalled and no longer exists.
+ const Extension* GetExtension() const;
+
+ // A copy of the extension's id.
+ std::string extension_id_;
// The extension action we are displaying the menu for (or NULL).
ExtensionAction* extension_action_;
diff --git a/chrome/browser/extensions/extension_cookies_api.cc b/chrome/browser/extensions/extension_cookies_api.cc
index b97c74d..e66c4b3 100644
--- a/chrome/browser/extensions/extension_cookies_api.cc
+++ b/chrome/browser/extensions/extension_cookies_api.cc
@@ -409,7 +409,7 @@ bool RemoveCookieFunction::RunImpl() {
// should happen after this.
bool rv = BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- new RemoveCookieTask(url, name, store_context));
+ new RemoveCookieTask(url, name, make_scoped_refptr(store_context)));
DCHECK(rv);
return true;
diff --git a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
index 32b67af..3ad8813 100644
--- a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
+++ b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
@@ -51,7 +51,8 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest {
void CrashExtension(size_t index) {
ASSERT_LT(index, GetExtensionsService()->extensions()->size());
- Extension* extension = GetExtensionsService()->extensions()->at(index);
+ const Extension* extension =
+ GetExtensionsService()->extensions()->at(index);
ASSERT_TRUE(extension);
std::string extension_id(extension->id());
ExtensionHost* extension_host =
@@ -69,7 +70,8 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest {
void CheckExtensionConsistency(size_t index) {
ASSERT_LT(index, GetExtensionsService()->extensions()->size());
- Extension* extension = GetExtensionsService()->extensions()->at(index);
+ const Extension* extension =
+ GetExtensionsService()->extensions()->at(index);
ASSERT_TRUE(extension);
ExtensionHost* extension_host =
GetExtensionProcessManager()->GetBackgroundHostForExtension(extension);
@@ -85,7 +87,7 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest {
const size_t size_before = GetExtensionsService()->extensions()->size();
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("common").AppendASCII("background_page")));
- Extension* extension = GetExtensionsService()->extensions()->back();
+ const Extension* extension = GetExtensionsService()->extensions()->back();
ASSERT_TRUE(extension);
first_extension_id_ = extension->id();
CheckExtensionConsistency(size_before);
@@ -95,7 +97,8 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest {
int offset = GetExtensionsService()->extensions()->size();
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("install").AppendASCII("install")));
- Extension* extension = GetExtensionsService()->extensions()->at(offset);
+ const Extension* extension =
+ GetExtensionsService()->extensions()->at(offset);
ASSERT_TRUE(extension);
second_extension_id_ = extension->id();
CheckExtensionConsistency(offset);
diff --git a/chrome/browser/extensions/extension_creator.cc b/chrome/browser/extensions/extension_creator.cc
index 86c78fe..8bd68a2 100644
--- a/chrome/browser/extensions/extension_creator.cc
+++ b/chrome/browser/extensions/extension_creator.cc
@@ -56,7 +56,7 @@ bool ExtensionCreator::InitializeInput(
// Load the extension once. We don't really need it, but this does a lot of
// useful validation of the structure.
- scoped_ptr<Extension> extension(
+ scoped_refptr<Extension> extension(
extension_file_util::LoadExtension(extension_dir,
Extension::INTERNAL,
false, // key not required
diff --git a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc
index 6e51c47..af38e4f 100644
--- a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc
+++ b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc
@@ -26,7 +26,7 @@ class ExtensionDisabledDialogDelegate
public:
ExtensionDisabledDialogDelegate(Profile* profile,
ExtensionsService* service,
- Extension* extension)
+ const Extension* extension)
: service_(service), extension_(extension) {
AddRef(); // Balanced in Proceed or Abort.
@@ -55,7 +55,7 @@ class ExtensionDisabledDialogDelegate
scoped_ptr<ExtensionInstallUI> install_ui_;
ExtensionsService* service_;
- Extension* extension_;
+ const Extension* extension_;
};
class ExtensionDisabledInfobarDelegate
@@ -64,7 +64,7 @@ class ExtensionDisabledInfobarDelegate
public:
ExtensionDisabledInfobarDelegate(TabContents* tab_contents,
ExtensionsService* service,
- Extension* extension)
+ const Extension* extension)
: ConfirmInfoBarDelegate(tab_contents),
tab_contents_(tab_contents),
service_(service),
@@ -110,7 +110,7 @@ class ExtensionDisabledInfobarDelegate
switch (type.value) {
case NotificationType::EXTENSION_LOADED:
case NotificationType::EXTENSION_UNLOADED_DISABLED: {
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
if (extension == extension_)
tab_contents_->RemoveInfoBar(this);
break;
@@ -124,11 +124,11 @@ class ExtensionDisabledInfobarDelegate
NotificationRegistrar registrar_;
TabContents* tab_contents_;
ExtensionsService* service_;
- Extension* extension_;
+ const Extension* extension_;
};
void ShowExtensionDisabledUI(ExtensionsService* service, Profile* profile,
- Extension* extension) {
+ const Extension* extension) {
Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
if (!browser)
return;
@@ -142,7 +142,7 @@ void ShowExtensionDisabledUI(ExtensionsService* service, Profile* profile,
}
void ShowExtensionDisabledDialog(ExtensionsService* service, Profile* profile,
- Extension* extension) {
+ 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 16d3b6f..430e652 100644
--- a/chrome/browser/extensions/extension_disabled_infobar_delegate.h
+++ b/chrome/browser/extensions/extension_disabled_infobar_delegate.h
@@ -13,10 +13,10 @@ class Profile;
// Shows UI to inform the user that an extension was disabled after upgrading
// to higher permissions.
void ShowExtensionDisabledUI(ExtensionsService* service, Profile* profile,
- Extension* extension);
+ const Extension* extension);
// Shows the extension install dialog.
void ShowExtensionDisabledDialog(ExtensionsService* service, Profile* profile,
- Extension* extension);
+ 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 08f3b45..602ad6a 100644
--- a/chrome/browser/extensions/extension_dom_ui.cc
+++ b/chrome/browser/extensions/extension_dom_ui.cc
@@ -112,7 +112,7 @@ class ExtensionDOMUIImageLoadingTracker : public ImageLoadingTracker::Observer {
ImageLoadingTracker tracker_;
scoped_refptr<FaviconService::GetFaviconRequest> request_;
- Extension* extension_;
+ const Extension* extension_;
DISALLOW_COPY_AND_ASSIGN(ExtensionDOMUIImageLoadingTracker);
};
@@ -122,10 +122,11 @@ class ExtensionDOMUIImageLoadingTracker : public ImageLoadingTracker::Observer {
const char ExtensionDOMUI::kExtensionURLOverrides[] =
"extensions.chrome_url_overrides";
-ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents, GURL url)
- : DOMUI(tab_contents) {
+ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents, const GURL& url)
+ : DOMUI(tab_contents),
+ url_(url) {
ExtensionsService* service = tab_contents->profile()->GetExtensionsService();
- Extension* extension = service->GetExtensionByURL(url);
+ const Extension* extension = service->GetExtensionByURL(url);
if (!extension)
extension = service->GetExtensionByWebExtent(url);
DCHECK(extension);
@@ -150,12 +151,10 @@ ExtensionDOMUI::~ExtensionDOMUI() {}
void ExtensionDOMUI::ResetExtensionFunctionDispatcher(
RenderViewHost* render_view_host) {
- // Use the NavigationController to get the URL rather than the TabContents
- // since this is the real underlying URL (see HandleChromeURLOverride).
- NavigationController& controller = tab_contents()->controller();
- const GURL& url = controller.GetActiveEntry()->url();
+ // TODO(jcivelli): http://crbug.com/60608 we should get the URL out of the
+ // active entry of the navigation controller.
extension_function_dispatcher_.reset(
- ExtensionFunctionDispatcher::Create(render_view_host, this, url));
+ ExtensionFunctionDispatcher::Create(render_view_host, this, url_));
DCHECK(extension_function_dispatcher_.get());
}
@@ -195,10 +194,6 @@ TabContents* ExtensionDOMUI::associated_tab_contents() const {
return tab_contents();
}
-Profile* ExtensionDOMUI::GetProfile() {
- return DOMUI::GetProfile();
-}
-
ExtensionBookmarkManagerEventRouter*
ExtensionDOMUI::extension_bookmark_manager_event_router() {
return extension_bookmark_manager_event_router_.get();
@@ -272,7 +267,7 @@ bool ExtensionDOMUI::HandleChromeURLOverride(GURL* url, Profile* profile) {
}
// Verify that the extension that's being referred to actually exists.
- Extension* extension = service->GetExtensionByURL(extension_url);
+ const Extension* extension = service->GetExtensionByURL(extension_url);
if (!extension) {
// This can currently happen if you use --load-extension one run, and
// then don't use it the next. It could also happen if an extension
diff --git a/chrome/browser/extensions/extension_dom_ui.h b/chrome/browser/extensions/extension_dom_ui.h
index 22a106c..ea59b41 100644
--- a/chrome/browser/extensions/extension_dom_ui.h
+++ b/chrome/browser/extensions/extension_dom_ui.h
@@ -33,7 +33,7 @@ class ExtensionDOMUI
public:
static const char kExtensionURLOverrides[];
- explicit ExtensionDOMUI(TabContents* tab_contents, GURL url);
+ explicit ExtensionDOMUI(TabContents* tab_contents, const GURL& url);
virtual ~ExtensionDOMUI();
@@ -51,7 +51,6 @@ class ExtensionDOMUI
virtual gfx::NativeView GetNativeViewOfHost();
virtual gfx::NativeWindow GetCustomFrameNativeWindow();
virtual TabContents* associated_tab_contents() const;
- virtual Profile* GetProfile();
virtual ExtensionBookmarkManagerEventRouter*
extension_bookmark_manager_event_router();
@@ -99,6 +98,9 @@ class ExtensionDOMUI
// the other extension APIs?
scoped_ptr<ExtensionBookmarkManagerEventRouter>
extension_bookmark_manager_event_router_;
+
+ // The URL this DOMUI was created for.
+ GURL url_;
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_DOM_UI_H_
diff --git a/chrome/browser/extensions/extension_error_reporter.h b/chrome/browser/extensions/extension_error_reporter.h
index 2866211..8753c39 100644
--- a/chrome/browser/extensions/extension_error_reporter.h
+++ b/chrome/browser/extensions/extension_error_reporter.h
@@ -28,7 +28,7 @@ class ExtensionErrorReporter {
// Get the singleton instance.
static ExtensionErrorReporter* GetInstance();
- // Report an error. Errors always go to LOG(INFO). Optionally, they can also
+ // Report an error. Errors always go to VLOG(1). Optionally, they can also
// cause a noisy alert box. This method can be called from any thread.
void ReportError(const std::string& message, bool be_noisy);
diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc
index 9d22da7..4fc48e3 100644
--- a/chrome/browser/extensions/extension_event_router.cc
+++ b/chrome/browser/extensions/extension_event_router.cc
@@ -33,17 +33,6 @@ static void DispatchEvent(RenderProcessHost* renderer,
extension_id, kDispatchEvent, args, event_url));
}
-static bool CanCrossIncognito(Profile* profile,
- const std::string& extension_id) {
- // 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.
- Extension* extension =
- profile->GetExtensionsService()->GetExtensionById(extension_id, false);
- return (profile->GetExtensionsService()->IsIncognitoEnabled(extension) &&
- !extension->incognito_split_mode());
-}
-
} // namespace
struct ExtensionEventRouter::EventListener {
@@ -63,6 +52,24 @@ struct ExtensionEventRouter::EventListener {
}
};
+// static
+bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
+ const std::string& extension_id) {
+ const Extension* extension =
+ profile->GetExtensionsService()->GetExtensionById(extension_id, false);
+ return CanCrossIncognito(profile, extension);
+}
+
+// static
+bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
+ 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 (profile->GetExtensionsService()->IsIncognitoEnabled(extension) &&
+ !extension->incognito_split_mode());
+}
+
ExtensionEventRouter::ExtensionEventRouter(Profile* profile)
: profile_(profile),
extension_devtools_manager_(profile->GetExtensionDevToolsManager()) {
@@ -161,6 +168,7 @@ void ExtensionEventRouter::DispatchEventImpl(
return;
std::set<EventListener>& listeners = it->second;
+ ExtensionsService* service = profile_->GetExtensionsService();
// Send the event only to renderers that are listening for it.
for (std::set<EventListener>::iterator listener = listeners.begin();
@@ -178,7 +186,9 @@ void ExtensionEventRouter::DispatchEventImpl(
// incognito tab event sent to a normal process, or vice versa).
bool cross_incognito = restrict_to_profile &&
listener->process->profile() != restrict_to_profile;
- if (cross_incognito && !CanCrossIncognito(profile_, listener->extension_id))
+ const Extension* extension = service->GetExtensionById(
+ listener->extension_id, false);
+ if (cross_incognito && !service->CanCrossIncognito(extension))
continue;
DispatchEvent(listener->process, listener->extension_id,
diff --git a/chrome/browser/extensions/extension_event_router.h b/chrome/browser/extensions/extension_event_router.h
index 5e1ca97..c9f1f21 100644
--- a/chrome/browser/extensions/extension_event_router.h
+++ b/chrome/browser/extensions/extension_event_router.h
@@ -15,12 +15,19 @@
#include "chrome/common/notification_registrar.h"
class GURL;
+class Extension;
class ExtensionDevToolsManager;
class Profile;
class RenderProcessHost;
class ExtensionEventRouter : public NotificationObserver {
public:
+ // Returns true if the given extension can see events and data from another
+ // sub-profile (incognito to original profile, or vice versa).
+ static bool CanCrossIncognito(Profile* profile,
+ const std::string& extension_id);
+ static bool CanCrossIncognito(Profile* profile, const Extension* extension);
+
explicit ExtensionEventRouter(Profile* profile);
~ExtensionEventRouter();
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index f285e9d..88a6c9e 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -21,7 +21,7 @@ ExtensionFunction::ExtensionFunction()
ExtensionFunction::~ExtensionFunction() {
}
-Extension* ExtensionFunction::GetExtension() {
+const Extension* ExtensionFunction::GetExtension() {
ExtensionsService* service = profile_->GetExtensionsService();
DCHECK(service);
return service->GetExtensionById(extension_id_, false);
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index b48d0a9..57a8665 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -107,7 +107,7 @@ class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> {
// Gets the extension that called this function. This can return NULL for
// async functions, for example if the extension is unloaded while the
// function is running.
- Extension* GetExtension();
+ const Extension* GetExtension();
// Gets the "current" browser, if any.
//
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index e3ca590..beb96e8 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -274,6 +274,7 @@ void FactoryRegistry::ResetFunctions() {
// Management.
RegisterFunction<GetAllExtensionsFunction>();
+ RegisterFunction<GetExtensionByIdFunction>();
RegisterFunction<LaunchAppFunction>();
RegisterFunction<SetEnabledFunction>();
RegisterFunction<UninstallFunction>();
@@ -341,7 +342,7 @@ ExtensionFunctionDispatcher* ExtensionFunctionDispatcher::Create(
if (!service->ExtensionBindingsAllowed(url))
return NULL;
- Extension* extension = service->GetExtensionByURL(url);
+ const Extension* extension = service->GetExtensionByURL(url);
if (!extension)
extension = service->GetExtensionByWebExtent(url);
@@ -355,7 +356,7 @@ ExtensionFunctionDispatcher* ExtensionFunctionDispatcher::Create(
ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
RenderViewHost* render_view_host,
Delegate* delegate,
- Extension* extension,
+ const Extension* extension,
const GURL& url)
: profile_(render_view_host->process()->profile()),
render_view_host_(render_view_host),
@@ -448,10 +449,9 @@ void ExtensionFunctionDispatcher::HandleRequest(
function->set_user_gesture(params.user_gesture);
ExtensionsService* service = profile()->GetExtensionsService();
DCHECK(service);
- Extension* extension = service->GetExtensionById(extension_id(), false);
+ const Extension* extension = service->GetExtensionById(extension_id(), false);
DCHECK(extension);
- function->set_include_incognito(service->IsIncognitoEnabled(extension) &&
- !extension->incognito_split_mode());
+ function->set_include_incognito(service->CanCrossIncognito(extension));
if (!service->ExtensionBindingsAllowed(function->source_url()) ||
!extension->HasApiPermission(function->name())) {
diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h
index 99328f7..9969b1f 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.h
+++ b/chrome/browser/extensions/extension_function_dispatcher.h
@@ -125,7 +125,7 @@ class ExtensionFunctionDispatcher {
private:
ExtensionFunctionDispatcher(RenderViewHost* render_view_host,
Delegate* delegate,
- Extension* extension,
+ const Extension* extension,
const GURL& url);
// We need to keep a pointer to the profile because we use it in the dtor
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index b35d58c..09d30b7 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -34,6 +34,7 @@
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_preferences_util.h"
+#include "chrome/browser/tab_contents/popup_menu_helper_mac.h"
#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"
@@ -121,8 +122,10 @@ class ExtensionHost::ProcessCreationQueue {
////////////////
// ExtensionHost
-ExtensionHost::ExtensionHost(Extension* extension, SiteInstance* site_instance,
- const GURL& url, ViewType::Type host_type)
+ExtensionHost::ExtensionHost(const Extension* extension,
+ SiteInstance* site_instance,
+ const GURL& url,
+ ViewType::Type host_type)
: extension_(extension),
profile_(site_instance->browsing_instance()->profile()),
did_stop_loading_(false),
@@ -235,7 +238,8 @@ void ExtensionHost::NavigateToURL(const GURL& url) {
url_ = url;
- if (!is_background_page() && !extension_->GetBackgroundPageReady()) {
+ if (!is_background_page() &&
+ !profile_->GetExtensionsService()->IsBackgroundPageReady(extension_)) {
// Make sure the background page loads before any others.
registrar_.Add(this, NotificationType::EXTENSION_BACKGROUND_PAGE_READY,
Source<Extension>(extension_));
@@ -250,7 +254,8 @@ void ExtensionHost::Observe(NotificationType type,
const NotificationDetails& details) {
switch (type.value) {
case NotificationType::EXTENSION_BACKGROUND_PAGE_READY:
- DCHECK(extension_->GetBackgroundPageReady());
+ DCHECK(profile_->GetExtensionsService()->
+ IsBackgroundPageReady(extension_));
NavigateToURL(url_);
break;
case NotificationType::RENDERER_PROCESS_CREATED:
@@ -264,7 +269,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<Extension>(details).ptr())
+ if (extension_ == Details<const Extension>(details).ptr())
extension_ = NULL;
break;
default:
@@ -394,7 +399,7 @@ void ExtensionHost::DocumentAvailableInMainFrame(RenderViewHost* rvh) {
document_element_available_ = true;
if (is_background_page()) {
- extension_->SetBackgroundPageReady();
+ profile_->GetExtensionsService()->SetBackgroundPageReady(extension_);
} else {
switch (extension_host_type_) {
case ViewType::EXTENSION_INFOBAR:
@@ -564,33 +569,43 @@ void ExtensionHost::ShowCreatedWindow(int route_id,
contents,
initial_pos);
browser->window()->Show();
- } else {
- Browser* browser = BrowserList::FindBrowserWithType(
+ return;
+ }
+
+ // If the tab contents isn't a popup, it's a normal tab. We need to find a
+ // home for it. This is typically a Browser, but it can also be some other
+ // TabContentsDelegate in the case of ChromeFrame.
+
+ // First, if the creating extension view was associated with a tab contents,
+ // use that tab content's delegate. We must be careful here that the
+ // associated tab contents has the same profile as the new tab contents. In
+ // the case of extensions in 'spanning' incognito mode, they can mismatch.
+ // We don't want to end up putting a normal tab into an incognito window, or
+ // vice versa.
+ TabContents* associated_contents = associated_tab_contents();
+ if (associated_contents &&
+ associated_contents->profile() == contents->profile()) {
+ associated_contents->AddNewContents(contents, disposition, initial_pos,
+ user_gesture);
+ return;
+ }
+
+ // If there's no associated tab contents, or it doesn't have a matching
+ // profile, try finding an open window. Again, we must make sure to find a
+ // window with the correct profile.
+ Browser* browser = BrowserList::FindBrowserWithType(
contents->profile(),
Browser::TYPE_NORMAL,
false); // Match incognito exactly.
- if (!browser) {
- // If no browser is associated with the created TabContents, then the
- // created TabContents may be an intermediate struct used during topmost
- // url navigation from within an experimental extension popup view.
- //
- // If the ExtensionHost has an associated TabContents, then register the
- // new contents with this contents. This will allow top-level link
- // navigation within the new contents to function just as navigation
- // within the current host.
- TabContents* associated_contents = associated_tab_contents();
- if (associated_contents) {
- associated_contents->AddNewContents(contents, disposition, initial_pos,
- user_gesture);
- } else {
- browser = Browser::Create(contents->profile());
- browser->window()->Show();
- }
- }
- if (browser)
- browser->AddTabContents(contents, disposition, initial_pos, user_gesture);
+ // If there's no Browser open with the right profile, create a new one.
+ if (!browser) {
+ browser = Browser::Create(contents->profile());
+ browser->window()->Show();
}
+
+ if (browser)
+ browser->AddTabContents(contents, disposition, initial_pos, user_gesture);
}
void ExtensionHost::ShowCreatedWidget(int route_id,
@@ -621,6 +636,22 @@ void ExtensionHost::ShowContextMenu(const ContextMenuParams& params) {
// TODO(erikkay) Show a default context menu.
}
+void ExtensionHost::ShowPopupMenu(const gfx::Rect& bounds,
+ int item_height,
+ double item_font_size,
+ int selected_item,
+ const std::vector<WebMenuItem>& items,
+ bool right_aligned) {
+#if defined(OS_MACOSX)
+ PopupMenuHelper popup_menu_helper(render_view_host());
+ popup_menu_helper.ShowPopupMenu(bounds, item_height, item_font_size,
+ selected_item, items, right_aligned);
+#else
+ // Only on Mac are select popup menus external.
+ NOTREACHED();
+#endif
+}
+
void ExtensionHost::StartDragging(const WebDropData& drop_data,
WebDragOperationsMask operation_mask,
const SkBitmap& image,
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index 49b8191..bb96c5d 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -6,8 +6,9 @@
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_HOST_H_
#pragma once
-#include <string>
#include <list>
+#include <string>
+#include <vector>
#include "base/perftimer.h"
#include "base/scoped_ptr.h"
@@ -50,7 +51,7 @@ class ExtensionHost : public RenderViewHostDelegate,
typedef std::list<ExtensionHost*> HostPointerList;
static HostPointerList* recently_deleted();
- ExtensionHost(Extension* extension, SiteInstance* site_instance,
+ ExtensionHost(const Extension* extension, SiteInstance* site_instance,
const GURL& url, ViewType::Type host_type);
~ExtensionHost();
@@ -72,7 +73,7 @@ class ExtensionHost : public RenderViewHostDelegate,
// instantiate Browser objects.
void CreateView(Browser* browser);
- Extension* extension() { return extension_; }
+ const Extension* extension() { return extension_; }
RenderViewHost* render_view_host() const { return render_view_host_; }
RenderProcessHost* render_process_host() const;
SiteInstance* site_instance() const;
@@ -155,6 +156,12 @@ class ExtensionHost : public RenderViewHostDelegate,
const gfx::Rect& initial_pos);
virtual void ShowCreatedFullscreenWidget(int route_id);
virtual void ShowContextMenu(const ContextMenuParams& params);
+ virtual void ShowPopupMenu(const gfx::Rect& bounds,
+ int item_height,
+ double item_font_size,
+ int selected_item,
+ const std::vector<WebMenuItem>& items,
+ bool right_aligned);
virtual void StartDragging(const WebDropData& drop_data,
WebKit::WebDragOperationsMask allowed_operations,
const SkBitmap& image,
@@ -231,7 +238,7 @@ class ExtensionHost : public RenderViewHostDelegate,
bool is_background_page() const { return !view(); }
// The extension that we're hosting in this view.
- Extension* extension_;
+ const Extension* extension_;
// The profile that this host is tied to.
Profile* profile_;
diff --git a/chrome/browser/extensions/extension_host_mac.h b/chrome/browser/extensions/extension_host_mac.h
index 65aceaa..da46f16 100644
--- a/chrome/browser/extensions/extension_host_mac.h
+++ b/chrome/browser/extensions/extension_host_mac.h
@@ -12,7 +12,7 @@ class RenderWidgetHostView;
class ExtensionHostMac : public ExtensionHost {
public:
- ExtensionHostMac(Extension* extension, SiteInstance* site_instance,
+ ExtensionHostMac(const Extension* extension, SiteInstance* site_instance,
const GURL& url, ViewType::Type host_type) :
ExtensionHost(extension, site_instance, url, host_type) {}
virtual ~ExtensionHostMac();
diff --git a/chrome/browser/extensions/extension_host_mac.mm b/chrome/browser/extensions/extension_host_mac.mm
index 3239ebd..d6de067 100644
--- a/chrome/browser/extensions/extension_host_mac.mm
+++ b/chrome/browser/extensions/extension_host_mac.mm
@@ -31,9 +31,6 @@ RenderWidgetHostView* ExtensionHostMac::CreateNewWidgetInternal(
static_cast<RenderWidgetHostViewMac*>(widget_view);
[widget_view_mac->native_view() retain];
- // |widget_view_mac| needs to know how to position itself in our view.
- widget_view_mac->set_parent_view(view()->native_view());
-
return widget_view;
}
diff --git a/chrome/browser/extensions/extension_icon_manager.cc b/chrome/browser/extensions/extension_icon_manager.cc
index 53c8923..887dc3f 100644
--- a/chrome/browser/extensions/extension_icon_manager.cc
+++ b/chrome/browser/extensions/extension_icon_manager.cc
@@ -45,7 +45,7 @@ ExtensionIconManager::ExtensionIconManager()
ExtensionIconManager::~ExtensionIconManager() {
}
-void ExtensionIconManager::LoadIcon(Extension* extension) {
+void ExtensionIconManager::LoadIcon(const Extension* extension) {
ExtensionResource icon_resource = extension->GetIconResource(
Extension::EXTENSION_ICON_BITTY, ExtensionIconSet::MATCH_BIGGER);
if (!icon_resource.extension_root().empty()) {
diff --git a/chrome/browser/extensions/extension_icon_manager.h b/chrome/browser/extensions/extension_icon_manager.h
index 876f5e0..cc0deb9 100644
--- a/chrome/browser/extensions/extension_icon_manager.h
+++ b/chrome/browser/extensions/extension_icon_manager.h
@@ -23,7 +23,7 @@ class ExtensionIconManager : public ImageLoadingTracker::Observer {
virtual ~ExtensionIconManager();
// Start loading the icon for the given extension.
- void LoadIcon(Extension* extension);
+ void LoadIcon(const Extension* extension);
// This returns a bitmap of width/height kFavIconSize, loaded either from an
// entry specified in the extension's 'icon' section of the manifest, or a
diff --git a/chrome/browser/extensions/extension_icon_manager_unittest.cc b/chrome/browser/extensions/extension_icon_manager_unittest.cc
index 51c76ea..37f3453 100644
--- a/chrome/browser/extensions/extension_icon_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_icon_manager_unittest.cc
@@ -109,26 +109,26 @@ TEST_F(ExtensionIconManagerTest, LoadRemoveLoad) {
static_cast<DictionaryValue*>(serializer.Deserialize(NULL, NULL)));
ASSERT_TRUE(manifest.get() != NULL);
- Extension extension(manifest_path.DirName());
- ASSERT_TRUE(extension.InitFromValue(*manifest.get(),
- false /* require_key */,
- NULL /* errors */));
+ scoped_refptr<Extension> extension(Extension::Create(
+ manifest_path.DirName(), Extension::INVALID, *manifest.get(),
+ false, NULL));
+ ASSERT_TRUE(extension.get());
TestIconManager icon_manager(this);
// Load the icon and grab the bitmap.
- icon_manager.LoadIcon(&extension);
+ icon_manager.LoadIcon(extension.get());
WaitForImageLoad();
- SkBitmap first_icon = icon_manager.GetIcon(extension.id());
+ SkBitmap first_icon = icon_manager.GetIcon(extension->id());
EXPECT_FALSE(gfx::BitmapsAreEqual(first_icon, default_icon));
// Remove the icon from the manager.
- icon_manager.RemoveIcon(extension.id());
+ icon_manager.RemoveIcon(extension->id());
// Now re-load the icon - we should get the same result bitmap (and not the
// default icon).
- icon_manager.LoadIcon(&extension);
+ icon_manager.LoadIcon(extension.get());
WaitForImageLoad();
- SkBitmap second_icon = icon_manager.GetIcon(extension.id());
+ SkBitmap second_icon = icon_manager.GetIcon(extension->id());
EXPECT_FALSE(gfx::BitmapsAreEqual(second_icon, default_icon));
EXPECT_TRUE(gfx::BitmapsAreEqual(first_icon, second_icon));
diff --git a/chrome/browser/extensions/extension_info_map.cc b/chrome/browser/extensions/extension_info_map.cc
index f9f90aa..313e573 100644
--- a/chrome/browser/extensions/extension_info_map.cc
+++ b/chrome/browser/extensions/extension_info_map.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/extensions/extension_info_map.h"
#include "chrome/browser/browser_thread.h"
+#include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
namespace {
@@ -21,13 +22,13 @@ ExtensionInfoMap::ExtensionInfoMap() {
ExtensionInfoMap::~ExtensionInfoMap() {
}
-void ExtensionInfoMap::AddExtension(const Extension::StaticData* data) {
+void ExtensionInfoMap::AddExtension(const Extension* extension) {
CheckOnValidThread();
- extension_info_[data->id] = data;
+ extension_info_[extension->id()] = extension;
// Our map has already added a reference. Balance the reference given at the
// call-site.
- data->Release();
+ extension->Release();
}
void ExtensionInfoMap::RemoveExtension(const std::string& id) {
@@ -48,7 +49,7 @@ void ExtensionInfoMap::RemoveExtension(const std::string& id) {
std::string ExtensionInfoMap::GetNameForExtension(const std::string& id) const {
Map::const_iterator iter = extension_info_.find(id);
if (iter != extension_info_.end())
- return iter->second->name;
+ return iter->second->name();
else
return std::string();
}
@@ -56,21 +57,22 @@ std::string ExtensionInfoMap::GetNameForExtension(const std::string& id) const {
FilePath ExtensionInfoMap::GetPathForExtension(const std::string& id) const {
Map::const_iterator iter = extension_info_.find(id);
if (iter != extension_info_.end())
- return iter->second->path;
+ return iter->second->path();
else
return FilePath();
}
bool ExtensionInfoMap::ExtensionHasWebExtent(const std::string& id) const {
Map::const_iterator iter = extension_info_.find(id);
- return iter != extension_info_.end() && !iter->second->extent.is_empty();
+ return iter != extension_info_.end() &&
+ !iter->second->web_extent().is_empty();
}
bool ExtensionInfoMap::ExtensionCanLoadInIncognito(
const std::string& id) const {
Map::const_iterator iter = extension_info_.find(id);
// Only split-mode extensions can load in incognito profiles.
- return iter != extension_info_.end() && iter->second->incognito_split_mode;
+ return iter != extension_info_.end() && iter->second->incognito_split_mode();
}
std::string ExtensionInfoMap::GetDefaultLocaleForExtension(
@@ -78,7 +80,7 @@ std::string ExtensionInfoMap::GetDefaultLocaleForExtension(
Map::const_iterator iter = extension_info_.find(id);
std::string result;
if (iter != extension_info_.end())
- result = iter->second->default_locale;
+ result = iter->second->default_locale();
return result;
}
@@ -88,7 +90,7 @@ ExtensionExtent ExtensionInfoMap::GetEffectiveHostPermissionsForExtension(
Map::const_iterator iter = extension_info_.find(id);
ExtensionExtent result;
if (iter != extension_info_.end())
- result = iter->second->effective_host_permissions;
+ result = iter->second->GetEffectiveHostPermissions();
return result;
}
@@ -106,15 +108,14 @@ bool ExtensionInfoMap::CheckURLAccessToExtensionPermission(
// disallowed, so only one will match.
info = extension_info_.begin();
while (info != extension_info_.end() &&
- !info->second->extent.ContainsURL(url))
+ !info->second->web_extent().ContainsURL(url))
++info;
}
if (info == extension_info_.end())
return false;
- const std::set<std::string>& api_permissions = info->second->api_permissions;
- return api_permissions.count(permission_name) != 0;
+ return info->second->api_permissions().count(permission_name) != 0;
}
bool ExtensionInfoMap::URLIsForExtensionIcon(const GURL& url) const {
@@ -127,5 +128,5 @@ bool ExtensionInfoMap::URLIsForExtensionIcon(const GURL& url) const {
std::string path = url.path();
DCHECK(path.length() > 0 && path[0] == '/');
path = path.substr(1);
- return iter->second->icons.ContainsPath(path);
+ return iter->second->icons().ContainsPath(path);
}
diff --git a/chrome/browser/extensions/extension_info_map.h b/chrome/browser/extensions/extension_info_map.h
index fb03162..7d872ba 100644
--- a/chrome/browser/extensions/extension_info_map.h
+++ b/chrome/browser/extensions/extension_info_map.h
@@ -12,9 +12,11 @@
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/ref_counted.h"
-#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_extent.h"
#include "googleurl/src/gurl.h"
+class Extension;
+
// Contains extension data that needs to be accessed on the IO thread. It can
// be created/destroyed on any thread, but all other methods must be called on
// the IO thread.
@@ -27,7 +29,7 @@ class ExtensionInfoMap : public base::RefCountedThreadSafe<ExtensionInfoMap> {
~ExtensionInfoMap();
// Callback for when new extensions are loaded.
- void AddExtension(const Extension::StaticData* data);
+ void AddExtension(const Extension* extension);
// Callback for when an extension is unloaded.
void RemoveExtension(const std::string& id);
@@ -63,8 +65,7 @@ class ExtensionInfoMap : public base::RefCountedThreadSafe<ExtensionInfoMap> {
private:
// Map of extension info by extension id.
- typedef std::map<std::string, scoped_refptr<const Extension::StaticData> >
- Map;
+ typedef std::map<std::string, scoped_refptr<const Extension> > Map;
Map extension_info_;
};
diff --git a/chrome/browser/extensions/extension_info_map_unittest.cc b/chrome/browser/extensions/extension_info_map_unittest.cc
index 559febb..d4892d1 100644
--- a/chrome/browser/extensions/extension_info_map_unittest.cc
+++ b/chrome/browser/extensions/extension_info_map_unittest.cc
@@ -7,6 +7,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/extension_info_map.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension.h"
#include "chrome/common/json_value_serializer.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -28,27 +29,27 @@ class ExtensionInfoMapTest : public testing::Test {
};
// Returns a barebones test Extension object with the given name.
-static Extension* CreateExtension(const std::string& name) {
+static scoped_refptr<Extension> CreateExtension(const std::string& name) {
#if defined(OS_WIN)
FilePath path(FILE_PATH_LITERAL("c:\\foo"));
#elif defined(OS_POSIX)
FilePath path(FILE_PATH_LITERAL("/foo"));
#endif
- scoped_ptr<Extension> extension(new Extension(path.AppendASCII(name)));
-
DictionaryValue manifest;
manifest.SetString(keys::kVersion, "1.0.0.0");
manifest.SetString(keys::kName, name);
std::string error;
- EXPECT_TRUE(extension->InitFromValue(manifest, false, &error)) << error;
+ scoped_refptr<Extension> extension = Extension::Create(
+ path.AppendASCII(name), Extension::INVALID, manifest, false, &error);
+ EXPECT_TRUE(extension) << error;
- return extension.release();
+ return extension;
}
-static Extension* LoadManifest(const std::string& dir,
- const std::string& test_file) {
+static scoped_refptr<Extension> LoadManifest(const std::string& dir,
+ const std::string& test_file) {
FilePath path;
PathService::Get(chrome::DIR_TEST_DATA, &path);
path = path.AppendASCII("extensions")
@@ -61,61 +62,61 @@ static Extension* LoadManifest(const std::string& dir,
return NULL;
std::string error;
- scoped_ptr<Extension> extension(new Extension(path));
- EXPECT_TRUE(extension->InitFromValue(
- *static_cast<DictionaryValue*>(result.get()), false, &error)) << error;
+ scoped_refptr<Extension> extension = Extension::Create(
+ path, Extension::INVALID, *static_cast<DictionaryValue*>(result.get()),
+ false, &error);
+ EXPECT_TRUE(extension) << error;
- return extension.release();
+ return extension;
}
// Test that the ExtensionInfoMap handles refcounting properly.
TEST_F(ExtensionInfoMapTest, RefCounting) {
scoped_refptr<ExtensionInfoMap> info_map(new ExtensionInfoMap());
- // New extensions should have a single reference holding onto their static
- // data.
- scoped_ptr<Extension> extension1(CreateExtension("extension1"));
- scoped_ptr<Extension> extension2(CreateExtension("extension2"));
- scoped_ptr<Extension> extension3(CreateExtension("extension3"));
- EXPECT_TRUE(extension1->static_data()->HasOneRef());
- EXPECT_TRUE(extension2->static_data()->HasOneRef());
- EXPECT_TRUE(extension3->static_data()->HasOneRef());
+ // New extensions should have a single reference holding onto them.
+ scoped_refptr<Extension> extension1(CreateExtension("extension1"));
+ scoped_refptr<Extension> extension2(CreateExtension("extension2"));
+ scoped_refptr<Extension> extension3(CreateExtension("extension3"));
+ EXPECT_TRUE(extension1->HasOneRef());
+ EXPECT_TRUE(extension2->HasOneRef());
+ EXPECT_TRUE(extension3->HasOneRef());
// Add a ref to each extension and give it to the info map. The info map
// expects the caller to add a ref for it, but then assumes ownership of that
// reference.
- extension1->static_data()->AddRef();
- info_map->AddExtension(extension1->static_data());
- extension2->static_data()->AddRef();
- info_map->AddExtension(extension2->static_data());
- extension3->static_data()->AddRef();
- info_map->AddExtension(extension3->static_data());
-
- // Delete extension1, and the info map should have the only ref.
- const Extension::StaticData* data1 = extension1->static_data();
- extension1.reset();
- EXPECT_TRUE(data1->HasOneRef());
+ extension1->AddRef();
+ info_map->AddExtension(extension1);
+ extension2->AddRef();
+ info_map->AddExtension(extension2);
+ extension3->AddRef();
+ info_map->AddExtension(extension3);
+
+ // Release extension1, and the info map should have the only ref.
+ const Extension* weak_extension1 = extension1;
+ extension1 = NULL;
+ EXPECT_TRUE(weak_extension1->HasOneRef());
// Remove extension2, and the extension2 object should have the only ref.
info_map->RemoveExtension(extension2->id());
- EXPECT_TRUE(extension2->static_data()->HasOneRef());
+ EXPECT_TRUE(extension2->HasOneRef());
// Delete the info map, and the extension3 object should have the only ref.
info_map = NULL;
- EXPECT_TRUE(extension3->static_data()->HasOneRef());
+ EXPECT_TRUE(extension3->HasOneRef());
}
// Tests that we can query a few extension properties from the ExtensionInfoMap.
TEST_F(ExtensionInfoMapTest, Properties) {
scoped_refptr<ExtensionInfoMap> info_map(new ExtensionInfoMap());
- scoped_ptr<Extension> extension1(CreateExtension("extension1"));
- scoped_ptr<Extension> extension2(CreateExtension("extension2"));
+ scoped_refptr<Extension> extension1(CreateExtension("extension1"));
+ scoped_refptr<Extension> extension2(CreateExtension("extension2"));
- extension1->static_data()->AddRef();
- info_map->AddExtension(extension1->static_data());
- extension2->static_data()->AddRef();
- info_map->AddExtension(extension2->static_data());
+ extension1->AddRef();
+ info_map->AddExtension(extension1);
+ extension2->AddRef();
+ info_map->AddExtension(extension2);
EXPECT_EQ(extension1->name(),
info_map->GetNameForExtension(extension1->id()));
@@ -132,19 +133,19 @@ TEST_F(ExtensionInfoMapTest, Properties) {
TEST_F(ExtensionInfoMapTest, CheckPermissions) {
scoped_refptr<ExtensionInfoMap> info_map(new ExtensionInfoMap());
- scoped_ptr<Extension> app(LoadManifest("manifest_tests",
+ scoped_refptr<Extension> app(LoadManifest("manifest_tests",
"valid_app.json"));
- scoped_ptr<Extension> extension(LoadManifest("manifest_tests",
+ scoped_refptr<Extension> extension(LoadManifest("manifest_tests",
"tabs_extension.json"));
GURL app_url("http://www.google.com/mail/foo.html");
ASSERT_TRUE(app->is_app());
ASSERT_TRUE(app->web_extent().ContainsURL(app_url));
- app->static_data()->AddRef();
- info_map->AddExtension(app->static_data());
- extension->static_data()->AddRef();
- info_map->AddExtension(extension->static_data());
+ app->AddRef();
+ info_map->AddExtension(app);
+ extension->AddRef();
+ info_map->AddExtension(extension);
// The app should have the notifications permission, either from a
// chrome-extension URL or from its web extent.
diff --git a/chrome/browser/extensions/extension_infobar_apitest.cc b/chrome/browser/extensions/extension_infobar_apitest.cc
index a7afb17..5932185 100644
--- a/chrome/browser/extensions/extension_infobar_apitest.cc
+++ b/chrome/browser/extensions/extension_infobar_apitest.cc
@@ -6,10 +6,11 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"
-#if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
+#if defined(TOOLKIT_VIEWS)
#define MAYBE_Infobars Infobars
#else
// Need to finish port to Linux. See http://crbug.com/39916 for details.
+// Temporarily marked as DISABLED on OSX too. See http://crbug.com/60990 for details.
#define MAYBE_Infobars DISABLED_Infobars
#endif
diff --git a/chrome/browser/extensions/extension_infobar_delegate.cc b/chrome/browser/extensions/extension_infobar_delegate.cc
index b3b8a39..0aea7ce 100644
--- a/chrome/browser/extensions/extension_infobar_delegate.cc
+++ b/chrome/browser/extensions/extension_infobar_delegate.cc
@@ -15,7 +15,7 @@
ExtensionInfoBarDelegate::ExtensionInfoBarDelegate(Browser* browser,
TabContents* tab_contents,
- Extension* extension,
+ const Extension* extension,
const GURL& url)
: InfoBarDelegate(tab_contents),
observer_(NULL),
@@ -78,7 +78,7 @@ void ExtensionInfoBarDelegate::Observe(NotificationType type,
break;
}
case NotificationType::EXTENSION_UNLOADED: {
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
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 dae7aa9..949b655 100644
--- a/chrome/browser/extensions/extension_infobar_delegate.h
+++ b/chrome/browser/extensions/extension_infobar_delegate.h
@@ -28,10 +28,10 @@ class ExtensionInfoBarDelegate : public InfoBarDelegate,
};
ExtensionInfoBarDelegate(Browser* browser, TabContents* contents,
- Extension* extension, const GURL& url);
+ const Extension* extension, const GURL& url);
~ExtensionInfoBarDelegate();
- Extension* extension() { return extension_; }
+ const Extension* extension() { return extension_; }
ExtensionHost* extension_host() { return extension_host_.get(); }
void set_observer(DelegateObserver* observer) { observer_ = observer; }
@@ -60,7 +60,7 @@ class ExtensionInfoBarDelegate : public InfoBarDelegate,
// The observer monitoring when the delegate dies.
DelegateObserver* observer_;
- Extension* extension_;
+ const Extension* extension_;
TabContents* tab_contents_;
diff --git a/chrome/browser/extensions/extension_infobar_module.cc b/chrome/browser/extensions/extension_infobar_module.cc
index 590bfc1..6662bea 100644
--- a/chrome/browser/extensions/extension_infobar_module.cc
+++ b/chrome/browser/extensions/extension_infobar_module.cc
@@ -32,7 +32,7 @@ bool ShowInfoBarFunction::RunImpl() {
std::string html_path;
EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kHtmlPath, &html_path));
- Extension* extension = GetExtension();
+ const Extension* extension = GetExtension();
GURL url = extension->GetResourceURL(extension->url(), html_path);
Browser* browser = NULL;
diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc
index b1b2205..3c5f819 100644
--- a/chrome/browser/extensions/extension_install_ui.cc
+++ b/chrome/browser/extensions/extension_install_ui.cc
@@ -82,7 +82,7 @@ ExtensionInstallUI::~ExtensionInstallUI() {
}
void ExtensionInstallUI::ConfirmInstall(Delegate* delegate,
- Extension* extension) {
+ const Extension* extension) {
DCHECK(ui_loop_ == MessageLoop::current());
extension_ = extension;
delegate_ = delegate;
@@ -92,7 +92,7 @@ void ExtensionInstallUI::ConfirmInstall(Delegate* delegate,
// 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.
- Extension* previous_theme = profile_->GetTheme();
+ const Extension* previous_theme = profile_->GetTheme();
if (previous_theme)
previous_theme_id_ = previous_theme->id();
@@ -113,7 +113,7 @@ void ExtensionInstallUI::ConfirmInstall(Delegate* delegate,
}
void ExtensionInstallUI::ConfirmUninstall(Delegate* delegate,
- Extension* extension) {
+ const Extension* extension) {
DCHECK(ui_loop_ == MessageLoop::current());
extension_ = extension;
delegate_ = delegate;
@@ -121,7 +121,7 @@ void ExtensionInstallUI::ConfirmUninstall(Delegate* delegate,
ShowConfirmation(UNINSTALL_PROMPT);
}
-void ExtensionInstallUI::OnInstallSuccess(Extension* extension) {
+void ExtensionInstallUI::OnInstallSuccess(const Extension* extension) {
if (extension->is_theme()) {
ShowThemeInfoBar(previous_theme_id_, previous_use_system_theme_,
extension, profile_);
@@ -226,7 +226,7 @@ void ExtensionInstallUI::OnImageLoaded(
void ExtensionInstallUI::ShowThemeInfoBar(
const std::string& previous_theme_id, bool previous_use_system_theme,
- Extension* new_theme, Profile* profile) {
+ const Extension* new_theme, Profile* profile) {
if (!new_theme->is_theme())
return;
@@ -283,7 +283,7 @@ void ExtensionInstallUI::ShowConfirmation(PromptType prompt_type) {
#if defined(OS_MACOSX)
void ExtensionInstallUI::ShowGenericExtensionInstalledInfoBar(
- Extension* new_extension) {
+ const Extension* new_extension) {
Browser* browser = BrowserList::GetLastActiveWithProfile(profile_);
if (!browser)
return;
@@ -304,7 +304,7 @@ void ExtensionInstallUI::ShowGenericExtensionInstalledInfoBar(
#endif
InfoBarDelegate* ExtensionInstallUI::GetNewThemeInstalledInfoBarDelegate(
- TabContents* tab_contents, Extension* new_theme,
+ TabContents* tab_contents, const Extension* new_theme,
const std::string& previous_theme_id, bool previous_use_system_theme) {
#if defined(TOOLKIT_GTK)
return new GtkThemeInstalledInfoBarDelegate(tab_contents, new_theme,
diff --git a/chrome/browser/extensions/extension_install_ui.h b/chrome/browser/extensions/extension_install_ui.h
index 7ab2c02..6cc8876 100644
--- a/chrome/browser/extensions/extension_install_ui.h
+++ b/chrome/browser/extensions/extension_install_ui.h
@@ -58,17 +58,17 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer {
//
// We *MUST* eventually call either Proceed() or Abort()
// on |delegate|.
- virtual void ConfirmInstall(Delegate* delegate, Extension* extension);
+ virtual void ConfirmInstall(Delegate* delegate, const Extension* extension);
// This is called by the extensions management page to verify whether the
// uninstallation should proceed. This is declared virtual for testing.
//
// We *MUST* eventually call either Proceed() or Abort()
// on |delegate|.
- virtual void ConfirmUninstall(Delegate* delegate, Extension* extension);
+ virtual void ConfirmUninstall(Delegate* delegate, const Extension* extension);
// Installation was successful. This is declared virtual for testing.
- virtual void OnInstallSuccess(Extension* extension);
+ virtual void OnInstallSuccess(const Extension* extension);
// Installation failed. This is declared virtual for testing.
virtual void OnInstallFailure(const std::string& error);
@@ -85,7 +85,7 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer {
// GetNewThemeInstalledInfoBarDelegate()).
static void ShowThemeInfoBar(
const std::string& previous_theme_id, bool previous_use_system_theme,
- Extension* new_theme, Profile* profile);
+ const Extension* new_theme, Profile* profile);
private:
// Starts the process of showing a confirmation UI, which is split into two.
@@ -96,25 +96,25 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer {
#if defined(OS_MACOSX)
// When an extension is installed on Mac with neither browser action nor
// page action icons, show an infobar instead of a popup bubble.
- void ShowGenericExtensionInstalledInfoBar(Extension* new_extension);
+ void ShowGenericExtensionInstalledInfoBar(const Extension* new_extension);
#endif
// Returns the delegate to control the browser's info bar. This is
// within its own function due to its platform-specific nature.
static InfoBarDelegate* GetNewThemeInstalledInfoBarDelegate(
- TabContents* tab_contents, Extension* new_theme,
+ TabContents* tab_contents, const Extension* new_theme,
const std::string& previous_theme_id, bool previous_use_system_theme);
// Implements the showing of the install/uninstall dialog prompt.
// NOTE: The implementations of this function is platform-specific.
static void ShowExtensionInstallUIPromptImpl(
- Profile* profile, Delegate* delegate, Extension* extension,
+ Profile* profile, Delegate* delegate, const Extension* extension,
SkBitmap* icon, PromptType type);
// Implements the showing of the new install dialog. The implementations of
// this function are platform-specific.
static void ShowExtensionInstallUIPrompt2Impl(
- Profile* profile, Delegate* delegate, Extension* extension,
+ Profile* profile, Delegate* delegate, const Extension* extension,
SkBitmap* icon, const std::vector<string16>& permissions);
Profile* profile_;
@@ -125,7 +125,7 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer {
bool previous_use_system_theme_;
SkBitmap icon_; // The extensions installation icon.
- Extension* extension_; // The extension we are showing the UI for.
+ const Extension* extension_; // The extension we are showing the UI for.
Delegate* delegate_; // The delegate we will call Proceed/Abort on after
// confirmation UI.
PromptType prompt_type_; // The type of prompt we are going to show.
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc
index 14a6a5b..9a5a9f2 100644
--- a/chrome/browser/extensions/extension_install_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -39,7 +39,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionInstallUIBrowserTest,
// Install theme once and undo to verify we go back to default theme.
FilePath theme_path = test_data_dir_.AppendASCII("theme.crx");
ASSERT_TRUE(InstallExtensionWithUI(theme_path, 1));
- Extension* theme = browser()->profile()->GetTheme();
+ const Extension* theme = browser()->profile()->GetTheme();
ASSERT_TRUE(theme);
ASSERT_EQ(theme_crx, theme->id());
VerifyThemeInfoBarAndUndoInstall();
diff --git a/chrome/browser/extensions/extension_management_api.cc b/chrome/browser/extensions/extension_management_api.cc
index 50777db..44fd63f 100644
--- a/chrome/browser/extensions/extension_management_api.cc
+++ b/chrome/browser/extensions/extension_management_api.cc
@@ -104,10 +104,28 @@ bool GetAllExtensionsFunction::RunImpl() {
return true;
}
+bool GetExtensionByIdFunction::RunImpl() {
+ std::string extension_id;
+ EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id));
+ const Extension* extension = service()->GetExtensionById(extension_id, true);
+ if (!extension) {
+ error_ = ExtensionErrorUtils::FormatErrorMessage(kNoExtensionError,
+ extension_id);
+ return false;
+ }
+ bool enabled = service()->extension_prefs()->
+ GetExtensionState(extension_id) == Extension::ENABLED;
+
+ DictionaryValue* result = CreateExtensionInfo(*extension, enabled);
+ result_.reset(result);
+
+ return true;
+}
+
bool LaunchAppFunction::RunImpl() {
std::string extension_id;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id));
- Extension* extension = service()->GetExtensionById(extension_id, true);
+ const Extension* extension = service()->GetExtensionById(extension_id, true);
if (!extension) {
error_ = ExtensionErrorUtils::FormatErrorMessage(kNoExtensionError,
extension_id);
@@ -219,7 +237,7 @@ void ExtensionManagementEventRouter::Observe(
Details<UninstalledExtensionInfo>(details).ptr()->extension_id;
args.Append(Value::CreateStringValue(extension_id));
} else {
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
CHECK(extension);
ExtensionsService* service = profile->GetExtensionsService();
bool enabled = service->GetExtensionById(extension->id(), false) != NULL;
diff --git a/chrome/browser/extensions/extension_management_api.h b/chrome/browser/extensions/extension_management_api.h
index 3176aef..864741f 100644
--- a/chrome/browser/extensions/extension_management_api.h
+++ b/chrome/browser/extensions/extension_management_api.h
@@ -24,6 +24,12 @@ class GetAllExtensionsFunction : public ExtensionManagementFunction {
DECLARE_EXTENSION_FUNCTION_NAME("management.getAll");
};
+class GetExtensionByIdFunction : public ExtensionManagementFunction {
+ ~GetExtensionByIdFunction() {}
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("management.get");
+};
+
class LaunchAppFunction : public ExtensionManagementFunction {
~LaunchAppFunction() {}
virtual bool RunImpl();
diff --git a/chrome/browser/extensions/extension_management_browsertest.cc b/chrome/browser/extensions/extension_management_browsertest.cc
index e6b1f8f..7931e91 100644
--- a/chrome/browser/extensions/extension_management_browsertest.cc
+++ b/chrome/browser/extensions/extension_management_browsertest.cc
@@ -25,7 +25,7 @@ class ExtensionManagementTest : public ExtensionBrowserTest {
// in the extension's manifest. We use the version as reported by the
// background page to test how overinstalling crx files with the same
// manifest version works.
- bool IsExtensionAtVersion(Extension* extension,
+ bool IsExtensionAtVersion(const Extension* extension,
const std::string& expected_version) {
// Test that the extension's version from the manifest and reported by the
// background page is correct. This is to ensure that the processes are in
@@ -171,7 +171,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, DisableEnable) {
.AppendASCII("1.0")));
ASSERT_EQ(size_before + 1, service->extensions()->size());
EXPECT_EQ(0u, service->disabled_extensions()->size());
- Extension* extension = service->extensions()->at(size_before);
+ const Extension* extension = service->extensions()->at(size_before);
EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension));
ASSERT_TRUE(service->HasInstalledExtensions());
@@ -274,7 +274,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) {
// is race-prone, because instantating the ExtensionService starts a read
// of external_extensions.json before this test function starts.
service->AddPendingExtensionFromExternalUpdateUrl(
- kExtensionId, GURL("http://localhost/autoupdate/manifest"));
+ kExtensionId, GURL("http://localhost/autoupdate/manifest"),
+ Extension::EXTERNAL_PREF_DOWNLOAD);
// Run autoupdate and make sure version 2 of the extension was installed.
service->updater()->CheckNow();
diff --git a/chrome/browser/extensions/extension_menu_manager.cc b/chrome/browser/extensions/extension_menu_manager.cc
index 307c339..eae74f6 100644
--- a/chrome/browser/extensions/extension_menu_manager.cc
+++ b/chrome/browser/extensions/extension_menu_manager.cc
@@ -125,7 +125,7 @@ const ExtensionMenuItem::List* ExtensionMenuManager::MenuItems(
return NULL;
}
-bool ExtensionMenuManager::AddContextItem(Extension* extension,
+bool ExtensionMenuManager::AddContextItem(const Extension* extension,
ExtensionMenuItem* item) {
const std::string& extension_id = item->extension_id();
// The item must have a non-empty extension id, and not have already been
@@ -276,8 +276,10 @@ bool ExtensionMenuManager::RemoveContextMenuItem(
items_by_id_.erase(*removed_iter);
}
- if (list.empty())
+ if (list.empty()) {
+ context_items_.erase(extension_id);
icon_manager_.RemoveIcon(extension_id);
+ }
return result;
}
@@ -387,9 +389,9 @@ void ExtensionMenuManager::ExecuteCommand(
ListValue args;
DictionaryValue* properties = new DictionaryValue();
- properties->SetInteger("menuItemId", item->id().second);
+ properties->SetInteger("menuItemId", item->id().uid);
if (item->parent_id())
- properties->SetInteger("parentMenuItemId", item->parent_id()->second);
+ properties->SetInteger("parentMenuItemId", item->parent_id()->uid);
switch (params.media_type) {
case WebKit::WebContextMenuData::MediaTypeImage:
@@ -453,7 +455,7 @@ void ExtensionMenuManager::Observe(NotificationType type,
NOTREACHED();
return;
}
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
if (ContainsKey(context_items_, extension->id())) {
RemoveAllContextItems(extension->id());
}
@@ -469,3 +471,36 @@ bool ExtensionMenuManager::HasAllowedScheme(const GURL& url) {
URLPattern pattern(kAllowedSchemes);
return pattern.SetScheme(url.scheme());
}
+
+ExtensionMenuItem::Id::Id()
+ : profile(NULL), uid(0) {
+}
+
+ExtensionMenuItem::Id::Id(Profile* profile, std::string extension_id, int uid)
+ : profile(profile), extension_id(extension_id), uid(uid) {
+}
+
+ExtensionMenuItem::Id::~Id() {
+}
+
+bool ExtensionMenuItem::Id::operator==(const Id& other) const {
+ return (profile == other.profile &&
+ extension_id == other.extension_id &&
+ uid == other.uid);
+}
+
+bool ExtensionMenuItem::Id::operator!=(const Id& other) const {
+ return !(*this == other);
+}
+
+bool ExtensionMenuItem::Id::operator<(const Id& other) const {
+ if (profile < other.profile)
+ return true;
+ if (profile == other.profile) {
+ if (extension_id < other.extension_id)
+ return true;
+ if (extension_id == other.extension_id)
+ return uid < other.uid;
+ }
+ return false;
+}
diff --git a/chrome/browser/extensions/extension_menu_manager.h b/chrome/browser/extensions/extension_menu_manager.h
index a58c1df..c8224d1 100644
--- a/chrome/browser/extensions/extension_menu_manager.h
+++ b/chrome/browser/extensions/extension_menu_manager.h
@@ -33,9 +33,20 @@ class ExtensionMenuItem {
// A list of ExtensionMenuItem's.
typedef std::vector<ExtensionMenuItem*> List;
- // An Id is a pair of |extension id|, |int| where the |int| is unique per
- // extension.
- typedef std::pair<std::string, int> Id;
+ // An Id uniquely identifies a context menu item registered by an extension.
+ struct Id {
+ Id();
+ Id(Profile* profile, std::string extension_id, int uid);
+ ~Id();
+
+ bool operator==(const Id& other) const;
+ bool operator!=(const Id& other) const;
+ bool operator<(const Id& other) const;
+
+ Profile* profile;
+ std::string extension_id;
+ int uid;
+ };
// For context menus, these are the contexts where an item can appear.
enum Context {
@@ -93,7 +104,7 @@ class ExtensionMenuItem {
virtual ~ExtensionMenuItem();
// Simple accessor methods.
- const std::string& extension_id() const { return id_.first; }
+ const std::string& extension_id() const { return id_.extension_id; }
const std::string& title() const { return title_; }
const List& children() { return children_; }
const Id& id() const { return id_; }
@@ -198,7 +209,7 @@ class ExtensionMenuManager : public NotificationObserver {
// Adds a top-level menu item for an extension, requiring the |extension|
// pointer so it can load the icon for the extension. Takes ownership of
// |item|. Returns a boolean indicating success or failure.
- bool AddContextItem(Extension* extension, ExtensionMenuItem* item);
+ bool AddContextItem(const Extension* extension, ExtensionMenuItem* item);
// Add an item as a child of another item which has been previously added, and
// takes ownership of |item|. Returns a boolean indicating success or failure.
@@ -244,6 +255,7 @@ class ExtensionMenuManager : public NotificationObserver {
private:
FRIEND_TEST_ALL_PREFIXES(ExtensionMenuManagerTest, DeleteParent);
+ FRIEND_TEST_ALL_PREFIXES(ExtensionMenuManagerTest, RemoveOneByOne);
// This is a helper function which takes care of de-selecting any other radio
// items in the same group (i.e. that are adjacent in the list).
diff --git a/chrome/browser/extensions/extension_menu_manager_unittest.cc b/chrome/browser/extensions/extension_menu_manager_unittest.cc
index 0b653ba..cbd9a52 100644
--- a/chrome/browser/extensions/extension_menu_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_menu_manager_unittest.cc
@@ -37,21 +37,21 @@ class ExtensionMenuManagerTest : public testing::Test {
ExtensionMenuItem* CreateTestItem(Extension* extension) {
ExtensionMenuItem::Type type = ExtensionMenuItem::NORMAL;
ExtensionMenuItem::ContextList contexts(ExtensionMenuItem::ALL);
- ExtensionMenuItem::Id id(extension->id(), next_id_++);
+ ExtensionMenuItem::Id id(NULL, extension->id(), next_id_++);
return new ExtensionMenuItem(id, "test", false, type, contexts);
}
// Creates and returns a test Extension. The caller does *not* own the return
// value.
Extension* AddExtension(std::string name) {
- Extension* extension = prefs_.AddExtension(name);
+ scoped_refptr<Extension> extension = prefs_.AddExtension(name);
extensions_.push_back(extension);
return extension;
}
protected:
ExtensionMenuManager manager_;
- ScopedVector<Extension> extensions_;
+ ExtensionList extensions_;
TestExtensionPrefs prefs_;
int next_id_;
@@ -94,7 +94,7 @@ TEST_F(ExtensionMenuManagerTest, AddGetRemoveItems) {
ASSERT_EQ(2u, manager_.MenuItems(extension_id)->size());
// Make sure removing a non-existent item returns false.
- ExtensionMenuItem::Id id(extension->id(), id3.second + 50);
+ ExtensionMenuItem::Id id(NULL, extension->id(), id3.uid + 50);
ASSERT_FALSE(manager_.RemoveContextMenuItem(id));
}
@@ -211,7 +211,7 @@ TEST_F(ExtensionMenuManagerTest, DeleteParent) {
// Now remove item1 and make sure item2 and item3 are gone as well.
ASSERT_TRUE(manager_.RemoveContextMenuItem(item1_id));
- ASSERT_EQ(0u, manager_.MenuItems(extension->id())->size());
+ ASSERT_EQ(NULL, manager_.MenuItems(extension->id()));
ASSERT_EQ(0u, manager_.items_by_id_.size());
ASSERT_EQ(NULL, manager_.GetItemById(item1_id));
ASSERT_EQ(NULL, manager_.GetItemById(item2_id));
@@ -323,7 +323,7 @@ TEST_F(ExtensionMenuManagerTest, ExtensionUnloadRemovesMenuItems) {
// gone.
notifier->Notify(NotificationType::EXTENSION_UNLOADED,
Source<Profile>(NULL),
- Details<Extension>(extension1));
+ Details<const Extension>(extension1));
ASSERT_EQ(NULL, manager_.MenuItems(extension1->id()));
ASSERT_EQ(1u, manager_.MenuItems(extension2->id())->size());
ASSERT_TRUE(manager_.GetItemById(id1) == NULL);
@@ -389,6 +389,23 @@ TEST_F(ExtensionMenuManagerTest, RemoveAll) {
EXPECT_EQ(NULL, manager_.MenuItems(extension1->id()));
}
+// Tests that removing all items one-by-one doesn't leave an entry around.
+TEST_F(ExtensionMenuManagerTest, RemoveOneByOne) {
+ // Add 2 test items.
+ Extension* extension1 = AddExtension("1111");
+ ExtensionMenuItem* item1 = CreateTestItem(extension1);
+ ExtensionMenuItem* item2 = CreateTestItem(extension1);
+ ASSERT_TRUE(manager_.AddContextItem(extension1, item1));
+ ASSERT_TRUE(manager_.AddContextItem(extension1, item2));
+
+ ASSERT_FALSE(manager_.context_items_.empty());
+
+ manager_.RemoveContextMenuItem(item1->id());
+ manager_.RemoveContextMenuItem(item2->id());
+
+ ASSERT_TRUE(manager_.context_items_.empty());
+}
+
TEST_F(ExtensionMenuManagerTest, ExecuteCommand) {
MessageLoopForUI message_loop;
BrowserThread ui_thread(BrowserThread::UI, &message_loop);
@@ -444,7 +461,7 @@ TEST_F(ExtensionMenuManagerTest, ExecuteCommand) {
int tmp_id = 0;
ASSERT_TRUE(info->GetInteger("menuItemId", &tmp_id));
- ASSERT_EQ(id.second, tmp_id);
+ ASSERT_EQ(id.uid, tmp_id);
std::string tmp;
ASSERT_TRUE(info->GetString("mediaType", &tmp));
diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc
index a3a13c1..01faa1d 100644
--- a/chrome/browser/extensions/extension_message_service.cc
+++ b/chrome/browser/extensions/extension_message_service.cc
@@ -74,9 +74,11 @@ static void DispatchOnConnect(const ExtensionMessageService::MessagePort& port,
}
static void DispatchOnDisconnect(
- const ExtensionMessageService::MessagePort& port, int source_port_id) {
+ const ExtensionMessageService::MessagePort& port, int source_port_id,
+ bool connection_error) {
ListValue args;
args.Set(0, Value::CreateIntegerValue(source_port_id));
+ args.Set(1, Value::CreateBooleanValue(connection_error));
port.sender->Send(new ViewMsg_ExtensionMessageInvoke(port.routing_id,
"", ExtensionMessageService::kDispatchOnDisconnect, args, GURL()));
}
@@ -183,7 +185,7 @@ void ExtensionMessageService::OpenChannelToTab(
// The tab isn't loaded yet. Don't attempt to connect. Treat this as a
// disconnect.
DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL),
- GET_OPPOSITE_PORT_ID(receiver_port_id));
+ GET_OPPOSITE_PORT_ID(receiver_port_id), true);
return;
}
@@ -209,14 +211,13 @@ bool ExtensionMessageService::OpenChannelImpl(
const std::string& source_extension_id,
const std::string& target_extension_id,
const std::string& channel_name) {
- // TODO(mpcomplete): notify source if receiver doesn't exist
if (!source)
return false; // Closed while in flight.
if (!receiver.sender) {
// Treat it as a disconnect.
DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL),
- GET_OPPOSITE_PORT_ID(receiver_port_id));
+ GET_OPPOSITE_PORT_ID(receiver_port_id), true);
return false;
}
@@ -303,7 +304,7 @@ void ExtensionMessageService::CloseChannelImpl(
channel_iter->second->receiver : channel_iter->second->opener;
if (notify_other_port)
- DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id));
+ DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id), false);
delete channel_iter->second;
channels_.erase(channel_iter);
}
diff --git a/chrome/browser/extensions/extension_metrics_apitest.cc b/chrome/browser/extensions/extension_metrics_apitest.cc
index ee4761c..c9464d2 100644
--- a/chrome/browser/extensions/extension_metrics_apitest.cc
+++ b/chrome/browser/extensions/extension_metrics_apitest.cc
@@ -146,7 +146,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Metrics) {
UserActionObserver observer;
ASSERT_TRUE(RunExtensionTest("metrics")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension);
observer.ValidateUserActions(extension,
diff --git a/chrome/browser/extensions/extension_omnibox_api.cc b/chrome/browser/extensions/extension_omnibox_api.cc
index 3e4887d..93b44bd 100644
--- a/chrome/browser/extensions/extension_omnibox_api.cc
+++ b/chrome/browser/extensions/extension_omnibox_api.cc
@@ -160,7 +160,7 @@ ExtensionOmniboxSuggestion::ExtensionOmniboxSuggestion() {}
ExtensionOmniboxSuggestion::~ExtensionOmniboxSuggestion() {}
-ExtensionOmniboxSuggestions::ExtensionOmniboxSuggestions() {}
+ExtensionOmniboxSuggestions::ExtensionOmniboxSuggestions() : request_id(0) {}
ExtensionOmniboxSuggestions::~ExtensionOmniboxSuggestions() {}
diff --git a/chrome/browser/extensions/extension_omnibox_api.h b/chrome/browser/extensions/extension_omnibox_api.h
index 538ce85..9d0dc99 100644
--- a/chrome/browser/extensions/extension_omnibox_api.h
+++ b/chrome/browser/extensions/extension_omnibox_api.h
@@ -7,7 +7,7 @@
#pragma once
#include "base/string16.h"
-#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/extensions/extension_function.h"
// Event router class for events related to the omnibox API.
diff --git a/chrome/browser/extensions/extension_omnibox_apitest.cc b/chrome/browser/extensions/extension_omnibox_apitest.cc
index f48d9a1..9f9c6a0 100644
--- a/chrome/browser/extensions/extension_omnibox_apitest.cc
+++ b/chrome/browser/extensions/extension_omnibox_apitest.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
+#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
diff --git a/chrome/browser/extensions/extension_popup_apitest.cc b/chrome/browser/extensions/extension_popup_apitest.cc
index 1bc4aed..d4afd66 100644
--- a/chrome/browser/extensions/extension_popup_apitest.cc
+++ b/chrome/browser/extensions/extension_popup_apitest.cc
@@ -6,8 +6,7 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"
-// Times out. See http://crbug.com/46601.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_Popup) {
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Popup) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
diff --git a/chrome/browser/extensions/extension_pref_store.cc b/chrome/browser/extensions/extension_pref_store.cc
index 773e94e..27719ed 100644
--- a/chrome/browser/extensions/extension_pref_store.cc
+++ b/chrome/browser/extensions/extension_pref_store.cc
@@ -25,7 +25,7 @@ ExtensionPrefStore::~ExtensionPrefStore() {
notification_registrar_.RemoveAll();
}
-void ExtensionPrefStore::InstallExtensionPref(Extension* extension,
+void ExtensionPrefStore::InstallExtensionPref(const Extension* extension,
const char* new_pref_path,
Value* new_pref_value) {
ExtensionStack::iterator i;
@@ -62,7 +62,7 @@ void ExtensionPrefStore::InstallExtensionPref(Extension* extension,
UpdateOnePref(new_pref_path);
}
-void ExtensionPrefStore::UninstallExtension(Extension* extension) {
+void ExtensionPrefStore::UninstallExtension(const Extension* extension) {
// Remove this extension from the stack.
for (ExtensionStack::iterator i = extension_stack_.begin();
i != extension_stack_.end(); ++i) {
@@ -178,7 +178,7 @@ void ExtensionPrefStore::Observe(NotificationType type,
}
case NotificationType::EXTENSION_UNLOADED: {
Profile* extension_profile = Source<Profile>(source).ptr();
- Extension* extension = Details<Extension>(details).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);
@@ -190,7 +190,7 @@ void ExtensionPrefStore::Observe(NotificationType type,
}
}
-ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs(Extension* extension,
+ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs(const Extension* extension,
PrefValueMap* values) : extension(extension), pref_values(values) {}
ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() {
diff --git a/chrome/browser/extensions/extension_pref_store.h b/chrome/browser/extensions/extension_pref_store.h
index 926f29e..f176758 100644
--- a/chrome/browser/extensions/extension_pref_store.h
+++ b/chrome/browser/extensions/extension_pref_store.h
@@ -33,32 +33,35 @@ class Value;
class ExtensionPrefStore : public PrefStore,
public NotificationObserver {
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(Extension* extension,
+ virtual void InstallExtensionPref(const Extension* extension,
const char* pref_path,
Value* pref_value);
// 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(Extension* extension);
+ virtual void UninstallExtension(const Extension* extension);
// PrefStore methods:
- virtual DictionaryValue* prefs() { return prefs_.get(); }
+ virtual DictionaryValue* prefs() const { return prefs_.get(); }
virtual PrefReadError ReadPrefs() { return PREF_READ_ERROR_NONE; }
- // 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<Extension*, std::pair<const char*, Value*> >
- ExtensionPrefDetails;
-
protected:
// Returns a vector of the extension IDs in the extension_stack_.
// This should only be accessed by subclasses for unit-testing.
@@ -70,8 +73,18 @@ class ExtensionPrefStore : public PrefStore,
virtual PrefService* GetPrefService();
private:
- // Maps preference paths to their values.
- typedef std::map<const char*, Value*> PrefValueMap;
+ // 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;
// Applies the highest-priority extension's setting for the given preference
// path to the |prefs_| store, or clears the setting there if no extensions
@@ -93,18 +106,6 @@ class ExtensionPrefStore : public PrefStore,
// extension is controlling, for quick read access. Owns the stored values.
scoped_ptr<DictionaryValue> prefs_;
- // Associates an extension with the prefs it sets. Owns the pref values.
- struct ExtensionPrefs {
- ExtensionPrefs(Extension* extension, PrefValueMap* values);
- ~ExtensionPrefs();
-
- 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;
ExtensionStack extension_stack_;
NotificationRegistrar notification_registrar_;
diff --git a/chrome/browser/extensions/extension_pref_store_unittest.cc b/chrome/browser/extensions/extension_pref_store_unittest.cc
index aebe5e6..90bed62 100644
--- a/chrome/browser/extensions/extension_pref_store_unittest.cc
+++ b/chrome/browser/extensions/extension_pref_store_unittest.cc
@@ -17,6 +17,8 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace keys = extension_manifest_keys;
+
namespace {
class TestExtensionPrefStore : public ExtensionPrefStore {
@@ -32,20 +34,25 @@ class TestExtensionPrefStore : public ExtensionPrefStore {
ADD_FAILURE() << "Failed to create temp dir";
return;
}
- DictionaryValue empty_dict;
+ DictionaryValue simple_dict;
std::string error;
- ext1_scoped_.reset(new Extension(temp_dir_.path().AppendASCII("ext1")));
- ext2_scoped_.reset(new Extension(temp_dir_.path().AppendASCII("ext2")));
- ext3_scoped_.reset(new Extension(temp_dir_.path().AppendASCII("ext3")));
+ 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();
-
- EXPECT_FALSE(ext1->InitFromValue(empty_dict, false, &error));
- EXPECT_FALSE(ext2->InitFromValue(empty_dict, false, &error));
- EXPECT_FALSE(ext3->InitFromValue(empty_dict, false, &error));
}
typedef std::vector<std::string> ExtensionIDs;
@@ -70,9 +77,9 @@ class TestExtensionPrefStore : public ExtensionPrefStore {
private:
ScopedTempDir temp_dir_;
- scoped_ptr<Extension> ext1_scoped_;
- scoped_ptr<Extension> ext2_scoped_;
- scoped_ptr<Extension> ext3_scoped_;
+ scoped_refptr<Extension> ext1_scoped_;
+ scoped_refptr<Extension> ext2_scoped_;
+ scoped_refptr<Extension> ext3_scoped_;
// Weak reference.
PrefService* pref_service_;
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 5ebae6a..bf80550 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -320,7 +320,7 @@ bool ExtensionPrefs::DidExtensionEscalatePermissions(
}
void ExtensionPrefs::SetDidExtensionEscalatePermissions(
- Extension* extension, bool did_escalate) {
+ const Extension* extension, bool did_escalate) {
UpdateExtensionPref(extension->id(), kExtensionDidEscalatePermissions,
Value::CreateBooleanValue(did_escalate));
prefs_->ScheduleSavePersistentPrefs();
@@ -518,7 +518,7 @@ void ExtensionPrefs::SetToolbarOrder(
}
void ExtensionPrefs::OnExtensionInstalled(
- Extension* extension, Extension::State initial_state,
+ const Extension* extension, Extension::State initial_state,
bool initial_incognito_enabled) {
const std::string& id = extension->id();
UpdateExtensionPref(id, kPrefState,
@@ -575,7 +575,7 @@ Extension::State ExtensionPrefs::GetExtensionState(
return static_cast<Extension::State>(state);
}
-void ExtensionPrefs::SetExtensionState(Extension* extension,
+void ExtensionPrefs::SetExtensionState(const Extension* extension,
Extension::State state) {
UpdateExtensionPref(extension->id(), kPrefState,
Value::CreateIntegerValue(state));
@@ -596,7 +596,7 @@ std::string ExtensionPrefs::GetVersionString(const std::string& extension_id) {
return version;
}
-void ExtensionPrefs::UpdateManifest(Extension* extension) {
+void ExtensionPrefs::UpdateManifest(const Extension* extension) {
if (extension->location() != Extension::LOAD) {
UpdateExtensionPref(extension->id(), kPrefManifest,
extension->manifest_value()->DeepCopy());
@@ -903,5 +903,6 @@ void ExtensionPrefs::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterDictionaryPref(kExtensionsBlacklistUpdate);
prefs->RegisterListPref(prefs::kExtensionInstallAllowList);
prefs->RegisterListPref(prefs::kExtensionInstallDenyList);
+ prefs->RegisterListPref(prefs::kExtensionInstallForceList);
prefs->RegisterStringPref(kWebStoreLogin, std::string() /* default_value */);
}
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 97547ea..eb16329 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -63,7 +63,7 @@ class ExtensionPrefs {
void SetToolbarOrder(const std::vector<std::string>& extension_ids);
// Called when an extension is installed, so that prefs get created.
- void OnExtensionInstalled(Extension* extension,
+ void OnExtensionInstalled(const Extension* extension,
Extension::State initial_state,
bool initial_incognito_enabled);
@@ -76,14 +76,14 @@ class ExtensionPrefs {
Extension::State GetExtensionState(const std::string& extension_id);
// Called to change the extension's state when it is enabled/disabled.
- void SetExtensionState(Extension* extension, Extension::State);
+ void SetExtensionState(const Extension* extension, Extension::State);
// Did the extension ask to escalate its permission during an upgrade?
bool DidExtensionEscalatePermissions(const std::string& id);
// If |did_escalate| is true, the preferences for |extension| will be set to
// require the install warning when the user tries to enable.
- void SetDidExtensionEscalatePermissions(Extension* extension,
+ void SetDidExtensionEscalatePermissions(const Extension* extension,
bool did_escalate);
// Returns the version string for the currently installed extension, or
@@ -92,7 +92,7 @@ class ExtensionPrefs {
// Re-writes the extension manifest into the prefs.
// Called to change the extension's manifest when it's re-localized.
- void UpdateManifest(Extension* extension);
+ void UpdateManifest(const Extension* extension);
// Returns extension path based on extension ID, or empty FilePath on error.
FilePath GetExtensionPath(const std::string& extension_id);
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index 8275a99..c8d1967 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -114,7 +114,7 @@ TEST_F(ExtensionPrefsToolbarOrder, ToolbarOrder) {}
class ExtensionPrefsExtensionState : public ExtensionPrefsTest {
public:
virtual void Initialize() {
- extension.reset(prefs_.AddExtension("test"));
+ extension = prefs_.AddExtension("test");
prefs()->SetExtensionState(extension.get(), Extension::DISABLED);
}
@@ -123,7 +123,7 @@ class ExtensionPrefsExtensionState : public ExtensionPrefsTest {
}
private:
- scoped_ptr<Extension> extension;
+ scoped_refptr<Extension> extension;
};
TEST_F(ExtensionPrefsExtensionState, ExtensionState) {}
@@ -131,7 +131,7 @@ TEST_F(ExtensionPrefsExtensionState, ExtensionState) {}
class ExtensionPrefsEscalatePermissions : public ExtensionPrefsTest {
public:
virtual void Initialize() {
- extension.reset(prefs_.AddExtension("test"));
+ extension = prefs_.AddExtension("test");
prefs()->SetDidExtensionEscalatePermissions(extension.get(), true);
}
@@ -140,7 +140,7 @@ class ExtensionPrefsEscalatePermissions : public ExtensionPrefsTest {
}
private:
- scoped_ptr<Extension> extension;
+ scoped_refptr<Extension> extension;
};
TEST_F(ExtensionPrefsEscalatePermissions, EscalatePermissions) {}
@@ -149,7 +149,7 @@ TEST_F(ExtensionPrefsEscalatePermissions, EscalatePermissions) {}
class ExtensionPrefsVersionString : public ExtensionPrefsTest {
public:
virtual void Initialize() {
- extension.reset(prefs_.AddExtension("test"));
+ extension = prefs_.AddExtension("test");
EXPECT_EQ("0.1", prefs()->GetVersionString(extension->id()));
prefs()->OnExtensionUninstalled(extension->id(),
Extension::INTERNAL, false);
@@ -160,7 +160,7 @@ class ExtensionPrefsVersionString : public ExtensionPrefsTest {
}
private:
- scoped_ptr<Extension> extension;
+ scoped_refptr<Extension> extension;
};
TEST_F(ExtensionPrefsVersionString, VersionString) {}
@@ -173,11 +173,11 @@ class ExtensionPrefsBlacklist : public ExtensionPrefsTest {
// Install 5 extensions.
for (int i = 0; i < 5; i++) {
std::string name = "test" + base::IntToString(i);
- extensions_.push_back(linked_ptr<Extension>(prefs_.AddExtension(name)));
+ extensions_.push_back(prefs_.AddExtension(name));
}
EXPECT_EQ(NULL, prefs()->GetInstalledExtensionInfo(not_installed_id_));
- std::vector<linked_ptr<Extension> >::const_iterator iter;
+ ExtensionList::const_iterator iter;
for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
EXPECT_FALSE(prefs()->IsExtensionBlacklisted((*iter)->id()));
}
@@ -194,7 +194,7 @@ class ExtensionPrefsBlacklist : public ExtensionPrefsTest {
EXPECT_TRUE(prefs()->IsExtensionBlacklisted(not_installed_id_));
// Make sure the other id's are not blacklisted.
- std::vector<linked_ptr<Extension> >::const_iterator iter;
+ ExtensionList::const_iterator iter;
for (iter = extensions_.begin() + 1; iter != extensions_.end(); ++iter) {
EXPECT_FALSE(prefs()->IsExtensionBlacklisted((*iter)->id()));
}
@@ -212,7 +212,7 @@ class ExtensionPrefsBlacklist : public ExtensionPrefsTest {
}
private:
- std::vector<linked_ptr<Extension> > extensions_;
+ ExtensionList extensions_;
// An id we'll make up that doesn't match any installed extension id.
std::string not_installed_id_;
@@ -315,7 +315,7 @@ TEST_F(ExtensionPrefsIdleInstallInfo, IdleInstallInfo) {}
class ExtensionPrefsOnExtensionInstalled : public ExtensionPrefsTest {
public:
virtual void Initialize() {
- extension_.reset(prefs_.AddExtension("on_extension_installed"));
+ extension_ = prefs_.AddExtension("on_extension_installed");
EXPECT_EQ(Extension::ENABLED,
prefs()->GetExtensionState(extension_->id()));
EXPECT_FALSE(prefs()->IsIncognitoEnabled(extension_->id()));
@@ -330,7 +330,7 @@ class ExtensionPrefsOnExtensionInstalled : public ExtensionPrefsTest {
}
private:
- scoped_ptr<Extension> extension_;
+ scoped_refptr<Extension> extension_;
};
TEST_F(ExtensionPrefsOnExtensionInstalled,
ExtensionPrefsOnExtensionInstalled) {}
@@ -341,7 +341,7 @@ public:
// No extensions yet.
EXPECT_EQ(0, prefs()->GetNextAppLaunchIndex());
- extension_.reset(prefs_.AddExtension("on_extension_installed"));
+ extension_ = prefs_.AddExtension("on_extension_installed");
EXPECT_EQ(Extension::ENABLED,
prefs()->GetExtensionState(extension_->id()));
prefs()->OnExtensionInstalled(extension_.get(),
@@ -364,6 +364,6 @@ public:
}
private:
- scoped_ptr<Extension> extension_;
+ scoped_refptr<Extension> extension_;
};
TEST_F(ExtensionPrefsAppLaunchIndex, ExtensionPrefsAppLaunchIndex) {}
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index 5a28617..c4e0799 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -32,11 +32,12 @@ class IncognitoExtensionProcessManager : public ExtensionProcessManager {
public:
explicit IncognitoExtensionProcessManager(Profile* profile);
virtual ~IncognitoExtensionProcessManager() {}
- virtual ExtensionHost* CreateView(Extension* extension,
+ virtual ExtensionHost* CreateView(const Extension* extension,
const GURL& url,
Browser* browser,
ViewType::Type view_type);
- virtual void CreateBackgroundHost(Extension* extension, const GURL& url);
+ virtual void CreateBackgroundHost(const Extension* extension,
+ const GURL& url);
virtual SiteInstance* GetSiteInstanceForURL(const GURL& url);
virtual RenderProcessHost* GetExtensionProcess(const GURL& url);
@@ -48,7 +49,7 @@ class IncognitoExtensionProcessManager : public ExtensionProcessManager {
// Returns the extension for an URL, which can either be a chrome-extension
// URL or a web app URL.
- Extension* GetExtensionOrAppByURL(const GURL& url);
+ const Extension* GetExtensionOrAppByURL(const GURL& url);
// Returns true if the extension is allowed to run in incognito mode.
bool IsIncognitoEnabled(const Extension* extension);
@@ -57,7 +58,7 @@ class IncognitoExtensionProcessManager : public ExtensionProcessManager {
};
static void CreateBackgroundHost(
- ExtensionProcessManager* manager, Extension* extension) {
+ ExtensionProcessManager* manager, const Extension* extension) {
// Start the process for the master page, if it exists.
if (extension->background_url().is_valid())
manager->CreateBackgroundHost(extension, extension->background_url());
@@ -105,12 +106,12 @@ ExtensionProcessManager::ExtensionProcessManager(Profile* profile)
}
ExtensionProcessManager::~ExtensionProcessManager() {
- LOG_IF(INFO, g_log_bug53991) << "~ExtensionProcessManager: " << this;
+ VLOG_IF(1, g_log_bug53991) << "~ExtensionProcessManager: " << this;
CloseBackgroundHosts();
DCHECK(background_hosts_.empty());
}
-ExtensionHost* ExtensionProcessManager::CreateView(Extension* extension,
+ExtensionHost* ExtensionProcessManager::CreateView(const Extension* extension,
const GURL& url,
Browser* browser,
ViewType::Type view_type) {
@@ -137,14 +138,14 @@ ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url,
ExtensionsService* service =
browsing_instance_->profile()->GetExtensionsService();
if (service) {
- Extension* extension = service->GetExtensionByURL(url);
+ const Extension* extension = service->GetExtensionByURL(url);
if (extension)
return CreateView(extension, url, browser, view_type);
}
return NULL;
}
-ExtensionHost* ExtensionProcessManager::CreatePopup(Extension* extension,
+ExtensionHost* ExtensionProcessManager::CreatePopup(const Extension* extension,
const GURL& url,
Browser* browser) {
return CreateView(extension, url, browser, ViewType::EXTENSION_POPUP);
@@ -155,9 +156,8 @@ ExtensionHost* ExtensionProcessManager::CreatePopup(const GURL& url,
return CreateView(url, browser, ViewType::EXTENSION_POPUP);
}
-ExtensionHost* ExtensionProcessManager::CreateInfobar(Extension* extension,
- const GURL& url,
- Browser* browser) {
+ExtensionHost* ExtensionProcessManager::CreateInfobar(
+ const Extension* extension, const GURL& url, Browser* browser) {
return CreateView(extension, url, browser, ViewType::EXTENSION_INFOBAR);
}
@@ -167,7 +167,7 @@ ExtensionHost* ExtensionProcessManager::CreateInfobar(const GURL& url,
}
void ExtensionProcessManager::CreateBackgroundHost(
- Extension* extension, const GURL& url) {
+ const Extension* extension, const GURL& url) {
// Don't create multiple background hosts for an extension.
if (GetBackgroundHostForExtension(extension))
return;
@@ -185,7 +185,7 @@ void ExtensionProcessManager::CreateBackgroundHost(
OnExtensionHostCreated(host, true);
}
-void ExtensionProcessManager::OpenOptionsPage(Extension* extension,
+void ExtensionProcessManager::OpenOptionsPage(const Extension* extension,
Browser* browser) {
DCHECK(!extension->options_url().is_empty());
@@ -203,7 +203,7 @@ void ExtensionProcessManager::OpenOptionsPage(Extension* extension,
}
ExtensionHost* ExtensionProcessManager::GetBackgroundHostForExtension(
- Extension* extension) {
+ const Extension* extension) {
for (ExtensionHostSet::iterator iter = background_hosts_.begin();
iter != background_hosts_.end(); ++iter) {
ExtensionHost* host = *iter;
@@ -230,7 +230,7 @@ void ExtensionProcessManager::RegisterExtensionProcess(
browsing_instance_->profile()->GetExtensionsService();
std::vector<std::string> page_action_ids;
- Extension* extension =
+ const Extension* extension =
extension_service->GetExtensionById(extension_id, false);
if (extension->page_action())
page_action_ids.push_back(extension->page_action()->id());
@@ -254,8 +254,8 @@ RenderProcessHost* ExtensionProcessManager::GetExtensionProcess(
const GURL& url) {
if (!browsing_instance_->HasSiteInstance(url))
return NULL;
- scoped_refptr<SiteInstance> site =
- browsing_instance_->GetSiteInstanceForURL(url);
+ scoped_refptr<SiteInstance> site(
+ browsing_instance_->GetSiteInstanceForURL(url));
if (site->HasProcess())
return site->GetProcess();
return NULL;
@@ -288,14 +288,14 @@ void ExtensionProcessManager::Observe(NotificationType type,
ExtensionsService* service =
Source<Profile>(source).ptr()->GetExtensionsService();
if (service->is_ready()) {
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
::CreateBackgroundHost(this, extension);
}
break;
}
case NotificationType::EXTENSION_UNLOADED: {
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
for (ExtensionHostSet::iterator iter = background_hosts_.begin();
iter != background_hosts_.end(); ++iter) {
ExtensionHost* host = *iter;
@@ -350,7 +350,7 @@ void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host,
}
void ExtensionProcessManager::CloseBackgroundHosts() {
- LOG_IF(INFO, g_log_bug53991) << "CloseBackgroundHosts: " << this;
+ VLOG_IF(1, g_log_bug53991) << "CloseBackgroundHosts: " << this;
for (ExtensionHostSet::iterator iter = background_hosts_.begin();
iter != background_hosts_.end(); ) {
ExtensionHostSet::iterator current = iter++;
@@ -374,7 +374,7 @@ IncognitoExtensionProcessManager::IncognitoExtensionProcessManager(
}
ExtensionHost* IncognitoExtensionProcessManager::CreateView(
- Extension* extension,
+ const Extension* extension,
const GURL& url,
Browser* browser,
ViewType::Type view_type) {
@@ -394,7 +394,7 @@ ExtensionHost* IncognitoExtensionProcessManager::CreateView(
}
void IncognitoExtensionProcessManager::CreateBackgroundHost(
- Extension* extension, const GURL& url) {
+ const Extension* extension, const GURL& url) {
if (extension->incognito_split_mode()) {
if (IsIncognitoEnabled(extension))
ExtensionProcessManager::CreateBackgroundHost(extension, url);
@@ -406,7 +406,7 @@ void IncognitoExtensionProcessManager::CreateBackgroundHost(
SiteInstance* IncognitoExtensionProcessManager::GetSiteInstanceForURL(
const GURL& url) {
- Extension* extension = GetExtensionOrAppByURL(url);
+ const Extension* extension = GetExtensionOrAppByURL(url);
if (!extension || extension->incognito_split_mode()) {
return ExtensionProcessManager::GetSiteInstanceForURL(url);
} else {
@@ -416,7 +416,7 @@ SiteInstance* IncognitoExtensionProcessManager::GetSiteInstanceForURL(
RenderProcessHost* IncognitoExtensionProcessManager::GetExtensionProcess(
const GURL& url) {
- Extension* extension = GetExtensionOrAppByURL(url);
+ const Extension* extension = GetExtensionOrAppByURL(url);
if (!extension || extension->incognito_split_mode()) {
return ExtensionProcessManager::GetExtensionProcess(url);
} else {
@@ -424,7 +424,7 @@ RenderProcessHost* IncognitoExtensionProcessManager::GetExtensionProcess(
}
}
-Extension* IncognitoExtensionProcessManager::GetExtensionOrAppByURL(
+const Extension* IncognitoExtensionProcessManager::GetExtensionOrAppByURL(
const GURL& url) {
ExtensionsService* service =
browsing_instance_->profile()->GetExtensionsService();
diff --git a/chrome/browser/extensions/extension_process_manager.h b/chrome/browser/extensions/extension_process_manager.h
index d284275..2d812ef 100644
--- a/chrome/browser/extensions/extension_process_manager.h
+++ b/chrome/browser/extensions/extension_process_manager.h
@@ -35,33 +35,34 @@ class ExtensionProcessManager : public NotificationObserver {
// Creates a new ExtensionHost with its associated view, grouping it in the
// appropriate SiteInstance (and therefore process) based on the URL and
// profile.
- virtual ExtensionHost* CreateView(Extension* extension,
+ virtual ExtensionHost* CreateView(const Extension* extension,
const GURL& url,
Browser* browser,
ViewType::Type view_type);
ExtensionHost* CreateView(const GURL& url,
Browser* browser,
ViewType::Type view_type);
- ExtensionHost* CreatePopup(Extension* extension,
+ ExtensionHost* CreatePopup(const Extension* extension,
const GURL& url,
Browser* browser);
ExtensionHost* CreatePopup(const GURL& url, Browser* browser);
- ExtensionHost* CreateInfobar(Extension* extension,
+ ExtensionHost* CreateInfobar(const Extension* extension,
const GURL& url,
Browser* browser);
ExtensionHost* CreateInfobar(const GURL& url,
Browser* browser);
// Open the extension's options page.
- void OpenOptionsPage(Extension* extension, Browser* browser);
+ void OpenOptionsPage(const Extension* extension, Browser* browser);
// Creates a new UI-less extension instance. Like CreateView, but not
// displayed anywhere.
- virtual void CreateBackgroundHost(Extension* extension, const GURL& url);
+ virtual void CreateBackgroundHost(const Extension* extension,
+ const GURL& url);
// Gets the ExtensionHost for the background page for an extension, or NULL if
// the extension isn't running or doesn't have a background page.
- ExtensionHost* GetBackgroundHostForExtension(Extension* extension);
+ ExtensionHost* GetBackgroundHostForExtension(const Extension* extension);
// Returns the SiteInstance that the given URL belongs to.
virtual SiteInstance* GetSiteInstanceForURL(const GURL& url);
diff --git a/chrome/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc
index ce56589..90d198c 100644
--- a/chrome/browser/extensions/extension_protocols.cc
+++ b/chrome/browser/extensions/extension_protocols.cc
@@ -84,7 +84,8 @@ bool AllowExtensionResourceLoad(URLRequest* request,
// chrome:// URLs are always allowed to load chrome-extension:// resources.
// The app launcher in the NTP uses this feature, as does dev tools.
- if (origin_url.SchemeIs(chrome::kChromeUIScheme))
+ if (origin_url.SchemeIs(chrome::kChromeDevToolsScheme) ||
+ origin_url.SchemeIs(chrome::kChromeUIScheme))
return true;
// Disallow loading of packaged resources for hosted apps. We don't allow
diff --git a/chrome/browser/extensions/extension_proxy_apitest.cc b/chrome/browser/extensions/extension_proxy_apitest.cc
index 9c127ad..a22baf8 100644
--- a/chrome/browser/extensions/extension_proxy_apitest.cc
+++ b/chrome/browser/extensions/extension_proxy_apitest.cc
@@ -16,7 +16,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyAutoSettings) {
switches::kEnableExperimentalExtensionApis);
ASSERT_TRUE(RunExtensionTest("proxy/auto")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension);
PrefService* pref_service = browser()->profile()->GetPrefs();
@@ -46,7 +46,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyManualSingle) {
switches::kEnableExperimentalExtensionApis);
ASSERT_TRUE(RunExtensionTest("proxy/single")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension);
PrefService* pref_service = browser()->profile()->GetPrefs();
@@ -81,7 +81,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyManualIndividual) {
switches::kEnableExperimentalExtensionApis);
ASSERT_TRUE(RunExtensionTest("proxy/individual")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension);
PrefService* pref_service = browser()->profile()->GetPrefs();
diff --git a/chrome/browser/extensions/extension_rlz_module.cc b/chrome/browser/extensions/extension_rlz_module.cc
index e31fc69..4f76bcc 100644
--- a/chrome/browser/extensions/extension_rlz_module.cc
+++ b/chrome/browser/extensions/extension_rlz_module.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/extensions/extension_rlz_module.h"
#include "base/scoped_ptr.h"
+#include "base/thread_restrictions.h"
#include "base/values.h"
#include "chrome/common/extensions/extension.h"
#include "rlz/win/lib/lib_values.h"
@@ -70,6 +71,11 @@ bool GetEventFromName(const std::string& event_name,
} // namespace
bool RlzRecordProductEventFunction::RunImpl() {
+ // This can be slow if registry access goes to disk. Should preferably
+ // perform registry operations on the File thread.
+ // http://code.google.com/p/chromium/issues/detail?id=62098
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
std::string product_name;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &product_name));
rlz_lib::Product product;
@@ -90,6 +96,11 @@ bool RlzRecordProductEventFunction::RunImpl() {
}
bool RlzGetAccessPointRlzFunction::RunImpl() {
+ // This can be slow if registry access goes to disk. Should preferably
+ // perform registry operations on the File thread.
+ // http://code.google.com/p/chromium/issues/detail?id=62098
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
std::string ap_name;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &ap_name));
rlz_lib::AccessPoint access_point;
@@ -103,6 +114,11 @@ bool RlzGetAccessPointRlzFunction::RunImpl() {
}
bool RlzSendFinancialPingFunction::RunImpl() {
+ // This can be slow if registry access goes to disk. Should preferably
+ // perform registry operations on the File thread.
+ // http://code.google.com/p/chromium/issues/detail?id=62098
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
std::string product_name;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &product_name));
rlz_lib::Product product;
@@ -159,6 +175,11 @@ bool RlzSendFinancialPingFunction::RunImpl() {
}
bool RlzClearProductStateFunction::RunImpl() {
+ // This can be slow if registry access goes to disk. Should preferably
+ // perform registry operations on the File thread.
+ // http://code.google.com/p/chromium/issues/detail?id=62098
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
std::string product_name;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &product_name));
rlz_lib::Product product;
diff --git a/chrome/browser/extensions/extension_sidebar_api.cc b/chrome/browser/extensions/extension_sidebar_api.cc
index 8b6913e..7dbb6fd 100644
--- a/chrome/browser/extensions/extension_sidebar_api.cc
+++ b/chrome/browser/extensions/extension_sidebar_api.cc
@@ -51,7 +51,7 @@ const char kShownState[] = "shown";
}
static GURL ResolvePossiblyRelativeURL(const std::string& url_string,
- Extension* extension) {
+ const Extension* extension) {
GURL url = GURL(url_string);
if (!url.is_valid())
url = extension->GetResourceURL(url_string);
@@ -59,7 +59,7 @@ static GURL ResolvePossiblyRelativeURL(const std::string& url_string,
return url;
}
-static bool CanUseHost(Extension* extension,
+static bool CanUseHost(const Extension* extension,
const GURL& url,
std::string* error) {
if (extension->HasHostPermission(url))
diff --git a/chrome/browser/extensions/extension_tabs_apitest.cc b/chrome/browser/extensions/extension_tabs_apitest.cc
index df108f3..b9aba66 100644
--- a/chrome/browser/extensions/extension_tabs_apitest.cc
+++ b/chrome/browser/extensions/extension_tabs_apitest.cc
@@ -9,21 +9,20 @@
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
-#if defined(OS_WIN)
-// This test times out on win.
-// http://crbug.com/58269
-#define MAYBE_Tabs FAILS_Tabs
-#else
-#define MAYBE_Tabs Tabs
-#endif
-
// Possible race in ChromeURLDataManager. http://crbug.com/59198
#if defined(OS_MACOSX) || defined(OS_LINUX)
-#define MAYBE_TabOnRemoved FLAKY_TabOnRemoved
+#define MAYBE_TabOnRemoved DISABLED_TabOnRemoved
#else
#define MAYBE_TabOnRemoved TabOnRemoved
#endif
+// Crashes on linux views. http://crbug.com/61592
+#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
+#define MAYBE_Tabs DISABLED_Tabs
+#else
+#define MAYBE_Tabs Tabs
+#endif
+
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Tabs) {
ASSERT_TRUE(test_server()->Start());
@@ -33,7 +32,28 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Tabs) {
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kHomePageIsNewTabPage, true);
- ASSERT_TRUE(RunExtensionTest("tabs/basics")) << message_;
+ ASSERT_TRUE(RunExtensionSubtest("tabs/basics", "crud.html")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabPinned) {
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(RunExtensionSubtest("tabs/basics", "pinned.html")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabMove) {
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(RunExtensionSubtest("tabs/basics", "move.html")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabEvents) {
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(RunExtensionSubtest("tabs/basics", "events.html")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabRelativeURLs) {
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(RunExtensionSubtest("tabs/basics", "relative_urls.html"))
+ << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabGetCurrent) {
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index 8da37de..8157f52 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -11,6 +11,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_navigator.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_host.h"
@@ -65,7 +66,7 @@ static bool GetTabById(int tab_id, Profile* profile,
// but because the api shipped with urls resolved relative to their extension
// base, we decided it wasn't worth breaking existing extensions to fix.
static GURL ResolvePossiblyRelativeURL(std::string url_string,
- Extension* extension);
+ const Extension* extension);
// Return the type name for a browser window type.
static std::string GetWindowTypeText(Browser::Type type);
@@ -89,14 +90,10 @@ int ExtensionTabUtil::GetWindowIdOfTab(const TabContents* tab_contents) {
DictionaryValue* ExtensionTabUtil::CreateTabValue(
const TabContents* contents) {
// Find the tab strip and index of this guy.
- for (BrowserList::const_iterator it = BrowserList::begin();
- it != BrowserList::end(); ++it) {
- TabStripModel* tab_strip = (*it)->tabstrip_model();
- int tab_index = tab_strip->GetIndexOfTabContents(contents);
- if (tab_index != -1) {
- return ExtensionTabUtil::CreateTabValue(contents, tab_strip, tab_index);
- }
- }
+ TabStripModel* tab_strip = NULL;
+ int tab_index;
+ if (ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index))
+ return ExtensionTabUtil::CreateTabValue(contents, tab_strip, tab_index);
// Couldn't find it. This can happen if the tab is being dragged.
return ExtensionTabUtil::CreateTabValue(contents, NULL, -1);
@@ -124,6 +121,8 @@ DictionaryValue* ExtensionTabUtil::CreateTabValue(
result->SetString(keys::kStatusKey, GetTabStatusText(contents->is_loading()));
result->SetBoolean(keys::kSelectedKey,
tab_strip && tab_index == tab_strip->selected_index());
+ result->SetBoolean(keys::kPinnedKey,
+ tab_strip && tab_strip->IsTabPinned(tab_index));
result->SetString(keys::kTitleKey, contents->GetTitle());
result->SetBoolean(keys::kIncognitoKey,
contents->profile()->IsOffTheRecord());
@@ -165,6 +164,27 @@ DictionaryValue* ExtensionTabUtil::CreateWindowValue(const Browser* browser,
return result;
}
+bool ExtensionTabUtil::GetTabStripModel(const TabContents* tab_contents,
+ TabStripModel** tab_strip_model,
+ int* tab_index) {
+ DCHECK(tab_contents);
+ DCHECK(tab_strip_model);
+ DCHECK(tab_index);
+
+ for (BrowserList::const_iterator it = BrowserList::begin();
+ it != BrowserList::end(); ++it) {
+ TabStripModel* tab_strip = (*it)->tabstrip_model();
+ int index = tab_strip->GetIndexOfTabContents(tab_contents);
+ if (index != -1) {
+ *tab_strip_model = tab_strip;
+ *tab_index = index;
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool ExtensionTabUtil::GetDefaultTab(Browser* browser, TabContents** contents,
int* tab_id) {
DCHECK(browser);
@@ -406,11 +426,8 @@ bool CreateWindowFunction::RunImpl() {
}
Browser* new_window = Browser::CreateForType(window_type, window_profile);
- for (std::vector<GURL>::iterator i = urls.begin(); i != urls.end(); ++i) {
- Browser::AddTabWithURLParams addTabParams =
- Browser::AddTabWithURLParams(*i, PageTransition::LINK);
- new_window->AddTabWithURL(&addTabParams);
- }
+ for (std::vector<GURL>::iterator i = urls.begin(); i != urls.end(); ++i)
+ new_window->AddSelectedTabWithURL(*i, PageTransition::LINK);
if (urls.size() == 0)
new_window->NewTab();
new_window->SelectNumberedTab(0);
@@ -600,9 +617,16 @@ bool CreateTabFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kSelectedKey,
&selected));
- // We can't load extension URLs into incognito windows. Special case to
- // fall back to a normal window.
+ // Default to not pinning the tab. Setting the 'pinned' property to true
+ // will override this default.
+ bool pinned = false;
+ if (args->HasKey(keys::kPinnedKey))
+ EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kPinnedKey, &pinned));
+
+ // We can't load extension URLs into incognito windows unless the extension
+ // uses split mode. Special case to fall back to a normal window.
if (url.SchemeIs(chrome::kExtensionScheme) &&
+ !GetExtension()->incognito_split_mode() &&
browser->profile()->IsOffTheRecord()) {
Profile* profile = browser->profile()->GetOriginalProfile();
browser = BrowserList::FindBrowserWithType(profile,
@@ -626,20 +650,25 @@ bool CreateTabFunction::RunImpl() {
int add_types = selected ? TabStripModel::ADD_SELECTED :
TabStripModel::ADD_NONE;
add_types |= TabStripModel::ADD_FORCE_INDEX;
- Browser::AddTabWithURLParams params(url, PageTransition::LINK);
- params.index = index;
- params.add_types = add_types;
- TabContents* contents = browser->AddTabWithURL(&params);
- index = browser->tabstrip_model()->GetIndexOfTabContents(contents);
+ if (pinned)
+ add_types |= TabStripModel::ADD_PINNED;
+ browser::NavigateParams params(browser, url, PageTransition::LINK);
+ params.disposition = selected ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
+ params.tabstrip_index = index;
+ params.tabstrip_add_types = add_types;
+ browser::Navigate(&params);
if (selected)
- contents->view()->SetInitialFocus();
+ params.target_contents->view()->SetInitialFocus();
// Return data about the newly created tab.
- if (has_callback())
- result_.reset(ExtensionTabUtil::CreateTabValue(contents,
- browser->tabstrip_model(),
- index));
+ if (has_callback()) {
+ result_.reset(ExtensionTabUtil::CreateTabValue(
+ params.target_contents,
+ params.browser->tabstrip_model(),
+ params.browser->tabstrip_model()->GetIndexOfTabContents(
+ params.target_contents)));
+ }
return true;
}
@@ -705,7 +734,7 @@ bool UpdateTabFunction::RunImpl() {
// JavaScript URLs can do the same kinds of things as cross-origin XHR, so
// we need to check host permissions before allowing them.
if (url.SchemeIs(chrome::kJavaScriptScheme)) {
- Extension* extension = GetExtension();
+ const Extension* extension = GetExtension();
const std::vector<URLPattern> host_permissions =
extension->host_permissions();
if (!Extension::CanExecuteScriptOnPage(
@@ -722,12 +751,6 @@ bool UpdateTabFunction::RunImpl() {
// controller->GetURL()?
}
- if (tab_strip->IsTabPinned(tab_index)) {
- // Don't allow changing the url of pinned tabs.
- error_ = keys::kCannotUpdatePinnedTab;
- return false;
- }
-
controller.LoadURL(url, GURL(), PageTransition::LINK);
// The URL of a tab contents never actually changes to a JavaScript URL, so
@@ -752,6 +775,16 @@ bool UpdateTabFunction::RunImpl() {
}
}
+ bool pinned = false;
+ if (update_props->HasKey(keys::kPinnedKey)) {
+ EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(keys::kPinnedKey,
+ &pinned));
+ tab_strip->SetTabPinned(tab_index, pinned);
+
+ // Update the tab index because it may move when being pinned.
+ tab_index = tab_strip->GetIndexOfTabContents(contents);
+ }
+
if (has_callback())
result_.reset(ExtensionTabUtil::CreateTabValue(contents, tab_strip,
tab_index));
@@ -942,7 +975,7 @@ bool CaptureVisibleTabFunction::CaptureSnapshotFromBackingStore(
&temp_canvas)) {
return false;
}
- LOG(INFO) << "captureVisibleTab() Got image from backing store.";
+ VLOG(1) << "captureVisibleTab() got image from backing store.";
SendResultFromBitmap(
temp_canvas.getTopPlatformDevice().accessBitmap(false));
@@ -964,7 +997,7 @@ void CaptureVisibleTabFunction::Observe(NotificationType type,
error_ = keys::kInternalVisibleTabCaptureError;
SendResponse(false);
} else {
- LOG(INFO) << "captureVisibleTab() Got image from renderer.";
+ VLOG(1) << "captureVisibleTab() got image from renderer.";
SendResultFromBitmap(*screen_capture);
}
@@ -1149,7 +1182,7 @@ static std::string GetWindowTypeText(Browser::Type type) {
}
static GURL ResolvePossiblyRelativeURL(std::string url_string,
- Extension* extension) {
+ const Extension* extension) {
GURL url = GURL(url_string);
if (!url.is_valid())
url = extension->GetResourceURL(url_string);
diff --git a/chrome/browser/extensions/extension_tabs_module.h b/chrome/browser/extensions/extension_tabs_module.h
index cee8a0d..9bf36cb 100644
--- a/chrome/browser/extensions/extension_tabs_module.h
+++ b/chrome/browser/extensions/extension_tabs_module.h
@@ -34,7 +34,10 @@ class ExtensionTabUtil {
int tab_index);
static DictionaryValue* CreateWindowValue(const Browser* browser,
bool populate_tabs);
-
+ // Gets the |tab_strip_model| and |tab_index| for the given |tab_contents|.
+ static bool GetTabStripModel(const TabContents* tab_contents,
+ TabStripModel** tab_strip_model,
+ int* tab_index);
static bool GetDefaultTab(Browser* browser, TabContents** contents,
int* tab_id);
// Any out parameter (|browser|, |tab_strip|, |contents|, & |tab_index|) may
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.cc b/chrome/browser/extensions/extension_tabs_module_constants.cc
index 9dc19b8..6405783 100644
--- a/chrome/browser/extensions/extension_tabs_module_constants.cc
+++ b/chrome/browser/extensions/extension_tabs_module_constants.cc
@@ -22,6 +22,7 @@ const char kNewPositionKey[] = "newPosition";
const char kNewWindowIdKey[] = "newWindowId";
const char kOldPositionKey[] = "oldPosition";
const char kOldWindowIdKey[] = "oldWindowId";
+const char kPinnedKey[] = "pinned";
const char kPopulateKey[] = "populate";
const char kQualityKey[] = "quality";
const char kSelectedKey[] = "selected";
@@ -68,7 +69,6 @@ const char kNoCodeOrFileToExecuteError[] = "No source code or file specified.";
const char kMoreThanOneValuesError[] = "Code and file should not be specified "
"at the same time in the second argument.";
const char kLoadFileError[] = "Failed to load file: \"*\". ";
-const char kCannotUpdatePinnedTab[] = "Cannot update pinned tabs";
const char kCannotDetermineLanguageOfUnloadedTab[] =
"Cannot determine language: tab not loaded";
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.h b/chrome/browser/extensions/extension_tabs_module_constants.h
index 7ae35b7..89c1cd3 100644
--- a/chrome/browser/extensions/extension_tabs_module_constants.h
+++ b/chrome/browser/extensions/extension_tabs_module_constants.h
@@ -26,6 +26,7 @@ extern const char kNewPositionKey[];
extern const char kNewWindowIdKey[];
extern const char kOldPositionKey[];
extern const char kOldWindowIdKey[];
+extern const char kPinnedKey[];
extern const char kPopulateKey[];
extern const char kQualityKey[];
extern const char kSelectedKey[];
@@ -69,7 +70,6 @@ extern const char kSupportedInWindowsOnlyError[];
extern const char kNoCodeOrFileToExecuteError[];
extern const char kMoreThanOneValuesError[];
extern const char kLoadFileError[];
-extern const char kCannotUpdatePinnedTab[];
extern const char kCannotDetermineLanguageOfUnloadedTab[];
}; // namespace extension_tabs_module_constants
diff --git a/chrome/browser/extensions/extension_test_message_listener.cc b/chrome/browser/extensions/extension_test_message_listener.cc
index 423bf3b..8ba0683 100644
--- a/chrome/browser/extensions/extension_test_message_listener.cc
+++ b/chrome/browser/extensions/extension_test_message_listener.cc
@@ -43,8 +43,8 @@ void ExtensionTestMessageListener::Observe(
const NotificationSource& source,
const NotificationDetails& details) {
const std::string& content = *Details<std::string>(details).ptr();
- function_ = Source<ExtensionTestSendMessageFunction>(source).ptr();
if (!satisfied_ && content == expected_message_) {
+ function_ = Source<ExtensionTestSendMessageFunction>(source).ptr();
satisfied_ = true;
registrar_.RemoveAll(); // Stop listening for more messages.
if (!will_reply_) {
diff --git a/chrome/browser/extensions/extension_test_message_listener.h b/chrome/browser/extensions/extension_test_message_listener.h
index bead446..86c4cf2 100644
--- a/chrome/browser/extensions/extension_test_message_listener.h
+++ b/chrome/browser/extensions/extension_test_message_listener.h
@@ -63,6 +63,8 @@ class ExtensionTestMessageListener : public NotificationObserver {
const NotificationSource& source,
const NotificationDetails& details);
+ bool was_satisfied() const { return satisfied_; }
+
private:
NotificationRegistrar registrar_;
diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/extensions/extension_toolbar_model.cc
index 086b8c4..9b36825 100644
--- a/chrome/browser/extensions/extension_toolbar_model.cc
+++ b/chrome/browser/extensions/extension_toolbar_model.cc
@@ -45,7 +45,7 @@ void ExtensionToolbarModel::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
-void ExtensionToolbarModel::MoveBrowserAction(Extension* extension,
+void ExtensionToolbarModel::MoveBrowserAction(const Extension* extension,
int index) {
ExtensionList::iterator pos = std::find(begin(), end(), extension);
if (pos == end()) {
@@ -58,7 +58,7 @@ void ExtensionToolbarModel::MoveBrowserAction(Extension* extension,
bool inserted = false;
for (ExtensionList::iterator iter = begin(); iter != end(); ++iter, ++i) {
if (i == index) {
- toolitems_.insert(iter, extension);
+ toolitems_.insert(iter, make_scoped_refptr(extension));
inserted = true;
break;
}
@@ -68,7 +68,7 @@ void ExtensionToolbarModel::MoveBrowserAction(Extension* extension,
DCHECK_EQ(index, static_cast<int>(toolitems_.size()));
index = toolitems_.size();
- toolitems_.push_back(extension);
+ toolitems_.push_back(make_scoped_refptr(extension));
}
FOR_EACH_OBSERVER(Observer, observers_, BrowserActionMoved(extension, index));
@@ -93,7 +93,7 @@ void ExtensionToolbarModel::Observe(NotificationType type,
if (!service_->is_ready())
return;
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
if (type == NotificationType::EXTENSION_LOADED) {
AddExtension(extension);
} else if (type == NotificationType::EXTENSION_UNLOADED ||
@@ -104,18 +104,19 @@ void ExtensionToolbarModel::Observe(NotificationType type,
}
}
-void ExtensionToolbarModel::AddExtension(Extension* extension) {
+void ExtensionToolbarModel::AddExtension(const Extension* extension) {
// We only care about extensions with browser actions.
if (!extension->browser_action())
return;
if (extension->id() == last_extension_removed_ &&
last_extension_removed_index_ < toolitems_.size()) {
- toolitems_.insert(begin() + last_extension_removed_index_, extension);
+ toolitems_.insert(begin() + last_extension_removed_index_,
+ make_scoped_refptr(extension));
FOR_EACH_OBSERVER(Observer, observers_,
BrowserActionAdded(extension, last_extension_removed_index_));
} else {
- toolitems_.push_back(extension);
+ toolitems_.push_back(make_scoped_refptr(extension));
FOR_EACH_OBSERVER(Observer, observers_,
BrowserActionAdded(extension, toolitems_.size() - 1));
}
@@ -126,7 +127,7 @@ void ExtensionToolbarModel::AddExtension(Extension* extension) {
UpdatePrefs();
}
-void ExtensionToolbarModel::RemoveExtension(Extension* extension) {
+void ExtensionToolbarModel::RemoveExtension(const Extension* extension) {
ExtensionList::iterator pos = std::find(begin(), end(), extension);
if (pos == end()) {
return;
@@ -162,7 +163,7 @@ void ExtensionToolbarModel::InitializeExtensionList() {
// Create the lists.
for (size_t i = 0; i < service_->extensions()->size(); ++i) {
- Extension* extension = service_->extensions()->at(i);
+ const Extension* extension = service_->extensions()->at(i);
if (!extension->browser_action())
continue;
@@ -172,7 +173,7 @@ void ExtensionToolbarModel::InitializeExtensionList() {
int index = std::distance(pref_order.begin(), pos);
sorted[index] = extension;
} else {
- unsorted.push_back(extension);
+ unsorted.push_back(make_scoped_refptr(extension));
}
}
@@ -208,7 +209,7 @@ void ExtensionToolbarModel::UpdatePrefs() {
service_->extension_prefs()->SetToolbarOrder(ids);
}
-Extension* ExtensionToolbarModel::GetExtensionByIndex(int index) const {
+const Extension* ExtensionToolbarModel::GetExtensionByIndex(int index) const {
return toolitems_.at(index);
}
diff --git a/chrome/browser/extensions/extension_toolbar_model.h b/chrome/browser/extensions/extension_toolbar_model.h
index a38fc8c..37c3a08 100644
--- a/chrome/browser/extensions/extension_toolbar_model.h
+++ b/chrome/browser/extensions/extension_toolbar_model.h
@@ -30,13 +30,13 @@ class ExtensionToolbarModel : public NotificationObserver {
public:
// An extension with a browser action button has been added, and should go
// in the toolbar at |index|.
- virtual void BrowserActionAdded(Extension* extension, int index) {}
+ virtual void BrowserActionAdded(const Extension* extension, int index) {}
// The browser action button for |extension| should no longer show.
- virtual void BrowserActionRemoved(Extension* extension) {}
+ virtual void BrowserActionRemoved(const Extension* extension) {}
// The browser action button for |extension| has been moved to |index|.
- virtual void BrowserActionMoved(Extension* extension, int index) {}
+ virtual void BrowserActionMoved(const Extension* extension, int index) {}
// Called when the model has finished loading.
virtual void ModelLoaded() {}
@@ -48,7 +48,7 @@ class ExtensionToolbarModel : public NotificationObserver {
// Functions called by the view.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
- void MoveBrowserAction(Extension* extension, int index);
+ void MoveBrowserAction(const Extension* extension, int index);
// If count == size(), this will set the visible icon count to -1, meaning
// "show all actions".
void SetVisibleIconCount(int count);
@@ -69,7 +69,7 @@ class ExtensionToolbarModel : public NotificationObserver {
return toolitems_.end();
}
- Extension* GetExtensionByIndex(int index) const;
+ const Extension* GetExtensionByIndex(int index) const;
// Utility functions for converting between an index into the list of
// incognito-enabled browser actions, and the list of all browser actions.
@@ -93,8 +93,8 @@ class ExtensionToolbarModel : public NotificationObserver {
// Our observers.
ObserverList<Observer> observers_;
- void AddExtension(Extension* extension);
- void RemoveExtension(Extension* extension);
+ void AddExtension(const Extension* extension);
+ void RemoveExtension(const Extension* extension);
// Our ExtensionsService, guaranteed to outlive us.
ExtensionsService* service_;
diff --git a/chrome/browser/extensions/extension_toolbar_model_browsertest.cc b/chrome/browser/extensions/extension_toolbar_model_browsertest.cc
index 031672e..45c936e 100644
--- a/chrome/browser/extensions/extension_toolbar_model_browsertest.cc
+++ b/chrome/browser/extensions/extension_toolbar_model_browsertest.cc
@@ -37,19 +37,19 @@ class ExtensionToolbarModelTest : public ExtensionBrowserTest,
model_->RemoveObserver(this);
}
- virtual void BrowserActionAdded(Extension* extension, int index) {
+ virtual void BrowserActionAdded(const Extension* extension, int index) {
inserted_count_++;
}
- virtual void BrowserActionRemoved(Extension* extension) {
+ virtual void BrowserActionRemoved(const Extension* extension) {
removed_count_++;
}
- virtual void BrowserActionMoved(Extension* extension, int index) {
+ virtual void BrowserActionMoved(const Extension* extension, int index) {
moved_count_++;
}
- Extension* ExtensionAt(int index) {
+ const Extension* ExtensionAt(int index) {
for (ExtensionList::iterator i = model_->begin(); i < model_->end(); ++i) {
if (index-- == 0)
return *i;
@@ -87,7 +87,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, Basic) {
// We should now find our extension in the model.
EXPECT_EQ(1, inserted_count_);
EXPECT_EQ(1u, model_->size());
- Extension* extension = ExtensionAt(0);
+ const Extension* extension = ExtensionAt(0);
ASSERT_TRUE(NULL != extension);
EXPECT_STREQ("A browser action with no icon that makes the page red",
extension->name().c_str());
@@ -96,7 +96,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, Basic) {
model_->MoveBrowserAction(extension, 0);
EXPECT_EQ(1, moved_count_);
EXPECT_EQ(1u, model_->size());
- Extension* extension2 = ExtensionAt(0);
+ const Extension* extension2 = ExtensionAt(0);
EXPECT_EQ(extension, extension2);
UnloadExtension(extension->id());
@@ -118,7 +118,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, ReorderAndReinsert) {
// First extension loaded.
EXPECT_EQ(1, inserted_count_);
EXPECT_EQ(1u, model_->size());
- Extension* extensionA = ExtensionAt(0);
+ const Extension* extensionA = ExtensionAt(0);
ASSERT_TRUE(NULL != extensionA);
EXPECT_STREQ("A browser action with no icon that makes the page red",
extensionA->name().c_str());
@@ -132,7 +132,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, ReorderAndReinsert) {
// Second extension loaded.
EXPECT_EQ(2, inserted_count_);
EXPECT_EQ(2u, model_->size());
- Extension* extensionB = ExtensionAt(1);
+ const Extension* extensionB = ExtensionAt(1);
ASSERT_TRUE(NULL != extensionB);
EXPECT_STREQ("Popup tester", extensionB->name().c_str());
@@ -145,7 +145,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, ReorderAndReinsert) {
// Third extension loaded.
EXPECT_EQ(3, inserted_count_);
EXPECT_EQ(3u, model_->size());
- Extension* extensionC = ExtensionAt(2);
+ const Extension* extensionC = ExtensionAt(2);
ASSERT_TRUE(NULL != extensionC);
EXPECT_STREQ("A page action which removes a popup.",
extensionC->name().c_str());
diff --git a/chrome/browser/extensions/extension_tts_api.cc b/chrome/browser/extensions/extension_tts_api.cc
index b022ec0..1654b07 100644
--- a/chrome/browser/extensions/extension_tts_api.cc
+++ b/chrome/browser/extensions/extension_tts_api.cc
@@ -7,68 +7,206 @@
#include <string>
#include "base/float_util.h"
+#include "base/message_loop.h"
#include "base/values.h"
namespace util = extension_tts_api_util;
namespace {
- const char kCrosLibraryNotLoadedError[] =
- "Cros shared library not loaded.";
+const char kCrosLibraryNotLoadedError[] =
+ "Cros shared library not loaded.";
+const int kSpeechCheckDelayIntervalMs = 100;
};
+// static
+ExtensionTtsController* ExtensionTtsController::GetInstance() {
+ return Singleton<ExtensionTtsController>::get();
+}
+
+ExtensionTtsController::ExtensionTtsController()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
+ current_utterance_(NULL),
+ platform_impl_(NULL) {
+}
+
+void ExtensionTtsController::SpeakOrEnqueue(
+ Utterance* utterance, bool can_enqueue) {
+ if (IsSpeaking() && can_enqueue) {
+ utterance_queue_.push(utterance);
+ } else {
+ Stop();
+ SpeakNow(utterance);
+ }
+}
+
+void ExtensionTtsController::SpeakNow(Utterance* utterance) {
+ GetPlatformImpl()->clear_error();
+ bool success = GetPlatformImpl()->Speak(
+ utterance->text,
+ utterance->language,
+ utterance->gender,
+ utterance->rate,
+ utterance->pitch,
+ utterance->volume);
+ if (!success) {
+ utterance->error = GetPlatformImpl()->error();
+ utterance->failure_task->Run();
+ delete utterance->success_task;
+ delete utterance;
+ 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);
+}
+
+void ExtensionTtsController::Stop() {
+ GetPlatformImpl()->clear_error();
+ GetPlatformImpl()->StopSpeaking();
+
+ FinishCurrentUtterance();
+ ClearUtteranceQueue();
+}
+
+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_ = NULL;
+ }
+}
+
+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;
+ }
+}
+
+void ExtensionTtsController::CheckSpeechStatus() {
+ if (!current_utterance_)
+ 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);
+ }
+ }
+
+ // If we're still speaking something (either the prevoius utterance or
+ // a new utterance), keep calling this method after another delay.
+ if (current_utterance_) {
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, method_factory_.NewRunnableMethod(
+ &ExtensionTtsController::CheckSpeechStatus),
+ kSpeechCheckDelayIntervalMs);
+ }
+}
+
+void ExtensionTtsController::SetPlatformImpl(
+ ExtensionTtsPlatformImpl* platform_impl) {
+ platform_impl_ = platform_impl;
+}
+
+ExtensionTtsPlatformImpl* ExtensionTtsController::GetPlatformImpl() {
+ if (!platform_impl_)
+ platform_impl_ = ExtensionTtsPlatformImpl::GetInstance();
+ return platform_impl_;
+}
+
+//
+// Extension API functions
+//
+
bool ExtensionTtsSpeakFunction::RunImpl() {
- std::string utterance;
- std::string language;
- std::string gender;
- double rate = -1.0;
- double pitch = -1.0;
- double volume = -1.0;
+ utterance_ = new ExtensionTtsController::Utterance();
+ bool can_enqueue = false;
DictionaryValue* speak_options = NULL;
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &utterance));
+ 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, &language);
+ speak_options->GetString(util::kLanguageNameKey, &utterance_->language);
}
if (speak_options->HasKey(util::kGenderKey)) {
- speak_options->GetString(util::kGenderKey, &gender);
+ 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, &rate)) {
- if (!base::IsFinite(rate) || rate < 0.0 || rate > 1.0) {
- rate = -1.0;
+ 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, &pitch)) {
- if (!base::IsFinite(pitch) || pitch < 0.0 || pitch > 1.0) {
- pitch = -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, &volume)) {
- if (!base::IsFinite(volume) || volume < 0.0 || volume > 1.0) {
- volume = -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;
}
}
}
- ExtensionTtsPlatformImpl* impl = ExtensionTtsPlatformImpl::GetInstance();
- impl->clear_error();
- return impl->Speak(utterance, language, gender, rate, pitch, volume);
+ 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);
+ return true;
+}
+
+void ExtensionTtsSpeakFunction::SpeechFinished(bool success) {
+ error_ = utterance_->error;
+ SendResponse(success);
+ Release(); // Balanced in Speak().
}
bool ExtensionTtsStopSpeakingFunction::RunImpl() {
- ExtensionTtsPlatformImpl* impl = ExtensionTtsPlatformImpl::GetInstance();
- impl->clear_error();
- return impl->StopSpeaking();
+ ExtensionTtsController::GetInstance()->Stop();
+ return true;
}
bool ExtensionTtsIsSpeakingFunction::RunImpl() {
- ExtensionTtsPlatformImpl* impl = ExtensionTtsPlatformImpl::GetInstance();
- impl->clear_error();
- result_.reset(Value::CreateBooleanValue(impl->IsSpeaking()));
+ result_.reset(Value::CreateBooleanValue(
+ ExtensionTtsController::GetInstance()->IsSpeaking()));
return true;
}
diff --git a/chrome/browser/extensions/extension_tts_api.h b/chrome/browser/extensions/extension_tts_api.h
index 73fc887..0eedcc2 100644
--- a/chrome/browser/extensions/extension_tts_api.h
+++ b/chrome/browser/extensions/extension_tts_api.h
@@ -5,6 +5,10 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_H_
+#include <queue>
+
+#include "base/singleton.h"
+#include "base/task.h"
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/browser/extensions/extension_tts_api_util.h"
@@ -17,6 +21,11 @@ class ExtensionTtsPlatformImpl {
// and return true on success. Utterance will always be nonempty.
// If the user does not specify the other values, language 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
+ // a time. If it wants to intterupt speech, it will always call Stop
+ // before speaking again, otherwise it will wait until IsSpeaking
+ // returns false before calling Speak again.
virtual bool Speak(
const std::string& utterance,
const std::string& language,
@@ -44,23 +53,108 @@ class ExtensionTtsPlatformImpl {
DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImpl);
};
+// 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);
+
+ // Stop all utterances and flush the queue.
+ void Stop();
+
+ // For unit testing.
+ void SetPlatformImpl(ExtensionTtsPlatformImpl* platform_impl);
+
+ private:
+ ExtensionTtsController();
+ virtual ~ExtensionTtsController() {}
+
+ // Get the platform TTS implementation (or injected mock).
+ ExtensionTtsPlatformImpl* GetPlatformImpl();
+
+ // Start speaking the given utterance. Will either take ownership of
+ // |utterance| or delete it if there's an error.
+ void SpeakNow(Utterance* utterance);
+
+ // Called periodically when speech is ongoing. Checks to see if the
+ // underlying platform speech system has finished the current utterance,
+ // and if so finishes it and pops the next utterance off the queue.
+ void CheckSpeechStatus();
+
+ // Clear the utterance queue.
+ void ClearUtteranceQueue();
+
+ // Finalize and delete the current utterance.
+ void FinishCurrentUtterance();
+
+ ScopedRunnableMethodFactory<ExtensionTtsController> method_factory_;
+ friend struct DefaultSingletonTraits<ExtensionTtsController>;
+
+ // The current utterance being spoken.
+ Utterance* current_utterance_;
+
+ // A queue of utterances to speak after the current one finishes.
+ std::queue<Utterance*> utterance_queue_;
+
+ // A pointer to the platform implementation of text-to-speech, for
+ // dependency injection.
+ ExtensionTtsPlatformImpl* platform_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionTtsController);
+};
+
//
// Extension API function definitions
//
-class ExtensionTtsSpeakFunction : public SyncExtensionFunction {
+class ExtensionTtsSpeakFunction : public AsyncExtensionFunction {
+ private:
~ExtensionTtsSpeakFunction() {}
virtual bool RunImpl();
+ void SpeechFinished(bool success);
+ ExtensionTtsController::Utterance* utterance_;
DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.speak")
};
class ExtensionTtsStopSpeakingFunction : public SyncExtensionFunction {
+ private:
~ExtensionTtsStopSpeakingFunction() {}
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.stop")
};
class ExtensionTtsIsSpeakingFunction : public SyncExtensionFunction {
+ private:
~ExtensionTtsIsSpeakingFunction() {}
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.isSpeaking")
diff --git a/chrome/browser/extensions/extension_tts_api_linux.cc b/chrome/browser/extensions/extension_tts_api_linux.cc
index 8ee228b..7b89799 100644
--- a/chrome/browser/extensions/extension_tts_api_linux.cc
+++ b/chrome/browser/extensions/extension_tts_api_linux.cc
@@ -38,7 +38,7 @@ class ExtensionTtsPlatformImplLinux : public ExtensionTtsPlatformImpl {
// Get the single instance of this class.
static ExtensionTtsPlatformImplLinux* GetInstance() {
- return ExtensionTtsPlatformImplLinux::GetInstance();
+ return Singleton<ExtensionTtsPlatformImplLinux>::get();
}
private:
diff --git a/chrome/browser/extensions/extension_tts_api_util.h b/chrome/browser/extensions/extension_tts_api_util.h
index 4b41871..cf0d702 100644
--- a/chrome/browser/extensions/extension_tts_api_util.h
+++ b/chrome/browser/extensions/extension_tts_api_util.h
@@ -17,6 +17,7 @@ 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[] = ";";
diff --git a/chrome/browser/extensions/extension_tts_apitest.cc b/chrome/browser/extensions/extension_tts_apitest.cc
index dcdfb9d..6f37404 100644
--- a/chrome/browser/extensions/extension_tts_apitest.cc
+++ b/chrome/browser/extensions/extension_tts_apitest.cc
@@ -2,19 +2,164 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/command_line.h"
-#include "chrome/browser/chromeos/cros/cros_mock.h"
#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_tts_api.h"
#include "chrome/common/chrome_switches.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Needed for CreateFunctor.
+#define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
+#include "testing/gmock_mutant.h"
-// This extension API is currently only supported on Chrome OS.
#if defined(OS_CHROMEOS)
-#define MAYBE_Tts Tts
-#else
-#define MAYBE_Tts DISABLED_Tts
+#include "chrome/browser/chromeos/cros/cros_mock.h"
#endif
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Tts) {
+using ::testing::CreateFunctor;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::InvokeWithoutArgs;
+using ::testing::Return;
+using ::testing::StrictMock;
+using ::testing::_;
+
+class MockExtensionTtsPlatformImpl : public ExtensionTtsPlatformImpl {
+ public:
+ MOCK_METHOD6(Speak,
+ bool(const std::string& utterance,
+ const std::string& language,
+ const std::string& gender,
+ double rate,
+ double pitch,
+ double volume));
+ MOCK_METHOD0(StopSpeaking, bool(void));
+ MOCK_METHOD0(IsSpeaking, bool(void));
+
+ void SetErrorToEpicFail() {
+ set_error("epic fail");
+ }
+};
+
+class TtsApiTest : public ExtensionApiTest {
+ public:
+ virtual void SetUpCommandLine(CommandLine* command_line) {
+ ExtensionApiTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
+ }
+
+ virtual void SetUpInProcessBrowserTestFixture() {
+ ExtensionApiTest::SetUpInProcessBrowserTestFixture();
+ ExtensionTtsController::GetInstance()->SetPlatformImpl(
+ &mock_platform_impl_);
+ }
+
+ protected:
+ StrictMock<MockExtensionTtsPlatformImpl> mock_platform_impl_;
+};
+
+IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakFinishesImmediately) {
+ InSequence s;
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, Speak(_, _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .WillOnce(Return(false));
+ ASSERT_TRUE(RunExtensionTest("tts/speak_once")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakKeepsSpeakingTwice) {
+ InSequence s;
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, Speak(_, _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .WillOnce(Return(true))
+ .WillOnce(Return(true))
+ .WillOnce(Return(false));
+ ASSERT_TRUE(RunExtensionTest("tts/speak_once")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakInterrupt) {
+ InSequence s;
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, Speak("text 1", _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, Speak("text 2", _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .WillOnce(Return(true))
+ .WillOnce(Return(true))
+ .WillOnce(Return(false));
+ ASSERT_TRUE(RunExtensionTest("tts/interrupt")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakQueueInterrupt) {
+ // In this test, two utterances are queued, and then a third
+ // interrupts. Speak() never gets called on the second utterance.
+ InSequence s;
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, Speak("text 1", _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, Speak("text 3", _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .WillOnce(Return(true))
+ .WillOnce(Return(true))
+ .WillOnce(Return(false));
+ ASSERT_TRUE(RunExtensionTest("tts/queue_interrupt")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakEnqueue) {
+ InSequence s;
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, Speak("text 1", _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .WillOnce(Return(true))
+ .WillOnce(Return(true))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_platform_impl_, Speak("text 2", _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .WillOnce(Return(true))
+ .WillOnce(Return(true))
+ .WillOnce(Return(false));
+ ASSERT_TRUE(RunExtensionTest("tts/enqueue")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakError) {
+ InSequence s;
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, Speak(_, _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_platform_impl_, Speak(_, _, _, _, _, _))
+ .WillOnce(DoAll(
+ InvokeWithoutArgs(
+ CreateFunctor(&mock_platform_impl_,
+ &MockExtensionTtsPlatformImpl::SetErrorToEpicFail)),
+ Return(false)));
+ EXPECT_CALL(mock_platform_impl_, Speak(_, _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .WillOnce(Return(false));
+ ASSERT_TRUE(RunExtensionTest("tts/speak_error")) << message_;
+}
+
+#if defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TtsChromeOs) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
@@ -24,3 +169,4 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Tts) {
ASSERT_TRUE(RunExtensionTest("tts/chromeos")) << message_;
}
+#endif
diff --git a/chrome/browser/extensions/extension_ui_unittest.cc b/chrome/browser/extensions/extension_ui_unittest.cc
index ba429ba..1bda60a 100644
--- a/chrome/browser/extensions/extension_ui_unittest.cc
+++ b/chrome/browser/extensions/extension_ui_unittest.cc
@@ -33,7 +33,6 @@ namespace {
#elif defined(OS_POSIX)
FilePath path(FILE_PATH_LITERAL("/foo"));
#endif
- Extension extension(path);
std::string error;
FilePath manifest_path = extension_path.Append(
@@ -41,7 +40,10 @@ namespace {
scoped_ptr<DictionaryValue> extension_data(DeserializeJSONTestData(
manifest_path, &error));
EXPECT_EQ("", error);
- EXPECT_TRUE(extension.InitFromValue(*extension_data, true, &error));
+
+ scoped_refptr<Extension> extension(Extension::Create(
+ path, Extension::INVALID, *extension_data, true, &error));
+ EXPECT_TRUE(extension.get());
EXPECT_EQ("", error);
scoped_ptr<DictionaryValue> expected_output_data(DeserializeJSONTestData(
@@ -50,7 +52,7 @@ namespace {
// Produce test output.
scoped_ptr<DictionaryValue> actual_output_data(
- ExtensionsDOMHandler::CreateExtensionDetailValue(NULL, &extension,
+ ExtensionsDOMHandler::CreateExtensionDetailValue(NULL, extension.get(),
pages, true));
// Compare the outputs.
diff --git a/chrome/browser/extensions/extension_uitest.cc b/chrome/browser/extensions/extension_uitest.cc
index 2076949..f074c9b 100644
--- a/chrome/browser/extensions/extension_uitest.cc
+++ b/chrome/browser/extensions/extension_uitest.cc
@@ -121,6 +121,7 @@ class ExtensionTestSimpleApiCall : public ExtensionUITest {
DISALLOW_COPY_AND_ASSIGN(ExtensionTestSimpleApiCall);
};
+// Flaky: http://crbug.com/44599
TEST_F(ExtensionTestSimpleApiCall, FLAKY_RunTest) {
namespace keys = extension_automation_constants;
diff --git a/chrome/browser/extensions/extension_updater.cc b/chrome/browser/extensions/extension_updater.cc
index f4e9e94..b2b3972 100644
--- a/chrome/browser/extensions/extension_updater.cc
+++ b/chrome/browser/extensions/extension_updater.cc
@@ -68,7 +68,7 @@ static const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days
// request. We want to stay under 2K because of proxies, etc.
static const int kExtensionsManifestMaxURLSize = 2000;
-ManifestFetchData::ManifestFetchData(GURL update_url)
+ManifestFetchData::ManifestFetchData(const GURL& update_url)
: base_url_(update_url),
full_url_(update_url) {
}
@@ -232,9 +232,7 @@ void ManifestFetchesBuilder::AddExtensionData(
PendingExtensionInfo::ExpectedCrxType crx_type,
GURL update_url) {
- // Only internal and external extensions can be autoupdated.
- if (location != Extension::INTERNAL &&
- !Extension::IsExternalLocation(location)) {
+ if (!Extension::IsAutoUpdateableLocation(location)) {
return;
}
@@ -520,13 +518,13 @@ void ExtensionUpdater::OnManifestFetchComplete(const GURL& url,
// We want to try parsing the manifest, and if it indicates updates are
// available, we want to fire off requests to fetch those updates.
if (status.status() == URLRequestStatus::SUCCESS && response_code == 200) {
- scoped_refptr<SafeManifestParser> safe_parser =
- new SafeManifestParser(data, current_manifest_fetch_.release(), this);
+ scoped_refptr<SafeManifestParser> safe_parser(
+ new SafeManifestParser(data, current_manifest_fetch_.release(), this));
safe_parser->Start();
} else {
// TODO(asargent) Do exponential backoff here. (http://crbug.com/12546).
- LOG(INFO) << "Failed to fetch manifest '" << url.possibly_invalid_spec() <<
- "' response code:" << response_code;
+ VLOG(1) << "Failed to fetch manifest '" << url.possibly_invalid_spec()
+ << "' response code:" << response_code;
}
manifest_fetcher_.reset();
current_manifest_fetch_.reset();
@@ -620,8 +618,8 @@ void ExtensionUpdater::OnCRXFetchComplete(const GURL& url,
// TODO(asargent) do things like exponential backoff, handling
// 503 Service Unavailable / Retry-After headers, etc. here.
// (http://crbug.com/12546).
- LOG(INFO) << "Failed to fetch extension '" <<
- url.possibly_invalid_spec() << "' response code:" << response_code;
+ VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec()
+ << "' response code:" << response_code;
}
extension_fetcher_.reset();
current_extension_fetch_ = ExtensionFetch();
@@ -736,7 +734,7 @@ bool ExtensionUpdater::GetExistingVersion(const std::string& id,
*version = prefs_->GetString(kExtensionBlacklistUpdateVersion);
return true;
}
- Extension* extension = service_->GetExtensionById(id, false);
+ const Extension* extension = service_->GetExtensionById(id, false);
if (!extension) {
return false;
}
@@ -835,7 +833,8 @@ void ExtensionUpdater::StartUpdateCheck(ManifestFetchData* fetch_data) {
URLFetcher::GET, this));
manifest_fetcher_->set_request_context(Profile::GetDefaultRequestContext());
manifest_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES |
- net::LOAD_DO_NOT_SAVE_COOKIES);
+ net::LOAD_DO_NOT_SAVE_COOKIES |
+ net::LOAD_DISABLE_CACHE);
manifest_fetcher_->Start();
}
}
@@ -862,7 +861,8 @@ void ExtensionUpdater::FetchUpdatedExtension(const std::string& id,
extension_fetcher_->set_request_context(
Profile::GetDefaultRequestContext());
extension_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES |
- net::LOAD_DO_NOT_SAVE_COOKIES);
+ net::LOAD_DO_NOT_SAVE_COOKIES |
+ net::LOAD_DISABLE_CACHE);
extension_fetcher_->Start();
current_extension_fetch_ = ExtensionFetch(id, url, hash, version);
}
diff --git a/chrome/browser/extensions/extension_updater.h b/chrome/browser/extensions/extension_updater.h
index 4540dd0..79fa166 100644
--- a/chrome/browser/extensions/extension_updater.h
+++ b/chrome/browser/extensions/extension_updater.h
@@ -36,7 +36,7 @@ class ManifestFetchData {
public:
static const int kNeverPinged = -1;
- explicit ManifestFetchData(GURL update_url);
+ explicit ManifestFetchData(const GURL& update_url);
~ManifestFetchData();
// Returns true if this extension information was successfully added. If the
@@ -112,7 +112,6 @@ class ManifestFetchesBuilder {
const Version& version,
PendingExtensionInfo::ExpectedCrxType crx_type,
GURL update_url);
-
ExtensionUpdateService* service_;
// List of data on fetches we're going to do. We limit the number of
diff --git a/chrome/browser/extensions/extension_updater_unittest.cc b/chrome/browser/extensions/extension_updater_unittest.cc
index 7989e7a..f099b86 100644
--- a/chrome/browser/extensions/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/extension_updater_unittest.cc
@@ -33,7 +33,9 @@ using base::Time;
using base::TimeDelta;
static int expected_load_flags =
- net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+ net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES |
+ net::LOAD_DISABLE_CACHE;
// Base class for further specialized test classes.
class MockService : public ExtensionUpdateService {
@@ -57,7 +59,7 @@ class MockService : public ExtensionUpdateService {
FAIL();
}
- virtual Extension* GetExtensionById(const std::string& id, bool) {
+ virtual const Extension* GetExtensionById(const std::string& id, bool) {
ADD_FAILURE();
return NULL;
}
@@ -94,7 +96,8 @@ class MockService : public ExtensionUpdateService {
base::StringPrintf("Extension %d", i));
if (update_url)
manifest.SetString(extension_manifest_keys::kUpdateURL, *update_url);
- Extension* e = prefs_.AddExtensionWithManifest(manifest, location);
+ scoped_refptr<Extension> e =
+ prefs_.AddExtensionWithManifest(manifest, location);
ASSERT_TRUE(e != NULL);
list->push_back(e);
}
@@ -141,7 +144,7 @@ class ServiceForManifestTests : public MockService {
virtual ~ServiceForManifestTests() {}
- virtual Extension* GetExtensionById(const std::string& id, bool) {
+ virtual const Extension* GetExtensionById(const std::string& id, bool) {
for (ExtensionList::iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
if ((*iter)->id() == id) {
@@ -193,7 +196,7 @@ class ServiceForDownloadTests : public MockService {
return pending_extensions_;
}
- virtual Extension* GetExtensionById(const std::string& id, bool) {
+ virtual const Extension* GetExtensionById(const std::string& id, bool) {
last_inquired_extension_id_ = id;
return NULL;
}
@@ -307,8 +310,8 @@ class ExtensionUpdaterTest : public testing::Test {
TestURLFetcherFactory factory;
URLFetcher::set_factory(&factory);
- scoped_refptr<ExtensionUpdater> updater =
- new ExtensionUpdater(&service, service.pref_service(), 60*60*24);
+ scoped_refptr<ExtensionUpdater> updater(
+ new ExtensionUpdater(&service, service.pref_service(), 60*60*24));
updater->Start();
// Tell the update that it's time to do update checks.
@@ -343,10 +346,6 @@ class ExtensionUpdaterTest : public testing::Test {
EXPECT_EQ(extensions[0]->VersionString(), params["v"]);
}
EXPECT_EQ("", params["uc"]);
-
- if (!pending) {
- STLDeleteElements(&extensions);
- }
}
static void TestBlacklistUpdateCheckRequests() {
@@ -359,8 +358,8 @@ class ExtensionUpdaterTest : public testing::Test {
TestURLFetcherFactory factory;
URLFetcher::set_factory(&factory);
- scoped_refptr<ExtensionUpdater> updater =
- new ExtensionUpdater(&service, service.pref_service(), 60*60*24);
+ scoped_refptr<ExtensionUpdater> updater(
+ new ExtensionUpdater(&service, service.pref_service(), 60*60*24));
updater->Start();
// Tell the updater that it's time to do update checks.
@@ -411,9 +410,9 @@ class ExtensionUpdaterTest : public testing::Test {
service.set_extensions(tmp);
MessageLoop message_loop;
- scoped_refptr<ExtensionUpdater> updater =
+ scoped_refptr<ExtensionUpdater> updater(
new ExtensionUpdater(&service, service.pref_service(),
- kUpdateFrequencySecs);
+ kUpdateFrequencySecs));
// Check passing an empty list of parse results to DetermineUpdates
ManifestFetchData fetch_data(GURL("http://localhost/foo"));
@@ -438,7 +437,6 @@ class ExtensionUpdaterTest : public testing::Test {
updateable = updater->DetermineUpdates(fetch_data, updates);
EXPECT_EQ(1u, updateable.size());
EXPECT_EQ(0, updateable[0]);
- STLDeleteElements(&tmp);
}
static void TestDetermineUpdatesPending() {
@@ -449,9 +447,9 @@ class ExtensionUpdaterTest : public testing::Test {
service.set_pending_extensions(pending_extensions);
MessageLoop message_loop;
- scoped_refptr<ExtensionUpdater> updater =
+ scoped_refptr<ExtensionUpdater> updater(
new ExtensionUpdater(&service, service.pref_service(),
- kUpdateFrequencySecs);
+ kUpdateFrequencySecs));
ManifestFetchData fetch_data(GURL("http://localhost/foo"));
UpdateManifest::Results updates;
@@ -483,9 +481,9 @@ class ExtensionUpdaterTest : public testing::Test {
TestURLFetcher* fetcher = NULL;
URLFetcher::set_factory(&factory);
ServiceForDownloadTests service;
- scoped_refptr<ExtensionUpdater> updater =
+ scoped_refptr<ExtensionUpdater> updater(
new ExtensionUpdater(&service, service.pref_service(),
- kUpdateFrequencySecs);
+ kUpdateFrequencySecs));
GURL url1("http://localhost/manifest1");
GURL url2("http://localhost/manifest2");
@@ -547,9 +545,9 @@ class ExtensionUpdaterTest : public testing::Test {
TestURLFetcher* fetcher = NULL;
URLFetcher::set_factory(&factory);
ServiceForDownloadTests service;
- scoped_refptr<ExtensionUpdater> updater =
+ scoped_refptr<ExtensionUpdater> updater(
new ExtensionUpdater(&service, service.pref_service(),
- kUpdateFrequencySecs);
+ kUpdateFrequencySecs));
GURL test_url("http://localhost/extension.crx");
@@ -610,9 +608,9 @@ class ExtensionUpdaterTest : public testing::Test {
TestURLFetcher* fetcher = NULL;
URLFetcher::set_factory(&factory);
ServiceForBlacklistTests service;
- scoped_refptr<ExtensionUpdater> updater =
+ scoped_refptr<ExtensionUpdater> updater(
new ExtensionUpdater(&service, service.pref_service(),
- kUpdateFrequencySecs);
+ kUpdateFrequencySecs));
service.pref_service()->
RegisterStringPref(prefs::kExtensionBlacklistUpdateVersion, "0");
GURL test_url("http://localhost/extension.crx");
@@ -657,9 +655,9 @@ class ExtensionUpdaterTest : public testing::Test {
TestURLFetcher* fetcher = NULL;
URLFetcher::set_factory(&factory);
ServiceForDownloadTests service;
- scoped_refptr<ExtensionUpdater> updater =
+ scoped_refptr<ExtensionUpdater> updater(
new ExtensionUpdater(&service, service.pref_service(),
- kUpdateFrequencySecs);
+ kUpdateFrequencySecs));
GURL url1("http://localhost/extension1.crx");
GURL url2("http://localhost/extension2.crx");
@@ -744,9 +742,9 @@ class ExtensionUpdaterTest : public testing::Test {
}
MessageLoop message_loop;
- scoped_refptr<ExtensionUpdater> updater =
+ scoped_refptr<ExtensionUpdater> updater(
new ExtensionUpdater(&service, service.pref_service(),
- kUpdateFrequencySecs);
+ kUpdateFrequencySecs));
updater->set_blacklist_checks_enabled(false);
// Make the updater do manifest fetching, and note the urls it tries to
@@ -788,8 +786,6 @@ class ExtensionUpdaterTest : public testing::Test {
size_t pos = url1_query.find(search_string);
EXPECT_TRUE(pos != std::string::npos);
}
-
- STLDeleteElements(&tmp);
}
// This makes sure that the extension updater properly stores the results
@@ -798,9 +794,9 @@ class ExtensionUpdaterTest : public testing::Test {
// >= 1 day for the extension.
static void TestHandleManifestResults() {
ServiceForManifestTests service;
- scoped_refptr<ExtensionUpdater> updater =
+ scoped_refptr<ExtensionUpdater> updater(
new ExtensionUpdater(&service, service.pref_service(),
- kUpdateFrequencySecs);
+ kUpdateFrequencySecs));
GURL update_url("http://www.google.com/manifest");
ExtensionList tmp;
@@ -809,7 +805,7 @@ class ExtensionUpdaterTest : public testing::Test {
service.set_extensions(tmp);
ManifestFetchData fetch_data(update_url);
- Extension* extension = tmp[0];
+ const Extension* extension = tmp[0];
fetch_data.AddExtension(extension->id(), extension->VersionString(),
ManifestFetchData::kNeverPinged);
UpdateManifest::Results results;
@@ -821,8 +817,6 @@ class ExtensionUpdaterTest : public testing::Test {
EXPECT_FALSE(last_ping_day.is_null());
int64 seconds_diff = (Time::Now() - last_ping_day).InSeconds();
EXPECT_LT(seconds_diff - results.daystart_elapsed_seconds, 5);
-
- STLDeleteElements(&tmp);
}
};
@@ -894,7 +888,6 @@ TEST(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) {
ASSERT_FALSE(extensions.empty());
builder.AddExtension(*extensions[0]);
EXPECT_TRUE(builder.GetFetches().empty());
- STLDeleteElements(&extensions);
}
// Extensions with invalid update URLs should be rejected.
diff --git a/chrome/browser/extensions/extension_webnavigation_api.cc b/chrome/browser/extensions/extension_webnavigation_api.cc
index 159fdb7..9a3e4ab 100644
--- a/chrome/browser/extensions/extension_webnavigation_api.cc
+++ b/chrome/browser/extensions/extension_webnavigation_api.cc
@@ -17,6 +17,7 @@
#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;
@@ -36,6 +37,71 @@ double MilliSecondsFromTime(const base::Time& time) {
} // namespace
+FrameNavigationState::FrameNavigationState() {
+}
+
+FrameNavigationState::~FrameNavigationState() {
+}
+
+bool FrameNavigationState::CanSendEvents(long long 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,
+ const GURL& url,
+ bool is_main_frame,
+ const TabContents* tab_contents) {
+ if (is_main_frame)
+ RemoveTabContentsState(tab_contents);
+ tab_contents_map_.insert(
+ TabContentsToFrameIdMap::value_type(tab_contents, frame_id));
+ FrameState& frame_state = frame_state_map_[frame_id];
+ frame_state.error_occurred = (url.spec() == chrome::kUnreachableWebDataURL);
+ frame_state.url = url;
+ frame_state.is_main_frame = is_main_frame;
+}
+
+GURL FrameNavigationState::GetUrl(long long frame_id) const {
+ FrameIdToStateMap::const_iterator frame_state =
+ frame_state_map_.find(frame_id);
+ if (frame_state == frame_state_map_.end()) {
+ NOTREACHED();
+ return GURL();
+ }
+ return frame_state->second.url;
+}
+
+bool FrameNavigationState::IsMainFrame(long long frame_id) const {
+ FrameIdToStateMap::const_iterator frame_state =
+ frame_state_map_.find(frame_id);
+ if (frame_state == frame_state_map_.end()) {
+ NOTREACHED();
+ return false;
+ }
+ return frame_state->second.is_main_frame;
+}
+
+void FrameNavigationState::ErrorOccurredInFrame(long long frame_id) {
+ DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end());
+ frame_state_map_[frame_id].error_occurred = true;
+}
+
+void FrameNavigationState::RemoveTabContentsState(
+ const TabContents* tab_contents) {
+ typedef TabContentsToFrameIdMap::iterator FrameIdIterator;
+ std::pair<FrameIdIterator, FrameIdIterator> frame_ids =
+ 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);
+ }
+ tab_contents_map_.erase(tab_contents);
+}
+
+
// static
ExtensionWebNavigationEventRouter*
ExtensionWebNavigationEventRouter::GetInstance() {
@@ -51,8 +117,17 @@ void ExtensionWebNavigationEventRouter::Init() {
NotificationType::FRAME_PROVISIONAL_LOAD_COMMITTED,
NotificationService::AllSources());
registrar_.Add(this,
+ NotificationType::FRAME_DOM_CONTENT_LOADED,
+ NotificationService::AllSources());
+ registrar_.Add(this,
+ NotificationType::FRAME_DID_FINISH_LOAD,
+ NotificationService::AllSources());
+ registrar_.Add(this,
NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR,
NotificationService::AllSources());
+ registrar_.Add(this,
+ NotificationType::TAB_CONTENTS_DESTROYED,
+ NotificationService::AllSources());
}
}
@@ -71,12 +146,27 @@ void ExtensionWebNavigationEventRouter::Observe(
Source<NavigationController>(source).ptr(),
Details<ProvisionalLoadDetails>(details).ptr());
break;
+ case NotificationType::FRAME_DOM_CONTENT_LOADED:
+ FrameDomContentLoaded(
+ Source<NavigationController>(source).ptr(),
+ *Details<long long>(details).ptr());
+ break;
+ case NotificationType::FRAME_DID_FINISH_LOAD:
+ FrameDidFinishLoad(
+ Source<NavigationController>(source).ptr(),
+ *Details<long long>(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());
+ break;
+
default:
NOTREACHED();
}
@@ -84,6 +174,12 @@ void ExtensionWebNavigationEventRouter::Observe(
void ExtensionWebNavigationEventRouter::FrameProvisionalLoadStart(
NavigationController* controller,
ProvisionalLoadDetails* details) {
+ navigation_state_.TrackFrame(details->frame_id(),
+ details->url(),
+ details->main_frame(),
+ controller->tab_contents());
+ if (!navigation_state_.CanSendEvents(details->frame_id()))
+ return;
ListValue args;
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger(keys::kTabIdKey,
@@ -103,6 +199,8 @@ void ExtensionWebNavigationEventRouter::FrameProvisionalLoadStart(
void ExtensionWebNavigationEventRouter::FrameProvisionalLoadCommitted(
NavigationController* controller,
ProvisionalLoadDetails* details) {
+ if (!navigation_state_.CanSendEvents(details->frame_id()))
+ return;
ListValue args;
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger(keys::kTabIdKey,
@@ -124,9 +222,49 @@ void ExtensionWebNavigationEventRouter::FrameProvisionalLoadCommitted(
DispatchEvent(controller->profile(), keys::kOnCommitted, json_args);
}
+void ExtensionWebNavigationEventRouter::FrameDomContentLoaded(
+ NavigationController* controller, long long frame_id) {
+ if (!navigation_state_.CanSendEvents(frame_id))
+ return;
+ ListValue args;
+ DictionaryValue* dict = new DictionaryValue();
+ 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->SetReal(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
+ args.Append(dict);
+
+ std::string json_args;
+ base::JSONWriter::Write(&args, false, &json_args);
+ DispatchEvent(controller->profile(), keys::kOnDOMContentLoaded, json_args);
+}
+
+void ExtensionWebNavigationEventRouter::FrameDidFinishLoad(
+ NavigationController* controller, long long frame_id) {
+ if (!navigation_state_.CanSendEvents(frame_id))
+ return;
+ ListValue args;
+ DictionaryValue* dict = new DictionaryValue();
+ 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->SetReal(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
+ args.Append(dict);
+
+ std::string json_args;
+ base::JSONWriter::Write(&args, false, &json_args);
+ DispatchEvent(controller->profile(), keys::kOnCompleted, json_args);
+}
+
void ExtensionWebNavigationEventRouter::FailProvisionalLoadWithError(
NavigationController* controller,
ProvisionalLoadDetails* details) {
+ if (!navigation_state_.CanSendEvents(details->frame_id()))
+ return;
ListValue args;
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger(keys::kTabIdKey,
@@ -141,6 +279,7 @@ void ExtensionWebNavigationEventRouter::FailProvisionalLoadWithError(
std::string json_args;
base::JSONWriter::Write(&args, false, &json_args);
+ navigation_state_.ErrorOccurredInFrame(details->frame_id());
DispatchEvent(controller->profile(), keys::kOnErrorOccurred, json_args);
}
diff --git a/chrome/browser/extensions/extension_webnavigation_api.h b/chrome/browser/extensions/extension_webnavigation_api.h
index 21cfb16..b595aca 100644
--- a/chrome/browser/extensions/extension_webnavigation_api.h
+++ b/chrome/browser/extensions/extension_webnavigation_api.h
@@ -22,6 +22,53 @@ class NavigationController;
class ProvisionalLoadDetails;
class TabContents;
+// Tracks which frames are in an error state, and no navigation events should
+// be sent for.
+class FrameNavigationState {
+ public:
+ FrameNavigationState();
+ ~FrameNavigationState();
+
+ // True if navigation events for the given frame can be sent.
+ bool CanSendEvents(long long 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,
+ const GURL& url,
+ bool is_main_frame,
+ const TabContents* tab_contents);
+
+ // Returns the URL corresponding to a tracked frame given by its |frame_id|.
+ GURL GetUrl(long long 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;
+
+ // Marks a frame as in an error state.
+ void ErrorOccurredInFrame(long long 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;
+ 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;
+
+ // Tracks which frames belong to a given tab contents object.
+ TabContentsToFrameIdMap tab_contents_map_;
+
+ // Tracks the state of known frames.
+ FrameIdToStateMap frame_state_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameNavigationState);
+};
+
// Observes navigation notifications and routes them as events to the extension
// system.
class ExtensionWebNavigationEventRouter : public NotificationObserver {
@@ -54,6 +101,15 @@ class ExtensionWebNavigationEventRouter : public NotificationObserver {
void FrameProvisionalLoadCommitted(NavigationController* controller,
ProvisionalLoadDetails* details);
+ // 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);
+
+ // 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);
+
// Handler for the FAIL_PROVISIONAL_LOAD_WITH_ERROR event. The method takes
// the details of such an event and constructs a suitable JSON formatted
// extension event from it.
@@ -65,6 +121,9 @@ class ExtensionWebNavigationEventRouter : public NotificationObserver {
const char* event_name,
const std::string& json_args);
+ // Tracks the state of the frames we are sending events for.
+ FrameNavigationState navigation_state_;
+
// Used for tracking registrations to navigation notifications.
NotificationRegistrar registrar_;
diff --git a/chrome/browser/extensions/extension_webnavigation_apitest.cc b/chrome/browser/extensions/extension_webnavigation_apitest.cc
index 5dd3f3e..b27887b 100644
--- a/chrome/browser/extensions/extension_webnavigation_apitest.cc
+++ b/chrome/browser/extensions/extension_webnavigation_apitest.cc
@@ -13,10 +13,16 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigation) {
ASSERT_TRUE(RunExtensionTest("webnavigation/api")) << message_;
}
-// This test is flaky: http://crbug.com/60229
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_WebNavigationEvents) {
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationEvents1) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
- ASSERT_TRUE(RunExtensionTest("webnavigation/navigation")) << message_;
+ ASSERT_TRUE(RunExtensionTest("webnavigation/navigation1")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigationEvents2) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+
+ ASSERT_TRUE(RunExtensionTest("webnavigation/navigation2")) << message_;
}
diff --git a/chrome/browser/extensions/extension_webnavigation_unittest.cc b/chrome/browser/extensions/extension_webnavigation_unittest.cc
new file mode 100644
index 0000000..5ac378e
--- /dev/null
+++ b/chrome/browser/extensions/extension_webnavigation_unittest.cc
@@ -0,0 +1,105 @@
+// 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.
+
+// Tests common functionality used by the Chrome Extensions webNavigation API
+// implementation.
+
+#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 {
+};
+
+// Test that a frame is correctly tracked, and removed once the tab contents
+// goes away.
+TEST_F(FrameNavigationStateTest, TrackFrame) {
+ FrameNavigationState navigation_state;
+ const long long frame_id1 = 23;
+ const long long 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());
+ 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());
+ EXPECT_TRUE(navigation_state.CanSendEvents(frame_id2));
+
+ // Check frame state.
+ EXPECT_TRUE(navigation_state.IsMainFrame(frame_id1));
+ EXPECT_EQ(url1, navigation_state.GetUrl(frame_id1));
+ EXPECT_FALSE(navigation_state.IsMainFrame(frame_id2));
+ EXPECT_EQ(url2, navigation_state.GetUrl(frame_id2));
+
+
+ // Removing the tab contents should also remove all state of its frames.
+ navigation_state.RemoveTabContentsState(contents());
+ EXPECT_FALSE(navigation_state.CanSendEvents(frame_id1));
+ EXPECT_FALSE(navigation_state.CanSendEvents(frame_id2));
+}
+
+// Test that no events can be sent for a frame after an error occurred, but
+// before a new navigation happened in this frame.
+TEST_F(FrameNavigationStateTest, ErrorState) {
+ FrameNavigationState navigation_state;
+ const long long frame_id = 42;
+ const GURL url("http://www.google.com/");
+
+ navigation_state.TrackFrame(frame_id, url, true, 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());
+ 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());
+ EXPECT_TRUE(navigation_state.CanSendEvents(frame_id));
+}
+
+// Tests that for a sub frame, no events are send after an error occurred, but
+// 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 GURL url("http://www.google.com/");
+
+ navigation_state.TrackFrame(frame_id1, url, true, contents());
+ navigation_state.TrackFrame(frame_id2, url, false, contents());
+ EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1));
+ EXPECT_TRUE(navigation_state.CanSendEvents(frame_id2));
+
+ // After an error occurred, no further events should be sent.
+ navigation_state.ErrorOccurredInFrame(frame_id2);
+ 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());
+ 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());
+ 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 bf965a3..092d395 100644
--- a/chrome/browser/extensions/extension_webstore_private_api.cc
+++ b/chrome/browser/extensions/extension_webstore_private_api.cc
@@ -7,25 +7,33 @@
#include <string>
#include <vector>
+#include "app/l10n_util.h"
#include "base/string_util.h"
#include "base/values.h"
#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/net/gaia/token_service.h"
+#include "chrome/browser/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
#include "net/base/escape.h"
namespace {
const char* install_base_url = extension_urls::kGalleryUpdateHttpsUrl;
-const char kAlreadyLoggedInError[] = "User already logged in";
const char kLoginKey[] = "login";
const char kTokenKey[] = "token";
ProfileSyncService* test_sync_service = NULL;
+BrowserSignin* test_signin = NULL;
// Returns either the test sync service, or the real one from |profile|.
ProfileSyncService* GetSyncService(Profile* profile) {
@@ -35,13 +43,46 @@ ProfileSyncService* GetSyncService(Profile* profile) {
return profile->GetProfileSyncService();
}
+BrowserSignin* GetBrowserSignin(Profile* profile) {
+ if (test_signin)
+ return test_signin;
+ else
+ return profile->GetBrowserSignin();
+}
+
bool IsWebStoreURL(Profile* profile, const GURL& url) {
ExtensionsService* service = profile->GetExtensionsService();
- Extension* store = service->GetWebStoreApp();
+ const Extension* store = service->GetWebStoreApp();
DCHECK(store);
return (service->GetExtensionByWebExtent(url) == store);
}
+// Helper to create a dictionary with login and token properties set from
+// the appropriate values in the passed-in |profile|.
+DictionaryValue* CreateLoginResult(Profile* profile) {
+ DictionaryValue* dictionary = new DictionaryValue();
+ std::string username = GetBrowserSignin(profile)->GetSignedInUsername();
+ dictionary->SetString(kLoginKey, username);
+ if (!username.empty()) {
+ TokenService* token_service = profile->GetTokenService();
+ if (token_service->HasTokenForService(GaiaConstants::kGaiaService)) {
+ dictionary->SetString(kTokenKey,
+ token_service->GetTokenForService(
+ GaiaConstants::kGaiaService));
+ }
+ }
+ return dictionary;
+}
+
+// If |profile| is not off the record, returns it. Otherwise returns the real
+// (not off the record) default profile.
+Profile* GetDefaultProfile(Profile* profile) {
+ if (!profile->IsOffTheRecord())
+ return profile;
+ else
+ return g_browser_process->profile_manager()->GetDefaultProfile();
+}
+
} // namespace
// static
@@ -51,6 +92,11 @@ void WebstorePrivateApi::SetTestingProfileSyncService(
}
// static
+void WebstorePrivateApi::SetTestingBrowserSignin(BrowserSignin* signin) {
+ test_signin = signin;
+}
+
+// static
void InstallFunction::SetTestingInstallBaseUrl(
const char* testing_install_base_url) {
install_base_url = testing_install_base_url;
@@ -92,13 +138,7 @@ bool InstallFunction::RunImpl() {
bool GetBrowserLoginFunction::RunImpl() {
if (!IsWebStoreURL(profile_, source_url()))
return false;
- string16 username = GetSyncService(profile_)->GetAuthenticatedUsername();
- DictionaryValue* dictionary = new DictionaryValue();
-
- dictionary->SetString(kLoginKey, username);
- // TODO(asargent) - send the browser login token here too if available.
-
- result_.reset(dictionary);
+ result_.reset(CreateLoginResult(GetDefaultProfile(profile_)));
return true;
}
@@ -127,50 +167,118 @@ bool SetStoreLoginFunction::RunImpl() {
return true;
}
-PromptBrowserLoginFunction::~PromptBrowserLoginFunction() {}
+PromptBrowserLoginFunction::PromptBrowserLoginFunction()
+ : waiting_for_token_(false) {}
+
+PromptBrowserLoginFunction::~PromptBrowserLoginFunction() {
+}
bool PromptBrowserLoginFunction::RunImpl() {
if (!IsWebStoreURL(profile_, source_url()))
return false;
std::string preferred_email;
- ProfileSyncService* sync_service = GetSyncService(profile_);
if (args_->GetSize() > 0) {
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &preferred_email));
- if (!sync_service->GetAuthenticatedUsername().empty()) {
- error_ = kAlreadyLoggedInError;
- return false;
- }
}
+ Profile* profile = GetDefaultProfile(profile_);
+
+ // Login can currently only be invoked tab-modal. Since this is
+ // coming from the webstore, we should always have a tab, but check
+ // just in case.
+ TabContents* tab = dispatcher()->delegate()->associated_tab_contents();
+ if (!tab)
+ return false;
+
// We return the result asynchronously, so we addref to keep ourself alive.
- // Matched with a Release in OnStateChanged().
+ // Matched with a Release in OnLoginSuccess() and OnLoginFailure().
AddRef();
- sync_service->AddObserver(this);
- // TODO(mirandac/estade) - make use of |preferred_email| to pre-populate the
- // browser login dialog if it was set to non-empty above.
- sync_service->ShowLoginDialog(NULL);
-
- // The response will be sent asynchronously in OnStateChanged().
+ // Start listening for notifications about the token.
+ TokenService* token_service = profile->GetTokenService();
+ registrar_.Add(this,
+ NotificationType::TOKEN_AVAILABLE,
+ Source<TokenService>(token_service));
+ registrar_.Add(this,
+ NotificationType::TOKEN_REQUEST_FAILED,
+ Source<TokenService>(token_service));
+
+ GetBrowserSignin(profile)->RequestSignin(tab,
+ ASCIIToUTF16(preferred_email),
+ GetLoginMessage(),
+ this);
+
+ // The response will be sent asynchronously in OnLoginSuccess/OnLoginFailure.
return true;
}
-void PromptBrowserLoginFunction::OnStateChanged() {
- ProfileSyncService* sync_service = GetSyncService(profile_);
- // If the setup is finished, we'll report back what happened.
- if (!sync_service->SetupInProgress()) {
- sync_service->RemoveObserver(this);
- DictionaryValue* dictionary = new DictionaryValue();
+string16 PromptBrowserLoginFunction::GetLoginMessage() {
+ using l10n_util::GetStringUTF16;
+ using l10n_util::GetStringFUTF16;
+
+ // TODO(johnnyg): This would be cleaner as an HTML template.
+ // http://crbug.com/60216
+ string16 message;
+ message = ASCIIToUTF16("<p>")
+ + GetStringUTF16(IDS_WEB_STORE_LOGIN_INTRODUCTION_1)
+ + ASCIIToUTF16("</p>");
+ message = message + ASCIIToUTF16("<p>")
+ + GetStringFUTF16(IDS_WEB_STORE_LOGIN_INTRODUCTION_2,
+ GetStringUTF16(IDS_PRODUCT_NAME))
+ + ASCIIToUTF16("</p>");
+ return message;
+}
- // TODO(asargent) - send the browser login token here too if available.
- string16 username = sync_service->GetAuthenticatedUsername();
- dictionary->SetString(kLoginKey, username);
+void PromptBrowserLoginFunction::OnLoginSuccess() {
+ // Ensure that apps are synced.
+ // - If the user has already setup sync, we add Apps to the current types.
+ // - If not, we create a new set which is just Apps.
+ ProfileSyncService* service = GetSyncService(GetDefaultProfile(profile_));
+ syncable::ModelTypeSet types;
+ if (service->HasSyncSetupCompleted())
+ service->GetPreferredDataTypes(&types);
+ types.insert(syncable::APPS);
+ service->ChangePreferredDataTypes(types);
+ service->SetSyncSetupCompleted();
+
+ // We'll finish up in Observe() when the token is ready.
+ waiting_for_token_ = true;
+}
+
+void PromptBrowserLoginFunction::OnLoginFailure(
+ const GoogleServiceAuthError& error) {
+ SendResponse(false);
+ // Matches the AddRef in RunImpl().
+ Release();
+}
- result_.reset(dictionary);
- SendResponse(true);
+void PromptBrowserLoginFunction::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ // Make sure this notification is for the service we are interested in.
+ std::string service;
+ if (type == NotificationType::TOKEN_AVAILABLE) {
+ TokenService::TokenAvailableDetails* available =
+ Details<TokenService::TokenAvailableDetails>(details).ptr();
+ service = available->service();
+ } else if (type == NotificationType::TOKEN_REQUEST_FAILED) {
+ TokenService::TokenRequestFailedDetails* failed =
+ Details<TokenService::TokenRequestFailedDetails>(details).ptr();
+ service = failed->service();
+ } else {
+ NOTREACHED();
+ }
- // Matches the AddRef in RunImpl().
- Release();
+ if (service != GaiaConstants::kGaiaService) {
+ return;
}
+
+ DCHECK(waiting_for_token_);
+
+ result_.reset(CreateLoginResult(GetDefaultProfile(profile_)));
+ SendResponse(true);
+
+ // Matches the AddRef in RunImpl().
+ Release();
}
diff --git a/chrome/browser/extensions/extension_webstore_private_api.h b/chrome/browser/extensions/extension_webstore_private_api.h
index a47ba2a..39d883c 100644
--- a/chrome/browser/extensions/extension_webstore_private_api.h
+++ b/chrome/browser/extensions/extension_webstore_private_api.h
@@ -6,8 +6,11 @@
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_WEBSTORE_PRIVATE_API_H_
#pragma once
+#include "chrome/browser/browser_signin.h"
#include "chrome/browser/extensions/extension_function.h"
-#include "chrome/browser/sync/profile_sync_service_observer.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
class ProfileSyncService;
@@ -16,6 +19,10 @@ class WebstorePrivateApi {
// Allows you to set the ProfileSyncService the function will use for
// testing purposes.
static void SetTestingProfileSyncService(ProfileSyncService* service);
+
+ // Allows you to set the BrowserSignin the function will use for
+ // testing purposes.
+ static void SetTestingBrowserSignin(BrowserSignin* signin);
};
class InstallFunction : public SyncExtensionFunction {
@@ -44,15 +51,33 @@ class SetStoreLoginFunction : public SyncExtensionFunction {
};
class PromptBrowserLoginFunction : public AsyncExtensionFunction,
- public ProfileSyncServiceObserver {
+ public NotificationObserver,
+ public BrowserSignin::SigninDelegate {
public:
- // Implements ProfileSyncServiceObserver interface.
- virtual void OnStateChanged();
+ PromptBrowserLoginFunction();
+ // Implements BrowserSignin::SigninDelegate interface.
+ virtual void OnLoginSuccess();
+ virtual void OnLoginFailure(const GoogleServiceAuthError& error);
+
+ // Implements the NotificationObserver interface.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
protected:
virtual ~PromptBrowserLoginFunction();
virtual bool RunImpl();
+ private:
+ // Creates the message for signing in.
+ virtual string16 GetLoginMessage();
+
+ // Are we waiting for a token available notification?
+ bool waiting_for_token_;
+
+ // Used for listening for TokenService notifications.
+ NotificationRegistrar registrar_;
+
DECLARE_EXTENSION_FUNCTION_NAME("webstorePrivate.promptBrowserLogin");
};
diff --git a/chrome/browser/extensions/extension_webstore_private_browsertest.cc b/chrome/browser/extensions/extension_webstore_private_browsertest.cc
index db9a027..01b8e45 100644
--- a/chrome/browser/extensions/extension_webstore_private_browsertest.cc
+++ b/chrome/browser/extensions/extension_webstore_private_browsertest.cc
@@ -4,11 +4,17 @@
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_signin.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#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/sync/profile_sync_service.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"
#include "googleurl/src/gurl.h"
@@ -26,43 +32,75 @@ const char kTestUrlHostname[] = "www.example.com";
// A fake version of ProfileSyncService used for testing.
class FakeProfileSyncService : public ProfileSyncService {
public:
- // The |username_after_login| parameter determines what this fake
- // ProfileSyncService will set the username to when ShowLoginDialog is called.
- FakeProfileSyncService(const std::string& initial_username,
- const std::string& username_after_login) :
- username_(ASCIIToUTF16(initial_username)),
- username_after_login_(username_after_login),
- observer_(NULL) {}
-
- virtual ~FakeProfileSyncService() {
- EXPECT_TRUE(observer_ == NULL);
+ FakeProfileSyncService()
+ : setup_(false) {
}
+ virtual ~FakeProfileSyncService() {}
// Overrides of virtual methods in ProfileSyncService.
- virtual string16 GetAuthenticatedUsername() const {
- return username_;
+ virtual bool HasSyncSetupCompleted() const {
+ return setup_;
}
- virtual void ShowLoginDialog(gfx::NativeWindow) {
- EXPECT_TRUE(observer_ != NULL);
- username_ = ASCIIToUTF16(username_after_login_);
- observer_->OnStateChanged();
+ virtual void ChangePreferredDataTypes(const syncable::ModelTypeSet& types) {
+ types_ = types;
}
- virtual bool SetupInProgress() const {
- return false;
+ virtual void GetPreferredDataTypes(syncable::ModelTypeSet* types) const {
+ *types = types_;
}
- virtual void AddObserver(ProfileSyncServiceObserver* observer) {
- EXPECT_TRUE(observer_ == NULL);
- observer_ = observer;
+ virtual void SetSyncSetupCompleted() {
+ setup_ = true;
}
- virtual void RemoveObserver(ProfileSyncServiceObserver* observer) {
- EXPECT_TRUE(observer == observer_);
- observer_ = NULL;
+
+ private:
+ bool setup_;
+ syncable::ModelTypeSet types_;
+};
+
+class FakeBrowserSignin : public BrowserSignin {
+ public:
+ // The |username_after_login| parameter determines what this fake
+ // BrowserSignin will set the username to when ShowLoginDialog is called.
+ FakeBrowserSignin(bool should_succeed,
+ const std::string& initial_username,
+ const std::string& username_after_login)
+ : BrowserSignin(NULL),
+ should_succeed_(should_succeed),
+ username_(initial_username),
+ username_after_login_(username_after_login) {
+ }
+ virtual ~FakeBrowserSignin() {}
+
+ virtual std::string GetSignedInUsername() const {
+ return username_;
+ }
+
+ virtual void RequestSignin(TabContents* tab_contents,
+ const string16& preferred_email,
+ const string16& message,
+ SigninDelegate* delegate) {
+ if (should_succeed_) {
+ // Simulate valid login.
+ username_ = username_after_login_;
+ delegate->OnLoginSuccess();
+
+ // Fake a token available notification.
+ Profile* profile = tab_contents->profile();
+ if (profile->IsOffTheRecord()) {
+ profile = g_browser_process->profile_manager()->GetDefaultProfile();
+ }
+ TokenService* token_service = profile->GetTokenService();
+ token_service->IssueAuthTokenForTest(GaiaConstants::kGaiaService,
+ "new_token");
+ } else {
+ delegate->OnLoginFailure(GoogleServiceAuthError(
+ GoogleServiceAuthError::REQUEST_CANCELED));
+ }
}
private:
- string16 username_;
+ bool should_succeed_;
+ std::string username_;
std::string username_after_login_;
- ProfileSyncServiceObserver* observer_;
};
class ExtensionWebstorePrivateBrowserTest : public ExtensionBrowserTest {
@@ -90,18 +128,54 @@ class ExtensionWebstorePrivateBrowserTest : public ExtensionBrowserTest {
return base_url.ReplaceComponents(replacements);
}
- void RunLoginTest(const std::string& relative_path,
- const std::string& initial_login,
- const std::string& login_result) {
- FakeProfileSyncService sync_service(initial_login, login_result);
+ void RunLoginTestImpl(bool incognito,
+ const std::string& relative_path,
+ const std::string& initial_login,
+ bool login_succeeds,
+ const std::string& login_result) {
+ // Clear the token service so previous tests don't affect things.
+ TokenService* token_service = browser()->profile()->GetTokenService();
+ token_service->ResetCredentialsInMemory();
+ if (!initial_login.empty()) {
+ // Initialize the token service with an existing token.
+ token_service->IssueAuthTokenForTest(GaiaConstants::kGaiaService,
+ "existing_token");
+ }
+
+ FakeProfileSyncService sync_service;
+ FakeBrowserSignin signin(login_succeeds, initial_login, login_result);
WebstorePrivateApi::SetTestingProfileSyncService(&sync_service);
+ WebstorePrivateApi::SetTestingBrowserSignin(&signin);
+
ExtensionTestMessageListener listener("success", false);
GURL url = GetUrl(relative_path);
- ui_test_utils::NavigateToURL(browser(), url);
+ if (incognito) {
+ ui_test_utils::OpenURLOffTheRecord(browser()->profile(), url);
+ } else {
+ ui_test_utils::NavigateToURL(browser(), url);
+ }
EXPECT_TRUE(listener.WaitUntilSatisfied());
+
+ WebstorePrivateApi::SetTestingBrowserSignin(NULL);
WebstorePrivateApi::SetTestingProfileSyncService(NULL);
}
+ void RunLoginTest(const std::string& relative_path,
+ const std::string& initial_login,
+ bool login_succeeds,
+ const std::string& login_result) {
+ RunLoginTestImpl(true,
+ relative_path,
+ initial_login,
+ login_succeeds,
+ login_result);
+ RunLoginTestImpl(false,
+ relative_path,
+ initial_login,
+ login_succeeds,
+ login_result);
+ }
+
protected:
std::string test_url_base_;
};
@@ -110,10 +184,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateBrowserTest, BrowserLogin) {
host_resolver()->AddRule(kTestUrlHostname, "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
- RunLoginTest("browser_login/expect_nonempty.html", "foo@bar.com", "");
- RunLoginTest("browser_login/prompt_no_preferred.html", "", "");
- RunLoginTest("browser_login/prompt_preferred.html", "", "foo@bar.com");
- RunLoginTest("browser_login/prompt_already_logged_in_error.html",
- "foo@bar.com",
- "foo@bar.com");
+ RunLoginTest("browser_login/expect_nonempty.html",
+ "foo@bar.com", false, "");
+
+ RunLoginTest("browser_login/prompt_no_preferred.html", "", true, "");
+
+ RunLoginTest("browser_login/prompt_preferred.html", "", true, "foo@bar.com");
+
+ RunLoginTest("browser_login/prompt_login_fails.html",
+ "", false, "foo@bar.com");
}
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index 33fade0..4227333 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -39,6 +39,7 @@
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/extensions/extension_webnavigation_api.h"
#include "chrome/browser/extensions/external_extension_provider.h"
+#include "chrome/browser/extensions/external_policy_extension_provider.h"
#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"
@@ -94,7 +95,7 @@ bool ShouldReloadExtensionManifest(const ExtensionInfo& info) {
return extension_l10n_util::ShouldRelocalizeManifest(info);
}
-void GetExplicitOriginsInExtent(Extension* extension,
+void GetExplicitOriginsInExtent(const Extension* extension,
std::vector<GURL>* origins) {
typedef std::vector<URLPattern> PatternList;
std::set<GURL> set;
@@ -150,6 +151,15 @@ PendingExtensionInfo::PendingExtensionInfo()
enable_incognito_on_install(false),
install_source(Extension::INVALID) {}
+
+ExtensionsService::ExtensionRuntimeData::ExtensionRuntimeData()
+ : background_page_ready(false),
+ being_upgraded(false) {
+}
+
+ExtensionsService::ExtensionRuntimeData::~ExtensionRuntimeData() {
+}
+
// ExtensionsService.
const char* ExtensionsService::kInstallDirectoryName = "Extensions";
@@ -164,7 +174,8 @@ class ExtensionsServiceBackend
// |install_directory| is a path where to look for extensions to load.
// |load_external_extensions| indicates whether or not backend should load
// external extensions listed in JSON file and Windows registry.
- ExtensionsServiceBackend(const FilePath& install_directory,
+ ExtensionsServiceBackend(PrefService* prefs,
+ const FilePath& install_directory,
bool load_external_extensions);
// Loads a single extension from |path| where |path| is the top directory of
@@ -179,22 +190,20 @@ class ExtensionsServiceBackend
// Check externally updated extensions for updates and install if necessary.
// Errors are reported through ExtensionErrorReporter. Succcess is not
// reported.
- void CheckForExternalUpdates(std::set<std::string> ids_to_ignore,
+ void CheckForExternalUpdates(const std::set<std::string>& ids_to_ignore,
scoped_refptr<ExtensionsService> 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,
- const std::string& id,
- Extension::Location location);
+ const std::string& id);
// Clear all ExternalExtensionProviders.
void ClearProvidersForTesting();
- // Sets an ExternalExtensionProvider for the service to use during testing.
- // |location| specifies what type of provider should be added.
- void SetProviderForTesting(Extension::Location location,
- ExternalExtensionProvider* test_provider);
+ // Adds an ExternalExtensionProvider for the service to use during testing.
+ // Takes ownership of |test_provider|.
+ void AddProviderForTesting(ExternalExtensionProvider* test_provider);
// ExternalExtensionProvider::Visitor implementation.
virtual void OnExternalExtensionFileFound(const std::string& id,
@@ -203,7 +212,8 @@ class ExtensionsServiceBackend
Extension::Location location);
virtual void OnExternalExtensionUpdateUrlFound(const std::string& id,
- const GURL& update_url);
+ const GURL& update_url,
+ Extension::Location location);
// Reloads the given extensions from their manifests on disk (instead of what
// we have cached in the prefs).
@@ -226,23 +236,13 @@ class ExtensionsServiceBackend
// Note: We take ownership of |extension|.
void OnExtensionUnpacked(const FilePath& crx_path,
const FilePath& unpacked_path,
- Extension* extension,
+ const Extension* extension,
const std::string expected_id);
// Notify the frontend that there was an error loading an extension.
void ReportExtensionLoadError(const FilePath& extension_path,
const std::string& error);
- // Lookup an external extension by |id| by going through all registered
- // external extension providers until we find a provider that contains an
- // extension that matches. If |version| is not NULL, the extension version
- // will be returned (caller is responsible for deleting that pointer).
- // |location| can also be null, if not needed. Returns true if extension is
- // found, false otherwise.
- bool LookupExternalExtension(const std::string& id,
- Version** version,
- Extension::Location* location);
-
// This is a naked pointer which is set by each entry point.
// The entry point is responsible for ensuring lifetime.
ExtensionsService* frontend_;
@@ -253,12 +253,12 @@ class ExtensionsServiceBackend
// Whether errors result in noisy alerts.
bool alert_on_error_;
- // A map from external extension type to the external extension provider
- // for that type. Because a single provider may handle more than one
- // external extension type, more than one key may map to the same object.
- typedef std::map<Extension::Location,
- linked_ptr<ExternalExtensionProvider> > ProviderMap;
- ProviderMap external_extension_providers_;
+ // A collection of external extension providers. Each provider reads
+ // a source of external extension information. Examples include the
+ // windows registry and external_extensions.json.
+ typedef std::vector<linked_ptr<ExternalExtensionProvider> >
+ ProviderCollection;
+ ProviderCollection external_extension_providers_;
// Set to true by OnExternalExtensionUpdateUrlFound() when an external
// extension URL is found. Used in CheckForExternalUpdates() to see
@@ -269,6 +269,7 @@ class ExtensionsServiceBackend
};
ExtensionsServiceBackend::ExtensionsServiceBackend(
+ PrefService* prefs,
const FilePath& install_directory,
bool load_external_extensions)
: frontend_(NULL),
@@ -281,18 +282,20 @@ ExtensionsServiceBackend::ExtensionsServiceBackend(
// TODO(aa): This ends up doing blocking IO on the UI thread because it reads
// pref data in the ctor and that is called on the UI thread. Would be better
// to re-read data each time we list external extensions, anyway.
- external_extension_providers_[Extension::EXTERNAL_PREF] =
+ external_extension_providers_.push_back(
linked_ptr<ExternalExtensionProvider>(
- new ExternalPrefExtensionProvider());
- // EXTERNAL_PREF_DOWNLOAD and EXTERNAL_PREF extensions are handled by the
- // same object.
- external_extension_providers_[Extension::EXTERNAL_PREF_DOWNLOAD] =
- external_extension_providers_[Extension::EXTERNAL_PREF];
+ new ExternalPrefExtensionProvider()));
#if defined(OS_WIN)
- external_extension_providers_[Extension::EXTERNAL_REGISTRY] =
+ external_extension_providers_.push_back(
linked_ptr<ExternalExtensionProvider>(
- new ExternalRegistryExtensionProvider());
+ new ExternalRegistryExtensionProvider()));
#endif
+ ExternalPolicyExtensionProvider* policy_extension_provider =
+ new ExternalPolicyExtensionProvider();
+ policy_extension_provider->SetPreferences(prefs);
+ external_extension_providers_.push_back(
+ linked_ptr<ExternalExtensionProvider>(policy_extension_provider));
+
}
ExtensionsServiceBackend::~ExtensionsServiceBackend() {
@@ -300,6 +303,8 @@ ExtensionsServiceBackend::~ExtensionsServiceBackend() {
void ExtensionsServiceBackend::LoadSingleExtension(
const FilePath& path_in, scoped_refptr<ExtensionsService> frontend) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
frontend_ = frontend;
// Explicit UI loads are always noisy.
@@ -309,11 +314,11 @@ void ExtensionsServiceBackend::LoadSingleExtension(
file_util::AbsolutePath(&extension_path);
std::string error;
- Extension* extension = extension_file_util::LoadExtension(
+ scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
extension_path,
Extension::LOAD,
false, // Don't require id
- &error);
+ &error));
if (!extension) {
ReportExtensionLoadError(extension_path, error);
@@ -330,6 +335,7 @@ void ExtensionsServiceBackend::LoadSingleExtension(
void ExtensionsServiceBackend::ReportExtensionLoadError(
const FilePath& extension_path, const std::string &error) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableMethod(
@@ -338,22 +344,6 @@ void ExtensionsServiceBackend::ReportExtensionLoadError(
error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_));
}
-bool ExtensionsServiceBackend::LookupExternalExtension(
- const std::string& id, Version** version, Extension::Location* location) {
- scoped_ptr<Version> extension_version;
- for (ProviderMap::const_iterator i = external_extension_providers_.begin();
- i != external_extension_providers_.end(); ++i) {
- const ExternalExtensionProvider* provider = i->second.get();
- extension_version.reset(provider->RegisteredVersion(id, location));
- if (extension_version.get()) {
- if (version)
- *version = extension_version.release();
- return true;
- }
- }
- return false;
-}
-
// Some extensions will autoupdate themselves externally from Chrome. These
// are typically part of some larger client application package. To support
// these, the extension will register its location in the the preferences file
@@ -361,8 +351,10 @@ bool ExtensionsServiceBackend::LookupExternalExtension(
// check that location for a .crx file, which it will then install locally if
// a new version is available.
void ExtensionsServiceBackend::CheckForExternalUpdates(
- std::set<std::string> ids_to_ignore,
+ const std::set<std::string>& ids_to_ignore,
scoped_refptr<ExtensionsService> frontend) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
// Note that this installation is intentionally silent (since it didn't
// go through the front-end). Extensions that are registered in this
// way are effectively considered 'pre-bundled', and so implicitly
@@ -374,10 +366,10 @@ void ExtensionsServiceBackend::CheckForExternalUpdates(
// Ask each external extension provider to give us a call back for each
// extension they know about. See OnExternalExtension(File|UpdateUrl)Found.
-
- for (ProviderMap::const_iterator i = external_extension_providers_.begin();
+ ProviderCollection::const_iterator i;
+ for (i = external_extension_providers_.begin();
i != external_extension_providers_.end(); ++i) {
- ExternalExtensionProvider* provider = i->second.get();
+ ExternalExtensionProvider* provider = i->get();
provider->VisitRegisteredExtension(this, ids_to_ignore);
}
@@ -390,21 +382,17 @@ void ExtensionsServiceBackend::CheckForExternalUpdates(
}
void ExtensionsServiceBackend::CheckExternalUninstall(
- scoped_refptr<ExtensionsService> frontend, const std::string& id,
- Extension::Location location) {
+ scoped_refptr<ExtensionsService> frontend, const std::string& id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
// Check if the providers know about this extension.
- ProviderMap::const_iterator i = external_extension_providers_.find(location);
- if (i == external_extension_providers_.end()) {
- NOTREACHED() << "CheckExternalUninstall called for non-external extension "
- << location;
- return;
+ ProviderCollection::const_iterator i;
+ for (i = external_extension_providers_.begin();
+ i != external_extension_providers_.end(); ++i) {
+ if (i->get()->HasExtension(id))
+ return; // Yup, known extension, don't uninstall.
}
- scoped_ptr<Version> version;
- version.reset(i->second->RegisteredVersion(id, NULL));
- if (version.get())
- return; // Yup, known extension, don't uninstall.
-
// This is an external extension that we don't have registered. Uninstall.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -416,17 +404,18 @@ void ExtensionsServiceBackend::ClearProvidersForTesting() {
external_extension_providers_.clear();
}
-void ExtensionsServiceBackend::SetProviderForTesting(
- Extension::Location location,
+void ExtensionsServiceBackend::AddProviderForTesting(
ExternalExtensionProvider* test_provider) {
DCHECK(test_provider);
- external_extension_providers_[location] =
- linked_ptr<ExternalExtensionProvider>(test_provider);
+ external_extension_providers_.push_back(
+ linked_ptr<ExternalExtensionProvider>(test_provider));
}
void ExtensionsServiceBackend::OnExternalExtensionFileFound(
const std::string& id, const Version* version, const FilePath& path,
Extension::Location location) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
DCHECK(version);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -437,13 +426,21 @@ void ExtensionsServiceBackend::OnExternalExtensionFileFound(
void ExtensionsServiceBackend::OnExternalExtensionUpdateUrlFound(
const std::string& id,
- const GURL& update_url) {
+ const GURL& update_url,
+ Extension::Location location) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
if (frontend_->GetExtensionById(id, true)) {
// Already installed. Do not change the update URL that the extension set.
return;
}
- frontend_->AddPendingExtensionFromExternalUpdateUrl(id, update_url);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend_,
+ &ExtensionsService::AddPendingExtensionFromExternalUpdateUrl,
+ id, update_url, location));
external_extension_added_ |= true;
}
@@ -451,6 +448,8 @@ void ExtensionsServiceBackend::ReloadExtensionManifests(
ExtensionPrefs::ExtensionsInfo* extensions_to_reload,
base::TimeTicks start_time,
scoped_refptr<ExtensionsService> frontend) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
frontend_ = frontend;
for (size_t i = 0; i < extensions_to_reload->size(); ++i) {
@@ -460,7 +459,7 @@ void ExtensionsServiceBackend::ReloadExtensionManifests(
// We need to reload original manifest in order to localize properly.
std::string error;
- scoped_ptr<Extension> extension(extension_file_util::LoadExtension(
+ scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
info->extension_path, info->extension_location, false, &error));
if (extension.get())
@@ -490,9 +489,9 @@ bool ExtensionsService::IsDownloadFromGallery(const GURL& download_url,
return true;
}
- Extension* download_extension = GetExtensionByWebExtent(download_url);
- Extension* referrer_extension = GetExtensionByWebExtent(referrer_url);
- Extension* webstore_app = GetWebStoreApp();
+ const Extension* download_extension = GetExtensionByWebExtent(download_url);
+ const Extension* referrer_extension = GetExtensionByWebExtent(referrer_url);
+ const Extension* webstore_app = GetWebStoreApp();
bool referrer_valid = (referrer_extension == webstore_app);
bool download_valid = (download_extension == webstore_app);
@@ -547,7 +546,7 @@ bool ExtensionsService::UninstallExtensionHelper(
extensions_service->UninstallExtension(extension_id, false);
} else {
LOG(WARNING) << "Attempted uninstallation of non-existent extension with "
- << "extension with id: " << extension_id;
+ << "id: " << extension_id;
return false;
}
@@ -568,6 +567,8 @@ ExtensionsService::ExtensionsService(Profile* profile,
ALLOW_THIS_IN_INITIALIZER_LIST(toolbar_model_(this)),
default_apps_(profile->GetPrefs()),
event_routers_initialized_(false) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
// Figure out if extension installation should be enabled.
if (command_line->HasSwitch(switches::kDisableExtensions)) {
extensions_enabled_ = false;
@@ -594,7 +595,8 @@ ExtensionsService::ExtensionsService(Profile* profile,
update_frequency);
}
- backend_ = new ExtensionsServiceBackend(install_directory_,
+ backend_ = new ExtensionsServiceBackend(profile->GetPrefs(),
+ install_directory_,
extensions_enabled_);
// Use monochrome icons for Omnibox icons.
@@ -629,6 +631,8 @@ void ExtensionsService::InitEventRouters() {
}
void ExtensionsService::Init() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
DCHECK(!ready_);
DCHECK_EQ(extensions_.size(), 0u);
@@ -667,6 +671,8 @@ namespace {
void ExtensionsService::UpdateExtension(const std::string& id,
const FilePath& extension_path,
const GURL& download_url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
PendingExtensionMap::const_iterator it = pending_extensions_.find(id);
bool is_pending_extension = (it != pending_extensions_.end());
@@ -718,7 +724,8 @@ void ExtensionsService::AddPendingExtensionFromSync(
}
void ExtensionsService::AddPendingExtensionFromExternalUpdateUrl(
- const std::string& id, const GURL& update_url) {
+ 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;
@@ -736,7 +743,7 @@ void ExtensionsService::AddPendingExtensionFromExternalUpdateUrl(
AddPendingExtensionInternal(id, update_url, kExpectedCrxType, kIsFromSync,
kInstallSilently, kEnableOnInstall,
kEnableIncognitoOnInstall,
- Extension::EXTERNAL_PREF_DOWNLOAD);
+ location);
}
void ExtensionsService::AddPendingExtensionFromDefaultAppList(
@@ -766,6 +773,27 @@ void ExtensionsService::AddPendingExtensionInternal(
bool is_from_sync, bool install_silently,
bool enable_on_install, bool enable_incognito_on_install,
Extension::Location install_source) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // If a non-sync update is pending, a sync request should not
+ // overwrite it. This is important for external extensions.
+ // If an external extension download is pending, and the user has
+ // the extension in their sync profile, the install should set the
+ // type to be external. An external extension should not be
+ // rejected if it fails the safty checks for a syncable extension.
+ // TODO(skerner): Work out other potential overlapping conditions.
+ // (crbug/61000)
+ PendingExtensionMap::iterator it = pending_extensions_.find(id);
+ if (it != pending_extensions_.end()) {
+ VLOG(1) << "Extension id " << id
+ << " was entered for update more than once."
+ << " old is_from_sync = " << it->second.is_from_sync
+ << " new is_from_sync = " << is_from_sync;
+ if (!it->second.is_from_sync && is_from_sync)
+ return;
+ }
+
+
pending_extensions_[id] =
PendingExtensionInfo(update_url, expected_crx_type, is_from_sync,
install_silently, enable_on_install,
@@ -773,8 +801,9 @@ void ExtensionsService::AddPendingExtensionInternal(
}
void ExtensionsService::ReloadExtension(const std::string& extension_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
FilePath path;
- Extension* current_extension = GetExtensionById(extension_id, false);
+ const Extension* current_extension = GetExtensionById(extension_id, false);
// Disable the extension if it's loaded. It might not be loaded if it crashed.
if (current_extension) {
@@ -816,7 +845,10 @@ void ExtensionsService::ReloadExtension(const std::string& extension_id) {
void ExtensionsService::UninstallExtension(const std::string& extension_id,
bool external_uninstall) {
- Extension* extension = GetExtensionByIdInternal(extension_id, true, true);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ const Extension* extension =
+ GetExtensionByIdInternal(extension_id, true, true);
// Callers should not send us nonexistent extensions.
DCHECK(extension);
@@ -870,7 +902,10 @@ void ExtensionsService::ClearExtensionData(const GURL& extension_url) {
}
void ExtensionsService::EnableExtension(const std::string& extension_id) {
- Extension* extension = GetExtensionByIdInternal(extension_id, false, true);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ const Extension* extension =
+ GetExtensionByIdInternal(extension_id, false, true);
if (!extension) {
return;
}
@@ -878,7 +913,7 @@ void ExtensionsService::EnableExtension(const std::string& extension_id) {
extension_prefs_->SetExtensionState(extension, Extension::ENABLED);
// Move it over to the enabled list.
- extensions_.push_back(extension);
+ extensions_.push_back(make_scoped_refptr(extension));
ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
disabled_extensions_.end(),
extension);
@@ -892,7 +927,10 @@ void ExtensionsService::EnableExtension(const std::string& extension_id) {
}
void ExtensionsService::DisableExtension(const std::string& extension_id) {
- Extension* extension = GetExtensionByIdInternal(extension_id, true, false);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ const Extension* extension =
+ GetExtensionByIdInternal(extension_id, true, false);
// The extension may have been disabled already.
if (!extension)
return;
@@ -900,7 +938,7 @@ void ExtensionsService::DisableExtension(const std::string& extension_id) {
extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
// Move it over to the disabled list.
- disabled_extensions_.push_back(extension);
+ disabled_extensions_.push_back(make_scoped_refptr(extension));
ExtensionList::iterator iter = std::find(extensions_.begin(),
extensions_.end(),
extension);
@@ -933,20 +971,19 @@ void ExtensionsService::LoadComponentExtensions() {
continue;
}
- scoped_ptr<Extension> extension(new Extension(it->root_directory));
- extension->set_location(Extension::COMPONENT);
-
std::string error;
- if (!extension->InitFromValue(
- *static_cast<DictionaryValue*>(manifest.get()),
- true, // require key
- &error)) {
+ scoped_refptr<const Extension> extension(Extension::Create(
+ it->root_directory,
+ Extension::COMPONENT,
+ *static_cast<DictionaryValue*>(manifest.get()),
+ true, // require key
+ &error));
+ if (!extension.get()) {
NOTREACHED() << error;
return;
}
- OnExtensionLoaded(extension.release(), false); // Don't allow privilege
- // increase.
+ OnExtensionLoaded(extension, false); // Don't allow privilege increase.
}
}
@@ -1075,15 +1112,14 @@ void ExtensionsService::ContinueLoadAllExtensions(
void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info,
bool write_to_prefs) {
std::string error;
- Extension* extension = NULL;
+ scoped_refptr<const Extension> extension(NULL);
if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
error = errors::kDisabledByPolicy;
} else if (info.extension_manifest.get()) {
- scoped_ptr<Extension> tmp(new Extension(info.extension_path));
bool require_key = info.extension_location != Extension::LOAD;
- tmp->set_location(info.extension_location);
- if (tmp->InitFromValue(*info.extension_manifest, require_key, &error))
- extension = tmp.release();
+ extension = Extension::Create(
+ info.extension_path, info.extension_location, *info.extension_manifest,
+ require_key, &error);
} else {
error = errors::kManifestUnreadable;
}
@@ -1108,12 +1144,11 @@ void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info,
backend_.get(),
&ExtensionsServiceBackend::CheckExternalUninstall,
scoped_refptr<ExtensionsService>(this),
- info.extension_id,
- info.extension_location));
+ info.extension_id));
}
}
-void ExtensionsService::NotifyExtensionLoaded(Extension* extension) {
+void ExtensionsService::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
@@ -1136,14 +1171,14 @@ void ExtensionsService::NotifyExtensionLoaded(Extension* extension) {
NotificationService::current()->Notify(
NotificationType::EXTENSION_LOADED,
Source<Profile>(profile_),
- Details<Extension>(extension));
+ Details<const Extension>(extension));
}
-void ExtensionsService::NotifyExtensionUnloaded(Extension* extension) {
+void ExtensionsService::NotifyExtensionUnloaded(const Extension* extension) {
NotificationService::current()->Notify(
NotificationType::EXTENSION_UNLOADED,
Source<Profile>(profile_),
- Details<Extension>(extension));
+ Details<const Extension>(extension));
if (profile_) {
profile_->UnregisterExtensionWithRequestContexts(extension);
@@ -1159,7 +1194,7 @@ void ExtensionsService::NotifyExtensionUnloaded(Extension* extension) {
}
}
-void ExtensionsService::GrantProtectedStorage(Extension* extension) {
+void ExtensionsService::GrantProtectedStorage(const Extension* extension) {
DCHECK(extension->is_app()) << "Only Apps are allowed protected storage.";
std::vector<GURL> origins;
GetExplicitOriginsInExtent(extension, &origins);
@@ -1167,7 +1202,7 @@ void ExtensionsService::GrantProtectedStorage(Extension* extension) {
++protected_storage_map_[origins[i]];
}
-void ExtensionsService::RevokeProtectedStorage(Extension* extension) {
+void ExtensionsService::RevokeProtectedStorage(const Extension* extension) {
DCHECK(extension->is_app()) << "Attempting to revoke protected storage from "
<< " a non-app extension.";
std::vector<GURL> origins;
@@ -1180,7 +1215,7 @@ void ExtensionsService::RevokeProtectedStorage(Extension* extension) {
}
}
-void ExtensionsService::GrantUnlimitedStorage(Extension* extension) {
+void ExtensionsService::GrantUnlimitedStorage(const Extension* extension) {
DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission));
std::vector<GURL> origins;
GetExplicitOriginsInExtent(extension, &origins);
@@ -1215,7 +1250,7 @@ void ExtensionsService::GrantUnlimitedStorage(Extension* extension) {
}
}
-void ExtensionsService::RevokeUnlimitedStorage(Extension* extension) {
+void ExtensionsService::RevokeUnlimitedStorage(const Extension* extension) {
DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission));
std::vector<GURL> origins;
GetExplicitOriginsInExtent(extension, &origins);
@@ -1264,7 +1299,7 @@ void ExtensionsService::UpdateExtensionBlacklist(
// Loop current extensions, unload installed extensions.
for (ExtensionList::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
- Extension* extension = (*iter);
+ const Extension* extension = (*iter);
if (blacklist_set.find(extension->id()) != blacklist_set.end()) {
to_be_removed.push_back(extension->id());
}
@@ -1288,7 +1323,7 @@ void ExtensionsService::CheckAdminBlacklist() {
// Loop through extensions list, unload installed extensions.
for (ExtensionList::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
- Extension* extension = (*iter);
+ const Extension* extension = (*iter);
if (!extension_prefs_->IsExtensionAllowedByPolicy(extension->id()))
to_be_removed.push_back(extension->id());
}
@@ -1309,7 +1344,7 @@ bool ExtensionsService::IsIncognitoEnabled(const Extension* extension) {
return extension_prefs_->IsIncognitoEnabled(extension->id());
}
-void ExtensionsService::SetIsIncognitoEnabled(Extension* extension,
+void ExtensionsService::SetIsIncognitoEnabled(const Extension* extension,
bool enabled) {
extension_prefs_->SetIsIncognitoEnabled(extension->id(), enabled);
@@ -1323,18 +1358,26 @@ void ExtensionsService::SetIsIncognitoEnabled(Extension* extension,
}
}
+bool ExtensionsService::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) {
return (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableExtensionsFileAccessCheck) ||
extension_prefs_->AllowFileAccess(extension->id()));
}
-void ExtensionsService::SetAllowFileAccess(Extension* extension, bool allow) {
+void ExtensionsService::SetAllowFileAccess(const Extension* extension,
+ bool allow) {
extension_prefs_->SetAllowFileAccess(extension->id(), allow);
NotificationService::current()->Notify(
NotificationType::EXTENSION_USER_SCRIPTS_UPDATED,
Source<Profile>(profile_),
- Details<Extension>(extension));
+ Details<const Extension>(extension));
}
void ExtensionsService::CheckForExternalUpdates() {
@@ -1352,7 +1395,7 @@ void ExtensionsService::CheckForExternalUpdates() {
void ExtensionsService::UnloadExtension(const std::string& extension_id) {
// Make sure the extension gets deleted after we return from this function.
- scoped_ptr<Extension> extension(
+ scoped_refptr<const Extension> extension(
GetExtensionByIdInternal(extension_id, true, true));
// Callers should not send us nonexistent extensions.
@@ -1365,6 +1408,9 @@ void ExtensionsService::UnloadExtension(const std::string& extension_id) {
// Clean up if the extension is meant to be enabled after a reload.
disabled_extension_paths_.erase(extension->id());
+ // Clean up runtime data.
+ extension_runtime_data_.erase(extension_id);
+
ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
extension->GetChromeURLOverrides());
@@ -1376,7 +1422,7 @@ void ExtensionsService::UnloadExtension(const std::string& extension_id) {
NotificationService::current()->Notify(
NotificationType::EXTENSION_UNLOADED_DISABLED,
Source<Profile>(profile_),
- Details<Extension>(extension.get()));
+ Details<const Extension>(extension.get()));
return;
}
@@ -1390,12 +1436,9 @@ void ExtensionsService::UnloadExtension(const std::string& extension_id) {
}
void ExtensionsService::UnloadAllExtensions() {
- STLDeleteContainerPointers(extensions_.begin(), extensions_.end());
extensions_.clear();
-
- STLDeleteContainerPointers(disabled_extensions_.begin(),
- disabled_extensions_.end());
disabled_extensions_.clear();
+ extension_runtime_data_.clear();
// TODO(erikkay) should there be a notification for this? We can't use
// EXTENSION_UNLOADED since that implies that the extension has been disabled
@@ -1436,10 +1479,10 @@ void ExtensionsService::OnLoadedInstalledExtensions() {
NotificationService::NoDetails());
}
-void ExtensionsService::OnExtensionLoaded(Extension* extension,
+void ExtensionsService::OnExtensionLoaded(const Extension* extension,
bool allow_privilege_increase) {
// Ensure extension is deleted unless we transfer ownership.
- scoped_ptr<Extension> scoped_extension(extension);
+ scoped_refptr<const Extension> scoped_extension(extension);
// The extension is now loaded, remove its data from unloaded extension map.
unloaded_extension_paths_.erase(extension->id());
@@ -1455,7 +1498,8 @@ void ExtensionsService::OnExtensionLoaded(Extension* extension,
extension->location() == Extension::LOAD ||
extension->location() == Extension::COMPONENT ||
Extension::IsExternalLocation(extension->location())) {
- Extension* old = GetExtensionByIdInternal(extension->id(), true, true);
+ const Extension* old = GetExtensionByIdInternal(extension->id(),
+ true, true);
if (old) {
// CrxInstaller should have guaranteed that we aren't downgrading.
CHECK(extension->version()->CompareTo(*(old->version())) >= 0);
@@ -1467,8 +1511,8 @@ void ExtensionsService::OnExtensionLoaded(Extension* extension,
// Extensions get upgraded if silent upgrades are allowed, otherwise
// they get disabled.
if (allow_silent_upgrade) {
- old->set_being_upgraded(true);
- extension->set_being_upgraded(true);
+ SetBeingUpgraded(old, true);
+ SetBeingUpgraded(extension, true);
}
// To upgrade an extension in place, unload the old one and
@@ -1486,7 +1530,7 @@ void ExtensionsService::OnExtensionLoaded(Extension* extension,
switch (extension_prefs_->GetExtensionState(extension->id())) {
case Extension::ENABLED:
- extensions_.push_back(scoped_extension.release());
+ extensions_.push_back(scoped_extension);
NotifyExtensionLoaded(extension);
@@ -1494,11 +1538,11 @@ void ExtensionsService::OnExtensionLoaded(Extension* extension,
extension->GetChromeURLOverrides());
break;
case Extension::DISABLED:
- disabled_extensions_.push_back(scoped_extension.release());
+ disabled_extensions_.push_back(scoped_extension);
NotificationService::current()->Notify(
NotificationType::EXTENSION_UPDATE_DISABLED,
Source<Profile>(profile_),
- Details<Extension>(extension));
+ Details<const Extension>(extension));
break;
default:
NOTREACHED();
@@ -1506,7 +1550,7 @@ void ExtensionsService::OnExtensionLoaded(Extension* extension,
}
}
- extension->set_being_upgraded(false);
+ SetBeingUpgraded(extension, false);
UpdateActiveExtensionsInCrashReporter();
@@ -1524,17 +1568,20 @@ void ExtensionsService::OnExtensionLoaded(Extension* extension,
void ExtensionsService::UpdateActiveExtensionsInCrashReporter() {
std::set<std::string> extension_ids;
for (size_t i = 0; i < extensions_.size(); ++i) {
- if (!extensions_[i]->is_theme())
+ if (!extensions_[i]->is_theme() &&
+ extensions_[i]->location() != Extension::COMPONENT)
extension_ids.insert(extensions_[i]->id());
}
child_process_logging::SetActiveExtensions(extension_ids);
}
-void ExtensionsService::OnExtensionInstalled(Extension* extension,
+void ExtensionsService::OnExtensionInstalled(const Extension* extension,
bool allow_privilege_increase) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
// Ensure extension is deleted unless we transfer ownership.
- scoped_ptr<Extension> scoped_extension(extension);
+ scoped_refptr<const Extension> scoped_extension(extension);
Extension::State initial_state = Extension::DISABLED;
bool initial_enable_incognito = false;
PendingExtensionMap::iterator it =
@@ -1656,12 +1703,12 @@ void ExtensionsService::OnExtensionInstalled(Extension* extension,
NotificationService::current()->Notify(
NotificationType::THEME_INSTALLED,
Source<Profile>(profile_),
- Details<Extension>(extension));
+ Details<const Extension>(extension));
} else {
NotificationService::current()->Notify(
NotificationType::EXTENSION_INSTALLED,
Source<Profile>(profile_),
- Details<Extension>(extension));
+ Details<const Extension>(extension));
}
if (extension->is_app()) {
@@ -1671,12 +1718,11 @@ void ExtensionsService::OnExtensionInstalled(Extension* extension,
}
// Transfer ownership of |extension| to OnExtensionLoaded.
- OnExtensionLoaded(scoped_extension.release(), allow_privilege_increase);
+ OnExtensionLoaded(scoped_extension, allow_privilege_increase);
}
-Extension* ExtensionsService::GetExtensionByIdInternal(const std::string& id,
- bool include_enabled,
- bool include_disabled) {
+const Extension* ExtensionsService::GetExtensionByIdInternal(
+ const std::string& id, bool include_enabled, bool include_disabled) {
std::string lowercase_id = StringToLowerASCII(id);
if (include_enabled) {
for (ExtensionList::const_iterator iter = extensions_.begin();
@@ -1695,16 +1741,16 @@ Extension* ExtensionsService::GetExtensionByIdInternal(const std::string& id,
return NULL;
}
-Extension* ExtensionsService::GetWebStoreApp() {
+const Extension* ExtensionsService::GetWebStoreApp() {
return GetExtensionById(extension_misc::kWebStoreAppId, false);
}
-Extension* ExtensionsService::GetExtensionByURL(const GURL& url) {
+const Extension* ExtensionsService::GetExtensionByURL(const GURL& url) {
return url.scheme() != chrome::kExtensionScheme ? NULL :
GetExtensionById(url.host(), false);
}
-Extension* ExtensionsService::GetExtensionByWebExtent(const GURL& url) {
+const Extension* ExtensionsService::GetExtensionByWebExtent(const GURL& url) {
for (size_t i = 0; i < extensions_.size(); ++i) {
if (extensions_[i]->web_extent().ContainsURL(url))
return extensions_[i];
@@ -1718,11 +1764,11 @@ bool ExtensionsService::ExtensionBindingsAllowed(const GURL& url) {
return true;
// Allow bindings for all component, hosted apps.
- Extension* extension = GetExtensionByWebExtent(url);
+ const Extension* extension = GetExtensionByWebExtent(url);
return (extension && extension->location() == Extension::COMPONENT);
}
-Extension* ExtensionsService::GetExtensionByOverlappingWebExtent(
+const Extension* ExtensionsService::GetExtensionByOverlappingWebExtent(
const ExtensionExtent& extent) {
for (size_t i = 0; i < extensions_.size(); ++i) {
if (extensions_[i]->web_extent().OverlapsWith(extent))
@@ -1749,13 +1795,13 @@ void ExtensionsService::ClearProvidersForTesting() {
backend_.get(), &ExtensionsServiceBackend::ClearProvidersForTesting));
}
-void ExtensionsService::SetProviderForTesting(
- Extension::Location location, ExternalExtensionProvider* test_provider) {
+void ExtensionsService::AddProviderForTesting(
+ ExternalExtensionProvider* test_provider) {
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
- backend_.get(), &ExtensionsServiceBackend::SetProviderForTesting,
- location, test_provider));
+ backend_.get(), &ExtensionsServiceBackend::AddProviderForTesting,
+ test_provider));
}
void ExtensionsService::OnExternalExtensionFileFound(
@@ -1763,10 +1809,12 @@ void ExtensionsService::OnExternalExtensionFileFound(
const std::string& version,
const FilePath& path,
Extension::Location location) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
// Before even bothering to unpack, check and see if we already have this
// version. This is important because these extensions are going to get
// installed on every startup.
- Extension* existing = GetExtensionById(id, true);
+ const Extension* existing = GetExtensionById(id, true);
scoped_ptr<Version> other(Version::GetVersionFromString(version));
if (existing) {
switch (existing->version()->CompareTo(*other)) {
@@ -1883,3 +1931,26 @@ ExtensionIdSet ExtensionsService::GetAppIds() const {
return result;
}
+
+bool ExtensionsService::IsBackgroundPageReady(const Extension* extension) {
+ return (extension->background_url().is_empty() ||
+ extension_runtime_data_[extension->id()].background_page_ready);
+}
+
+void ExtensionsService::SetBackgroundPageReady(const Extension* extension) {
+ DCHECK(!extension->background_url().is_empty());
+ extension_runtime_data_[extension->id()].background_page_ready = true;
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_BACKGROUND_PAGE_READY,
+ Source<const Extension>(extension),
+ NotificationService::NoDetails());
+}
+
+bool ExtensionsService::IsBeingUpgraded(const Extension* extension) {
+ return extension_runtime_data_[extension->id()].being_upgraded;
+}
+
+void ExtensionsService::SetBeingUpgraded(const Extension* extension,
+ bool value) {
+ extension_runtime_data_[extension->id()].being_upgraded = value;
+}
diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h
index bf398de..d3fd80b 100644
--- a/chrome/browser/extensions/extensions_service.h
+++ b/chrome/browser/extensions/extensions_service.h
@@ -89,8 +89,8 @@ class ExtensionUpdateService {
virtual const PendingExtensionMap& pending_extensions() const = 0;
virtual void UpdateExtension(const std::string& id, const FilePath& path,
const GURL& download_url) = 0;
- virtual Extension* GetExtensionById(const std::string& id,
- bool include_disabled) = 0;
+ virtual const Extension* GetExtensionById(const std::string& id,
+ bool include_disabled) = 0;
virtual void UpdateExtensionBlacklist(
const std::vector<std::string>& blacklist) = 0;
virtual void CheckAdminBlacklist() = 0;
@@ -179,11 +179,26 @@ class ExtensionsService
// Whether this extension can run in an incognito window.
bool IsIncognitoEnabled(const Extension* extension);
- void SetIsIncognitoEnabled(Extension* extension, bool enabled);
+ void SetIsIncognitoEnabled(const Extension* extension, bool enabled);
+
+ // Returns true if the given extension can see events and data from another
+ // sub-profile (incognito to original profile, or vice versa).
+ bool CanCrossIncognito(const Extension* extension);
// Whether this extension can inject scripts into pages with file URLs.
bool AllowFileAccess(const Extension* extension);
- void SetAllowFileAccess(Extension* extension, bool allow);
+ void SetAllowFileAccess(const Extension* extension, bool allow);
+
+ // Whether the background page, if any, is ready. We don't load other
+ // components until then. If there is no background page, we consider it to
+ // be ready.
+ bool IsBackgroundPageReady(const Extension* extension);
+ void SetBackgroundPageReady(const Extension* extension);
+
+ // Getter and setter for the flag that specifies whether the extension is
+ // being upgraded.
+ bool IsBeingUpgraded(const Extension* extension);
+ void SetBeingUpgraded(const Extension* extension, bool value);
// Initialize and start all installed extensions.
void Init();
@@ -192,7 +207,8 @@ class ExtensionsService
void InitEventRouters();
// Look up an extension by ID.
- Extension* GetExtensionById(const std::string& id, bool include_disabled) {
+ const Extension* GetExtensionById(const std::string& id,
+ bool include_disabled) {
return GetExtensionByIdInternal(id, true, include_disabled);
}
@@ -229,7 +245,8 @@ class ExtensionsService
// Given an extension id and an update URL, schedule the extension
// to be fetched, installed, and activated.
void AddPendingExtensionFromExternalUpdateUrl(const std::string& id,
- const GURL& update_url);
+ const GURL& update_url,
+ Extension::Location location);
// Like the above. Always installed silently, and defaults update url
// from extension id.
@@ -285,18 +302,19 @@ class ExtensionsService
void GarbageCollectExtensions();
// The App that represents the web store.
- Extension* GetWebStoreApp();
+ const Extension* GetWebStoreApp();
// Lookup an extension by |url|.
- Extension* GetExtensionByURL(const GURL& url);
+ const Extension* GetExtensionByURL(const GURL& url);
// If there is an extension for the specified url it is returned. Otherwise
// returns the extension whose web extent contains |url|.
- Extension* GetExtensionByWebExtent(const GURL& url);
+ const Extension* GetExtensionByWebExtent(const GURL& url);
// Returns an extension that contains any URL that overlaps with the given
// extent, if one exists.
- Extension* GetExtensionByOverlappingWebExtent(const ExtensionExtent& extent);
+ const Extension* GetExtensionByOverlappingWebExtent(
+ const ExtensionExtent& extent);
// Returns true if |url| should get extension api bindings and be permitted
// to make api calls. Note that this is independent of what extension
@@ -314,19 +332,18 @@ class ExtensionsService
void ClearProvidersForTesting();
// Sets an ExternalExtensionProvider for the service to use during testing.
- // |location| specifies what type of provider should be added.
- void SetProviderForTesting(Extension::Location location,
- ExternalExtensionProvider* test_provider);
+ // Takes ownership of |test_provider|.
+ void AddProviderForTesting(ExternalExtensionProvider* test_provider);
// Called when the initial extensions load has completed.
virtual void OnLoadedInstalledExtensions();
// Called when an extension has been loaded.
- void OnExtensionLoaded(Extension* extension,
+ void OnExtensionLoaded(const Extension* extension,
bool allow_privilege_increase);
// Called by the backend when an extension has been installed.
- void OnExtensionInstalled(Extension* extension,
+ void OnExtensionInstalled(const Extension* extension,
bool allow_privilege_increase);
// Called by the backend when an external extension is found.
@@ -403,18 +420,33 @@ class ExtensionsService
ExtensionIdSet GetAppIds() const;
private:
- virtual ~ExtensionsService();
friend class BrowserThread;
friend class DeleteTask<ExtensionsService>;
+ // Contains Extension data that can change during the life of the process,
+ // but does not persist across restarts.
+ struct ExtensionRuntimeData {
+ // True if the background page is ready.
+ bool background_page_ready;
+
+ // True while the extension is being upgraded.
+ bool being_upgraded;
+
+ ExtensionRuntimeData();
+ ~ExtensionRuntimeData();
+ };
+ typedef std::map<std::string, ExtensionRuntimeData> ExtensionRuntimeDataMap;
+
+ virtual ~ExtensionsService();
+
// Clear all persistent data that may have been stored by the extension.
void ClearExtensionData(const GURL& extension_url);
// Look up an extension by ID, optionally including either or both of enabled
// and disabled extensions.
- Extension* GetExtensionByIdInternal(const std::string& id,
- bool include_enabled,
- bool include_disabled);
+ const Extension* GetExtensionByIdInternal(const std::string& id,
+ bool include_enabled,
+ bool include_disabled);
// Like AddPendingExtension() but assumes an extension with the same
// id is not already installed.
@@ -426,10 +458,10 @@ class ExtensionsService
Extension::Location install_source);
// Handles sending notification that |extension| was loaded.
- void NotifyExtensionLoaded(Extension* extension);
+ void NotifyExtensionLoaded(const Extension* extension);
// Handles sending notification that |extension| was unloaded.
- void NotifyExtensionUnloaded(Extension* extension);
+ void NotifyExtensionUnloaded(const Extension* extension);
// Helper that updates the active extension list used for crash reporting.
void UpdateActiveExtensionsInCrashReporter();
@@ -438,10 +470,10 @@ class ExtensionsService
void LoadInstalledExtension(const ExtensionInfo& info, bool write_to_prefs);
// Helper methods to configure the storage services accordingly.
- void GrantProtectedStorage(Extension* extension);
- void RevokeProtectedStorage(Extension* extension);
- void GrantUnlimitedStorage(Extension* extension);
- void RevokeUnlimitedStorage(Extension* extension);
+ void GrantProtectedStorage(const Extension* extension);
+ void RevokeProtectedStorage(const Extension* extension);
+ void GrantUnlimitedStorage(const Extension* extension);
+ void RevokeUnlimitedStorage(const Extension* extension);
// The profile this ExtensionsService is part of.
Profile* profile_;
@@ -458,6 +490,9 @@ class ExtensionsService
// The set of pending extensions.
PendingExtensionMap pending_extensions_;
+ // The map of extension IDs to their runtime data.
+ ExtensionRuntimeDataMap extension_runtime_data_;
+
// The full path to the directory where extensions are installed.
FilePath install_directory_;
diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc
index df29995..fa8f341 100644
--- a/chrome/browser/extensions/extensions_service_unittest.cc
+++ b/chrome/browser/extensions/extensions_service_unittest.cc
@@ -103,7 +103,7 @@ static std::vector<std::string> GetErrors() {
class MockExtensionProvider : public ExternalExtensionProvider {
public:
explicit MockExtensionProvider(Extension::Location location)
- : location_(location) {}
+ : location_(location), visit_count_(0) {}
virtual ~MockExtensionProvider() {}
void UpdateOrAddExtension(const std::string& id,
@@ -119,6 +119,7 @@ class MockExtensionProvider : public ExternalExtensionProvider {
// ExternalExtensionProvider implementation:
virtual void VisitRegisteredExtension(
Visitor* visitor, const std::set<std::string>& ids_to_ignore) 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())
@@ -131,15 +132,28 @@ class MockExtensionProvider : public ExternalExtensionProvider {
}
}
- virtual Version* RegisteredVersion(const std::string& id,
- Extension::Location* location) const {
+ virtual bool HasExtension(const std::string& id) const {
+ return extension_map_.find(id) != extension_map_.end();
+ }
+
+ virtual bool GetExtensionDetails(const std::string& id,
+ Extension::Location* location,
+ scoped_ptr<Version>* version) const {
DataMap::const_iterator it = extension_map_.find(id);
if (it == extension_map_.end())
- return NULL;
+ return false;
+
+ if (version)
+ version->reset(Version::GetVersionFromString(it->second.first));
if (location)
*location = location_;
- return Version::GetVersionFromString(it->second.first);
+
+ return true;
+ }
+ int visit_count() const { return visit_count_; }
+ void set_visit_count(int visit_count) {
+ visit_count_ = visit_count;
}
private:
@@ -147,6 +161,12 @@ class MockExtensionProvider : public ExternalExtensionProvider {
DataMap extension_map_;
Extension::Location location_;
+ // visit_count_ tracks the number of calls to VisitRegisteredExtension().
+ // Mutable because it must be incremented on each call to
+ // VisitRegisteredExtension(), which must be a const method to inherit
+ // from the class being mocked.
+ mutable int visit_count_;
+
DISALLOW_COPY_AND_ASSIGN(MockExtensionProvider);
};
@@ -197,10 +217,18 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor {
<< "Got back ID (" << id.c_str() << ") we weren't expecting";
if (pref) {
+ EXPECT_TRUE(provider_->HasExtension(id));
+
// Ask provider if the extension we got back is registered.
Extension::Location location = Extension::INVALID;
- scoped_ptr<Version> v1(provider_->RegisteredVersion(id, NULL));
- scoped_ptr<Version> v2(provider_->RegisteredVersion(id, &location));
+ scoped_ptr<Version> v1;
+ FilePath crx_path;
+
+ EXPECT_TRUE(provider_->GetExtensionDetails(id, NULL, &v1));
+ EXPECT_STREQ(version->GetString().c_str(), v1->GetString().c_str());
+
+ scoped_ptr<Version> v2;
+ EXPECT_TRUE(provider_->GetExtensionDetails(id, &location, &v2));
EXPECT_STREQ(version->GetString().c_str(), v1->GetString().c_str());
EXPECT_STREQ(version->GetString().c_str(), v2->GetString().c_str());
EXPECT_EQ(Extension::EXTERNAL_PREF, location);
@@ -210,8 +238,9 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor {
}
}
- virtual void OnExternalExtensionUpdateUrlFound(const std::string& id,
- const GURL& update_url) {
+ virtual void OnExternalExtensionUpdateUrlFound(
+ const std::string& id, const GURL& update_url,
+ Extension::Location location) {
++ids_found_;
DictionaryValue* pref;
// This tests is to make sure that the provider only notifies us of the
@@ -219,8 +248,18 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor {
// dictionary then something is wrong.
EXPECT_TRUE(prefs_->GetDictionary(id, &pref))
<< L"Got back ID (" << id.c_str() << ") we weren't expecting";
+ EXPECT_EQ(Extension::EXTERNAL_PREF_DOWNLOAD, location);
if (pref) {
+ EXPECT_TRUE(provider_->HasExtension(id));
+
+ // External extensions with update URLs do not have versions.
+ scoped_ptr<Version> v1;
+ Extension::Location location1 = Extension::INVALID;
+ EXPECT_TRUE(provider_->GetExtensionDetails(id, &location1, &v1));
+ EXPECT_FALSE(v1.get());
+ EXPECT_EQ(Extension::EXTERNAL_PREF_DOWNLOAD, location1);
+
// Remove it so we won't count it again.
prefs_->Remove(id, NULL);
}
@@ -303,12 +342,6 @@ void ExtensionsServiceTestBase::InitializeExtensionsService(
profile_.reset(profile);
- // TODO(scherkus): Remove this when we no longer need to have Talk
- // component extension state as a preference http://crbug.com/56429
- DictionaryValue* dict =
- profile->GetPrefs()->GetMutableDictionary("extensions.settings");
- dict->Remove("ggnioahjipcehijkhpdjekioddnjoben", NULL);
-
service_ = profile->CreateExtensionsService(
CommandLine::ForCurrentProcess(),
extensions_install_dir);
@@ -386,8 +419,8 @@ class ExtensionsServiceTest
const NotificationDetails& details) {
switch (type.value) {
case NotificationType::EXTENSION_LOADED: {
- Extension* extension = Details<Extension>(details).ptr();
- loaded_.push_back(extension);
+ const Extension* extension = Details<const Extension>(details).ptr();
+ loaded_.push_back(make_scoped_refptr(extension));
// The tests rely on the errors being in a certain order, which can vary
// depending on how filesystem iteration works.
std::stable_sort(loaded_.begin(), loaded_.end(), ExtensionsOrder());
@@ -395,7 +428,7 @@ class ExtensionsServiceTest
}
case NotificationType::EXTENSION_UNLOADED: {
- Extension* e = Details<Extension>(details).ptr();
+ const Extension* e = Details<const Extension>(details).ptr();
unloaded_id_ = e->id();
ExtensionList::iterator i =
std::find(loaded_.begin(), loaded_.end(), e);
@@ -408,7 +441,7 @@ class ExtensionsServiceTest
}
case NotificationType::EXTENSION_INSTALLED:
case NotificationType::THEME_INSTALLED:
- installed_ = Details<Extension>(details).ptr();
+ installed_ = Details<const Extension>(details).ptr();
break;
default:
@@ -416,9 +449,8 @@ class ExtensionsServiceTest
}
}
- void SetMockExternalProvider(Extension::Location location,
- ExternalExtensionProvider* provider) {
- service_->SetProviderForTesting(location, provider);
+ void AddMockExternalProvider(ExternalExtensionProvider* provider) {
+ service_->AddProviderForTesting(provider);
}
protected:
@@ -644,7 +676,7 @@ class ExtensionsServiceTest
protected:
ExtensionList loaded_;
std::string unloaded_id_;
- Extension* installed_;
+ const Extension* installed_;
private:
NotificationRegistrar registrar_;
@@ -742,7 +774,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) {
ValidateIntegerPref(good2, "state", Extension::ENABLED);
ValidateIntegerPref(good2, "location", Extension::INTERNAL);
- Extension* extension = loaded_[0];
+ const Extension* extension = loaded_[0];
const UserScriptList& scripts = extension->content_scripts();
ASSERT_EQ(2u, scripts.size());
EXPECT_EQ(3u, scripts[0].url_patterns().size());
@@ -1223,9 +1255,8 @@ TEST_F(ExtensionsServiceTest, InstallApps) {
ValidatePrefKeyCount(++pref_count);
// A third app whose extent overlaps the first. Should fail.
- // TODO(aa): bring this back when overlap is fixed. http://crbug.com/47445.
- // PackAndInstallExtension(extensions_path.AppendASCII("app3"), false);
- // ValidatePrefKeyCount(pref_count);
+ PackAndInstallExtension(extensions_path.AppendASCII("app3"), false);
+ ValidatePrefKeyCount(pref_count);
}
TEST_F(ExtensionsServiceTest, InstallAppsWithUnlimtedStorage) {
@@ -1243,7 +1274,7 @@ TEST_F(ExtensionsServiceTest, InstallAppsWithUnlimtedStorage) {
PackAndInstallExtension(extensions_path.AppendASCII("app1"), true);
ValidatePrefKeyCount(++pref_count);
ASSERT_EQ(1u, service_->extensions()->size());
- Extension* extension = service_->extensions()->at(0);
+ const Extension* extension = service_->extensions()->at(0);
const std::string id1 = extension->id();
EXPECT_TRUE(extension->HasApiPermission(
Extension::kUnlimitedStoragePermission));
@@ -1301,7 +1332,7 @@ TEST_F(ExtensionsServiceTest, InstallAppsAndCheckStorageProtection) {
PackAndInstallExtension(extensions_path.AppendASCII("app1"), true);
ValidatePrefKeyCount(++pref_count);
ASSERT_EQ(1u, service_->extensions()->size());
- Extension* extension = service_->extensions()->at(0);
+ const Extension* extension = service_->extensions()->at(0);
EXPECT_TRUE(extension->is_app());
const std::string id1 = extension->id();
EXPECT_FALSE(service_->protected_storage_map_.empty());
@@ -1430,7 +1461,7 @@ TEST_F(ExtensionsServiceTest, UpdateExtension) {
FilePath path = extensions_path.AppendASCII("good.crx");
InstallExtension(path, true);
- Extension* good = service_->extensions()->at(0);
+ const Extension* good = service_->extensions()->at(0);
ASSERT_EQ("1.0.0.0", good->VersionString());
ASSERT_EQ(good_crx, good->id());
@@ -1465,7 +1496,7 @@ TEST_F(ExtensionsServiceTest, UpdateWillNotDowngrade) {
FilePath path = extensions_path.AppendASCII("good2.crx");
InstallExtension(path, true);
- Extension* good = service_->extensions()->at(0);
+ const Extension* good = service_->extensions()->at(0);
ASSERT_EQ("1.0.0.1", good->VersionString());
ASSERT_EQ(good_crx, good->id());
@@ -1485,7 +1516,7 @@ TEST_F(ExtensionsServiceTest, UpdateToSameVersionIsNoop) {
FilePath path = extensions_path.AppendASCII("good.crx");
InstallExtension(path, true);
- Extension* good = service_->extensions()->at(0);
+ const Extension* good = service_->extensions()->at(0);
ASSERT_EQ(good_crx, good->id());
UpdateExtension(good_crx, path, FAILED_SILENTLY);
}
@@ -1500,7 +1531,7 @@ TEST_F(ExtensionsServiceTest, UpdateExtensionPreservesState) {
FilePath path = extensions_path.AppendASCII("good.crx");
InstallExtension(path, true);
- Extension* good = service_->extensions()->at(0);
+ const Extension* good = service_->extensions()->at(0);
ASSERT_EQ("1.0.0.0", good->VersionString());
ASSERT_EQ(good_crx, good->id());
@@ -1512,7 +1543,7 @@ TEST_F(ExtensionsServiceTest, UpdateExtensionPreservesState) {
path = extensions_path.AppendASCII("good2.crx");
UpdateExtension(good_crx, path, INSTALLED);
ASSERT_EQ(1u, service_->disabled_extensions()->size());
- Extension* good2 = service_->disabled_extensions()->at(0);
+ const Extension* good2 = service_->disabled_extensions()->at(0);
ASSERT_EQ("1.0.0.1", good2->version()->GetString());
EXPECT_TRUE(service_->IsIncognitoEnabled(good2));
}
@@ -1570,7 +1601,7 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExtension) {
EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
- Extension* extension = service_->GetExtensionById(kGoodId, true);
+ const Extension* extension = service_->GetExtensionById(kGoodId, true);
ASSERT_TRUE(extension);
bool enabled = service_->GetExtensionById(kGoodId, false);
@@ -1597,7 +1628,7 @@ TEST_F(ExtensionsServiceTest, UpdatePendingTheme) {
EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
- Extension* extension = service_->GetExtensionById(theme_crx, true);
+ const Extension* extension = service_->GetExtensionById(theme_crx, true);
ASSERT_TRUE(extension);
EXPECT_EQ(Extension::ENABLED,
@@ -1610,7 +1641,8 @@ TEST_F(ExtensionsServiceTest, UpdatePendingTheme) {
// or not.
TEST_F(ExtensionsServiceTest, UpdatePendingExternalCrx) {
InitializeEmptyExtensionsService();
- service_->AddPendingExtensionFromExternalUpdateUrl(theme_crx, GURL());
+ service_->AddPendingExtensionFromExternalUpdateUrl(
+ theme_crx, GURL(), Extension::EXTERNAL_PREF_DOWNLOAD);
EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx));
@@ -1622,7 +1654,7 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExternalCrx) {
EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
- Extension* extension = service_->GetExtensionById(theme_crx, true);
+ const Extension* extension = service_->GetExtensionById(theme_crx, true);
ASSERT_TRUE(extension);
EXPECT_EQ(Extension::ENABLED,
@@ -1630,6 +1662,45 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExternalCrx) {
EXPECT_FALSE(service_->IsIncognitoEnabled(extension));
}
+// 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();
+
+ // Add a crx to be installed from the update mechanism.
+ service_->AddPendingExtensionFromSync(
+ kGoodId, GURL(kGoodUpdateURL), kCrxTypeExtension,
+ kGoodInstallSilently, kGoodInitialState,
+ kGoodInitialIncognitoEnabled);
+
+ // Check that there is a pending crx, with is_from_sync set to true.
+ PendingExtensionMap::const_iterator it;
+ it = service_->pending_extensions().find(kGoodId);
+ ASSERT_TRUE(it != service_->pending_extensions().end());
+ EXPECT_TRUE(it->second.is_from_sync);
+
+ // Add a crx to be updated, with the same ID, from a non-sync source.
+ service_->AddPendingExtensionFromExternalUpdateUrl(
+ kGoodId, GURL(kGoodUpdateURL), Extension::EXTERNAL_PREF_DOWNLOAD);
+
+ // Check that there is a pending crx, with is_from_sync set to false.
+ it = service_->pending_extensions().find(kGoodId);
+ ASSERT_TRUE(it != service_->pending_extensions().end());
+ EXPECT_FALSE(it->second.is_from_sync);
+
+ // Add a crx to be installed from the update mechanism.
+ service_->AddPendingExtensionFromSync(
+ kGoodId, GURL(kGoodUpdateURL), kCrxTypeExtension,
+ kGoodInstallSilently, kGoodInitialState,
+ kGoodInitialIncognitoEnabled);
+
+ // Check that the external, non-sync update was not overridden.
+ it = service_->pending_extensions().find(kGoodId);
+ ASSERT_TRUE(it != service_->pending_extensions().end());
+ EXPECT_FALSE(it->second.is_from_sync);
+}
+
// Updating a theme should fail if the updater is explicitly told that
// the CRX is not a theme.
TEST_F(ExtensionsServiceTest, UpdatePendingCrxThemeMismatch) {
@@ -1649,7 +1720,7 @@ TEST_F(ExtensionsServiceTest, UpdatePendingCrxThemeMismatch) {
EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
- Extension* extension = service_->GetExtensionById(theme_crx, true);
+ const Extension* extension = service_->GetExtensionById(theme_crx, true);
ASSERT_FALSE(extension);
}
@@ -1706,7 +1777,7 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExtensionAlreadyInstalled) {
FilePath path = extensions_path.AppendASCII("good.crx");
InstallExtension(path, true);
ASSERT_EQ(1u, service_->extensions()->size());
- Extension* good = service_->extensions()->at(0);
+ const Extension* good = service_->extensions()->at(0);
EXPECT_FALSE(good->is_theme());
@@ -1761,7 +1832,7 @@ TEST_F(ExtensionsServiceTest, UnloadBlacklistedExtension) {
FilePath path = extensions_path.AppendASCII("good.crx");
InstallExtension(path, true);
- Extension* good = service_->extensions()->at(0);
+ const Extension* good = service_->extensions()->at(0);
EXPECT_EQ(good_crx, good->id());
UpdateExtension(good_crx, path, FAILED_SILENTLY);
@@ -2094,7 +2165,7 @@ TEST_F(ExtensionsServiceTest, ClearExtensionData) {
path = path.AppendASCII("extensions");
path = path.AppendASCII("good.crx");
InstallExtension(path, true);
- Extension* extension = service_->GetExtensionById(good_crx, false);
+ const Extension* extension = service_->GetExtensionById(good_crx, false);
ASSERT_TRUE(extension);
GURL ext_url(extension->url());
string16 origin_id =
@@ -2227,6 +2298,8 @@ void ExtensionsServiceTest::TestExternalProvider(
loop_.RunAllPending();
ASSERT_EQ(0u, loaded_.size());
+ provider->set_visit_count(0);
+
// Register a test extension externally using the mock registry provider.
FilePath source_path;
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_path));
@@ -2342,6 +2415,8 @@ void ExtensionsServiceTest::TestExternalProvider(
loop_.RunAllPending();
ASSERT_EQ(0u, loaded_.size());
ValidatePrefKeyCount(1);
+
+ EXPECT_EQ(5, provider->visit_count());
}
// Tests the external installation feature
@@ -2354,7 +2429,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) {
// Now add providers. Extension system takes ownership of the objects.
MockExtensionProvider* reg_provider =
new MockExtensionProvider(Extension::EXTERNAL_REGISTRY);
- SetMockExternalProvider(Extension::EXTERNAL_REGISTRY, reg_provider);
+ AddMockExternalProvider(reg_provider);
TestExternalProvider(reg_provider, Extension::EXTERNAL_REGISTRY);
}
#endif
@@ -2367,7 +2442,8 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) {
// Now add providers. Extension system takes ownership of the objects.
MockExtensionProvider* pref_provider =
new MockExtensionProvider(Extension::EXTERNAL_PREF);
- SetMockExternalProvider(Extension::EXTERNAL_PREF, pref_provider);
+
+ AddMockExternalProvider(pref_provider);
TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF);
}
@@ -2376,10 +2452,16 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPrefUpdateUrl) {
InitializeEmptyExtensionsService();
set_extensions_enabled(false);
- // Now add providers. Extension system takes ownership of the objects.
+ // TODO(skerner): The mock provider is not a good model of a provider
+ // that works with update URLs, because it adds file and version info.
+ // Extend the mock to work with update URLs. This test checks the
+ // behavior that is common to all external extension visitors. The
+ // browser test ExtensionManagementTest.ExternalUrlUpdate tests that
+ // what the visitor does results in an extension being downloaded and
+ // installed.
MockExtensionProvider* pref_provider =
new MockExtensionProvider(Extension::EXTERNAL_PREF_DOWNLOAD);
- SetMockExternalProvider(Extension::EXTERNAL_PREF_DOWNLOAD, pref_provider);
+ AddMockExternalProvider(pref_provider);
TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF_DOWNLOAD);
}
diff --git a/chrome/browser/extensions/extensions_startup.cc b/chrome/browser/extensions/extensions_startup.cc
index 1286179..9faeac6 100644
--- a/chrome/browser/extensions/extensions_startup.cc
+++ b/chrome/browser/extensions/extensions_startup.cc
@@ -83,8 +83,8 @@ bool HandlePackExtension(const CommandLine& cmd_line) {
// 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);
+ 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
diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc
index 586ec6f..d3f6a6c 100644
--- a/chrome/browser/extensions/extensions_ui.cc
+++ b/chrome/browser/extensions/extensions_ui.cc
@@ -58,8 +58,7 @@
namespace {
-bool ShouldShowExtension(Extension* extension) {
-
+bool ShouldShowExtension(const Extension* extension) {
// Don't show themes since this page's UI isn't really useful for themes.
if (extension->is_theme())
return false;
@@ -407,7 +406,7 @@ void ExtensionsDOMHandler::OnIconsLoaded(DictionaryValue* json) {
}
ExtensionResource ExtensionsDOMHandler::PickExtensionIcon(
- Extension* extension) {
+ const Extension* extension) {
return extension->GetIconResource(Extension::EXTENSION_ICON_MEDIUM,
ExtensionIconSet::MATCH_BIGGER);
}
@@ -459,7 +458,7 @@ void ExtensionsDOMHandler::HandleEnableMessage(const ListValue* args) {
if (enable_str == "true") {
ExtensionPrefs* prefs = extensions_service_->extension_prefs();
if (prefs->DidExtensionEscalatePermissions(extension_id)) {
- Extension* extension =
+ const Extension* extension =
extensions_service_->GetExtensionById(extension_id, true);
ShowExtensionDisabledDialog(extensions_service_,
dom_ui_->GetProfile(), extension);
@@ -476,8 +475,8 @@ void ExtensionsDOMHandler::HandleEnableIncognitoMessage(const ListValue* args) {
std::string extension_id, enable_str;
CHECK(args->GetString(0, &extension_id));
CHECK(args->GetString(1, &enable_str));
- Extension* extension = extensions_service_->GetExtensionById(extension_id,
- true);
+ const Extension* extension =
+ extensions_service_->GetExtensionById(extension_id, true);
DCHECK(extension);
// Flipping the incognito bit will generate unload/load notifications for the
@@ -501,15 +500,15 @@ void ExtensionsDOMHandler::HandleAllowFileAccessMessage(const ListValue* args) {
std::string extension_id, allow_str;
CHECK(args->GetString(0, &extension_id));
CHECK(args->GetString(1, &allow_str));
- Extension* extension = extensions_service_->GetExtensionById(extension_id,
- true);
+ const Extension* extension =
+ extensions_service_->GetExtensionById(extension_id, true);
DCHECK(extension);
extensions_service_->SetAllowFileAccess(extension, allow_str == "true");
}
void ExtensionsDOMHandler::HandleUninstallMessage(const ListValue* args) {
- Extension* extension = GetExtension(args);
+ const Extension* extension = GetExtension(args);
if (!extension)
return;
@@ -527,7 +526,7 @@ void ExtensionsDOMHandler::InstallUIProceed() {
// The extension can be uninstalled in another window while the UI was
// showing. Do nothing in that case.
- Extension* extension =
+ const Extension* extension =
extensions_service_->GetExtensionById(extension_id_prompting_, true);
if (!extension)
return;
@@ -542,7 +541,7 @@ void ExtensionsDOMHandler::InstallUIAbort() {
}
void ExtensionsDOMHandler::HandleOptionsMessage(const ListValue* args) {
- Extension* extension = GetExtension(args);
+ const Extension* extension = GetExtension(args);
if (!extension || extension->options_url().is_empty())
return;
dom_ui_->GetProfile()->GetExtensionProcessManager()->OpenOptionsPage(
@@ -703,7 +702,7 @@ void ExtensionsDOMHandler::Observe(NotificationType type,
}
}
-Extension* ExtensionsDOMHandler::GetExtension(const ListValue* args) {
+const Extension* ExtensionsDOMHandler::GetExtension(const ListValue* args) {
std::string extension_id = WideToASCII(ExtractStringValue(args));
CHECK(!extension_id.empty());
return extensions_service_->GetExtensionById(extension_id, true);
@@ -840,13 +839,13 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
extension_data->Set("views", views);
extension_data->SetBoolean("hasPopupAction",
extension->browser_action() || extension->page_action());
- extension_data->SetString("galleryUrl", extension->GalleryUrl().spec());
+ extension_data->SetString("homepageUrl", extension->GetHomepageURL().spec());
return extension_data;
}
std::vector<ExtensionPage> ExtensionsDOMHandler::GetActivePagesForExtension(
- Extension* extension) {
+ const Extension* extension) {
std::vector<ExtensionPage> result;
// Get the extension process's active views.
@@ -872,7 +871,7 @@ std::vector<ExtensionPage> ExtensionsDOMHandler::GetActivePagesForExtension(
void ExtensionsDOMHandler::GetActivePagesForExtensionProcess(
RenderProcessHost* process,
- Extension* extension,
+ const Extension* extension,
std::vector<ExtensionPage> *result) {
if (!process)
return;
diff --git a/chrome/browser/extensions/extensions_ui.h b/chrome/browser/extensions/extensions_ui.h
index 5660eaa..c8c6143 100644
--- a/chrome/browser/extensions/extensions_ui.h
+++ b/chrome/browser/extensions/extensions_ui.h
@@ -178,7 +178,7 @@ class ExtensionsDOMHandler
void HandleSelectFilePathMessage(const ListValue* args);
// Utility for callbacks that get an extension ID as the sole argument.
- Extension* GetExtension(const ListValue* args);
+ const Extension* GetExtension(const ListValue* args);
// Forces a UI update if appropriate after a notification is received.
void MaybeUpdateAfterNotification();
@@ -198,15 +198,16 @@ class ExtensionsDOMHandler
const NotificationDetails& details);
// Helper that lists the current active html pages for an extension.
- std::vector<ExtensionPage> GetActivePagesForExtension(Extension* extension);
+ std::vector<ExtensionPage> GetActivePagesForExtension(
+ const Extension* extension);
void GetActivePagesForExtensionProcess(
RenderProcessHost* process,
- Extension* extension,
+ const Extension* extension,
std::vector<ExtensionPage> *result);
// Returns the best icon to display in the UI for an extension, or an empty
// ExtensionResource if no good icon exists.
- ExtensionResource PickExtensionIcon(Extension* extension);
+ ExtensionResource PickExtensionIcon(const Extension* extension);
// Loads the extension resources into the json data, then calls OnIconsLoaded.
// Takes ownership of |icons|.
diff --git a/chrome/browser/extensions/external_extension_provider.h b/chrome/browser/extensions/external_extension_provider.h
index eddea62..1d040bd 100644
--- a/chrome/browser/extensions/external_extension_provider.h
+++ b/chrome/browser/extensions/external_extension_provider.h
@@ -32,7 +32,8 @@ class ExternalExtensionProvider {
virtual void OnExternalExtensionUpdateUrlFound(
const std::string& id,
- const GURL& update_url) = 0;
+ const GURL& update_url,
+ Extension::Location location) = 0;
protected:
virtual ~Visitor() {}
@@ -46,11 +47,16 @@ class ExternalExtensionProvider {
virtual void VisitRegisteredExtension(
Visitor* visitor, const std::set<std::string>& ids_to_ignore) const = 0;
- // Gets the version of extension with |id| and its |location|. |location| can
- // be NULL. The caller is responsible for cleaning up the Version object
- // returned. This function returns NULL if the extension is not found.
- virtual Version* RegisteredVersion(const std::string& id,
- Extension::Location* location) const = 0;
+ // Test if this provider has an extension with id |id| registered.
+ virtual bool HasExtension(const std::string& id) const = 0;
+
+ // Gets details of an extension by its id. Output params will be set only
+ // if they are not NULL. If an output parameter is not specified by the
+ // provider type, it will not be changed.
+ // This function is no longer used outside unit tests.
+ virtual bool GetExtensionDetails(const std::string& id,
+ Extension::Location* location,
+ scoped_ptr<Version>* version) const = 0;
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_H_
diff --git a/chrome/browser/extensions/external_policy_extension_provider.cc b/chrome/browser/extensions/external_policy_extension_provider.cc
new file mode 100644
index 0000000..0eabccb
--- /dev/null
+++ b/chrome/browser/extensions/external_policy_extension_provider.cc
@@ -0,0 +1,68 @@
+// 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/external_policy_extension_provider.h"
+
+#include "base/values.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/browser/extensions/stateful_external_extension_provider.h"
+#include "chrome/browser/prefs/pref_service.h"
+
+namespace {
+
+// Check an extension ID and an URL to be syntactically correct.
+bool CheckExtension(std::string id, std::string update_url) {
+ GURL url(update_url);
+ if (!url.is_valid()) {
+ LOG(WARNING) << "Policy specifies invalid update URL for external "
+ << "extension: " << update_url;
+ return false;
+ }
+ if (!Extension::IdIsValid(id)) {
+ LOG(WARNING) << "Policy specifies invalid ID for external "
+ << "extension: " << id;
+ return false;
+ }
+ return true;
+}
+
+}
+
+ExternalPolicyExtensionProvider::ExternalPolicyExtensionProvider()
+ : StatefulExternalExtensionProvider(Extension::INVALID,
+ Extension::EXTERNAL_POLICY_DOWNLOAD) {
+}
+
+ExternalPolicyExtensionProvider::~ExternalPolicyExtensionProvider() {
+}
+
+void ExternalPolicyExtensionProvider::SetPreferences(
+ PrefService* prefs) {
+ SetPreferences(prefs->GetList(prefs::kExtensionInstallForceList));
+}
+
+void ExternalPolicyExtensionProvider::SetPreferences(
+ const ListValue* forcelist) {
+ DictionaryValue* result = new DictionaryValue();
+ if (forcelist != NULL) {
+ std::string extension_desc;
+ for (ListValue::const_iterator it = forcelist->begin();
+ it != forcelist->end(); ++it) {
+ if (!(*it)->GetAsString(&extension_desc)) {
+ LOG(WARNING) << "Failed to read forcelist string.";
+ } else {
+ // Each string item of the list has the following form:
+ // extension_id_code;extension_update_url
+ // The update URL might also contain semicolons.
+ size_t pos = extension_desc.find(';');
+ std::string id = extension_desc.substr(0, pos);
+ std::string update_url = extension_desc.substr(pos+1);
+ if (CheckExtension(id, update_url)) {
+ result->SetString(id + ".external_update_url", update_url);
+ }
+ }
+ }
+ }
+ prefs_.reset(result);
+}
diff --git a/chrome/browser/extensions/external_policy_extension_provider.h b/chrome/browser/extensions/external_policy_extension_provider.h
new file mode 100644
index 0000000..8f34a34
--- /dev/null
+++ b/chrome/browser/extensions/external_policy_extension_provider.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTERNAL_POLICY_EXTENSION_PROVIDER_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_POLICY_EXTENSION_PROVIDER_H_
+#pragma once
+
+#include "chrome/browser/extensions/stateful_external_extension_provider.h"
+
+class ListValue;
+class MockExternalPolicyExtensionProviderVisitor;
+class PrefService;
+
+// A specialization of the ExternalExtensionProvider that uses
+// prefs::kExtensionInstallForceList to look up which external extensions are
+// registered.
+class ExternalPolicyExtensionProvider
+ : public StatefulExternalExtensionProvider {
+ public:
+ explicit ExternalPolicyExtensionProvider();
+ virtual ~ExternalPolicyExtensionProvider();
+
+ // Set the internal list of extensions based on
+ // prefs::kExtensionInstallForceList.
+ void SetPreferences(PrefService* prefs);
+
+ private:
+ friend class MockExternalPolicyExtensionProviderVisitor;
+
+ // Set the internal list of extensions based on |forcelist|.
+ void SetPreferences(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
new file mode 100644
index 0000000..4fb5117
--- /dev/null
+++ b/chrome/browser/extensions/external_policy_extension_provider_unittest.cc
@@ -0,0 +1,113 @@
+// 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 "base/logging.h"
+#include "base/values.h"
+#include "base/version.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 {
+};
+
+class MockExternalPolicyExtensionProviderVisitor
+ : public ExternalExtensionProvider::Visitor {
+ public:
+ MockExternalPolicyExtensionProviderVisitor() {
+ }
+
+ // Initialize a provider with |policy_forcelist|, and check that it parses
+ // exactly those extensions, that are specified in |policy_validlist|.
+ 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);
+
+ // 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);
+ EXPECT_EQ(0u, remaining_extensions->GetSize());
+ }
+
+ virtual void OnExternalExtensionFileFound(const std::string& id,
+ const Version* version,
+ const FilePath& path,
+ Extension::Location unused) {
+ ADD_FAILURE() << "There should be no external extensions from files.";
+ }
+
+ virtual void OnExternalExtensionUpdateUrlFound(
+ const std::string& id, const GURL& update_url,
+ Extension::Location location) {
+ // Extension has the correct location.
+ EXPECT_EQ(Extension::EXTERNAL_POLICY_DOWNLOAD, location);
+
+ // Provider returns the correct location when asked.
+ Extension::Location location1;
+ scoped_ptr<Version> version1;
+ provider_->GetExtensionDetails(id, &location1, &version1);
+ EXPECT_EQ(Extension::EXTERNAL_POLICY_DOWNLOAD, location1);
+ EXPECT_FALSE(version1.get());
+
+ // Remove the extension from our list.
+ StringValue ext_str(id + ";" + update_url.spec());
+ EXPECT_NE(-1, remaining_extensions->Remove(ext_str));
+ }
+
+ private:
+ ListValue* remaining_extensions;
+
+ scoped_ptr<ExternalPolicyExtensionProvider> provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockExternalPolicyExtensionProviderVisitor);
+};
+
+TEST_F(ExternalPolicyExtensionProviderTest, PolicyIsParsed) {
+ ListValue forced_extensions;
+ forced_extensions.Append(Value::CreateStringValue(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;http://www.example.com/crx?a=5;b=6"));
+ forced_extensions.Append(Value::CreateStringValue(
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;"
+ "https://clients2.google.com/service/update2/crx"));
+
+ MockExternalPolicyExtensionProviderVisitor mv;
+ std::set<std::string> empty;
+ mv.Visit(&forced_extensions, &forced_extensions, empty);
+}
+
+TEST_F(ExternalPolicyExtensionProviderTest, InvalidPolicyIsNotParsed) {
+ ListValue forced_extensions, valid_extensions;
+ StringValue valid(
+ "cccccccccccccccccccccccccccccccc;http://www.example.com/crx");
+ valid_extensions.Append(valid.DeepCopy());
+ forced_extensions.Append(valid.DeepCopy());
+ // Add invalid strings:
+ forced_extensions.Append(Value::CreateStringValue(""));
+ forced_extensions.Append(Value::CreateStringValue(";"));
+ forced_extensions.Append(Value::CreateStringValue(";;"));
+ forced_extensions.Append(Value::CreateStringValue(
+ ";http://www.example.com/crx"));
+ forced_extensions.Append(Value::CreateStringValue(
+ ";aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ forced_extensions.Append(Value::CreateStringValue(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;"));
+ forced_extensions.Append(Value::CreateStringValue(
+ "http://www.example.com/crx;aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ forced_extensions.Append(Value::CreateStringValue(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;http#//www.example.com/crx"));
+ forced_extensions.Append(Value::CreateStringValue(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ forced_extensions.Append(Value::CreateStringValue(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahttp#//www.example.com/crx"));
+
+ MockExternalPolicyExtensionProviderVisitor mv;
+ std::set<std::string> empty;
+ mv.Visit(&forced_extensions, &valid_extensions, empty);
+}
diff --git a/chrome/browser/extensions/external_pref_extension_provider.cc b/chrome/browser/extensions/external_pref_extension_provider.cc
index 3eaafc9..7580388 100644
--- a/chrome/browser/extensions/external_pref_extension_provider.cc
+++ b/chrome/browser/extensions/external_pref_extension_provider.cc
@@ -7,20 +7,14 @@
#include "app/app_paths.h"
#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/logging.h"
#include "base/path_service.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "base/version.h"
+#include "chrome/browser/extensions/stateful_external_extension_provider.h"
#include "chrome/common/json_value_serializer.h"
-// Constants for keeping track of extension preferences.
-const char kLocation[] = "location";
-const char kState[] = "state";
-const char kExternalCrx[] = "external_crx";
-const char kExternalVersion[] = "external_version";
-const char kExternalUpdateUrl[] = "external_update_url";
-
-ExternalPrefExtensionProvider::ExternalPrefExtensionProvider() {
+ExternalPrefExtensionProvider::ExternalPrefExtensionProvider()
+ : StatefulExternalExtensionProvider(Extension::EXTERNAL_PREF,
+ Extension::EXTERNAL_PREF_DOWNLOAD) {
FilePath json_file;
PathService::Get(app::DIR_EXTERNAL_EXTENSIONS, &json_file);
json_file = json_file.Append(FILE_PATH_LITERAL("external_extensions.json"));
@@ -42,100 +36,6 @@ void ExternalPrefExtensionProvider::SetPreferencesForTesting(
SetPreferences(&serializer);
}
-void ExternalPrefExtensionProvider::VisitRegisteredExtension(
- Visitor* visitor, const std::set<std::string>& ids_to_ignore) const {
- 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;
-
- FilePath::StringType external_crx;
- std::string external_version;
- std::string external_update_url;
-
- bool has_external_crx = extension->GetString(kExternalCrx, &external_crx);
- bool has_external_version = extension->GetString(kExternalVersion,
- &external_version);
- bool has_external_update_url = extension->GetString(kExternalUpdateUrl,
- &external_update_url);
- if (has_external_crx != has_external_version) {
- LOG(WARNING) << "Malformed extension dictionary for extension: "
- << extension_id.c_str() << ". " << kExternalCrx
- << " and " << kExternalVersion << " must be used together.";
- continue;
- }
-
- if (has_external_crx == has_external_update_url) {
- LOG(WARNING) << "Malformed extension dictionary for extension: "
- << extension_id.c_str() << ". Exactly one of the "
- << "followng keys should be used: " << kExternalCrx
- << ", " << kExternalUpdateUrl << ".";
- continue;
- }
-
- if (has_external_crx) {
- if (external_crx.find(FilePath::kParentDirectory) !=
- base::StringPiece::npos) {
- LOG(WARNING) << "Path traversal not allowed in path: "
- << external_crx.c_str();
- continue;
- }
-
- // If the path is relative, make it absolute.
- FilePath path(external_crx);
- if (!path.IsAbsolute()) {
- // Try path as relative path from external extension dir.
- FilePath base_path;
- PathService::Get(app::DIR_EXTERNAL_EXTENSIONS, &base_path);
- path = base_path.Append(external_crx);
- }
-
- scoped_ptr<Version> version;
- version.reset(Version::GetVersionFromString(external_version));
- if (!version.get()) {
- LOG(ERROR) << "Malformed extension dictionary for extension: "
- << extension_id.c_str() << ". Invalid version string \""
- << external_version << "\".";
- continue;
- }
- visitor->OnExternalExtensionFileFound(extension_id, version.get(), path,
- Extension::EXTERNAL_PREF);
- continue;
- }
-
- DCHECK(has_external_update_url); // Checking of keys above ensures this.
- GURL update_url(external_update_url);
- if (!update_url.is_valid()) {
- LOG(WARNING) << "Malformed extension dictionary for extension: "
- << extension_id.c_str() << ". " << kExternalUpdateUrl
- << " must be a valid URL. Saw \"" << external_update_url
- << "\".";
- continue;
- }
- visitor->OnExternalExtensionUpdateUrlFound(extension_id, update_url);
- }
-}
-
-Version* ExternalPrefExtensionProvider::RegisteredVersion(
- const std::string& id, Extension::Location* location) const {
- DictionaryValue* extension = NULL;
- if (!prefs_->GetDictionary(id, &extension))
- return NULL;
-
- std::string external_version;
- if (!extension->GetString(kExternalVersion, &external_version))
- return NULL;
-
- if (location)
- *location = Extension::EXTERNAL_PREF;
- return Version::GetVersionFromString(external_version);
-}
-
void ExternalPrefExtensionProvider::SetPreferences(
ValueSerializer* serializer) {
std::string error_msg;
diff --git a/chrome/browser/extensions/external_pref_extension_provider.h b/chrome/browser/extensions/external_pref_extension_provider.h
index aef6b17..8b9eb0b 100644
--- a/chrome/browser/extensions/external_pref_extension_provider.h
+++ b/chrome/browser/extensions/external_pref_extension_provider.h
@@ -6,18 +6,11 @@
#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_PREF_EXTENSION_PROVIDER_H_
#pragma once
-#include <set>
-#include <string>
-
-#include "chrome/browser/extensions/external_extension_provider.h"
-
-class DictionaryValue;
-class ValueSerializer;
-class Version;
+#include "chrome/browser/extensions/stateful_external_extension_provider.h"
// A specialization of the ExternalExtensionProvider that uses a json file to
// look up which external extensions are registered.
-class ExternalPrefExtensionProvider : public ExternalExtensionProvider {
+class ExternalPrefExtensionProvider : public StatefulExternalExtensionProvider {
public:
explicit ExternalPrefExtensionProvider();
virtual ~ExternalPrefExtensionProvider();
@@ -26,15 +19,6 @@ class ExternalPrefExtensionProvider : public ExternalExtensionProvider {
// but instead parse a json file specified by the test.
void SetPreferencesForTesting(const std::string& json_data_for_testing);
- // ExternalExtensionProvider implementation:
- virtual void VisitRegisteredExtension(
- Visitor* visitor, const std::set<std::string>& ids_to_ignore) const;
-
- virtual Version* RegisteredVersion(const std::string& id,
- Extension::Location* location) const;
- protected:
- scoped_ptr<DictionaryValue> prefs_;
-
private:
void SetPreferences(ValueSerializer* serializer);
};
diff --git a/chrome/browser/extensions/external_registry_extension_provider_win.cc b/chrome/browser/extensions/external_registry_extension_provider_win.cc
index 02ae850..00bea09 100644
--- a/chrome/browser/extensions/external_registry_extension_provider_win.cc
+++ b/chrome/browser/extensions/external_registry_extension_provider_win.cc
@@ -10,6 +10,8 @@
#include "base/version.h"
#include "base/win/registry.h"
+namespace {
+
// The Registry hive where to look for external extensions.
const HKEY kRegRoot = HKEY_LOCAL_MACHINE;
@@ -22,6 +24,16 @@ const wchar_t kRegistryExtensionPath[] = L"path";
// Registry value of that key that defines the current version of the .crx file.
const wchar_t kRegistryExtensionVersion[] = L"version";
+bool OpenKeyById(const std::string& id, base::win::RegKey *key) {
+ std::wstring key_path = ASCIIToWide(kRegistryExtensions);
+ key_path.append(L"\\");
+ key_path.append(ASCIIToWide(id));
+
+ return key->Open(kRegRoot, key_path.c_str(), KEY_READ);
+}
+
+} // namespace
+
ExternalRegistryExtensionProvider::ExternalRegistryExtensionProvider() {
}
@@ -54,6 +66,7 @@ void ExternalRegistryExtensionProvider::VisitRegisteredExtension(
if (!version.get()) {
LOG(ERROR) << "Invalid version value " << extension_version
<< " for key " << key_path;
+ ++iterator;
continue;
}
@@ -75,22 +88,29 @@ void ExternalRegistryExtensionProvider::VisitRegisteredExtension(
}
}
-Version* ExternalRegistryExtensionProvider::RegisteredVersion(
- const std::string& id,
- Extension::Location* location) const {
+
+bool ExternalRegistryExtensionProvider::HasExtension(
+ const std::string& id) const {
base::win::RegKey key;
- std::wstring key_path = ASCIIToWide(kRegistryExtensions);
- key_path.append(L"\\");
- key_path.append(ASCIIToWide(id));
+ return OpenKeyById(id, &key);
+}
- if (!key.Open(kRegRoot, key_path.c_str(), KEY_READ))
- return NULL;
+bool ExternalRegistryExtensionProvider::GetExtensionDetails(
+ const std::string& id,
+ Extension::Location* location,
+ scoped_ptr<Version>* version) const {
+ base::win::RegKey key;
+ if (!OpenKeyById(id, &key))
+ return false;
std::wstring extension_version;
if (!key.ReadValue(kRegistryExtensionVersion, &extension_version))
- return NULL;
+ return false;
+
+ if (version)
+ version->reset(Version::GetVersionFromString(extension_version));
if (location)
*location = Extension::EXTERNAL_REGISTRY;
- return Version::GetVersionFromString(extension_version);
+ return true;
}
diff --git a/chrome/browser/extensions/external_registry_extension_provider_win.h b/chrome/browser/extensions/external_registry_extension_provider_win.h
index b5b44bb..bb60106 100644
--- a/chrome/browser/extensions/external_registry_extension_provider_win.h
+++ b/chrome/browser/extensions/external_registry_extension_provider_win.h
@@ -24,8 +24,11 @@ class ExternalRegistryExtensionProvider : public ExternalExtensionProvider {
virtual void VisitRegisteredExtension(
Visitor* visitor, const std::set<std::string>& ids_to_ignore) const;
- virtual Version* RegisteredVersion(const std::string& id,
- Extension::Location* location) const;
+ virtual bool HasExtension(const std::string& id) const;
+
+ virtual bool GetExtensionDetails(const std::string& id,
+ Extension::Location* location,
+ scoped_ptr<Version>* version) const;
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_PROVIDER_WIN_H_
diff --git a/chrome/browser/extensions/image_loading_tracker.cc b/chrome/browser/extensions/image_loading_tracker.cc
index f4f9bfd..496c3ad 100644
--- a/chrome/browser/extensions/image_loading_tracker.cc
+++ b/chrome/browser/extensions/image_loading_tracker.cc
@@ -134,7 +134,7 @@ ImageLoadingTracker::~ImageLoadingTracker() {
loader_->StopTracking();
}
-void ImageLoadingTracker::LoadImage(Extension* extension,
+void ImageLoadingTracker::LoadImage(const Extension* extension,
const ExtensionResource& resource,
const gfx::Size& max_size,
CacheParam cache) {
@@ -187,7 +187,7 @@ void ImageLoadingTracker::Observe(NotificationType type,
DCHECK(type == NotificationType::EXTENSION_UNLOADED ||
type == NotificationType::EXTENSION_UNLOADED_DISABLED);
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
// 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.h b/chrome/browser/extensions/image_loading_tracker.h
index bac2f04..0ce3703 100644
--- a/chrome/browser/extensions/image_loading_tracker.h
+++ b/chrome/browser/extensions/image_loading_tracker.h
@@ -64,13 +64,13 @@ class ImageLoadingTracker : public NotificationObserver {
// |max_size| it will be resized to those dimensions. IMPORTANT NOTE: this
// function may call back your observer synchronously (ie before it returns)
// if the image was found in the cache.
- void LoadImage(Extension* extension,
+ void LoadImage(const Extension* extension,
const ExtensionResource& resource,
const gfx::Size& max_size,
CacheParam cache);
private:
- typedef std::map<int, Extension*> LoadMap;
+ typedef std::map<int, const Extension*> LoadMap;
class ImageLoader;
diff --git a/chrome/browser/extensions/image_loading_tracker_unittest.cc b/chrome/browser/extensions/image_loading_tracker_unittest.cc
index f796a36..57b5268 100644
--- a/chrome/browser/extensions/image_loading_tracker_unittest.cc
+++ b/chrome/browser/extensions/image_loading_tracker_unittest.cc
@@ -51,7 +51,7 @@ class ImageLoadingTrackerTest : public testing::Test,
return result;
}
- Extension* CreateExtension() {
+ scoped_refptr<Extension> CreateExtension() {
// Create and load an extension.
FilePath test_file;
if (!PathService::Get(chrome::DIR_TEST_DATA, &test_file)) {
@@ -74,11 +74,8 @@ class ImageLoadingTrackerTest : public testing::Test,
if (!valid_value.get())
return NULL;
- scoped_ptr<Extension> extension(new Extension(test_file));
- if (!extension->InitFromValue(*valid_value, false, &error))
- return NULL;
-
- return extension.release();
+ return Extension::Create(
+ test_file, Extension::INVALID, *valid_value, false, &error);
}
SkBitmap image_;
@@ -99,7 +96,7 @@ class ImageLoadingTrackerTest : public testing::Test,
// Tests asking ImageLoadingTracker to cache pushes the result to the Extension.
TEST_F(ImageLoadingTrackerTest, Cache) {
- scoped_ptr<Extension> extension(CreateExtension());
+ scoped_refptr<Extension> extension(CreateExtension());
ASSERT_TRUE(extension.get() != NULL);
ExtensionResource image_resource =
@@ -146,7 +143,7 @@ TEST_F(ImageLoadingTrackerTest, Cache) {
// Tests deleting an extension while waiting for the image to load doesn't cause
// problems.
TEST_F(ImageLoadingTrackerTest, DeleteExtensionWhileWaitingForCache) {
- scoped_ptr<Extension> extension(CreateExtension());
+ scoped_refptr<Extension> extension(CreateExtension());
ASSERT_TRUE(extension.get() != NULL);
ExtensionResource image_resource =
@@ -166,11 +163,11 @@ TEST_F(ImageLoadingTrackerTest, DeleteExtensionWhileWaitingForCache) {
NotificationService::current()->Notify(
NotificationType::EXTENSION_UNLOADED,
NotificationService::AllSources(),
- Details<Extension>(extension.get()));
+ Details<const Extension>(extension.get()));
// Chuck the extension, that way if anyone tries to access it we should crash
// or get valgrind errors.
- extension.reset();
+ extension = NULL;
WaitForImageLoad();
diff --git a/chrome/browser/extensions/page_action_apitest.cc b/chrome/browser/extensions/page_action_apitest.cc
index c03c030..95e029e 100644
--- a/chrome/browser/extensions/page_action_apitest.cc
+++ b/chrome/browser/extensions/page_action_apitest.cc
@@ -18,7 +18,7 @@
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PageAction) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("page_action/basics")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
{
// Tell the extension to update the page action state.
@@ -62,7 +62,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PageAction) {
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PageActionAddPopup) {
// Load the extension, which has no default popup.
ASSERT_TRUE(RunExtensionTest("page_action/add_popup")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
int tab_id = ExtensionTabUtil::GetTabId(browser()->GetSelectedTabContents());
@@ -107,7 +107,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PageActionAddPopup) {
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PageActionRemovePopup) {
// Load the extension, which has a page action with a default popup.
ASSERT_TRUE(RunExtensionTest("page_action/remove_popup")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
int tab_id = ExtensionTabUtil::GetTabId(browser()->GetSelectedTabContents());
@@ -136,7 +136,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PageActionRemovePopup) {
// break.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, OldPageActions) {
ASSERT_TRUE(RunExtensionTest("page_action/old_api")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
// Have the extension enable the page action.
@@ -161,7 +161,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, OldPageActions) {
// Tests popups in page actions.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ShowPageActionPopup) {
ASSERT_TRUE(RunExtensionTest("page_action/popup")) << message_;
- Extension* extension = GetSingleLoadedExtension();
+ const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.cc b/chrome/browser/extensions/sandboxed_extension_unpacker.cc
index fc8aea8..c1702b1 100644
--- a/chrome/browser/extensions/sandboxed_extension_unpacker.cc
+++ b/chrome/browser/extensions/sandboxed_extension_unpacker.cc
@@ -9,6 +9,7 @@
#include "base/base64.h"
#include "base/crypto/signature_verifier.h"
#include "base/file_util.h"
+#include "base/file_util_proxy.h"
#include "base/message_loop.h"
#include "base/scoped_handle.h"
#include "base/task.h"
@@ -116,7 +117,13 @@ void SandboxedExtensionUnpacker::Start() {
}
}
-SandboxedExtensionUnpacker::~SandboxedExtensionUnpacker() {}
+SandboxedExtensionUnpacker::~SandboxedExtensionUnpacker() {
+ base::FileUtilProxy::Delete(
+ BrowserThread::GetMessageLoopProxyForThread(thread_identifier_),
+ temp_dir_.Take(),
+ true,
+ NULL);
+}
void SandboxedExtensionUnpacker::StartProcessOnIOThread(
const FilePath& temp_crx_path) {
@@ -140,18 +147,20 @@ void SandboxedExtensionUnpacker::OnUnpackExtensionSucceeded(
// extension was unpacked to. We use this until the extension is finally
// installed. For example, the install UI shows images from inside the
// extension.
- extension_.reset(new Extension(extension_root_));
// Localize manifest now, so confirm UI gets correct extension name.
std::string error;
- if (!extension_l10n_util::LocalizeExtension(extension_.get(),
+ if (!extension_l10n_util::LocalizeExtension(extension_root_,
final_manifest.get(),
&error)) {
ReportFailure(error);
return;
}
- if (!extension_->InitFromValue(*final_manifest, true, &error)) {
+ extension_ = Extension::Create(
+ extension_root_, Extension::INTERNAL, *final_manifest, true, &error);
+
+ if (!extension_.get()) {
ReportFailure(std::string("Manifest is invalid: ") + error);
return;
}
@@ -270,8 +279,8 @@ void SandboxedExtensionUnpacker::ReportFailure(const std::string& error) {
void SandboxedExtensionUnpacker::ReportSuccess() {
// Client takes ownership of temporary directory and extension.
- client_->OnUnpackSuccess(temp_dir_.Take(), extension_root_,
- extension_.release());
+ client_->OnUnpackSuccess(temp_dir_.Take(), extension_root_, extension_);
+ extension_ = NULL;
}
DictionaryValue* SandboxedExtensionUnpacker::RewriteManifestFile(
diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.h b/chrome/browser/extensions/sandboxed_extension_unpacker.h
index 8df1414..8438482 100644
--- a/chrome/browser/extensions/sandboxed_extension_unpacker.h
+++ b/chrome/browser/extensions/sandboxed_extension_unpacker.h
@@ -29,7 +29,7 @@ class SandboxedExtensionUnpackerClient
// for deleting this memory.
virtual void OnUnpackSuccess(const FilePath& temp_dir,
const FilePath& extension_root,
- Extension* extension) = 0;
+ const Extension* extension) = 0;
virtual void OnUnpackFailure(const std::string& error) = 0;
protected:
@@ -160,7 +160,7 @@ class SandboxedExtensionUnpacker : public UtilityProcessHost::Client {
FilePath extension_root_;
// Represents the extension we're unpacking.
- scoped_ptr<Extension> extension_;
+ scoped_refptr<Extension> extension_;
// Whether we've received a response from the utility process yet.
bool got_response_;
diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker_unittest.cc b/chrome/browser/extensions/sandboxed_extension_unpacker_unittest.cc
index d461ff4..1842e00 100644
--- a/chrome/browser/extensions/sandboxed_extension_unpacker_unittest.cc
+++ b/chrome/browser/extensions/sandboxed_extension_unpacker_unittest.cc
@@ -25,8 +25,7 @@ using testing::Invoke;
void OnUnpackSuccess(const FilePath& temp_dir,
const FilePath& extension_root,
- Extension* extension) {
- delete extension;
+ const Extension* extension) {
// Don't delete temp_dir here, we need to do some post op checking.
}
@@ -38,7 +37,7 @@ class MockSandboxedExtensionUnpackerClient
MOCK_METHOD3(OnUnpackSuccess,
void(const FilePath& temp_dir,
const FilePath& extension_root,
- Extension* extension));
+ const Extension* extension));
MOCK_METHOD1(OnUnpackFailure,
void(const std::string& error));
@@ -52,12 +51,17 @@ class MockSandboxedExtensionUnpackerClient
class SandboxedExtensionUnpackerTest : public testing::Test {
public:
virtual void SetUp() {
+ file_thread_.reset(new BrowserThread(BrowserThread::FILE, &loop_));
// It will delete itself.
client_ = new MockSandboxedExtensionUnpackerClient;
client_->DelegateToFake();
}
virtual void TearDown() {
+ // Need to destruct SandboxedExtensionUnpacker before the message loop since
+ // it posts a task to it.
+ sandboxed_unpacker_ = NULL;
+ loop_.RunAllPending();
// Clean up finally.
ASSERT_TRUE(file_util::Delete(install_dir_, true)) <<
install_dir_.value();
@@ -94,6 +98,9 @@ class SandboxedExtensionUnpackerTest : public testing::Test {
sandboxed_unpacker_ =
new SandboxedExtensionUnpacker(crx_path, temp_dir_, NULL, client_);
+ // Hack since SandboxedExtensionUnpacker gets its background thread id from
+ // the Start call, but we don't call it here.
+ sandboxed_unpacker_->thread_identifier_ = BrowserThread::FILE;
PrepareUnpackerEnv();
}
@@ -145,6 +152,8 @@ class SandboxedExtensionUnpackerTest : public testing::Test {
MockSandboxedExtensionUnpackerClient* client_;
scoped_ptr<ExtensionUnpacker> unpacker_;
scoped_refptr<SandboxedExtensionUnpacker> sandboxed_unpacker_;
+ MessageLoop loop_;
+ scoped_ptr<BrowserThread> file_thread_;
};
TEST_F(SandboxedExtensionUnpackerTest, NoCatalogsSuccess) {
diff --git a/chrome/browser/extensions/stateful_external_extension_provider.cc b/chrome/browser/extensions/stateful_external_extension_provider.cc
new file mode 100644
index 0000000..63899da
--- /dev/null
+++ b/chrome/browser/extensions/stateful_external_extension_provider.cc
@@ -0,0 +1,159 @@
+// 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/stateful_external_extension_provider.h"
+
+#include "app/app_paths.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "base/version.h"
+
+namespace {
+
+// Constants for keeping track of extension preferences.
+const char kLocation[] = "location";
+const char kState[] = "state";
+const char kExternalCrx[] = "external_crx";
+const char kExternalVersion[] = "external_version";
+const char kExternalUpdateUrl[] = "external_update_url";
+
+}
+
+StatefulExternalExtensionProvider::StatefulExternalExtensionProvider(
+ Extension::Location crx_location,
+ Extension::Location download_location)
+ : crx_location_(crx_location),
+ download_location_(download_location) {
+}
+
+StatefulExternalExtensionProvider::~StatefulExternalExtensionProvider() {
+}
+
+void StatefulExternalExtensionProvider::VisitRegisteredExtension(
+ Visitor* visitor, const std::set<std::string>& ids_to_ignore) const {
+ 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;
+
+ FilePath::StringType external_crx;
+ std::string external_version;
+ std::string external_update_url;
+
+ bool has_external_crx = extension->GetString(kExternalCrx, &external_crx);
+ bool has_external_version = extension->GetString(kExternalVersion,
+ &external_version);
+ bool has_external_update_url = extension->GetString(kExternalUpdateUrl,
+ &external_update_url);
+ if (has_external_crx != has_external_version) {
+ LOG(WARNING) << "Malformed extension dictionary for extension: "
+ << extension_id.c_str() << ". " << kExternalCrx
+ << " and " << kExternalVersion << " must be used together.";
+ continue;
+ }
+
+ if (has_external_crx == has_external_update_url) {
+ LOG(WARNING) << "Malformed extension dictionary for extension: "
+ << extension_id.c_str() << ". Exactly one of the "
+ << "followng keys should be used: " << kExternalCrx
+ << ", " << kExternalUpdateUrl << ".";
+ continue;
+ }
+
+ if (has_external_crx) {
+ if (crx_location_ == Extension::INVALID) {
+ LOG(WARNING) << "This provider does not support installing external "
+ << "extensions from crx files.";
+ continue;
+ }
+ if (external_crx.find(FilePath::kParentDirectory) !=
+ base::StringPiece::npos) {
+ LOG(WARNING) << "Path traversal not allowed in path: "
+ << external_crx.c_str();
+ continue;
+ }
+
+ // If the path is relative, make it absolute.
+ FilePath path(external_crx);
+ if (!path.IsAbsolute()) {
+ // Try path as relative path from external extension dir.
+ FilePath base_path;
+ PathService::Get(app::DIR_EXTERNAL_EXTENSIONS, &base_path);
+ path = base_path.Append(external_crx);
+ }
+
+ scoped_ptr<Version> version;
+ version.reset(Version::GetVersionFromString(external_version));
+ if (!version.get()) {
+ LOG(WARNING) << "Malformed extension dictionary for extension: "
+ << extension_id.c_str() << ". Invalid version string \""
+ << external_version << "\".";
+ continue;
+ }
+ visitor->OnExternalExtensionFileFound(extension_id, version.get(), path,
+ crx_location_);
+ } else { // if (has_external_update_url)
+ DCHECK(has_external_update_url); // Checking of keys above ensures this.
+ if (download_location_ == Extension::INVALID) {
+ LOG(WARNING) << "This provider does not support installing external "
+ << "extensions from update URLs.";
+ continue;
+ }
+ GURL update_url(external_update_url);
+ if (!update_url.is_valid()) {
+ LOG(WARNING) << "Malformed extension dictionary for extension: "
+ << extension_id.c_str() << ". " << kExternalUpdateUrl
+ << " must be a valid URL. Saw \"" << external_update_url
+ << "\".";
+ continue;
+ }
+ visitor->OnExternalExtensionUpdateUrlFound(
+ extension_id, update_url, download_location_);
+ }
+ }
+}
+
+bool StatefulExternalExtensionProvider::HasExtension(
+ const std::string& id) const {
+ return prefs_->HasKey(id);
+}
+
+bool StatefulExternalExtensionProvider::GetExtensionDetails(
+ const std::string& id, Extension::Location* location,
+ scoped_ptr<Version>* version) const {
+ DictionaryValue* extension = NULL;
+ if (!prefs_->GetDictionary(id, &extension))
+ return false;
+
+ Extension::Location loc = Extension::INVALID;
+ if (extension->HasKey(kExternalUpdateUrl)) {
+ loc = download_location_;
+
+ } else if (extension->HasKey(kExternalCrx)) {
+ loc = crx_location_;
+
+ std::string external_version;
+ if (!extension->GetString(kExternalVersion, &external_version))
+ return false;
+
+ if (version)
+ version->reset(Version::GetVersionFromString(external_version));
+
+ } else {
+ NOTREACHED(); // Chrome should not allow prefs to get into this state.
+ return false;
+ }
+
+ if (location)
+ *location = loc;
+
+ return true;
+}
diff --git a/chrome/browser/extensions/stateful_external_extension_provider.h b/chrome/browser/extensions/stateful_external_extension_provider.h
new file mode 100644
index 0000000..506873d
--- /dev/null
+++ b/chrome/browser/extensions/stateful_external_extension_provider.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_STATEFUL_EXTERNAL_EXTENSION_PROVIDER_H_
+#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;
+class ValueSerializer;
+class Version;
+
+// A specialization of the ExternalExtensionProvider that stores the registered
+// external extensions in a dictionary. This dictionary (|prefs_|) will be used
+// by HasExtension() and GetExtensionDetails() to return information about the
+// stored external extensions. It is the responsibility of specialized
+// subclasses to initialize this internal dictionary.
+// 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.
+class StatefulExternalExtensionProvider : public ExternalExtensionProvider {
+ public:
+ // Initialize the location for external extensions originating from crx
+ // files: |crx_location|, and originating from update URLs:
+ // |download_location|. If either of the origins is not supported by this
+ // provider, then it should be initialized as Extensions::INVALID.
+ StatefulExternalExtensionProvider(
+ Extension::Location crx_location,
+ Extension::Location download_location);
+ virtual ~StatefulExternalExtensionProvider();
+
+ // ExternalExtensionProvider implementation:
+ virtual void VisitRegisteredExtension(
+ Visitor* visitor, const std::set<std::string>& ids_to_ignore) const;
+
+ virtual bool HasExtension(const std::string& id) const;
+
+ virtual bool GetExtensionDetails(const std::string& id,
+ Extension::Location* location,
+ scoped_ptr<Version>* version) const;
+ protected:
+ // Location for external extensions that are provided by this provider from
+ // local crx files.
+ const Extension::Location crx_location_;
+ // Location for external extensions that are provided by this provider from
+ // update URLs.
+ const Extension::Location download_location_;
+ // Dictionary of the external extensions that are provided by this provider.
+ scoped_ptr<DictionaryValue> prefs_;
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_STATEFUL_EXTERNAL_EXTENSION_PROVIDER_H_
diff --git a/chrome/browser/extensions/test_extension_prefs.cc b/chrome/browser/extensions/test_extension_prefs.cc
index a32f847..2cbb2d1 100644
--- a/chrome/browser/extensions/test_extension_prefs.cc
+++ b/chrome/browser/extensions/test_extension_prefs.cc
@@ -45,22 +45,25 @@ void TestExtensionPrefs::RecreateExtensionPrefs() {
prefs_.reset(new ExtensionPrefs(pref_service_.get(), temp_dir_.path()));
}
-Extension* TestExtensionPrefs::AddExtension(std::string name) {
+scoped_refptr<Extension> TestExtensionPrefs::AddExtension(std::string name) {
DictionaryValue dictionary;
dictionary.SetString(extension_manifest_keys::kName, name);
dictionary.SetString(extension_manifest_keys::kVersion, "0.1");
return AddExtensionWithManifest(dictionary, Extension::INTERNAL);
}
-Extension* TestExtensionPrefs::AddExtensionWithManifest(
+scoped_refptr<Extension> TestExtensionPrefs::AddExtensionWithManifest(
const DictionaryValue& manifest, Extension::Location location) {
std::string name;
EXPECT_TRUE(manifest.GetString(extension_manifest_keys::kName, &name));
FilePath path = extensions_dir_.AppendASCII(name);
- Extension* extension = new Extension(path);
std::string errors;
- extension->set_location(location);
- EXPECT_TRUE(extension->InitFromValue(manifest, false, &errors));
+ scoped_refptr<Extension> extension = Extension::Create(
+ path, location, manifest, false, &errors);
+ EXPECT_TRUE(extension);
+ if (!extension)
+ return NULL;
+
EXPECT_TRUE(Extension::IdIsValid(extension->id()));
const bool kInitialIncognitoEnabled = false;
prefs_->OnExtensionInstalled(extension, Extension::ENABLED,
@@ -69,6 +72,6 @@ Extension* TestExtensionPrefs::AddExtensionWithManifest(
}
std::string TestExtensionPrefs::AddExtensionAndReturnId(std::string name) {
- scoped_ptr<Extension> extension(AddExtension(name));
+ scoped_refptr<Extension> extension(AddExtension(name));
return extension->id();
}
diff --git a/chrome/browser/extensions/test_extension_prefs.h b/chrome/browser/extensions/test_extension_prefs.h
index 1523bee..cb723b2 100644
--- a/chrome/browser/extensions/test_extension_prefs.h
+++ b/chrome/browser/extensions/test_extension_prefs.h
@@ -34,11 +34,11 @@ class TestExtensionPrefs {
// Creates a new Extension with the given name in our temp dir, adds it to
// our ExtensionPrefs, and returns it.
- Extension* AddExtension(std::string name);
+ scoped_refptr<Extension> AddExtension(std::string name);
// Similar to AddExtension, but takes a dictionary with manifest values.
- Extension* AddExtensionWithManifest(const DictionaryValue& manifest,
- Extension::Location location);
+ scoped_refptr<Extension> AddExtensionWithManifest(
+ const DictionaryValue& manifest, Extension::Location location);
// Similar to AddExtension, this adds a new test Extension. This is useful for
// cases when you don't need the Extension object, but just the id it was
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
index 6d00c22..ebfbe98 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
@@ -81,7 +81,7 @@ bool ThemeInstalledInfoBarDelegate::Cancel() {
if (!previous_theme_id_.empty()) {
ExtensionsService* service = profile_->GetExtensionsService();
if (service) {
- Extension* previous_theme =
+ const Extension* previous_theme =
service->GetExtensionById(previous_theme_id_, true);
if (previous_theme) {
profile_->SetTheme(previous_theme);
@@ -102,7 +102,7 @@ void ThemeInstalledInfoBarDelegate::Observe(
case NotificationType::BROWSER_THEME_CHANGED: {
// If the new theme is different from what this info bar is associated
// with, close this info bar since it is no longer relevant.
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
if (!extension || theme_id_ != extension->id())
tab_contents_->RemoveInfoBar(this);
break;
@@ -113,6 +113,6 @@ void ThemeInstalledInfoBarDelegate::Observe(
}
}
-bool ThemeInstalledInfoBarDelegate::MatchesTheme(Extension* theme) {
+bool ThemeInstalledInfoBarDelegate::MatchesTheme(const Extension* theme) {
return (theme && theme->id() == theme_id_);
}
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.h b/chrome/browser/extensions/theme_installed_infobar_delegate.h
index 2c54fa5..b1ed99e 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.h
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.h
@@ -33,7 +33,7 @@ class ThemeInstalledInfoBarDelegate : public ConfirmInfoBarDelegate,
// Returns true if the given theme is the same as the one associated with this
// info bar.
- bool MatchesTheme(Extension* theme);
+ bool MatchesTheme(const Extension* theme);
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
diff --git a/chrome/browser/extensions/user_script_listener.cc b/chrome/browser/extensions/user_script_listener.cc
index 4e84045..c553b1f 100644
--- a/chrome/browser/extensions/user_script_listener.cc
+++ b/chrome/browser/extensions/user_script_listener.cc
@@ -98,7 +98,7 @@ void UserScriptListener::ReplaceURLPatterns(const URLPatterns& patterns) {
url_patterns_ = patterns;
}
-void UserScriptListener::CollectURLPatterns(Extension* extension,
+void UserScriptListener::CollectURLPatterns(const Extension* extension,
URLPatterns* patterns) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -118,12 +118,13 @@ void UserScriptListener::Observe(NotificationType type,
switch (type.value) {
case NotificationType::EXTENSION_LOADED: {
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
if (extension->content_scripts().empty())
return; // no new patterns from this extension.
URLPatterns new_patterns;
- CollectURLPatterns(Details<Extension>(details).ptr(), &new_patterns);
+ CollectURLPatterns(Details<const Extension>(details).ptr(),
+ &new_patterns);
if (!new_patterns.empty()) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
@@ -134,7 +135,8 @@ void UserScriptListener::Observe(NotificationType type,
}
case NotificationType::EXTENSION_UNLOADED: {
- Extension* unloaded_extension = Details<Extension>(details).ptr();
+ const Extension* unloaded_extension =
+ Details<const Extension>(details).ptr();
if (unloaded_extension->content_scripts().empty())
return; // no patterns to delete for this extension.
diff --git a/chrome/browser/extensions/user_script_listener.h b/chrome/browser/extensions/user_script_listener.h
index 05de21a..3ac83ed 100644
--- a/chrome/browser/extensions/user_script_listener.h
+++ b/chrome/browser/extensions/user_script_listener.h
@@ -82,7 +82,7 @@ class UserScriptListener
// Helper to collect the extension's user script URL patterns in a list and
// return it.
- void CollectURLPatterns(Extension* extension, URLPatterns* patterns);
+ void CollectURLPatterns(const Extension* extension, URLPatterns* patterns);
// NotificationObserver
virtual void Observe(NotificationType type,
diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc
index 560fda3..1712bb6 100644
--- a/chrome/browser/extensions/user_script_master.cc
+++ b/chrome/browser/extensions/user_script_master.cc
@@ -108,7 +108,7 @@ bool UserScriptMaster::ScriptReloader::ParseMetadataHeader(
script->set_description(value);
} else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
URLPattern pattern(UserScript::kValidUserScriptSchemes);
- if (!pattern.Parse(value))
+ if (URLPattern::PARSE_SUCCESS != pattern.Parse(value))
return false;
script->add_url_pattern(pattern);
} else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
@@ -253,14 +253,7 @@ static base::SharedMemory* Serialize(const UserScriptList& scripts) {
// Create the shared memory object.
scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
- if (!shared_memory->Create(std::string(), // anonymous
- false, // read-only
- false, // open existing
- pickle.size()))
- return NULL;
-
- // Map into our process.
- if (!shared_memory->Map(pickle.size()))
+ if (!shared_memory->CreateAndMapAnonymous(pickle.size()))
return NULL;
// Copy the pickle to shared memory.
@@ -346,7 +339,7 @@ void UserScriptMaster::Observe(NotificationType type,
break;
case NotificationType::EXTENSION_LOADED: {
// Add any content scripts inside the extension.
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
bool incognito_enabled = profile_->GetExtensionsService()->
IsIncognitoEnabled(extension);
bool allow_file_access = profile_->GetExtensionsService()->
@@ -364,7 +357,7 @@ void UserScriptMaster::Observe(NotificationType type,
}
case NotificationType::EXTENSION_UNLOADED: {
// Remove any content scripts.
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
UserScriptList new_lone_scripts;
for (UserScriptList::iterator iter = lone_scripts_.begin();
iter != lone_scripts_.end(); ++iter) {
@@ -380,7 +373,7 @@ void UserScriptMaster::Observe(NotificationType type,
break;
}
case NotificationType::EXTENSION_USER_SCRIPTS_UPDATED: {
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension = Details<const Extension>(details).ptr();
UserScriptList new_lone_scripts;
bool incognito_enabled = profile_->GetExtensionsService()->
IsIncognitoEnabled(extension);
diff --git a/chrome/browser/extensions/window_open_apitest.cc b/chrome/browser/extensions/window_open_apitest.cc
index 27c1b96..5de474b 100644
--- a/chrome/browser/extensions/window_open_apitest.cc
+++ b/chrome/browser/extensions/window_open_apitest.cc
@@ -11,13 +11,7 @@
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"
-// crbug.com/60156
-#if defined(OS_MACOSX)
-// On mac, this test basically never succeeds.
-#define FLAKY_WindowOpen DISABLED_WindowOpen
-#endif
-
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_WindowOpen) {
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpen) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);