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_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();