Temporarily disable extensions and sync while a profile is locked.
Place all the heavy lifting and logic in profiles code, with extensions providing a new collection for holding "locked" extensions.
This replaces CL 697143003.
BUG=354124
Review URL: https://codereview.chromium.org/695133005
Cr-Commit-Position: refs/heads/master@{#305897}
diff --git a/chrome/browser/background/background_contents_service.cc b/chrome/browser/background/background_contents_service.cc
index 5f8a3e8..338a076 100644
--- a/chrome/browser/background/background_contents_service.cc
+++ b/chrome/browser/background/background_contents_service.cc
@@ -458,10 +458,11 @@
case UnloadedExtensionInfo::REASON_TERMINATE: // Fall through.
case UnloadedExtensionInfo::REASON_UNINSTALL: // Fall through.
case UnloadedExtensionInfo::REASON_BLACKLIST: // Fall through.
+ case UnloadedExtensionInfo::REASON_LOCK_ALL: // Fall through.
case UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN:
ShutdownAssociatedBackgroundContents(base::ASCIIToUTF16(extension->id()));
SendChangeNotification(Profile::FromBrowserContext(browser_context));
- break;
+ return;
case UnloadedExtensionInfo::REASON_UPDATE: {
// If there is a manifest specified background page, then shut it down
// here, since if the updated extension still has the background page,
@@ -473,13 +474,15 @@
ShutdownAssociatedBackgroundContents(
base::ASCIIToUTF16(extension->id()));
}
+ return;
+ case UnloadedExtensionInfo::REASON_UNDEFINED:
+ // Fall through to undefined case.
break;
}
- default:
- NOTREACHED();
- ShutdownAssociatedBackgroundContents(base::ASCIIToUTF16(extension->id()));
- break;
}
+ NOTREACHED() << "Undefined case " << reason;
+ return ShutdownAssociatedBackgroundContents(
+ base::ASCIIToUTF16(extension->id()));
}
void BackgroundContentsService::OnExtensionUninstalled(
diff --git a/chrome/browser/extensions/api/screenlock_private/screenlock_private_apitest.cc b/chrome/browser/extensions/api/screenlock_private/screenlock_private_apitest.cc
index 0c22acd..66256377 100644
--- a/chrome/browser/extensions/api/screenlock_private/screenlock_private_apitest.cc
+++ b/chrome/browser/extensions/api/screenlock_private/screenlock_private_apitest.cc
@@ -73,14 +73,9 @@
}
}
- // Loads |extension_name| as appropriate for the platform and waits for a
- // pass / fail notification.
+ // Loads |extension_name| and waits for a pass / fail notification.
void RunTest(const std::string& extension_name) {
-#if defined(OS_CHROMEOS)
ASSERT_TRUE(RunComponentExtensionTest(extension_name)) << message_;
-#else
- ASSERT_TRUE(RunExtensionTest(extension_name)) << message_;
-#endif
}
private:
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 390092d..b4e4820 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -167,10 +167,10 @@
void ExtensionService::BlacklistExtensionForTest(
const std::string& extension_id) {
- ExtensionIdSet blocked;
+ ExtensionIdSet blacklisted;
ExtensionIdSet unchanged;
- blocked.insert(extension_id);
- UpdateBlockedExtensions(blocked, unchanged);
+ blacklisted.insert(extension_id);
+ UpdateBlacklistedExtensions(blacklisted, unchanged);
}
bool ExtensionService::OnExternalExtensionUpdateUrlFound(
@@ -270,6 +270,7 @@
browser_terminating_(false),
installs_delayed_for_gc_(false),
is_first_run_(false),
+ block_extensions_(false),
shared_module_service_(new extensions::SharedModuleService(profile_)) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -370,11 +371,11 @@
const std::string& id, bool include_disabled) const {
int include_mask = ExtensionRegistry::ENABLED;
if (include_disabled) {
- // Include blacklisted extensions here because there are hundreds of
- // callers of this function, and many might assume that this includes those
- // that have been disabled due to blacklisting.
+ // Include blacklisted and blocked extensions here because there are
+ // hundreds of callers of this function, and many might assume that this
+ // includes those that have been disabled due to blacklisting or blocking.
include_mask |= ExtensionRegistry::DISABLED |
- ExtensionRegistry::BLACKLISTED;
+ ExtensionRegistry::BLACKLISTED | ExtensionRegistry::BLOCKED;
}
return registry_->GetExtensionById(id, include_mask);
}
@@ -575,12 +576,14 @@
return;
}
- // Ignore attempts to reload a blacklisted extension. Sometimes this can
- // happen in a convoluted reload sequence triggered by the termination of a
- // blacklisted extension and a naive attempt to reload it. For an example see
- // http://crbug.com/373842.
- if (registry_->blacklisted_extensions().Contains(transient_extension_id))
+ // Ignore attempts to reload a blacklisted or blocked extension. Sometimes
+ // this can happen in a convoluted reload sequence triggered by the
+ // termination of a blacklisted or blocked extension and a naive attempt to
+ // reload it. For an example see http://crbug.com/373842.
+ if (registry_->blacklisted_extensions().Contains(transient_extension_id) ||
+ registry_->blocked_extensions().Contains(transient_extension_id)) {
return;
+ }
base::FilePath path;
@@ -785,10 +788,15 @@
}
if (registry_->disabled_extensions().Contains(extension_id) ||
- registry_->blacklisted_extensions().Contains(extension_id)) {
+ registry_->blacklisted_extensions().Contains(extension_id) ||
+ registry_->blocked_extensions().Contains(extension_id)) {
return false;
}
+ if (block_extensions_ &&
+ CanBlockExtension(GetInstalledExtension(extension_id)))
+ return false;
+
// If the extension hasn't been loaded yet, check the prefs for it. Assume
// enabled unless otherwise noted.
return !extension_prefs_->IsExtensionDisabled(extension_id) &&
@@ -916,6 +924,48 @@
}
}
+// Extensions that are not locked, components or forced by policy should be
+// locked. Extensions are no longer considered enabled or disabled. Blacklisted
+// extensions are now considered both blacklisted and locked.
+void ExtensionService::BlockAllExtensions() {
+ if (block_extensions_)
+ return;
+ block_extensions_ = true;
+
+ // Blacklisted extensions are already unloaded, need not be blocked.
+ scoped_ptr<ExtensionSet> extensions =
+ registry_->GenerateInstalledExtensionsSet(ExtensionRegistry::ENABLED |
+ ExtensionRegistry::DISABLED |
+ ExtensionRegistry::TERMINATED);
+
+ for (const scoped_refptr<const Extension>& extension : *extensions) {
+ const std::string& id = extension->id();
+
+ if (!CanBlockExtension(extension.get()))
+ continue;
+
+ registry_->RemoveEnabled(id);
+ registry_->RemoveDisabled(id);
+ registry_->RemoveTerminated(id);
+
+ registry_->AddBlocked(extension.get());
+ UnloadExtension(id, extensions::UnloadedExtensionInfo::REASON_LOCK_ALL);
+ }
+}
+
+// All locked extensions should revert to being either enabled or disabled
+// as appropriate.
+void ExtensionService::UnblockAllExtensions() {
+ block_extensions_ = false;
+ scoped_ptr<ExtensionSet> to_unblock =
+ registry_->GenerateInstalledExtensionsSet(ExtensionRegistry::BLOCKED);
+
+ for (const scoped_refptr<const Extension>& extension : *to_unblock) {
+ registry_->RemoveBlocked(extension->id());
+ AddExtension(extension.get());
+ }
+}
+
void ExtensionService::GrantPermissionsAndEnableExtension(
const Extension* extension) {
GrantPermissions(extension);
@@ -1371,6 +1421,8 @@
// installation then threads through the install and pending install flow
// of this class, and we check when loading installed extensions.
registry_->AddBlacklisted(extension);
+ } else if (block_extensions_ && CanBlockExtension(extension)) {
+ registry_->AddBlocked(extension);
} else if (!reloading &&
extension_prefs_->IsExtensionDisabled(extension->id())) {
registry_->AddDisabled(extension);
@@ -2194,6 +2246,13 @@
return Extension::DISABLE_NONE;
}
+// Helper method to determine if an extension can be blocked.
+bool ExtensionService::CanBlockExtension(const Extension* extension) const {
+ return extension->location() != Manifest::COMPONENT &&
+ extension->location() != Manifest::EXTERNAL_COMPONENT &&
+ !system_->management_policy()->MustRemainEnabled(extension, NULL);
+}
+
bool ExtensionService::ShouldDelayExtensionUpdate(
const std::string& extension_id,
bool install_immediately) const {
@@ -2255,7 +2314,7 @@
const extensions::Blacklist::BlacklistStateMap& state_map) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- std::set<std::string> blocked;
+ std::set<std::string> blacklisted;
ExtensionIdSet greylist;
ExtensionIdSet unchanged;
for (extensions::Blacklist::BlacklistStateMap::const_iterator it =
@@ -2267,7 +2326,7 @@
break;
case extensions::BLACKLISTED_MALWARE:
- blocked.insert(it->first);
+ blacklisted.insert(it->first);
break;
case extensions::BLACKLISTED_SECURITY_VULNERABILITY:
@@ -2282,7 +2341,7 @@
}
}
- UpdateBlockedExtensions(blocked, unchanged);
+ UpdateBlacklistedExtensions(blacklisted, unchanged);
UpdateGreylistedExtensions(greylist, unchanged, state_map);
error_controller_->ShowErrorIfNeeded();
@@ -2300,21 +2359,20 @@
}
} // namespace
-void ExtensionService::UpdateBlockedExtensions(
- const ExtensionIdSet& blocked,
+void ExtensionService::UpdateBlacklistedExtensions(
+ const ExtensionIdSet& blacklisted,
const ExtensionIdSet& unchanged) {
ExtensionIdSet not_yet_blocked, no_longer_blocked;
- Partition(registry_->blacklisted_extensions().GetIDs(),
- blocked, unchanged,
- &no_longer_blocked, ¬_yet_blocked);
+ Partition(registry_->blacklisted_extensions().GetIDs(), blacklisted,
+ unchanged, &no_longer_blocked, ¬_yet_blocked);
for (ExtensionIdSet::iterator it = no_longer_blocked.begin();
it != no_longer_blocked.end(); ++it) {
scoped_refptr<const Extension> extension =
registry_->blacklisted_extensions().GetByID(*it);
if (!extension.get()) {
- NOTREACHED() << "Extension " << *it << " no longer blocked, "
- << "but it was never blocked.";
+ NOTREACHED() << "Extension " << *it << " no longer blacklisted, "
+ << "but it was never blacklisted.";
continue;
}
registry_->RemoveBlacklisted(*it);
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 5d9ecc9..8f760f95 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -289,6 +289,18 @@
// |was_installed_by_default| flag.
void DisableUserExtensions(const std::vector<std::string>& except_ids);
+ // Puts all extensions in a blocked state: Unloading every extension, and
+ // preventing them from ever loading until UnblockAllExtensions is called.
+ // This state is stored in preferences, so persists until Chrome restarts.
+ //
+ // Component, external component and whitelisted policy installed extensions
+ // are exempt from being Blocked (see CanBlockExtension).
+ void BlockAllExtensions();
+
+ // All blocked extensions are reverted to their previous state, and are
+ // reloaded. Newly added extensions are no longer automatically blocked.
+ void UnblockAllExtensions();
+
// Updates the |extension|'s granted permissions lists to include all
// permissions in the |extension|'s manifest and re-enables the
// extension.
@@ -546,6 +558,9 @@
// this extension initially.
int GetDisableReasonsOnInstalled(const extensions::Extension* extension);
+ // Helper method to determine if an extension can be blocked.
+ bool CanBlockExtension(const extensions::Extension* extension) const;
+
// Helper to determine if updating an extensions should proceed immediately,
// or if we should delay the update until further notice.
bool ShouldDelayExtensionUpdate(const std::string& extension_id,
@@ -556,10 +571,11 @@
void ManageBlacklist(
const extensions::Blacklist::BlacklistStateMap& blacklisted_ids);
- // Add extensions in |blocked| to blacklisted_extensions, remove extensions
- // that are neither in |blocked|, nor in |unchanged|.
- void UpdateBlockedExtensions(const extensions::ExtensionIdSet& blocked,
- const extensions::ExtensionIdSet& unchanged);
+ // Add extensions in |blacklisted| to blacklisted_extensions, remove
+ // extensions that are neither in |blacklisted|, nor in |unchanged|.
+ void UpdateBlacklistedExtensions(
+ const extensions::ExtensionIdSet& to_blacklist,
+ const extensions::ExtensionIdSet& unchanged);
void UpdateGreylistedExtensions(
const extensions::ExtensionIdSet& greylist,
@@ -684,6 +700,9 @@
// first time.
bool is_first_run_;
+ // Set to true if extensions are all to be blocked.
+ bool block_extensions_;
+
// Store the ids of reloading extensions. We use this to re-enable extensions
// which were disabled for a reload.
std::set<std::string> reloading_extensions_;
@@ -732,6 +751,8 @@
GreylistUnknownDontChange);
FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest,
ManagementPolicyProhibitsEnableOnInstalled);
+ FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest,
+ BlockAndUnblockBlacklistedExtension);
DISALLOW_COPY_AND_ASSIGN(ExtensionService);
};
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 4c09b930..ae5b0dd 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -871,6 +871,39 @@
service()->TrackTerminatedExtensionForTest(extension);
}
+ testing::AssertionResult IsBlocked(const std::string& id) {
+ scoped_ptr<extensions::ExtensionSet> all_unblocked_extensions =
+ registry()->GenerateInstalledExtensionsSet(
+ ExtensionRegistry::EVERYTHING & ~ExtensionRegistry::BLOCKED);
+ if (all_unblocked_extensions.get()->Contains(id))
+ return testing::AssertionFailure() << id << " is still unblocked!";
+ if (!registry()->blocked_extensions().Contains(id))
+ return testing::AssertionFailure() << id << " is not blocked!";
+ return testing::AssertionSuccess();
+ }
+
+ // Helper method to test that an extension moves through being blocked and
+ // unblocked as appropriate for its type.
+ void AssertExtensionBlocksAndUnblocks(
+ bool should_block, const std::string extension_id) {
+ // Assume we start in an unblocked state.
+ EXPECT_FALSE(IsBlocked(extension_id));
+
+ // Block the extensions.
+ service()->BlockAllExtensions();
+ base::RunLoop().RunUntilIdle();
+
+ if (should_block)
+ ASSERT_TRUE(IsBlocked(extension_id));
+ else
+ ASSERT_FALSE(IsBlocked(extension_id));
+
+ service()->UnblockAllExtensions();
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_FALSE(IsBlocked(extension_id));
+ }
+
size_t GetPrefKeyCount() {
const base::DictionaryValue* dict =
profile()->GetPrefs()->GetDictionary("extensions.settings");
@@ -3585,6 +3618,157 @@
#endif // defined(ENABLE_BLACKLIST_TESTS)
+// Tests blocking then unblocking enabled extensions after the service has been
+// initialized.
+TEST_F(ExtensionServiceTest, BlockAndUnblockEnabledExtension) {
+ InitializeGoodInstalledExtensionService();
+ service()->Init();
+
+ AssertExtensionBlocksAndUnblocks(true, good0);
+}
+
+// Tests blocking then unblocking disabled extensions after the service has been
+// initialized.
+TEST_F(ExtensionServiceTest, BlockAndUnblockDisabledExtension) {
+ InitializeGoodInstalledExtensionService();
+ service()->Init();
+
+ service()->DisableExtension(good0, Extension::DISABLE_RELOAD);
+
+ AssertExtensionBlocksAndUnblocks(true, good0);
+}
+
+// Tests blocking then unblocking terminated extensions after the service has
+// been initialized.
+TEST_F(ExtensionServiceTest, BlockAndUnblockTerminatedExtension) {
+ InitializeGoodInstalledExtensionService();
+ service()->Init();
+
+ TerminateExtension(good0);
+
+ AssertExtensionBlocksAndUnblocks(true, good0);
+}
+
+// Tests blocking then unblocking policy-forced extensions after the service has
+// been initialized.
+TEST_F(ExtensionServiceTest, BlockAndUnblockPolicyExtension) {
+ InitializeEmptyExtensionServiceWithTestingPrefs();
+
+ {
+ ManagementPrefUpdater pref(profile_->GetTestingPrefService());
+ // // Blacklist everything.
+ // pref.SetBlacklistedByDefault(true);
+ // Mark good.crx for force-installation.
+ pref.SetIndividualExtensionAutoInstalled(
+ good_crx, "http://example.com/update_url", true);
+ }
+
+ // Have policy force-install an extension.
+ MockExtensionProvider* provider =
+ new MockExtensionProvider(service(), Manifest::EXTERNAL_POLICY_DOWNLOAD);
+ AddMockExternalProvider(provider);
+ provider->UpdateOrAddExtension(
+ good_crx, "1.0.0.0", data_dir().AppendASCII("good_crx"));
+
+ // Reloading extensions should find our externally registered extension
+ // and install it.
+ content::WindowedNotificationObserver observer(
+ extensions::NOTIFICATION_CRX_INSTALLER_DONE,
+ content::NotificationService::AllSources());
+ service()->CheckForExternalUpdates();
+ observer.Wait();
+
+ AssertExtensionBlocksAndUnblocks(false, good_crx);
+}
+
+
+#if defined(ENABLE_BLACKLIST_TESTS)
+// Tests blocking then unblocking extensions that are blacklisted both before
+// and after Init().
+TEST_F(ExtensionServiceTest, BlockAndUnblockBlacklistedExtension) {
+ extensions::TestBlacklist test_blacklist;
+
+ InitializeGoodInstalledExtensionService();
+ test_blacklist.Attach(service()->blacklist_);
+
+ test_blacklist.SetBlacklistState(
+ good0, extensions::BLACKLISTED_MALWARE, true);
+ base::RunLoop().RunUntilIdle();
+
+ service()->Init();
+
+ test_blacklist.SetBlacklistState(
+ good1, extensions::BLACKLISTED_MALWARE, true);
+ base::RunLoop().RunUntilIdle();
+
+ // Blacklisted extensions stay blacklisted.
+ AssertExtensionBlocksAndUnblocks(false, good0);
+ AssertExtensionBlocksAndUnblocks(false, good1);
+
+ service()->BlockAllExtensions();
+
+ // Remove an extension from the blacklist while the service is blocked.
+ test_blacklist.SetBlacklistState(
+ good0, extensions::NOT_BLACKLISTED, true);
+ // Add an extension to the blacklist while the service is blocked.
+ test_blacklist.SetBlacklistState(
+ good2, extensions::BLACKLISTED_MALWARE, true);
+ base::RunLoop().RunUntilIdle();
+
+ // Go directly to blocked, do not pass go, do not collect $200.
+ ASSERT_TRUE(IsBlocked(good0));
+ // Get on the blacklist - even if you were blocked!
+ ASSERT_FALSE(IsBlocked(good2));
+}
+#endif // defined(ENABLE_BLACKLIST_TESTS)
+
+// Tests blocking then unblocking enabled component extensions after the service
+// has been initialized.
+TEST_F(ExtensionServiceTest, BlockAndUnblockEnabledComponentExtension) {
+ InitializeEmptyExtensionServiceWithTestingPrefs();
+
+ // Install a component extension.
+ base::FilePath path = data_dir()
+ .AppendASCII("good")
+ .AppendASCII("Extensions")
+ .AppendASCII(good0)
+ .AppendASCII("1.0.0.0");
+ std::string manifest;
+ ASSERT_TRUE(base::ReadFileToString(
+ path.Append(extensions::kManifestFilename), &manifest));
+ service()->component_loader()->Add(manifest, path);
+ service()->Init();
+
+ // Component extension should never block.
+ AssertExtensionBlocksAndUnblocks(false, good0);
+}
+
+// Tests blocking then unblocking a theme after the service has been
+// initialized.
+TEST_F(ExtensionServiceTest, BlockAndUnblockTheme) {
+ InitializeEmptyExtensionService();
+ service()->Init();
+
+ base::FilePath path = data_dir().AppendASCII("theme.crx");
+ InstallCRX(path, INSTALL_NEW);
+
+ AssertExtensionBlocksAndUnblocks(true, theme_crx);
+}
+
+// Tests that blocking extensions before Init() results in loading blocked
+// extensions.
+TEST_F(ExtensionServiceTest, WillNotLoadExtensionsWhenBlocked) {
+ InitializeGoodInstalledExtensionService();
+
+ service()->BlockAllExtensions();
+
+ service()->Init();
+
+ ASSERT_TRUE(IsBlocked(good0));
+ ASSERT_TRUE(IsBlocked(good0));
+ ASSERT_TRUE(IsBlocked(good0));
+}
+
// Will not install extension blacklisted by policy.
TEST_F(ExtensionServiceTest, BlacklistedByPolicyWillNotInstall) {
InitializeEmptyExtensionServiceWithTestingPrefs();
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 1eceba9..2def7686 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -993,6 +993,7 @@
void ProfileManager::DoFinalInitForServices(Profile* profile,
bool go_off_the_record) {
#if defined(ENABLE_EXTENSIONS)
+ ProfileInfoCache& cache = GetProfileInfoCache();
extensions::ExtensionSystem::Get(profile)->InitForRegularProfile(
!go_off_the_record);
// During tests, when |profile| is an instance of TestingProfile,
@@ -1001,6 +1002,16 @@
extensions::ExtensionSystem::Get(profile)->extension_service()->
RegisterContentSettings(profile->GetHostContentSettingsMap());
}
+ // Set the block extensions bit on the ExtensionService. There likely are no
+ // blockable extensions to block.
+ size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
+ if (profile_index != std::string::npos &&
+ cache.ProfileIsSigninRequiredAtIndex(profile_index)) {
+ extensions::ExtensionSystem::Get(profile)
+ ->extension_service()
+ ->BlockAllExtensions();
+ }
+
#endif
#if defined(ENABLE_MANAGED_USERS) && !defined(OS_ANDROID)
// Initialization needs to happen after extension system initialization (for
diff --git a/chrome/browser/profiles/profile_window.cc b/chrome/browser/profiles/profile_window.cc
index 4cb2940..96310bd0 100644
--- a/chrome/browser/profiles/profile_window.cc
+++ b/chrome/browser/profiles/profile_window.cc
@@ -17,6 +17,8 @@
#include "chrome/browser/profiles/profile_avatar_icon_util.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/account_reconcilor_factory.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/profile_chooser_constants.h"
@@ -29,6 +31,14 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/user_metrics.h"
+#if defined(ENABLE_EXTENSIONS)
+#include "chrome/browser/extensions/extension_service.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_registry_factory.h"
+#include "extensions/browser/extension_system.h"
+#endif // defined(ENABLE_EXTENSIONS)
+
#if !defined(OS_IOS)
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
@@ -45,6 +55,20 @@
const char kNewProfileManagementExperimentInternalName[] =
"enable-new-profile-management";
+#if defined(ENABLE_EXTENSIONS)
+void BlockExtensions(Profile* profile) {
+ ExtensionService* extension_service =
+ extensions::ExtensionSystem::Get(profile)->extension_service();
+ extension_service->BlockAllExtensions();
+}
+
+void UnblockExtensions(Profile* profile) {
+ ExtensionService* extension_service =
+ extensions::ExtensionSystem::Get(profile)->extension_service();
+ extension_service->UnblockAllExtensions();
+}
+#endif // defined(ENABLE_EXTENSIONS)
+
// Handles running a callback when a new Browser for the given profile
// has been completely created.
class BrowserAddedForProfileObserver : public chrome::BrowserListObserver {
@@ -98,6 +122,19 @@
is_first_run = chrome::startup::IS_FIRST_RUN;
}
+#if defined(ENABLE_EXTENSIONS)
+ // The signin bit will still be set if the profile is being unlocked and the
+ // browser window for it is opening. As part of this unlock process, unblock
+ // all the extensions.
+ const ProfileInfoCache& cache =
+ g_browser_process->profile_manager()->GetProfileInfoCache();
+ int index = cache.GetIndexOfProfileWithPath(profile->GetPath());
+ if (!profile->IsGuestSession() &&
+ cache.ProfileIsSigninRequiredAtIndex(index)) {
+ UnblockExtensions(profile);
+ }
+#endif // defined(ENABLE_EXTENSIONS)
+
// If |always_create| is false, and we have a |callback| to run, check
// whether a browser already exists so that we can run the callback. We don't
// want to rely on the observer listening to OnBrowserSetLastActive in this
@@ -297,11 +334,17 @@
}
void LockBrowserCloseSuccess(const base::FilePath& profile_path) {
- ProfileInfoCache* cache =
- &g_browser_process->profile_manager()->GetProfileInfoCache();
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ ProfileInfoCache* cache = &profile_manager->GetProfileInfoCache();
cache->SetProfileSigninRequiredAtIndex(
cache->GetIndexOfProfileWithPath(profile_path), true);
+
+#if defined(ENABLE_EXTENSIONS)
+ // Profile guaranteed to exist for it to have been locked.
+ BlockExtensions(profile_manager->GetProfileByPath(profile_path));
+#endif // defined(ENABLE_EXTENSIONS)
+
chrome::HideTaskManager();
UserManager::Show(profile_path,
profiles::USER_MANAGER_NO_TUTORIAL,
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index cecfd459..758b5d97 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -300,6 +300,7 @@
case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
Details<const UnloadedExtensionInfo> unloaded_details(details);
if (unloaded_details->reason != UnloadedExtensionInfo::REASON_UPDATE &&
+ unloaded_details->reason != UnloadedExtensionInfo::REASON_LOCK_ALL &&
unloaded_details->extension->is_theme() &&
unloaded_details->extension->id() == GetThemeID()) {
UseDefaultTheme();
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index a7831ef..3502e0d 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -922,20 +922,11 @@
"312745D9BF916161191143F6490085EEA0434997" // Google Talk debug
]
},
- "screenlockPrivate": [{
- "platforms": ["chromeos"],
+ "screenlockPrivate": {
"channel": "stable",
"extension_types": ["platform_app"],
"location": "component"
- }, {
- "platforms": ["mac", "win", "linux"],
- "channel": "stable",
- "extension_types": ["platform_app"],
- "whitelist": [
- "lkegkdgachcnekllcdfkijonogckdnjo", // API test
- "E13990DC5440B6E270503DA27A35762F423725C3" // dogfood
- ]
- }],
+ },
"screensaver": {
"channel": "stable",
"extension_types": ["legacy_packaged_app", "hosted_app", "platform_app"]
diff --git a/extensions/browser/extension_registry.cc b/extensions/browser/extension_registry.cc
index 769539e9..62891d8 100644
--- a/extensions/browser/extension_registry.cc
+++ b/extensions/browser/extension_registry.cc
@@ -21,11 +21,22 @@
scoped_ptr<ExtensionSet> ExtensionRegistry::GenerateInstalledExtensionsSet()
const {
+ return GenerateInstalledExtensionsSet(EVERYTHING).Pass();
+}
+
+scoped_ptr<ExtensionSet> ExtensionRegistry::GenerateInstalledExtensionsSet(
+ int include_mask) const {
scoped_ptr<ExtensionSet> installed_extensions(new ExtensionSet);
- installed_extensions->InsertAll(enabled_extensions_);
- installed_extensions->InsertAll(disabled_extensions_);
- installed_extensions->InsertAll(terminated_extensions_);
- installed_extensions->InsertAll(blacklisted_extensions_);
+ if (include_mask & IncludeFlag::ENABLED)
+ installed_extensions->InsertAll(enabled_extensions_);
+ if (include_mask & IncludeFlag::DISABLED)
+ installed_extensions->InsertAll(disabled_extensions_);
+ if (include_mask & IncludeFlag::TERMINATED)
+ installed_extensions->InsertAll(terminated_extensions_);
+ if (include_mask & IncludeFlag::BLACKLISTED)
+ installed_extensions->InsertAll(blacklisted_extensions_);
+ if (include_mask & IncludeFlag::BLOCKED)
+ installed_extensions->InsertAll(blocked_extensions_);
return installed_extensions.Pass();
}
@@ -108,6 +119,11 @@
if (extension)
return extension;
}
+ if (include_mask & BLOCKED) {
+ const Extension* extension = blocked_extensions_.GetByID(lowercase_id);
+ if (extension)
+ return extension;
+ }
return NULL;
}
@@ -147,11 +163,21 @@
return blacklisted_extensions_.Remove(id);
}
+bool ExtensionRegistry::AddBlocked(
+ const scoped_refptr<const Extension>& extension) {
+ return blocked_extensions_.Insert(extension);
+}
+
+bool ExtensionRegistry::RemoveBlocked(const std::string& id) {
+ return blocked_extensions_.Remove(id);
+}
+
void ExtensionRegistry::ClearAll() {
enabled_extensions_.Clear();
disabled_extensions_.Clear();
terminated_extensions_.Clear();
blacklisted_extensions_.Clear();
+ blocked_extensions_.Clear();
}
void ExtensionRegistry::SetDisabledModificationCallback(
diff --git a/extensions/browser/extension_registry.h b/extensions/browser/extension_registry.h
index 50f75c9..d29a37b 100644
--- a/extensions/browser/extension_registry.h
+++ b/extensions/browser/extension_registry.h
@@ -33,12 +33,13 @@
public:
// Flags to pass to GetExtensionById() to select which sets to look in.
enum IncludeFlag {
- NONE = 0,
- ENABLED = 1 << 0,
- DISABLED = 1 << 1,
- TERMINATED = 1 << 2,
+ NONE = 0,
+ ENABLED = 1 << 0,
+ DISABLED = 1 << 1,
+ TERMINATED = 1 << 2,
BLACKLISTED = 1 << 3,
- EVERYTHING = (1 << 4) - 1,
+ BLOCKED = 1 << 4,
+ EVERYTHING = (1 << 5) - 1,
};
explicit ExtensionRegistry(content::BrowserContext* browser_context);
@@ -63,11 +64,21 @@
const ExtensionSet& blacklisted_extensions() const {
return blacklisted_extensions_;
}
+ const ExtensionSet& blocked_extensions() const { return blocked_extensions_; }
- // Returns a set of all installed, disabled, blacklisted, and terminated
- // extensions.
+ // Returns the set of all installed extensions, regardless of state (enabled,
+ // disabled, etc). Equivalent to GenerateInstalledExtensionSet(EVERYTHING).
scoped_ptr<ExtensionSet> GenerateInstalledExtensionsSet() const;
+ // Returns a set of all extensions in the subsets specified by |include_mask|.
+ // * enabled_extensions() --> ExtensionRegistry::ENABLED
+ // * disabled_extensions() --> ExtensionRegistry::DISABLED
+ // * terminated_extensions() --> ExtensionRegistry::TERMINATED
+ // * blacklisted_extensions() --> ExtensionRegistry::BLACKLISTED
+ // * blocked_extensions() --> ExtensionRegistry::BLOCKED
+ scoped_ptr<ExtensionSet> GenerateInstalledExtensionsSet(
+ int include_mask) const;
+
// The usual observer interface.
void AddObserver(ExtensionRegistryObserver* observer);
void RemoveObserver(ExtensionRegistryObserver* observer);
@@ -107,6 +118,7 @@
// * disabled_extensions() --> ExtensionRegistry::DISABLED
// * terminated_extensions() --> ExtensionRegistry::TERMINATED
// * blacklisted_extensions() --> ExtensionRegistry::BLACKLISTED
+ // * blocked_extensions() --> ExtensionRegistry::BLOCKED
// Returns NULL if the extension is not found in the selected sets.
const Extension* GetExtensionById(const std::string& id,
int include_mask) const;
@@ -136,6 +148,10 @@
bool AddBlacklisted(const scoped_refptr<const Extension>& extension);
bool RemoveBlacklisted(const std::string& id);
+ // As above, but for the blocked set.
+ bool AddBlocked(const scoped_refptr<const Extension>& extension);
+ bool RemoveBlocked(const std::string& id);
+
// Removes all extensions from all sets.
void ClearAll();
@@ -164,6 +180,9 @@
// un-blacklisted.
ExtensionSet blacklisted_extensions_;
+ // Extensions that are installed and blocked. Will never be loaded.
+ ExtensionSet blocked_extensions_;
+
ObserverList<ExtensionRegistryObserver> observers_;
content::BrowserContext* const browser_context_;
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
index 391c7e5..d845332 100644
--- a/extensions/common/extension.h
+++ b/extensions/common/extension.h
@@ -69,6 +69,7 @@
// DEPRECATED: Special state for component extensions.
// Maintained as a placeholder since states may be stored to disk.
ENABLED_COMPONENT_DEPRECATED,
+ // Add new states here as this enum is stored in prefs.
NUM_STATES
};
@@ -541,6 +542,7 @@
REASON_TERMINATE, // Extension has terminated.
REASON_BLACKLIST, // Extension has been blacklisted.
REASON_PROFILE_SHUTDOWN, // Profile is being shut down.
+ REASON_LOCK_ALL, // All extensions for the profile are blocked.
};
Reason reason;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 09c35fb..131479a 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -44424,7 +44424,6 @@
<int value="1024" label="CORRUPTED"/>
<int value="2048" label="REMOTE_INSTALL"/>
<int value="4096" label="INACTIVE_EPHEMERAL_APP"/>
- <int value="8192" label="EXTERNAL_EXTENSION"/>
</enum>
<enum name="ExtensionFileWriteResult" type="int">