summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorrdevlin.cronin <rdevlin.cronin@chromium.org>2015-09-24 12:50:55 -0700
committerCommit bot <commit-bot@chromium.org>2015-09-24 19:52:04 +0000
commitcce78d017ca073f0719a8967e29c68f3553cbf4a (patch)
treeb043cba86b44197a02f50a6f77fd78407044df2b /chrome
parent1748d384c547136d059d413f5acbb1622ba548f0 (diff)
downloadchromium_src-cce78d017ca073f0719a8967e29c68f3553cbf4a.zip
chromium_src-cce78d017ca073f0719a8967e29c68f3553cbf4a.tar.gz
chromium_src-cce78d017ca073f0719a8967e29c68f3553cbf4a.tar.bz2
[Extensions] Fix race condition crashes in the extension bubbles
There were race conditions due to the asynchronous display of extension bubbles where the extension(s) could have been uninstalled before the bubble is displayed (it seems the most common time these happen is when an extension to be warned about is queued for uninstallation via sync). Handle this situation gracefully. BUG=531648 TBR=sky@chromium.org (micro ui changes in files that aren't explicitly owned by finnur@) Review URL: https://codereview.chromium.org/1352103003 Cr-Commit-Position: refs/heads/master@{#350627}
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/dev_mode_bubble_controller.cc23
-rw-r--r--chrome/browser/extensions/dev_mode_bubble_controller.h9
-rw-r--r--chrome/browser/extensions/extension_message_bubble_controller.cc48
-rw-r--r--chrome/browser/extensions/extension_message_bubble_controller.h14
-rw-r--r--chrome/browser/extensions/extension_message_bubble_controller_unittest.cc20
-rw-r--r--chrome/browser/extensions/ntp_overridden_bubble_controller.cc37
-rw-r--r--chrome/browser/extensions/ntp_overridden_bubble_controller.h4
-rw-r--r--chrome/browser/extensions/proxy_overridden_bubble_controller.cc36
-rw-r--r--chrome/browser/extensions/proxy_overridden_bubble_controller.h4
-rw-r--r--chrome/browser/extensions/settings_api_bubble_controller.cc57
-rw-r--r--chrome/browser/extensions/settings_api_bubble_controller.h4
-rw-r--r--chrome/browser/extensions/suspicious_extension_bubble_controller.cc25
-rw-r--r--chrome/browser/extensions/suspicious_extension_bubble_controller.h6
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm14
-rw-r--r--chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc32
-rw-r--r--chrome/browser/ui/extensions/extension_message_bubble_browsertest.h9
-rw-r--r--chrome/browser/ui/extensions/extension_message_bubble_factory.cc14
-rw-r--r--chrome/browser/ui/toolbar/toolbar_actions_bar.cc4
-rw-r--r--chrome/browser/ui/views/extensions/extension_message_bubble_view.cc7
-rw-r--r--chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc13
-rw-r--r--chrome/browser/ui/views/settings_api_bubble_helper_views.cc2
-rw-r--r--chrome/test/data/extensions/api_test/proxy/register/manifest.json10
-rw-r--r--chrome/test/data/extensions/api_test/proxy/register/test.js13
23 files changed, 223 insertions, 182 deletions
diff --git a/chrome/browser/extensions/dev_mode_bubble_controller.cc b/chrome/browser/extensions/dev_mode_bubble_controller.cc
index cbce3db..fcb3990 100644
--- a/chrome/browser/extensions/dev_mode_bubble_controller.cc
+++ b/chrome/browser/extensions/dev_mode_bubble_controller.cc
@@ -35,7 +35,7 @@ class DevModeBubbleDelegate
~DevModeBubbleDelegate() override;
// ExtensionMessageBubbleController::Delegate methods.
- bool ShouldIncludeExtension(const std::string& extension_id) override;
+ bool ShouldIncludeExtension(const Extension* extension) override;
void AcknowledgeExtension(
const std::string& extension_id,
ExtensionMessageBubbleController::BubbleAction user_action) override;
@@ -50,9 +50,11 @@ class DevModeBubbleDelegate
base::string16 GetDismissButtonLabel() const override;
bool ShouldShowExtensionList() const override;
bool ShouldHighlightExtensions() const override;
+ bool ShouldLimitToEnabledExtensions() const override;
void LogExtensionCount(size_t count) override;
void LogAction(
ExtensionMessageBubbleController::BubbleAction action) override;
+ std::set<Profile*>* GetProfileSet() override;
private:
DISALLOW_COPY_AND_ASSIGN(DevModeBubbleDelegate);
@@ -65,11 +67,7 @@ DevModeBubbleDelegate::DevModeBubbleDelegate(Profile* profile)
DevModeBubbleDelegate::~DevModeBubbleDelegate() {
}
-bool DevModeBubbleDelegate::ShouldIncludeExtension(
- const std::string& extension_id) {
- const Extension* extension = service()->GetExtensionById(extension_id, false);
- if (!extension)
- return false;
+bool DevModeBubbleDelegate::ShouldIncludeExtension(const Extension* extension) {
return (extension->location() == Manifest::UNPACKED ||
extension->location() == Manifest::COMMAND_LINE);
}
@@ -121,6 +119,10 @@ bool DevModeBubbleDelegate::ShouldHighlightExtensions() const {
return true;
}
+bool DevModeBubbleDelegate::ShouldLimitToEnabledExtensions() const {
+ return true;
+}
+
void DevModeBubbleDelegate::LogExtensionCount(size_t count) {
UMA_HISTOGRAM_COUNTS_100(
"ExtensionBubble.ExtensionsInDevModeCount", count);
@@ -133,6 +135,10 @@ void DevModeBubbleDelegate::LogAction(
action, ExtensionMessageBubbleController::ACTION_BOUNDARY);
}
+std::set<Profile*>* DevModeBubbleDelegate::GetProfileSet() {
+ return g_shown_for_profiles.Pointer();
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -150,11 +156,6 @@ DevModeBubbleController::DevModeBubbleController(Browser* browser)
DevModeBubbleController::~DevModeBubbleController() {
}
-bool DevModeBubbleController::ShouldShow() {
- return !g_shown_for_profiles.Get().count(profile()->GetOriginalProfile()) &&
- !GetExtensionList().empty();
-}
-
void DevModeBubbleController::Show(ExtensionMessageBubble* bubble) {
g_shown_for_profiles.Get().insert(profile()->GetOriginalProfile());
ExtensionMessageBubbleController::Show(bubble);
diff --git a/chrome/browser/extensions/dev_mode_bubble_controller.h b/chrome/browser/extensions/dev_mode_bubble_controller.h
index 48246d2..d5f2569 100644
--- a/chrome/browser/extensions/dev_mode_bubble_controller.h
+++ b/chrome/browser/extensions/dev_mode_bubble_controller.h
@@ -22,17 +22,10 @@ class DevModeBubbleController : public ExtensionMessageBubbleController {
explicit DevModeBubbleController(Browser* browser);
~DevModeBubbleController() override;
- // Whether the controller knows of extensions to list in the bubble. Returns
- // true if so.
- bool ShouldShow();
-
- // ExtensionMessageBubbleController methods.
+ // ExtensionMessageBubbleController:
void Show(ExtensionMessageBubble* bubble) override;
private:
- // A weak pointer to the profile we are associated with. Not owned by us.
- Profile* profile_;
-
DISALLOW_COPY_AND_ASSIGN(DevModeBubbleController);
};
diff --git a/chrome/browser/extensions/extension_message_bubble_controller.cc b/chrome/browser/extensions/extension_message_bubble_controller.cc
index 3fe6dc5..4f0bf9f 100644
--- a/chrome/browser/extensions/extension_message_bubble_controller.cc
+++ b/chrome/browser/extensions/extension_message_bubble_controller.cc
@@ -44,11 +44,6 @@ ExtensionMessageBubbleController::Delegate::Delegate(Profile* profile)
ExtensionMessageBubbleController::Delegate::~Delegate() {
}
-void ExtensionMessageBubbleController::Delegate::RestrictToSingleExtension(
- const std::string& extension_id) {
- NOTIMPLEMENTED(); // Derived classes that need this should implement.
-}
-
base::string16 ExtensionMessageBubbleController::Delegate::GetLearnMoreLabel()
const {
return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
@@ -77,6 +72,11 @@ void ExtensionMessageBubbleController::Delegate::SetBubbleInfoBeenAcknowledged(
value ? new base::FundamentalValue(value) : NULL);
}
+std::set<Profile*>*
+ExtensionMessageBubbleController::Delegate::GetProfileSet() {
+ return nullptr;
+}
+
std::string
ExtensionMessageBubbleController::Delegate::get_acknowledged_flag_pref_name()
const {
@@ -109,6 +109,12 @@ Profile* ExtensionMessageBubbleController::profile() {
return browser_->profile();
}
+bool ExtensionMessageBubbleController::ShouldShow() {
+ std::set<Profile*>* profiles = delegate_->GetProfileSet();
+ return (!profiles || !profiles->count(profile()->GetOriginalProfile())) &&
+ !GetExtensionList().empty();
+}
+
std::vector<base::string16>
ExtensionMessageBubbleController::GetExtensionList() {
ExtensionIdList* list = GetOrCreateExtensionList();
@@ -117,17 +123,13 @@ ExtensionMessageBubbleController::GetExtensionList() {
ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
std::vector<base::string16> return_value;
- for (ExtensionIdList::const_iterator it = list->begin();
- it != list->end(); ++it) {
+ for (const std::string& id : *list) {
const Extension* extension =
- registry->GetExtensionById(*it, ExtensionRegistry::EVERYTHING);
- if (extension) {
+ registry->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
+ // The extension may have been removed, since showing the bubble is an
+ // asynchronous process.
+ if (extension)
return_value.push_back(base::UTF8ToUTF16(extension->name()));
- } else {
- return_value.push_back(
- base::ASCIIToUTF16(std::string("(unknown name) ") + *it));
- // TODO(finnur): Add this as a string to the grd, for next milestone.
- }
}
return return_value;
}
@@ -228,14 +230,16 @@ void ExtensionMessageBubbleController::AcknowledgeExtensions() {
ExtensionIdList* ExtensionMessageBubbleController::GetOrCreateExtensionList() {
if (!initialized_) {
- scoped_ptr<const ExtensionSet> extension_set(
- ExtensionRegistry::Get(profile())->GenerateInstalledExtensionsSet());
- for (ExtensionSet::const_iterator it = extension_set->begin();
- it != extension_set->end(); ++it) {
- std::string id = (*it)->id();
- if (!delegate_->ShouldIncludeExtension(id))
- continue;
- extension_list_.push_back(id);
+ ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
+ scoped_ptr<const ExtensionSet> all_extensions;
+ if (!delegate_->ShouldLimitToEnabledExtensions())
+ all_extensions = registry->GenerateInstalledExtensionsSet();
+ const ExtensionSet& extensions_to_check =
+ all_extensions ? *all_extensions : registry->enabled_extensions();
+ for (const scoped_refptr<const Extension>& extension :
+ extensions_to_check) {
+ if (delegate_->ShouldIncludeExtension(extension.get()))
+ extension_list_.push_back(extension->id());
}
delegate_->LogExtensionCount(extension_list_.size());
diff --git a/chrome/browser/extensions/extension_message_bubble_controller.h b/chrome/browser/extensions/extension_message_bubble_controller.h
index a2024a2..babbdfd 100644
--- a/chrome/browser/extensions/extension_message_bubble_controller.h
+++ b/chrome/browser/extensions/extension_message_bubble_controller.h
@@ -34,7 +34,7 @@ class ExtensionMessageBubbleController {
explicit Delegate(Profile* profile);
virtual ~Delegate();
- virtual bool ShouldIncludeExtension(const std::string& extension_id) = 0;
+ virtual bool ShouldIncludeExtension(const Extension* extension) = 0;
virtual void AcknowledgeExtension(
const std::string& extension_id,
BubbleAction action) = 0;
@@ -65,9 +65,8 @@ class ExtensionMessageBubbleController {
// the toolbar.
virtual bool ShouldHighlightExtensions() const = 0;
- // In some cases, we want the delegate only to handle a single extension
- // and this sets which extension.
- virtual void RestrictToSingleExtension(const std::string& extension_id);
+ // Returns true if only enabled extensions should be considered.
+ virtual bool ShouldLimitToEnabledExtensions() const = 0;
// Record, through UMA, how many extensions were found.
virtual void LogExtensionCount(size_t count) = 0;
@@ -78,6 +77,10 @@ class ExtensionMessageBubbleController {
virtual void SetBubbleInfoBeenAcknowledged(const std::string& extension_id,
bool value);
+ // Returns the set of profiles for which this bubble has been shown.
+ // If profiles are not tracked, returns null (default).
+ virtual std::set<Profile*>* GetProfileSet();
+
protected:
Profile* profile() { return profile_; }
ExtensionService* service() { return service_; }
@@ -109,6 +112,9 @@ class ExtensionMessageBubbleController {
Delegate* delegate() const { return delegate_.get(); }
Profile* profile();
+ // Returns true if the bubble should be displayed.
+ bool ShouldShow();
+
// Obtains a list of all extensions (by name) the controller knows about.
std::vector<base::string16> GetExtensionList();
diff --git a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
index 4ec423f..2126ce5 100644
--- a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
+++ b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
@@ -732,7 +732,7 @@ TEST_F(ExtensionMessageBubbleTest, NtpOverriddenControllerTest) {
new TestNtpOverriddenBubbleController(browser()));
// The list will contain one enabled unpacked extension (ext 2).
- EXPECT_TRUE(controller->ShouldShow(kId2));
+ EXPECT_TRUE(controller->ShouldShow());
std::vector<base::string16> override_extensions =
controller->GetExtensionList();
ASSERT_EQ(1U, override_extensions.size());
@@ -746,7 +746,7 @@ TEST_F(ExtensionMessageBubbleTest, NtpOverriddenControllerTest) {
FakeExtensionMessageBubble bubble;
bubble.set_action_on_show(
FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON);
- EXPECT_TRUE(controller->ShouldShow(kId2));
+ EXPECT_TRUE(controller->ShouldShow());
bubble.set_controller(controller.get());
controller->Show(&bubble);
EXPECT_EQ(0U, controller->link_click_count());
@@ -768,7 +768,7 @@ TEST_F(ExtensionMessageBubbleTest, NtpOverriddenControllerTest) {
bubble.set_action_on_show(
FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK);
controller.reset(new TestNtpOverriddenBubbleController(browser()));
- EXPECT_TRUE(controller->ShouldShow(kId2));
+ EXPECT_TRUE(controller->ShouldShow());
bubble.set_controller(controller.get());
controller->Show(&bubble);
EXPECT_EQ(1U, controller->link_click_count());
@@ -789,7 +789,7 @@ TEST_F(ExtensionMessageBubbleTest, NtpOverriddenControllerTest) {
bubble.set_action_on_show(
FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_ACTION_BUTTON);
controller.reset(new TestNtpOverriddenBubbleController(browser()));
- EXPECT_TRUE(controller->ShouldShow(kId2));
+ EXPECT_TRUE(controller->ShouldShow());
override_extensions = controller->GetExtensionList();
EXPECT_EQ(1U, override_extensions.size());
bubble.set_controller(controller.get());
@@ -860,14 +860,14 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_ProxyOverriddenControllerTest) {
new TestProxyOverriddenBubbleController(browser()));
// The second extension is too new to warn about.
- EXPECT_FALSE(controller->ShouldShow(kId1));
- EXPECT_FALSE(controller->ShouldShow(kId2));
+ EXPECT_FALSE(controller->ShouldShow());
+ EXPECT_FALSE(controller->ShouldShow());
// Lets make it old enough.
SetInstallTime(kId2, old_enough, prefs);
// The list will contain one enabled unpacked extension (ext 2).
- EXPECT_TRUE(controller->ShouldShow(kId2));
- EXPECT_FALSE(controller->ShouldShow(kId3));
+ EXPECT_TRUE(controller->ShouldShow());
+ EXPECT_FALSE(controller->ShouldShow());
std::vector<base::string16> override_extensions =
controller->GetExtensionList();
ASSERT_EQ(1U, override_extensions.size());
@@ -901,7 +901,7 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_ProxyOverriddenControllerTest) {
bubble.set_action_on_show(
FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK);
controller.reset(new TestProxyOverriddenBubbleController(browser()));
- EXPECT_TRUE(controller->ShouldShow(kId2));
+ EXPECT_TRUE(controller->ShouldShow());
bubble.set_controller(controller.get());
controller->Show(&bubble);
EXPECT_EQ(1U, controller->link_click_count());
@@ -922,7 +922,7 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_ProxyOverriddenControllerTest) {
bubble.set_action_on_show(
FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_ACTION_BUTTON);
controller.reset(new TestProxyOverriddenBubbleController(browser()));
- EXPECT_TRUE(controller->ShouldShow(kId2));
+ EXPECT_TRUE(controller->ShouldShow());
override_extensions = controller->GetExtensionList();
EXPECT_EQ(1U, override_extensions.size());
bubble.set_controller(controller.get());
diff --git a/chrome/browser/extensions/ntp_overridden_bubble_controller.cc b/chrome/browser/extensions/ntp_overridden_bubble_controller.cc
index f982408..c46e67c 100644
--- a/chrome/browser/extensions/ntp_overridden_bubble_controller.cc
+++ b/chrome/browser/extensions/ntp_overridden_bubble_controller.cc
@@ -6,6 +6,7 @@
#include "base/metrics/histogram.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_web_ui.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/url_constants.h"
@@ -34,7 +35,7 @@ class NtpOverriddenBubbleDelegate
~NtpOverriddenBubbleDelegate() override;
// ExtensionMessageBubbleController::Delegate methods.
- bool ShouldIncludeExtension(const std::string& extension_id) override;
+ bool ShouldIncludeExtension(const extensions::Extension* extension) override;
void AcknowledgeExtension(
const std::string& extension_id,
extensions::ExtensionMessageBubbleController::BubbleAction user_action)
@@ -50,7 +51,7 @@ class NtpOverriddenBubbleDelegate
base::string16 GetDismissButtonLabel() const override;
bool ShouldShowExtensionList() const override;
bool ShouldHighlightExtensions() const override;
- void RestrictToSingleExtension(const std::string& extension_id) override;
+ bool ShouldLimitToEnabledExtensions() const override;
void LogExtensionCount(size_t count) override;
void LogAction(extensions::ExtensionMessageBubbleController::BubbleAction
action) override;
@@ -71,19 +72,21 @@ NtpOverriddenBubbleDelegate::NtpOverriddenBubbleDelegate(
NtpOverriddenBubbleDelegate::~NtpOverriddenBubbleDelegate() {}
bool NtpOverriddenBubbleDelegate::ShouldIncludeExtension(
- const std::string& extension_id) {
- if (!extension_id_.empty() && extension_id_ != extension_id)
+ const extensions::Extension* extension) {
+ if (!extension_id_.empty() && extension_id_ != extension->id())
return false;
- const extensions::Extension* extension =
- registry()->GetExtensionById(extension_id,
- extensions::ExtensionRegistry::ENABLED);
- if (!extension)
- return false; // The extension provided is no longer enabled.
+ GURL url(chrome::kChromeUINewTabURL);
+ if (!ExtensionWebUI::HandleChromeURLOverride(&url, profile()))
+ return false; // No override for newtab found.
- if (HasBubbleInfoBeenAcknowledged(extension_id))
+ if (extension->id() != url.host())
return false;
+ if (HasBubbleInfoBeenAcknowledged(extension->id()))
+ return false;
+
+ extension_id_ = extension->id();
return true;
}
@@ -144,9 +147,8 @@ bool NtpOverriddenBubbleDelegate::ShouldHighlightExtensions() const {
return false;
}
-void NtpOverriddenBubbleDelegate::RestrictToSingleExtension(
- const std::string& extension_id) {
- extension_id_ = extension_id;
+bool NtpOverriddenBubbleDelegate::ShouldLimitToEnabledExtensions() const {
+ return true;
}
void NtpOverriddenBubbleDelegate::LogExtensionCount(size_t count) {
@@ -174,15 +176,6 @@ NtpOverriddenBubbleController::NtpOverriddenBubbleController(Browser* browser)
NtpOverriddenBubbleController::~NtpOverriddenBubbleController() {}
-bool NtpOverriddenBubbleController::ShouldShow(
- const std::string& extension_id) {
- if (!delegate()->ShouldIncludeExtension(extension_id))
- return false;
-
- delegate()->RestrictToSingleExtension(extension_id);
- return true;
-}
-
bool NtpOverriddenBubbleController::CloseOnDeactivate() {
return true;
}
diff --git a/chrome/browser/extensions/ntp_overridden_bubble_controller.h b/chrome/browser/extensions/ntp_overridden_bubble_controller.h
index 4e43b85..d5d84b0 100644
--- a/chrome/browser/extensions/ntp_overridden_bubble_controller.h
+++ b/chrome/browser/extensions/ntp_overridden_bubble_controller.h
@@ -15,10 +15,6 @@ class NtpOverriddenBubbleController : public ExtensionMessageBubbleController {
explicit NtpOverriddenBubbleController(Browser* browser);
~NtpOverriddenBubbleController() override;
- // Whether the controller knows that we should show the bubble for extension
- // with |extension_id|. Returns true if so.
- bool ShouldShow(const std::string& extension_id);
-
// ExtensionMessageBubbleController:
bool CloseOnDeactivate() override;
diff --git a/chrome/browser/extensions/proxy_overridden_bubble_controller.cc b/chrome/browser/extensions/proxy_overridden_bubble_controller.cc
index 0c47a28..fa66901f 100644
--- a/chrome/browser/extensions/proxy_overridden_bubble_controller.cc
+++ b/chrome/browser/extensions/proxy_overridden_bubble_controller.cc
@@ -39,7 +39,7 @@ class ProxyOverriddenBubbleDelegate
~ProxyOverriddenBubbleDelegate() override;
// ExtensionMessageBubbleController::Delegate methods.
- bool ShouldIncludeExtension(const std::string& extension_id) override;
+ bool ShouldIncludeExtension(const Extension* extension) override;
void AcknowledgeExtension(
const std::string& extension_id,
ExtensionMessageBubbleController::BubbleAction user_action) override;
@@ -54,7 +54,7 @@ class ProxyOverriddenBubbleDelegate
base::string16 GetDismissButtonLabel() const override;
bool ShouldShowExtensionList() const override;
bool ShouldHighlightExtensions() const override;
- void RestrictToSingleExtension(const std::string& extension_id) override;
+ bool ShouldLimitToEnabledExtensions() const override;
void LogExtensionCount(size_t count) override;
void LogAction(
ExtensionMessageBubbleController::BubbleAction action) override;
@@ -75,17 +75,12 @@ ProxyOverriddenBubbleDelegate::ProxyOverriddenBubbleDelegate(
ProxyOverriddenBubbleDelegate::~ProxyOverriddenBubbleDelegate() {}
bool ProxyOverriddenBubbleDelegate::ShouldIncludeExtension(
- const std::string& extension_id) {
- if (!extension_id_.empty() && extension_id_ != extension_id)
- return false;
-
- const Extension* extension =
- registry()->enabled_extensions().GetByID(extension_id);
- if (!extension)
- return false; // The extension provided is no longer enabled.
+ const Extension* extension) {
+ if (!extension_id_.empty() && extension_id_ != extension->id())
+ return false; // Only one extension can be controlling the proxy at a time.
const Extension* overriding = GetExtensionOverridingProxy(profile());
- if (!overriding || overriding->id() != extension_id)
+ if (!overriding || overriding != extension)
return false;
ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
@@ -94,9 +89,12 @@ bool ProxyOverriddenBubbleDelegate::ShouldIncludeExtension(
if (since_install.InDays() < kDaysSinceInstallMin)
return false;
- if (HasBubbleInfoBeenAcknowledged(extension_id))
+ if (HasBubbleInfoBeenAcknowledged(extension->id()))
return false;
+ // Found the only extension; restrict to this one.
+ extension_id_ = extension->id();
+
return true;
}
@@ -161,9 +159,8 @@ bool ProxyOverriddenBubbleDelegate::ShouldHighlightExtensions() const {
return true;
}
-void ProxyOverriddenBubbleDelegate::RestrictToSingleExtension(
- const std::string& extension_id) {
- extension_id_ = extension_id;
+bool ProxyOverriddenBubbleDelegate::ShouldLimitToEnabledExtensions() const {
+ return true;
}
void ProxyOverriddenBubbleDelegate::LogExtensionCount(size_t count) {
@@ -190,15 +187,6 @@ ProxyOverriddenBubbleController::ProxyOverriddenBubbleController(
ProxyOverriddenBubbleController::~ProxyOverriddenBubbleController() {}
-bool ProxyOverriddenBubbleController::ShouldShow(
- const std::string& extension_id) {
- if (!delegate()->ShouldIncludeExtension(extension_id))
- return false;
-
- delegate()->RestrictToSingleExtension(extension_id);
- return true;
-}
-
bool ProxyOverriddenBubbleController::CloseOnDeactivate() {
return false;
}
diff --git a/chrome/browser/extensions/proxy_overridden_bubble_controller.h b/chrome/browser/extensions/proxy_overridden_bubble_controller.h
index 8e9a90d..d5d46b8 100644
--- a/chrome/browser/extensions/proxy_overridden_bubble_controller.h
+++ b/chrome/browser/extensions/proxy_overridden_bubble_controller.h
@@ -20,10 +20,6 @@ class ProxyOverriddenBubbleController
explicit ProxyOverriddenBubbleController(Browser* browser);
~ProxyOverriddenBubbleController() override;
- // Whether the controller knows that we should show the bubble for extension
- // with |extension_id|. Returns true if so.
- bool ShouldShow(const std::string& extension_id);
-
// ExtensionMessageBubbleController:
bool CloseOnDeactivate() override;
diff --git a/chrome/browser/extensions/settings_api_bubble_controller.cc b/chrome/browser/extensions/settings_api_bubble_controller.cc
index d550019..8ffef42 100644
--- a/chrome/browser/extensions/settings_api_bubble_controller.cc
+++ b/chrome/browser/extensions/settings_api_bubble_controller.cc
@@ -39,7 +39,7 @@ class SettingsApiBubbleDelegate
~SettingsApiBubbleDelegate() override;
// ExtensionMessageBubbleController::Delegate methods.
- bool ShouldIncludeExtension(const std::string& extension_id) override;
+ bool ShouldIncludeExtension(const Extension* extension) override;
void AcknowledgeExtension(
const std::string& extension_id,
ExtensionMessageBubbleController::BubbleAction user_action) override;
@@ -54,6 +54,7 @@ class SettingsApiBubbleDelegate
base::string16 GetDismissButtonLabel() const override;
bool ShouldShowExtensionList() const override;
bool ShouldHighlightExtensions() const override;
+ bool ShouldLimitToEnabledExtensions() const override;
void LogExtensionCount(size_t count) override;
void LogAction(
ExtensionMessageBubbleController::BubbleAction action) override;
@@ -81,16 +82,17 @@ SettingsApiBubbleDelegate::SettingsApiBubbleDelegate(
SettingsApiBubbleDelegate::~SettingsApiBubbleDelegate() {}
bool SettingsApiBubbleDelegate::ShouldIncludeExtension(
- const std::string& extension_id) {
- const Extension* extension =
- registry()->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
- if (!extension)
- return false; // The extension provided is no longer enabled.
+ const Extension* extension) {
+ // If the browser is showing the 'Chrome crashed' infobar, it won't be showing
+ // the startup pages, so there's no point in showing the bubble now.
+ if (type_ == BUBBLE_TYPE_STARTUP_PAGES &&
+ profile()->GetLastSessionExitType() == Profile::EXIT_CRASHED)
+ return false;
- if (HasBubbleInfoBeenAcknowledged(extension_id))
+ if (HasBubbleInfoBeenAcknowledged(extension->id()))
return false;
- const Extension* override = NULL;
+ const Extension* override = nullptr;
switch (type_) {
case extensions::BUBBLE_TYPE_HOME_PAGE:
override = extensions::GetExtensionOverridingHomepage(profile());
@@ -103,10 +105,10 @@ bool SettingsApiBubbleDelegate::ShouldIncludeExtension(
break;
}
- if (!override || override->id() != extension->id())
+ if (!override || override != extension)
return false;
- extension_id_ = extension_id;
+ extension_id_ = extension->id();
return true;
}
@@ -239,6 +241,10 @@ bool SettingsApiBubbleDelegate::ShouldHighlightExtensions() const {
return type_ == BUBBLE_TYPE_STARTUP_PAGES;
}
+bool SettingsApiBubbleDelegate::ShouldLimitToEnabledExtensions() const {
+ return true;
+}
+
void SettingsApiBubbleDelegate::LogExtensionCount(size_t count) {
}
@@ -281,37 +287,6 @@ SettingsApiBubbleController::SettingsApiBubbleController(
SettingsApiBubbleController::~SettingsApiBubbleController() {}
-bool SettingsApiBubbleController::ShouldShow() {
- const Extension* extension = nullptr;
- switch (type_) {
- case BUBBLE_TYPE_HOME_PAGE:
- extension = GetExtensionOverridingHomepage(profile());
- break;
- case BUBBLE_TYPE_SEARCH_ENGINE:
- extension = GetExtensionOverridingSearchEngine(profile());
- break;
- case BUBBLE_TYPE_STARTUP_PAGES:
- extension = GetExtensionOverridingStartupPages(profile());
- break;
- }
-
- if (!extension)
- return false;
-
- if (delegate()->HasBubbleInfoBeenAcknowledged(extension->id()))
- return false;
-
- if (!delegate()->ShouldIncludeExtension(extension->id()))
- return false;
-
- // If the browser is showing the 'Chrome crashed' infobar, it won't be showing
- // the startup pages, so there's no point in showing the bubble now.
- if (type_ == BUBBLE_TYPE_STARTUP_PAGES)
- return profile()->GetLastSessionExitType() != Profile::EXIT_CRASHED;
-
- return true;
-}
-
bool SettingsApiBubbleController::CloseOnDeactivate() {
// Startup bubbles tend to get lost in the focus storm that happens on
// startup. Other types should dismiss on focus loss.
diff --git a/chrome/browser/extensions/settings_api_bubble_controller.h b/chrome/browser/extensions/settings_api_bubble_controller.h
index 6daf755..0e1c620 100644
--- a/chrome/browser/extensions/settings_api_bubble_controller.h
+++ b/chrome/browser/extensions/settings_api_bubble_controller.h
@@ -19,10 +19,6 @@ class SettingsApiBubbleController : public ExtensionMessageBubbleController {
SettingsApiBubbleController(Browser* browser, SettingsApiOverrideType type);
~SettingsApiBubbleController() override;
- // Returns true if we should show the bubble for the extension actively
- // overriding the setting of |type_|.
- bool ShouldShow();
-
// ExtensionMessageBubbleController:
bool CloseOnDeactivate() override;
diff --git a/chrome/browser/extensions/suspicious_extension_bubble_controller.cc b/chrome/browser/extensions/suspicious_extension_bubble_controller.cc
index be2d2e7..56b943f 100644
--- a/chrome/browser/extensions/suspicious_extension_bubble_controller.cc
+++ b/chrome/browser/extensions/suspicious_extension_bubble_controller.cc
@@ -40,7 +40,7 @@ class SuspiciousExtensionBubbleDelegate
~SuspiciousExtensionBubbleDelegate() override;
// ExtensionMessageBubbleController::Delegate methods.
- bool ShouldIncludeExtension(const std::string& extension_id) override;
+ bool ShouldIncludeExtension(const extensions::Extension* extension) override;
void AcknowledgeExtension(
const std::string& extension_id,
ExtensionMessageBubbleController::BubbleAction user_action) override;
@@ -55,9 +55,11 @@ class SuspiciousExtensionBubbleDelegate
base::string16 GetDismissButtonLabel() const override;
bool ShouldShowExtensionList() const override;
bool ShouldHighlightExtensions() const override;
+ bool ShouldLimitToEnabledExtensions() const override;
void LogExtensionCount(size_t count) override;
void LogAction(
ExtensionMessageBubbleController::BubbleAction action) override;
+ std::set<Profile*>* GetProfileSet() override;
private:
DISALLOW_COPY_AND_ASSIGN(SuspiciousExtensionBubbleDelegate);
@@ -73,15 +75,15 @@ SuspiciousExtensionBubbleDelegate::~SuspiciousExtensionBubbleDelegate() {
}
bool SuspiciousExtensionBubbleDelegate::ShouldIncludeExtension(
- const std::string& extension_id) {
+ const extensions::Extension* extension) {
extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(
profile());
- if (!prefs->IsExtensionDisabled(extension_id))
+ if (!prefs->IsExtensionDisabled(extension->id()))
return false;
- int disable_reasons = prefs->GetDisableReasons(extension_id);
+ int disable_reasons = prefs->GetDisableReasons(extension->id());
if (disable_reasons & extensions::Extension::DISABLE_NOT_VERIFIED)
- return !HasBubbleInfoBeenAcknowledged(extension_id);
+ return !HasBubbleInfoBeenAcknowledged(extension->id());
return false;
}
@@ -141,6 +143,10 @@ bool SuspiciousExtensionBubbleDelegate::ShouldHighlightExtensions() const {
return false;
}
+bool SuspiciousExtensionBubbleDelegate::ShouldLimitToEnabledExtensions() const {
+ return false;
+}
+
void SuspiciousExtensionBubbleDelegate::LogExtensionCount(
size_t count) {
UMA_HISTOGRAM_COUNTS_100(
@@ -154,6 +160,10 @@ void SuspiciousExtensionBubbleDelegate::LogAction(
action, ExtensionMessageBubbleController::ACTION_BOUNDARY);
}
+std::set<Profile*>* SuspiciousExtensionBubbleDelegate::GetProfileSet() {
+ return g_shown_for_profiles.Pointer();
+}
+
} // namespace
namespace extensions {
@@ -175,11 +185,6 @@ SuspiciousExtensionBubbleController::SuspiciousExtensionBubbleController(
SuspiciousExtensionBubbleController::~SuspiciousExtensionBubbleController() {
}
-bool SuspiciousExtensionBubbleController::ShouldShow() {
- return !g_shown_for_profiles.Get().count(profile()->GetOriginalProfile()) &&
- !GetExtensionList().empty();
-}
-
void SuspiciousExtensionBubbleController::Show(ExtensionMessageBubble* bubble) {
g_shown_for_profiles.Get().insert(profile()->GetOriginalProfile());
ExtensionMessageBubbleController::Show(bubble);
diff --git a/chrome/browser/extensions/suspicious_extension_bubble_controller.h b/chrome/browser/extensions/suspicious_extension_bubble_controller.h
index d44d2eb..5b9f5b6 100644
--- a/chrome/browser/extensions/suspicious_extension_bubble_controller.h
+++ b/chrome/browser/extensions/suspicious_extension_bubble_controller.h
@@ -21,11 +21,7 @@ class SuspiciousExtensionBubbleController
explicit SuspiciousExtensionBubbleController(Browser* browser);
~SuspiciousExtensionBubbleController() override;
- // Whether the controller knows of extensions to list in the bubble. Returns
- // true if so.
- bool ShouldShow();
-
- // ExtensionMessageBubbleController methods.
+ // ExtensionMessageBubbleController:
void Show(ExtensionMessageBubble* bubble) override;
private:
diff --git a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm
index ed4886f2..8813bfa 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm
@@ -72,6 +72,7 @@ class ExtensionMessageBubbleBrowserTestMac
void SetUpCommandLine(base::CommandLine* command_line) override;
void CheckBubble(Browser* browser, AnchorPosition anchor) override;
void CloseBubble(Browser* browser) override;
+ void CheckBubbleIsNotPresent(Browser* browser) override;
DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleBrowserTestMac);
};
@@ -110,6 +111,14 @@ void ExtensionMessageBubbleBrowserTestMac::CloseBubble(Browser* browser) {
EXPECT_EQ(nil, [controller activeBubble]);
}
+void ExtensionMessageBubbleBrowserTestMac::CheckBubbleIsNotPresent(
+ Browser* browser) {
+ EXPECT_EQ(
+ nil,
+ [[ToolbarControllerForBrowser(browser) browserActionsController]
+ activeBubble]);
+}
+
IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleBrowserTestMac,
ExtensionBubbleAnchoredToExtensionAction) {
TestBubbleAnchoredToExtensionAction();
@@ -134,3 +143,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleBrowserTestMac,
ExtensionBubbleShowsOnStartup) {
TestBubbleShowsOnStartup();
}
+
+IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleBrowserTestMac,
+ TestUninstallDangerousExtension) {
+ TestUninstallDangerousExtension();
+}
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
index ff3b3c4..06eff9e 100644
--- a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
+++ b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
@@ -4,11 +4,13 @@
#include "chrome/browser/ui/extensions/extension_message_bubble_browsertest.h"
+#include "base/bind_helpers.h"
#include "base/run_loop.h"
#include "chrome/browser/extensions/extension_action_test_util.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/ui/extensions/extension_message_bubble_factory.h"
#include "extensions/common/feature_switch.h"
+#include "extensions/test/extension_test_message_listener.h"
ExtensionMessageBubbleBrowserTest::ExtensionMessageBubbleBrowserTest() {
}
@@ -29,6 +31,12 @@ void ExtensionMessageBubbleBrowserTest::SetUpCommandLine(
ExtensionMessageBubbleFactory::OVERRIDE_ENABLED);
}
+void ExtensionMessageBubbleBrowserTest::TearDownOnMainThread() {
+ ExtensionMessageBubbleFactory::set_override_for_tests(
+ ExtensionMessageBubbleFactory::NO_OVERRIDE);
+ BrowserActionsBarBrowserTest::TearDownOnMainThread();
+}
+
void ExtensionMessageBubbleBrowserTest::TestBubbleAnchoredToExtensionAction() {
scoped_refptr<const extensions::Extension> action_extension =
extensions::extension_action_test_util::CreateActionExtension(
@@ -85,6 +93,30 @@ TestBubbleAnchoredToWrenchMenuWithOtherAction() {
CloseBubble(second_browser);
}
+void ExtensionMessageBubbleBrowserTest::TestUninstallDangerousExtension() {
+ // Load an extension that overrides the proxy setting.
+ ExtensionTestMessageListener listener("registered", false);
+ const extensions::Extension* extension =
+ LoadExtension(test_data_dir_.AppendASCII("api_test")
+ .AppendASCII("proxy")
+ .AppendASCII("register"));
+ // Wait for it to complete.
+ listener.WaitUntilSatisfied();
+
+ // Create a second browser with the extension installed - the bubble will be
+ // set to show.
+ Browser* second_browser = new Browser(
+ Browser::CreateParams(profile(), browser()->host_desktop_type()));
+ ASSERT_TRUE(second_browser);
+ // Uninstall the extension before the bubble is shown. This should not crash,
+ // and the bubble shouldn't be shown.
+ extension_service()->UninstallExtension(
+ extension->id(), extensions::UNINSTALL_REASON_FOR_TESTING,
+ base::Bind(&base::DoNothing), nullptr);
+ base::RunLoop().RunUntilIdle();
+ CheckBubbleIsNotPresent(second_browser);
+}
+
void ExtensionMessageBubbleBrowserTest::PreBubbleShowsOnStartup() {
LoadExtension(test_data_dir_.AppendASCII("good_unpacked"));
}
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.h b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.h
index c11f8c25..c6d0412 100644
--- a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.h
+++ b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.h
@@ -22,6 +22,7 @@ class ExtensionMessageBubbleBrowserTest
// BrowserActionsBarBrowserTest:
void SetUpCommandLine(base::CommandLine* command_line) override;
+ void TearDownOnMainThread() override;
// Checks the position of the bubble present in the given |browser|, when the
// bubble should be anchored at the given |anchor|.
@@ -30,6 +31,9 @@ class ExtensionMessageBubbleBrowserTest
// Closes the bubble present in the given |browser|.
virtual void CloseBubble(Browser* browser) = 0;
+ // Checks that there is no active bubble for the given |browser|.
+ virtual void CheckBubbleIsNotPresent(Browser* browser) = 0;
+
// The following are essentially the different tests, but we can't define the
// tests in this file, since it relies on platform-specific implementation
// (the above virtual methods).
@@ -49,6 +53,11 @@ class ExtensionMessageBubbleBrowserTest
// Regression test for crbug.com/485614.
void TestBubbleAnchoredToWrenchMenuWithOtherAction();
+ // Tests that uninstalling the extension between when the bubble is originally
+ // slated to show and when it does show is handled gracefully.
+ // Regression test for crbug.com/531648.
+ void TestUninstallDangerousExtension();
+
// Tests that the extension bubble will show on startup.
void PreBubbleShowsOnStartup();
void TestBubbleShowsOnStartup();
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_factory.cc b/chrome/browser/ui/extensions/extension_message_bubble_factory.cc
index a483caf..6bda1e5 100644
--- a/chrome/browser/ui/extensions/extension_message_bubble_factory.cc
+++ b/chrome/browser/ui/extensions/extension_message_bubble_factory.cc
@@ -138,16 +138,10 @@ ExtensionMessageBubbleFactory::GetController() {
}
if (EnableProxyOverrideBubble()) {
- // TODO(devlin): Move the "GetExtensionOverridingProxy" part into the
- // proxy bubble controller.
- const extensions::Extension* extension =
- extensions::GetExtensionOverridingProxy(browser_->profile());
- if (extension) {
- scoped_ptr<extensions::ProxyOverriddenBubbleController> controller(
- new extensions::ProxyOverriddenBubbleController(browser_));
- if (controller->ShouldShow(extension->id()))
- return controller.Pass();
- }
+ scoped_ptr<extensions::ProxyOverriddenBubbleController> controller(
+ new extensions::ProxyOverriddenBubbleController(browser_));
+ if (controller->ShouldShow())
+ return controller.Pass();
}
if (EnableDevModeBubble()) {
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
index 4028a72..4db2bed 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
@@ -558,7 +558,9 @@ void ToolbarActionsBar::MaybeShowExtensionBubble(
// If the toolbar is animating, we can't effectively anchor the bubble,
// so wait until animation stops.
pending_extension_bubble_controller_ = controller.Pass();
- } else {
+ } else if (controller->ShouldShow()) {
+ // We check ShouldShow() above because the affected extensions may have been
+ // removed since the controller was initialized.
const std::vector<std::string>& affected_extensions =
controller->GetExtensionIdList();
ToolbarActionViewController* anchor_action = nullptr;
diff --git a/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
index d13c87e..5db213f 100644
--- a/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc
@@ -87,7 +87,12 @@ void ExtensionMessageBubbleView::OnWidgetDestroying(views::Widget* widget) {
ExtensionMessageBubbleView::~ExtensionMessageBubbleView() {}
void ExtensionMessageBubbleView::ShowBubble() {
- GetWidget()->Show();
+ // Since we delay in showing the bubble, the applicable extension(s) may
+ // have been removed.
+ if (controller_->ShouldShow())
+ GetWidget()->Show();
+ else
+ GetWidget()->Close();
}
void ExtensionMessageBubbleView::Init() {
diff --git a/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc
index abf6f1d..8b66ee6 100644
--- a/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc
@@ -56,6 +56,7 @@ class ExtensionMessageBubbleViewBrowserTest
// ExtensionMessageBubbleBrowserTest:
void CheckBubble(Browser* browser, AnchorPosition anchor) override;
void CloseBubble(Browser* browser) override;
+ void CheckBubbleIsNotPresent(Browser* browser) override;
DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleViewBrowserTest);
};
@@ -86,6 +87,13 @@ void ExtensionMessageBubbleViewBrowserTest::CloseBubble(Browser* browser) {
EXPECT_EQ(nullptr, container->active_bubble());
}
+void ExtensionMessageBubbleViewBrowserTest::CheckBubbleIsNotPresent(
+ Browser* browser) {
+ EXPECT_EQ(
+ nullptr,
+ GetToolbarViewForBrowser(browser)->browser_actions()->active_bubble());
+}
+
IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleViewBrowserTest,
ExtensionBubbleAnchoredToExtensionAction) {
TestBubbleAnchoredToExtensionAction();
@@ -110,3 +118,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleViewBrowserTest,
ExtensionBubbleShowsOnStartup) {
TestBubbleShowsOnStartup();
}
+
+IN_PROC_BROWSER_TEST_F(ExtensionMessageBubbleViewBrowserTest,
+ TestUninstallDangerousExtension) {
+ TestUninstallDangerousExtension();
+}
diff --git a/chrome/browser/ui/views/settings_api_bubble_helper_views.cc b/chrome/browser/ui/views/settings_api_bubble_helper_views.cc
index bac9adb..832ec6d 100644
--- a/chrome/browser/ui/views/settings_api_bubble_helper_views.cc
+++ b/chrome/browser/ui/views/settings_api_bubble_helper_views.cc
@@ -102,7 +102,7 @@ void MaybeShowExtensionControlledNewTabPage(
scoped_ptr<NtpOverriddenBubbleController> ntp_overridden_bubble(
new NtpOverriddenBubbleController(browser));
- if (!ntp_overridden_bubble->ShouldShow(ntp_url.host()))
+ if (!ntp_overridden_bubble->ShouldShow())
return;
NtpOverriddenBubbleController* controller = ntp_overridden_bubble.get();
diff --git a/chrome/test/data/extensions/api_test/proxy/register/manifest.json b/chrome/test/data/extensions/api_test/proxy/register/manifest.json
new file mode 100644
index 0000000..cf16b7f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/proxy/register/manifest.json
@@ -0,0 +1,10 @@
+{
+ "name": "chrome.proxy",
+ "version": "0.1",
+ "manifest_version": 2,
+ "description": "Registers a proxy setting and then messages the browser",
+ "background": {
+ "scripts": ["test.js"]
+ },
+ "permissions": ["proxy"]
+}
diff --git a/chrome/test/data/extensions/api_test/proxy/register/test.js b/chrome/test/data/extensions/api_test/proxy/register/test.js
new file mode 100644
index 0000000..16d0f9e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/proxy/register/test.js
@@ -0,0 +1,13 @@
+// Copyright 2015 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.
+
+// Register a proxy setting, and inform the browser.
+var config = {
+ mode: "auto_detect"
+};
+
+chrome.proxy.settings.set(
+ {'value': { mode: 'auto_detect' } },
+ function() { chrome.test.sendMessage('registered');
+});