summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
authorkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-31 19:52:07 +0000
committerkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-31 19:52:07 +0000
commit9f3c853d2c154744e7240988b86f1b4b86a39244 (patch)
treedbd050915d3a06d0b4f0fcc9cd1273ba557414e6 /chrome/browser/extensions
parent68476cbd621d10d779d2a316854841666f16de8f (diff)
downloadchromium_src-9f3c853d2c154744e7240988b86f1b4b86a39244.zip
chromium_src-9f3c853d2c154744e7240988b86f1b4b86a39244.tar.gz
chromium_src-9f3c853d2c154744e7240988b86f1b4b86a39244.tar.bz2
Silently install blacklisted extensions from auto-install locations (sync,
policy, etc) into a blacklisted state, rather than not-silently not-installing them. This new behaviour is correct from a sync perspective, and the old behaviour is quite annoying. BUG=257677 R=yoz@chromium.org,isherman@chromium.org TBR=akalin@chromium.org,dimich@chromium.org,estade@chromium.org Review URL: https://chromiumcodereview.appspot.com/20217002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@214806 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r--chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc4
-rw-r--r--chrome/browser/extensions/app_process_apitest.cc1
-rw-r--r--chrome/browser/extensions/blacklist.cc4
-rw-r--r--chrome/browser/extensions/blacklist.h7
-rw-r--r--chrome/browser/extensions/crx_installer.cc79
-rw-r--r--chrome/browser/extensions/crx_installer.h16
-rw-r--r--chrome/browser/extensions/crx_installer_browsertest.cc15
-rw-r--r--chrome/browser/extensions/extension_blacklist_browsertest.cc138
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc4
-rw-r--r--chrome/browser/extensions/extension_notification_observer.cc141
-rw-r--r--chrome/browser/extensions/extension_notification_observer.h69
-rw-r--r--chrome/browser/extensions/extension_prefs.cc9
-rw-r--r--chrome/browser/extensions/extension_prefs.h4
-rw-r--r--chrome/browser/extensions/extension_prefs_unittest.cc15
-rw-r--r--chrome/browser/extensions/extension_service.cc61
-rw-r--r--chrome/browser/extensions/extension_service.h16
-rw-r--r--chrome/browser/extensions/extension_service_unittest.cc62
-rw-r--r--chrome/browser/extensions/extension_sorting_unittest.cc27
-rw-r--r--chrome/browser/extensions/test_extension_prefs.cc1
-rw-r--r--chrome/browser/extensions/unpacked_installer.cc10
20 files changed, 447 insertions, 236 deletions
diff --git a/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc b/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc
index 41e797c..8a69ab3 100644
--- a/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc
+++ b/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc
@@ -152,7 +152,9 @@ void ExtensionControlledPrefsTest::EnsureExtensionInstalled(
extension4() };
for (size_t i = 0; i < kNumInstalledExtensions; ++i) {
if (extension == extensions[i] && !installed_[i]) {
- prefs()->OnExtensionInstalled(extension, Extension::ENABLED,
+ prefs()->OnExtensionInstalled(extension,
+ Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
syncer::StringOrdinal());
installed_[i] = true;
break;
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index 85f6ef8..b1a2b08 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -308,6 +308,7 @@ IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_BookmarkAppGetsNormalProcess) {
service->OnExtensionInstalled(extension.get(),
syncer::StringOrdinal::CreateInitialOrdinal(),
false /* no requirement errors */,
+ extensions::Blacklist::NOT_BLACKLISTED,
false /* don't wait for idle */);
ASSERT_TRUE(extension.get());
ASSERT_TRUE(extension->from_bookmark());
diff --git a/chrome/browser/extensions/blacklist.cc b/chrome/browser/extensions/blacklist.cc
index 87c7e28..e0f6dbb5 100644
--- a/chrome/browser/extensions/blacklist.cc
+++ b/chrome/browser/extensions/blacklist.cc
@@ -13,7 +13,6 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/safe_browsing/database_manager.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/safe_browsing/safe_browsing_util.h"
#include "chrome/common/pref_names.h"
@@ -116,7 +115,8 @@ class SafeBrowsingClientImpl
void IsNotEmpty(const Blacklist::IsBlacklistedCallback& callback,
const std::set<std::string>& set) {
- callback.Run(!set.empty());
+ callback.Run(set.empty() ? Blacklist::NOT_BLACKLISTED
+ : Blacklist::BLACKLISTED);
}
} // namespace
diff --git a/chrome/browser/extensions/blacklist.h b/chrome/browser/extensions/blacklist.h
index 3d6dd8b..ed7acf4 100644
--- a/chrome/browser/extensions/blacklist.h
+++ b/chrome/browser/extensions/blacklist.h
@@ -52,10 +52,15 @@ class Blacklist : public content::NotificationObserver,
DISALLOW_COPY_AND_ASSIGN(ScopedDatabaseManagerForTest);
};
+ enum BlacklistState {
+ NOT_BLACKLISTED,
+ BLACKLISTED,
+ };
+
typedef base::Callback<void(const std::set<std::string>&)>
GetBlacklistedIDsCallback;
- typedef base::Callback<void(bool)> IsBlacklistedCallback;
+ typedef base::Callback<void(BlacklistState)> IsBlacklistedCallback;
// |prefs_| must outlive this.
explicit Blacklist(ExtensionPrefs* prefs);
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 588e2f1..a80d1e0 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -100,13 +100,13 @@ CrxInstaller::CrxInstaller(
client_(client),
apps_require_extension_mime_type_(false),
allow_silent_install_(false),
- bypass_blacklist_for_test_(false),
install_cause_(extension_misc::INSTALL_CAUSE_UNSET),
creation_flags_(Extension::NO_FLAGS),
off_store_install_allow_reason_(OffStoreInstallDisallowed),
did_handle_successfully_(true),
error_on_unsupported_requirements_(false),
has_requirement_errors_(false),
+ blacklist_state_(extensions::Blacklist::NOT_BLACKLISTED),
install_wait_for_idle_(true),
update_from_settings_page_(false),
installer_(service_weak->profile()) {
@@ -429,6 +429,9 @@ void CrxInstaller::CheckImportsAndRequirements() {
void CrxInstaller::OnRequirementsChecked(
std::vector<std::string> requirement_errors) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!service_weak_)
+ return;
+
if (!requirement_errors.empty()) {
if (error_on_unsupported_requirements_) {
ReportFailureFromUIThread(CrxInstallerError(
@@ -437,6 +440,36 @@ void CrxInstaller::OnRequirementsChecked(
}
has_requirement_errors_ = true;
}
+
+ ExtensionSystem::Get(profile())->blacklist()->IsBlacklisted(
+ extension()->id(),
+ base::Bind(&CrxInstaller::OnBlacklistChecked, this));
+}
+
+void CrxInstaller::OnBlacklistChecked(
+ extensions::Blacklist::BlacklistState blacklist_state) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!service_weak_)
+ return;
+
+ blacklist_state_ = blacklist_state;
+
+ if (blacklist_state_ == extensions::Blacklist::BLACKLISTED &&
+ !allow_silent_install_) {
+ // User tried to install a blacklisted extension. Show an error and
+ // refuse to install it.
+ ReportFailureFromUIThread(extensions::CrxInstallerError(
+ l10n_util::GetStringFUTF16(IDS_EXTENSION_IS_BLACKLISTED,
+ UTF8ToUTF16(extension()->name()))));
+ UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlockCRX",
+ extension()->location(),
+ Manifest::NUM_LOCATIONS);
+ return;
+ }
+
+ // NOTE: extension may still be blacklisted, but we're forced to silently
+ // install it. In this case, ExtensionService::OnExtensionInstalled needs to
+ // deal with it.
ConfirmInstall();
}
@@ -673,43 +706,12 @@ void CrxInstaller::ReportSuccessFromUIThread() {
}
}
- // Install the extension if it's not blacklisted, but notify either way.
- base::Closure on_success =
- base::Bind(&ExtensionService::OnExtensionInstalled,
- service_weak_,
- extension(),
- page_ordinal_,
- has_requirement_errors_,
- install_wait_for_idle_);
- if (bypass_blacklist_for_test_) {
- HandleIsBlacklistedResponse(on_success, false);
- } else {
- ExtensionSystem::Get(profile())->blacklist()->IsBlacklisted(
- extension()->id(),
- base::Bind(&CrxInstaller::HandleIsBlacklistedResponse,
- this,
- on_success));
- }
-}
-
-void CrxInstaller::HandleIsBlacklistedResponse(
- const base::Closure& on_success,
- bool is_blacklisted) {
- if (is_blacklisted) {
- string16 error = l10n_util::GetStringFUTF16(
- IDS_EXTENSION_IS_BLACKLISTED,
- UTF8ToUTF16(extension()->name()));
- make_scoped_ptr(ExtensionInstallUI::Create(profile()))->OnInstallFailure(
- extensions::CrxInstallerError(error));
- // Show error via reporter to make tests happy.
- ExtensionErrorReporter::GetInstance()->ReportError(error, false); // quiet
- UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlockCRX",
- extension()->location(),
- Manifest::NUM_LOCATIONS);
- } else {
- on_success.Run();
- }
- NotifyCrxInstallComplete(!is_blacklisted);
+ service_weak_->OnExtensionInstalled(extension(),
+ page_ordinal_,
+ has_requirement_errors_,
+ blacklist_state_,
+ install_wait_for_idle_);
+ NotifyCrxInstallComplete(true);
}
void CrxInstaller::NotifyCrxInstallComplete(bool success) {
@@ -726,7 +728,6 @@ void CrxInstaller::NotifyCrxInstallComplete(bool success) {
if (success)
ConfirmReEnable();
-
}
void CrxInstaller::CleanupTempFiles() {
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index dd2e9216..6f71868 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -12,6 +12,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/version.h"
+#include "chrome/browser/extensions/blacklist.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_installer.h"
#include "chrome/browser/extensions/sandboxed_unpacker.h"
@@ -131,10 +132,6 @@ class CrxInstaller
bool allow_silent_install() const { return allow_silent_install_; }
void set_allow_silent_install(bool val) { allow_silent_install_ = val; }
- void set_bypass_blacklist_for_test(bool val) {
- bypass_blacklist_for_test_ = val;
- }
-
bool is_gallery_install() const {
return (creation_flags_ & Extension::FROM_WEBSTORE) > 0;
}
@@ -231,6 +228,10 @@ class CrxInstaller
// Runs on the UI thread. Callback from RequirementsChecker.
void OnRequirementsChecked(std::vector<std::string> requirement_errors);
+ // Runs on the UI thread. Callback from Blacklist.
+ void OnBlacklistChecked(
+ extensions::Blacklist::BlacklistState blacklist_state);
+
// Runs on the UI thread. Confirms the installation to the ExtensionService.
void ConfirmInstall();
@@ -243,8 +244,6 @@ class CrxInstaller
void ReportFailureFromUIThread(const CrxInstallerError& error);
void ReportSuccessFromFileThread();
void ReportSuccessFromUIThread();
- void HandleIsBlacklistedResponse(const base::Closure& on_success,
- bool success);
void NotifyCrxInstallComplete(bool success);
// Deletes temporary directory and crx file if needed.
@@ -349,9 +348,6 @@ class CrxInstaller
// dialog.
bool allow_silent_install_;
- // Allows for bypassing the blacklist check. Only use for tests.
- bool bypass_blacklist_for_test_;
-
// The value of the content type header sent with the CRX.
// Ignorred unless |require_extension_mime_type_| is true.
std::string original_mime_type_;
@@ -381,6 +377,8 @@ class CrxInstaller
bool has_requirement_errors_;
+ extensions::Blacklist::BlacklistState blacklist_state_;
+
bool install_wait_for_idle_;
// Sequenced task runner where file I/O operations will be performed.
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index 9a764d9..9cdfcaf 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -107,7 +107,6 @@ class ExtensionCrxInstallerTest : public ExtensionBrowserTest {
approval.get() /* keep ownership */));
installer->set_allow_silent_install(true);
installer->set_is_gallery_install(true);
- installer->set_bypass_blacklist_for_test(true);
installer->InstallCrx(PackExtension(ext_path));
content::RunMessageLoop();
@@ -379,4 +378,18 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
ASSERT_EQ("3.0", extension->version()->GetString());
}
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, Blacklist) {
+ extensions::Blacklist* blacklist =
+ ExtensionSystem::Get(profile())->blacklist();
+
+ // Fake the blacklisting of the extension we're about to install by
+ // pretending that we get a blacklist update which includes it.
+ const std::string kId = "gllekhaobjnhgeagipipnkpmmmpchacm";
+ blacklist->SetFromUpdater(std::vector<std::string>(1, kId), "some-version");
+
+ base::FilePath crx_path = test_data_dir_.AppendASCII("theme_hidpi_crx")
+ .AppendASCII("theme_hidpi.crx");
+ EXPECT_FALSE(InstallExtension(crx_path, 0));
+}
+
} // namespace extensions
diff --git a/chrome/browser/extensions/extension_blacklist_browsertest.cc b/chrome/browser/extensions/extension_blacklist_browsertest.cc
index a75706c..3f57cb6 100644
--- a/chrome/browser/extensions/extension_blacklist_browsertest.cc
+++ b/chrome/browser/extensions/extension_blacklist_browsertest.cc
@@ -3,151 +3,19 @@
// found in the LICENSE file.
#include "base/run_loop.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/blacklist.h"
#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/extensions/extension_notification_observer.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
namespace extensions {
namespace {
-// Records notifications, but only for extensions with specific IDs.
-class FilteringNotificationObserver : public content::NotificationObserver {
- public:
- FilteringNotificationObserver(
- content::NotificationSource source,
- const std::set<std::string>& extension_ids)
- : extension_ids_(extension_ids) {
- registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, source);
- registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, source);
- registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, source);
- }
-
- // Checks then clears notifications for our extensions.
- testing::AssertionResult CheckNotifications(chrome::NotificationType type) {
- return CheckNotifications(std::vector<chrome::NotificationType>(1, type));
- }
-
- // Checks then clears notifications for our extensions.
- testing::AssertionResult CheckNotifications(chrome::NotificationType t1,
- chrome::NotificationType t2) {
- std::vector<chrome::NotificationType> types;
- types.push_back(t1);
- types.push_back(t2);
- return CheckNotifications(types);
- }
-
- // Checks then clears notifications for our extensions.
- testing::AssertionResult CheckNotifications(chrome::NotificationType t1,
- chrome::NotificationType t2,
- chrome::NotificationType t3) {
- std::vector<chrome::NotificationType> types;
- types.push_back(t1);
- types.push_back(t2);
- types.push_back(t3);
- return CheckNotifications(types);
- }
-
- // Checks then clears notifications for our extensions.
- testing::AssertionResult CheckNotifications(chrome::NotificationType t1,
- chrome::NotificationType t2,
- chrome::NotificationType t3,
- chrome::NotificationType t4,
- chrome::NotificationType t5,
- chrome::NotificationType t6) {
- std::vector<chrome::NotificationType> types;
- types.push_back(t1);
- types.push_back(t2);
- types.push_back(t3);
- types.push_back(t4);
- types.push_back(t5);
- types.push_back(t6);
- return CheckNotifications(types);
- }
-
- private:
- // content::NotificationObserver implementation.
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE {
- switch (type) {
- case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
- const Extension* extension =
- content::Details<const InstalledExtensionInfo>(details)->extension;
- if (extension_ids_.count(extension->id()))
- notifications_.push_back(static_cast<chrome::NotificationType>(type));
- break;
- }
-
- case chrome::NOTIFICATION_EXTENSION_LOADED: {
- const Extension* extension =
- content::Details<const Extension>(details).ptr();
- if (extension_ids_.count(extension->id()))
- notifications_.push_back(static_cast<chrome::NotificationType>(type));
- break;
- }
-
- case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
- UnloadedExtensionInfo* reason =
- content::Details<UnloadedExtensionInfo>(details).ptr();
- if (extension_ids_.count(reason->extension->id())) {
- notifications_.push_back(static_cast<chrome::NotificationType>(type));
- // The only way that extensions are unloaded in these tests is
- // by blacklisting.
- EXPECT_EQ(extension_misc::UNLOAD_REASON_BLACKLIST,
- reason->reason);
- }
- break;
- }
-
- default:
- NOTREACHED();
- break;
- }
- }
-
- // Checks then clears notifications for our extensions.
- testing::AssertionResult CheckNotifications(
- const std::vector<chrome::NotificationType>& types) {
- testing::AssertionResult result = (notifications_ == types) ?
- testing::AssertionSuccess() :
- testing::AssertionFailure() << "Expected " << Str(types) << ", " <<
- "Got " << Str(notifications_);
- notifications_.clear();
- return result;
- }
-
- std::string Str(const std::vector<chrome::NotificationType>& types) {
- std::string str = "[";
- bool needs_comma = false;
- for (std::vector<chrome::NotificationType>::const_iterator it =
- types.begin(); it != types.end(); ++it) {
- if (needs_comma)
- str += ",";
- needs_comma = true;
- str += base::StringPrintf("%d", *it);
- }
- return str + "]";
- }
-
- const std::set<std::string> extension_ids_;
-
- std::vector<chrome::NotificationType> notifications_;
-
- content::NotificationRegistrar registrar_;
-};
-
// Stores the paths to CRX files of extensions, and the extension's ID.
// Use arbitrary extensions; we're just testing blacklisting behavior.
class CrxInfo {
@@ -243,7 +111,7 @@ class ExtensionBlacklistBrowserTest : public ExtensionBrowserTest {
// Stage 1: blacklisting when there weren't any extensions installed when the
// browser started.
IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, PRE_Blacklist) {
- FilteringNotificationObserver notifications(
+ ExtensionNotificationObserver notifications(
content::NotificationService::AllSources(), GetTestExtensionIDs());
scoped_refptr<const Extension> extension_a =
@@ -361,7 +229,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, PRE_Blacklist) {
// Stage 2: blacklisting with extensions A and B having been installed,
// with A actually in the blacklist.
IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, Blacklist) {
- FilteringNotificationObserver notifications(
+ ExtensionNotificationObserver notifications(
content::Source<Profile>(profile()), GetTestExtensionIDs());
scoped_refptr<const Extension> extension_a =
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index f71864f..05e426c 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -159,7 +159,9 @@ const Extension* ExtensionBrowserTest::LoadExtensionWithFlags(
// The call to OnExtensionInstalled ensures the other extension prefs
// are set up with the defaults.
service->extension_prefs()->OnExtensionInstalled(
- extension, Extension::ENABLED,
+ extension,
+ Extension::ENABLED,
+ extensions::Blacklist::NOT_BLACKLISTED,
syncer::StringOrdinal::CreateInitialOrdinal());
// Toggling incognito or file access will reload the extension, so wait for
diff --git a/chrome/browser/extensions/extension_notification_observer.cc b/chrome/browser/extensions/extension_notification_observer.cc
new file mode 100644
index 0000000..7f5baf9
--- /dev/null
+++ b/chrome/browser/extensions/extension_notification_observer.cc
@@ -0,0 +1,141 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_notification_observer.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/common/extensions/extension.h"
+
+namespace extensions {
+
+namespace {
+
+std::string Str(const std::vector<chrome::NotificationType>& types) {
+ std::string str = "[";
+ bool needs_comma = false;
+ for (std::vector<chrome::NotificationType>::const_iterator it =
+ types.begin(); it != types.end(); ++it) {
+ if (needs_comma)
+ str += ",";
+ needs_comma = true;
+ str += base::StringPrintf("%d", *it);
+ }
+ str += "]";
+ return str;
+}
+
+} // namespace
+
+ExtensionNotificationObserver::ExtensionNotificationObserver(
+ content::NotificationSource source,
+ const std::set<std::string>& extension_ids)
+ : extension_ids_(extension_ids) {
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, source);
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, source);
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, source);
+}
+
+ExtensionNotificationObserver::~ExtensionNotificationObserver() {}
+
+testing::AssertionResult ExtensionNotificationObserver::CheckNotifications() {
+ return CheckNotifications(std::vector<chrome::NotificationType>());
+}
+
+testing::AssertionResult ExtensionNotificationObserver::CheckNotifications(
+ chrome::NotificationType type) {
+ return CheckNotifications(std::vector<chrome::NotificationType>(1, type));
+}
+
+testing::AssertionResult ExtensionNotificationObserver::CheckNotifications(
+ chrome::NotificationType t1,
+ chrome::NotificationType t2) {
+ std::vector<chrome::NotificationType> types;
+ types.push_back(t1);
+ types.push_back(t2);
+ return CheckNotifications(types);
+}
+
+testing::AssertionResult ExtensionNotificationObserver::CheckNotifications(
+ chrome::NotificationType t1,
+ chrome::NotificationType t2,
+ chrome::NotificationType t3) {
+ std::vector<chrome::NotificationType> types;
+ types.push_back(t1);
+ types.push_back(t2);
+ types.push_back(t3);
+ return CheckNotifications(types);
+}
+
+testing::AssertionResult ExtensionNotificationObserver::CheckNotifications(
+ chrome::NotificationType t1,
+ chrome::NotificationType t2,
+ chrome::NotificationType t3,
+ chrome::NotificationType t4,
+ chrome::NotificationType t5,
+ chrome::NotificationType t6) {
+ std::vector<chrome::NotificationType> types;
+ types.push_back(t1);
+ types.push_back(t2);
+ types.push_back(t3);
+ types.push_back(t4);
+ types.push_back(t5);
+ types.push_back(t6);
+ return CheckNotifications(types);
+}
+
+// content::NotificationObserver implementation.
+void ExtensionNotificationObserver::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
+ const Extension* extension =
+ content::Details<const InstalledExtensionInfo>(details)->extension;
+ if (extension_ids_.count(extension->id()))
+ notifications_.push_back(static_cast<chrome::NotificationType>(type));
+ break;
+ }
+
+ case chrome::NOTIFICATION_EXTENSION_LOADED: {
+ const Extension* extension =
+ content::Details<const Extension>(details).ptr();
+ if (extension_ids_.count(extension->id()))
+ notifications_.push_back(static_cast<chrome::NotificationType>(type));
+ break;
+ }
+
+ case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
+ UnloadedExtensionInfo* reason =
+ content::Details<UnloadedExtensionInfo>(details).ptr();
+ if (extension_ids_.count(reason->extension->id())) {
+ notifications_.push_back(static_cast<chrome::NotificationType>(type));
+ // The only way that extensions are unloaded in these tests is
+ // by blacklisting.
+ EXPECT_EQ(extension_misc::UNLOAD_REASON_BLACKLIST,
+ reason->reason);
+ }
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+testing::AssertionResult ExtensionNotificationObserver::CheckNotifications(
+ const std::vector<chrome::NotificationType>& types) {
+ testing::AssertionResult result = (notifications_ == types) ?
+ testing::AssertionSuccess() :
+ testing::AssertionFailure() << "Expected " << Str(types) << ", " <<
+ "Got " << Str(notifications_);
+ notifications_.clear();
+ return result;
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/extension_notification_observer.h b/chrome/browser/extensions/extension_notification_observer.h
new file mode 100644
index 0000000..facb403
--- /dev/null
+++ b/chrome/browser/extensions/extension_notification_observer.h
@@ -0,0 +1,69 @@
+// Copyright 2013 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_EXTENSION_NOTIFICATION_OBSERVER_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_NOTIFICATION_OBSERVER_H_
+
+#include <set>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+// Records LOADED, INSTALLED, and UNLOADED notifications for extensions with
+// specific IDs. Use in tests only.
+class ExtensionNotificationObserver : public content::NotificationObserver {
+ public:
+ ExtensionNotificationObserver(content::NotificationSource source,
+ const std::set<std::string>& extension_ids);
+
+ virtual ~ExtensionNotificationObserver();
+
+ // Each of these methods returns a testing::AssertionSuccess if exactly those
+ // notifications occurred for any extensions in |extension_ids|, and no more,
+ // since the last time any of these methods were called.
+ testing::AssertionResult CheckNotifications() WARN_UNUSED_RESULT;
+ testing::AssertionResult CheckNotifications(
+ chrome::NotificationType type) WARN_UNUSED_RESULT;
+ testing::AssertionResult CheckNotifications(
+ chrome::NotificationType t1,
+ chrome::NotificationType t2) WARN_UNUSED_RESULT;
+ testing::AssertionResult CheckNotifications(
+ chrome::NotificationType t1,
+ chrome::NotificationType t2,
+ chrome::NotificationType t3) WARN_UNUSED_RESULT;
+ testing::AssertionResult CheckNotifications(
+ chrome::NotificationType t1,
+ chrome::NotificationType t2,
+ chrome::NotificationType t3,
+ chrome::NotificationType t4,
+ chrome::NotificationType t5,
+ chrome::NotificationType t6) WARN_UNUSED_RESULT;
+
+ private:
+ // content::NotificationObserver implementation.
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ // Checks then clears notifications for our extensions.
+ testing::AssertionResult CheckNotifications(
+ const std::vector<chrome::NotificationType>& types);
+
+ const std::set<std::string> extension_ids_;
+ std::vector<chrome::NotificationType> notifications_;
+ content::NotificationRegistrar registrar_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_NOTIFICATION_OBSERVER_H_
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 904527d..6447ad3 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -1163,12 +1163,13 @@ void ExtensionPrefs::SetToolbarOrder(const ExtensionIdList& extension_ids) {
void ExtensionPrefs::OnExtensionInstalled(
const Extension* extension,
Extension::State initial_state,
+ Blacklist::BlacklistState blacklist_state,
const syncer::StringOrdinal& page_ordinal) {
ScopedExtensionPrefUpdate update(prefs_, extension->id());
DictionaryValue* extension_dict = update.Get();
const base::Time install_time = time_provider_->GetCurrentTime();
PopulateExtensionInfoPrefs(extension, install_time, initial_state,
- extension_dict);
+ blacklist_state, extension_dict);
FinishExtensionInfoPrefs(extension->id(), install_time,
extension->RequiresSortOrdinal(),
page_ordinal, extension_dict);
@@ -1329,11 +1330,12 @@ ExtensionPrefs::GetInstalledExtensionsInfo() const {
void ExtensionPrefs::SetDelayedInstallInfo(
const Extension* extension,
Extension::State initial_state,
+ Blacklist::BlacklistState blacklist_state,
DelayReason delay_reason,
const syncer::StringOrdinal& page_ordinal) {
DictionaryValue* extension_dict = new DictionaryValue();
PopulateExtensionInfoPrefs(extension, time_provider_->GetCurrentTime(),
- initial_state, extension_dict);
+ initial_state, blacklist_state, extension_dict);
// Add transient data that is needed by FinishDelayedInstallInfo(), but
// should not be in the final extension prefs. All entries here should have
@@ -1766,6 +1768,7 @@ void ExtensionPrefs::PopulateExtensionInfoPrefs(
const Extension* extension,
const base::Time install_time,
Extension::State initial_state,
+ Blacklist::BlacklistState blacklist_state,
DictionaryValue* extension_dict) {
// Leave the state blank for component extensions so that old chrome versions
// loading new profiles do not fail in GetInstalledExtensionInfo. Older
@@ -1787,6 +1790,8 @@ void ExtensionPrefs::PopulateExtensionInfoPrefs(
extension_dict->Set(kPrefInstallTime,
Value::CreateStringValue(
base::Int64ToString(install_time.ToInternalValue())));
+ if (blacklist_state == Blacklist::BLACKLISTED)
+ extension_dict->Set(kPrefBlacklist, Value::CreateBooleanValue(true));
base::FilePath::StringType path = MakePathRelative(install_directory_,
extension->path());
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 354420e..eb731c6 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -13,6 +13,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "chrome/browser/extensions/blacklist.h"
#include "chrome/browser/extensions/extension_scoped_prefs.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/common/extensions/extension.h"
@@ -187,6 +188,7 @@ class ExtensionPrefs : public ExtensionScopedPrefs,
// for the App.
void OnExtensionInstalled(const Extension* extension,
Extension::State initial_state,
+ Blacklist::BlacklistState blacklist_state,
const syncer::StringOrdinal& page_ordinal);
// Called when an extension is uninstalled, so that prefs get cleaned up.
@@ -408,6 +410,7 @@ class ExtensionPrefs : public ExtensionScopedPrefs,
// to install it.
void SetDelayedInstallInfo(const Extension* extension,
Extension::State initial_state,
+ Blacklist::BlacklistState blacklist_state,
DelayReason delay_reason,
const syncer::StringOrdinal& page_ordinal);
@@ -585,6 +588,7 @@ class ExtensionPrefs : public ExtensionScopedPrefs,
void PopulateExtensionInfoPrefs(const Extension* extension,
const base::Time install_time,
Extension::State initial_state,
+ Blacklist::BlacklistState blacklist_state,
base::DictionaryValue* extension_dict);
// Helper function to complete initialization of the values in
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index 08d07d6..c7034d1 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -451,7 +451,9 @@ class ExtensionPrefsDelayedInstallInfo : public ExtensionPrefsTest {
path, Manifest::INTERNAL, manifest, Extension::NO_FLAGS, id, &errors);
ASSERT_TRUE(extension.get()) << errors;
ASSERT_EQ(id, extension->id());
- prefs()->SetDelayedInstallInfo(extension.get(), Extension::ENABLED,
+ prefs()->SetDelayedInstallInfo(extension.get(),
+ Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE,
syncer::StringOrdinal());
}
@@ -551,9 +553,10 @@ class ExtensionPrefsOnExtensionInstalled : public ExtensionPrefsTest {
virtual void Initialize() OVERRIDE {
extension_ = prefs_.AddExtension("on_extension_installed");
EXPECT_FALSE(prefs()->IsExtensionDisabled(extension_->id()));
- prefs()->OnExtensionInstalled(
- extension_.get(), Extension::DISABLED,
- syncer::StringOrdinal());
+ prefs()->OnExtensionInstalled(extension_.get(),
+ Extension::DISABLED,
+ Blacklist::NOT_BLACKLISTED,
+ syncer::StringOrdinal());
}
virtual void Verify() OVERRIDE {
@@ -571,7 +574,9 @@ class ExtensionPrefsAppDraggedByUser : public ExtensionPrefsTest {
virtual void Initialize() OVERRIDE {
extension_ = prefs_.AddExtension("on_extension_installed");
EXPECT_FALSE(prefs()->WasAppDraggedByUser(extension_->id()));
- prefs()->OnExtensionInstalled(extension_.get(), Extension::ENABLED,
+ prefs()->OnExtensionInstalled(extension_.get(),
+ Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
syncer::StringOrdinal());
}
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index ec57c0a..42cb3fa 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -2038,7 +2038,8 @@ void ExtensionService::AddExtension(const Extension* extension) {
if (extension_prefs_->IsExtensionBlacklisted(extension->id())) {
// Only prefs is checked for the blacklist. We rely on callers to check the
// blacklist before calling into here, e.g. CrxInstaller checks before
- // installation, we check when loading installed extensions.
+ // installation then threads through the install and pending install flow
+ // of this class, and we check when loading installed extensions.
blacklisted_extensions_.Insert(extension);
} else if (!reloading &&
extension_prefs_->IsExtensionDisabled(extension->id())) {
@@ -2090,6 +2091,7 @@ void ExtensionService::AddComponentExtension(const Extension* extension) {
AddNewOrUpdatedExtension(extension,
Extension::ENABLED_COMPONENT,
+ extensions::Blacklist::NOT_BLACKLISTED,
syncer::StringOrdinal());
return;
}
@@ -2328,6 +2330,7 @@ void ExtensionService::OnExtensionInstalled(
const Extension* extension,
const syncer::StringOrdinal& page_ordinal,
bool has_requirement_errors,
+ extensions::Blacklist::BlacklistState blacklist_state,
bool wait_for_idle) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -2384,6 +2387,18 @@ void ExtensionService::OnExtensionInstalled(
extension_prefs_->ClearDisableReasons(id);
}
+ if (blacklist_state == extensions::Blacklist::BLACKLISTED) {
+ // Installation of a blacklisted extension can happen from sync, policy,
+ // etc, where to maintain consistency we need to install it, just never
+ // load it (see AddExtension). Usually it should be the job of callers to
+ // incercept blacklisted extension earlier (e.g. CrxInstaller, before even
+ // showing the install dialogue).
+ extension_prefs()->AcknowledgeBlacklistedExtension(id);
+ UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.SilentInstall",
+ extension->location(),
+ Manifest::NUM_LOCATIONS);
+ }
+
if (!GetInstalledExtension(extension->id())) {
UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType",
extension->GetType(), 100);
@@ -2405,8 +2420,12 @@ void ExtensionService::OnExtensionInstalled(
const Extension::State initial_state =
initial_enable ? Extension::ENABLED : Extension::DISABLED;
if (ShouldDelayExtensionUpdate(id, wait_for_idle)) {
- extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
- extensions::ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE, page_ordinal);
+ extension_prefs_->SetDelayedInstallInfo(
+ extension,
+ initial_state,
+ blacklist_state,
+ extensions::ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE,
+ page_ordinal);
// Transfer ownership of |extension|.
delayed_installs_.Insert(extension);
@@ -2423,34 +2442,42 @@ void ExtensionService::OnExtensionInstalled(
ImportStatus status = SatisfyImports(extension);
if (installs_delayed_for_gc()) {
- extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
- extensions::ExtensionPrefs::DELAY_REASON_GC, page_ordinal);
+ extension_prefs_->SetDelayedInstallInfo(
+ extension,
+ initial_state,
+ blacklist_state,
+ extensions::ExtensionPrefs::DELAY_REASON_GC,
+ page_ordinal);
delayed_installs_.Insert(extension);
} else if (status != IMPORT_STATUS_OK) {
if (status == IMPORT_STATUS_UNSATISFIED) {
- extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
+ extension_prefs_->SetDelayedInstallInfo(
+ extension,
+ initial_state,
+ blacklist_state,
extensions::ExtensionPrefs::DELAY_REASON_WAIT_FOR_IMPORTS,
page_ordinal);
delayed_installs_.Insert(extension);
}
} else {
- AddNewOrUpdatedExtension(extension, initial_state, page_ordinal);
+ AddNewOrUpdatedExtension(extension,
+ initial_state,
+ blacklist_state,
+ page_ordinal);
}
}
void ExtensionService::AddNewOrUpdatedExtension(
const Extension* extension,
Extension::State initial_state,
+ extensions::Blacklist::BlacklistState blacklist_state,
const syncer::StringOrdinal& page_ordinal) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- extension_prefs_->OnExtensionInstalled(
- extension,
- initial_state,
- page_ordinal);
-
+ extension_prefs_->OnExtensionInstalled(extension,
+ initial_state,
+ blacklist_state,
+ page_ordinal);
delayed_installs_.Remove(extension->id());
-
FinishInstallation(extension);
}
@@ -3056,7 +3083,8 @@ void ExtensionService::ManageBlacklist(
it != no_longer_blacklisted.end(); ++it) {
scoped_refptr<const Extension> extension =
blacklisted_extensions_.GetByID(*it);
- DCHECK(extension.get());
+ DCHECK(extension.get()) << "Extension " << *it << " no longer blacklisted, "
+ << "but it was never blacklisted.";
if (!extension.get())
continue;
blacklisted_extensions_.Remove(*it);
@@ -3069,7 +3097,8 @@ void ExtensionService::ManageBlacklist(
for (std::set<std::string>::iterator it = not_yet_blacklisted.begin();
it != not_yet_blacklisted.end(); ++it) {
scoped_refptr<const Extension> extension = GetInstalledExtension(*it);
- DCHECK(extension.get());
+ DCHECK(extension.get()) << "Extension " << *it << " needs to be "
+ << "blacklisted, but it's not installed.";
if (!extension.get())
continue;
blacklisted_extensions_.Insert(extension);
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index a6ac7ee..1564587 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -432,12 +432,16 @@ class ExtensionService
// Informs the service that an extension's files are in place for loading.
//
- // Please make sure the Blacklist is checked some time before calling this
- // method.
+ // |page_ordinal| is the location of the extension in the app launcher.
+ // |has_requirement_errors| is true if requirements of the extension weren't
+ // met (for example graphics capabilities).
+ // |blacklist_state| will be BLACKLISTED if the extension is blacklisted.
+ // |wait_for_idle| may be false to install the extension immediately.
void OnExtensionInstalled(
const extensions::Extension* extension,
const syncer::StringOrdinal& page_ordinal,
bool has_requirement_errors,
+ extensions::Blacklist::BlacklistState blacklist_state,
bool wait_for_idle);
// Checks for delayed installation for all pending installs.
@@ -737,9 +741,11 @@ class ExtensionService
// the extension is installed, e.g., to update event handlers on background
// pages; and perform other extension install tasks before calling
// AddExtension.
- void AddNewOrUpdatedExtension(const extensions::Extension* extension,
- extensions::Extension::State initial_state,
- const syncer::StringOrdinal& page_ordinal);
+ void AddNewOrUpdatedExtension(
+ const extensions::Extension* extension,
+ extensions::Extension::State initial_state,
+ extensions::Blacklist::BlacklistState blacklist_state,
+ const syncer::StringOrdinal& page_ordinal);
// Handles sending notification that |extension| was loaded.
void NotifyExtensionLoaded(const extensions::Extension* extension);
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 86dd4f1..bf6c949 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -37,6 +37,7 @@
#include "chrome/browser/extensions/extension_creator.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_error_ui.h"
+#include "chrome/browser/extensions/extension_notification_observer.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_sorting.h"
#include "chrome/browser/extensions/extension_special_storage_policy.h"
@@ -69,12 +70,14 @@
#include "chrome/common/extensions/api/plugins/plugins_handler.h"
#include "chrome/common/extensions/background_info.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_builder.h"
#include "chrome/common/extensions/extension_l10n_util.h"
#include "chrome/common/extensions/extension_manifest_constants.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h"
#include "chrome/common/extensions/manifest_url_handler.h"
#include "chrome/common/extensions/permissions/permission_set.h"
+#include "chrome/common/extensions/value_builder.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/testing_profile.h"
@@ -3331,20 +3334,22 @@ TEST_F(ExtensionServiceTest, UnloadBlacklistedExtension) {
// Unload installed extension from blacklist.
TEST_F(ExtensionServiceTest, BlacklistedExtensionWillNotInstall) {
InitializeEmptyExtensionService();
- std::vector<std::string> blacklist;
- blacklist.push_back(good_crx);
- ExtensionSystem::Get(profile_.get())->blacklist()->SetFromUpdater(blacklist,
- "v1");
- // Make sure pref is updated
- loop_.RunUntilIdle();
+ // Fake the blacklisting of good_crx by pretending that we get an update
+ // which includes it.
+ extensions::Blacklist* blacklist =
+ ExtensionSystem::Get(profile_.get())->blacklist();
+ blacklist->SetFromUpdater(std::vector<std::string>(1, good_crx), "v1");
- // Now, the good_crx is blacklisted.
+ // Now good_crx is blacklisted.
ValidateBooleanPref(good_crx, "blacklist", true);
- // We can not install good_crx.
+ // We cannot install good_crx.
base::FilePath path = data_dir_.AppendASCII("good.crx");
- InstallCRX(path, INSTALL_FAILED);
+ // HACK: specify WAS_INSTALLED_BY_DEFAULT so that test machinery doesn't
+ // decide to install this silently. Somebody should fix these tests, all
+ // 6,000 lines of them. Hah!
+ InstallCRX(path, INSTALL_FAILED, Extension::WAS_INSTALLED_BY_DEFAULT);
EXPECT_EQ(0u, service_->extensions()->size());
ValidateBooleanPref(good_crx, "blacklist", true);
}
@@ -6347,3 +6352,42 @@ TEST_F(ExtensionServiceTest, ExternalInstallUpdatesFromWebstoreNewProfile) {
EXPECT_FALSE(extensions::HasExternalInstallBubble(service_));
EXPECT_FALSE(service_->IsExtensionEnabled(updates_from_webstore));
}
+
+TEST_F(ExtensionServiceTest, InstallBlacklistedExtension) {
+ InitializeEmptyExtensionService();
+
+ scoped_refptr<Extension> extension = extensions::ExtensionBuilder()
+ .SetManifest(extensions::DictionaryBuilder()
+ .Set("name", "extension")
+ .Set("version", "1.0")
+ .Set("manifest_version", 2).Build())
+ .Build();
+ ASSERT_TRUE(extension.get());
+ const std::string& id = extension->id();
+
+ std::set<std::string> id_set;
+ id_set.insert(id);
+ extensions::ExtensionNotificationObserver notifications(
+ content::NotificationService::AllSources(), id_set);
+
+ // Installation should be allowed but the extension should never have been
+ // loaded and it should be blacklisted in prefs.
+ service_->OnExtensionInstalled(
+ extension.get(),
+ syncer::StringOrdinal(),
+ false /* has requirement errors */,
+ extensions::Blacklist::BLACKLISTED,
+ false /* wait for idle */);
+ loop_.RunUntilIdle();
+
+ // Extension was installed but not loaded.
+ EXPECT_TRUE(notifications.CheckNotifications(
+ chrome::NOTIFICATION_EXTENSION_INSTALLED));
+
+ EXPECT_TRUE(service_->GetInstalledExtension(id));
+ EXPECT_FALSE(service_->extensions()->Contains(id));
+ EXPECT_TRUE(service_->blacklisted_extensions()->Contains(id));
+ EXPECT_TRUE(service_->extension_prefs()->IsExtensionBlacklisted(id));
+ EXPECT_TRUE(
+ service_->extension_prefs()->IsBlacklistedExtensionAcknowledged(id));
+}
diff --git a/chrome/browser/extensions/extension_sorting_unittest.cc b/chrome/browser/extensions/extension_sorting_unittest.cc
index ff219b3..b84535e 100644
--- a/chrome/browser/extensions/extension_sorting_unittest.cc
+++ b/chrome/browser/extensions/extension_sorting_unittest.cc
@@ -11,6 +11,7 @@
#include "sync/api/string_ordinal.h"
#include "testing/gtest/include/gtest/gtest.h"
+using extensions::Blacklist;
using extensions::Extension;
using extensions::Manifest;
@@ -28,7 +29,9 @@ class ExtensionSortingAppLocation : public ExtensionSortingTest {
virtual void Initialize() OVERRIDE {
extension_ = prefs_.AddExtension("not_an_app");
// Non-apps should not have any app launch ordinal or page ordinal.
- prefs()->OnExtensionInstalled(extension_.get(), Extension::ENABLED,
+ prefs()->OnExtensionInstalled(extension_.get(),
+ Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
syncer::StringOrdinal());
}
@@ -54,7 +57,9 @@ class ExtensionSortingAppLaunchOrdinal : public ExtensionSortingTest {
extension_ = prefs_.AddApp("on_extension_installed");
EXPECT_FALSE(prefs()->IsExtensionDisabled(extension_->id()));
- prefs()->OnExtensionInstalled(extension_.get(), Extension::ENABLED,
+ prefs()->OnExtensionInstalled(extension_.get(),
+ Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
syncer::StringOrdinal());
}
@@ -104,7 +109,9 @@ class ExtensionSortingPageOrdinal : public ExtensionSortingTest {
extension_ = prefs_.AddApp("page_ordinal");
// Install with a page preference.
first_page_ = syncer::StringOrdinal::CreateInitialOrdinal();
- prefs()->OnExtensionInstalled(extension_.get(), Extension::ENABLED,
+ prefs()->OnExtensionInstalled(extension_.get(),
+ Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
first_page_);
EXPECT_TRUE(first_page_.Equals(
extension_sorting()->GetPageOrdinal(extension_->id())));
@@ -112,7 +119,9 @@ class ExtensionSortingPageOrdinal : public ExtensionSortingTest {
scoped_refptr<Extension> extension2 = prefs_.AddApp("page_ordinal_2");
// Install without any page preference.
- prefs()->OnExtensionInstalled(extension2.get(), Extension::ENABLED,
+ prefs()->OnExtensionInstalled(extension2.get(),
+ Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
syncer::StringOrdinal());
EXPECT_TRUE(first_page_.Equals(
extension_sorting()->GetPageOrdinal(extension2->id())));
@@ -638,6 +647,7 @@ class ExtensionSortingPreinstalledAppsBase
simple_dict, Extension::NO_FLAGS, &error);
prefs()->OnExtensionInstalled(app1_scoped_.get(),
Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
syncer::StringOrdinal());
app2_scoped_ = Extension::Create(
@@ -645,6 +655,7 @@ class ExtensionSortingPreinstalledAppsBase
simple_dict, Extension::NO_FLAGS, &error);
prefs()->OnExtensionInstalled(app2_scoped_.get(),
Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
syncer::StringOrdinal());
app1_ = app1_scoped_.get();
@@ -828,7 +839,9 @@ class ExtensionSortingDefaultOrdinalsBase : public ExtensionSortingTest {
virtual void SetupUserOrdinals() {}
virtual void InstallApps() {
- prefs()->OnExtensionInstalled(app_.get(), Extension::ENABLED,
+ prefs()->OnExtensionInstalled(app_.get(),
+ Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
syncer::StringOrdinal());
}
@@ -874,7 +887,9 @@ class ExtensionSortingDefaultOrdinalOverriddenByInstallPage
protected:
virtual void InstallApps() OVERRIDE {
install_page_ = default_page_ordinal_.CreateAfter();
- prefs()->OnExtensionInstalled(app_.get(), Extension::ENABLED,
+ prefs()->OnExtensionInstalled(app_.get(),
+ Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
install_page_);
}
diff --git a/chrome/browser/extensions/test_extension_prefs.cc b/chrome/browser/extensions/test_extension_prefs.cc
index e2d8a70..018ff42 100644
--- a/chrome/browser/extensions/test_extension_prefs.cc
+++ b/chrome/browser/extensions/test_extension_prefs.cc
@@ -161,6 +161,7 @@ scoped_refptr<Extension> TestExtensionPrefs::AddExtensionWithManifestAndFlags(
EXPECT_TRUE(Extension::IdIsValid(extension->id()));
prefs_->OnExtensionInstalled(extension.get(),
Extension::ENABLED,
+ Blacklist::NOT_BLACKLISTED,
syncer::StringOrdinal::CreateInitialOrdinal());
return extension;
}
diff --git a/chrome/browser/extensions/unpacked_installer.cc b/chrome/browser/extensions/unpacked_installer.cc
index b394f00..adfd3e5 100644
--- a/chrome/browser/extensions/unpacked_installer.cc
+++ b/chrome/browser/extensions/unpacked_installer.cc
@@ -274,10 +274,12 @@ void UnpackedInstaller::ConfirmInstall() {
PermissionsUpdater perms_updater(service_weak_->profile());
perms_updater.GrantActivePermissions(installer_.extension().get());
- service_weak_->OnExtensionInstalled(installer_.extension().get(),
- syncer::StringOrdinal(),
- false /* no requirement errors */,
- false /* don't wait for idle */);
+ service_weak_->OnExtensionInstalled(
+ installer_.extension().get(),
+ syncer::StringOrdinal(),
+ false /* no requirement errors */,
+ Blacklist::NOT_BLACKLISTED,
+ false /* don't wait for idle */);
}
} // namespace extensions