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/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, &not_yet_blocked);
+  Partition(registry_->blacklisted_extensions().GetIDs(), blacklisted,
+            unchanged, &no_longer_blocked, &not_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);