| Index: chrome/browser/extensions/extension_service.cc
 | 
| diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
 | 
| index 779456147d73a23a45189e6b4b28fe095f16f287..a52dc40aaa6bc930235109e836159966a2836028 100644
 | 
| --- a/chrome/browser/extensions/extension_service.cc
 | 
| +++ b/chrome/browser/extensions/extension_service.cc
 | 
| @@ -5,6 +5,7 @@
 | 
|  #include "chrome/browser/extensions/extension_service.h"
 | 
|  
 | 
|  #include <algorithm>
 | 
| +#include <iterator>
 | 
|  #include <set>
 | 
|  
 | 
|  #include "base/basictypes.h"
 | 
| @@ -362,6 +363,7 @@ ExtensionService::ExtensionService(Profile* profile,
 | 
|        profile_(profile),
 | 
|        system_(extensions::ExtensionSystem::Get(profile)),
 | 
|        extension_prefs_(extension_prefs),
 | 
| +      blacklist_(blacklist),
 | 
|        settings_frontend_(extensions::SettingsFrontend::Create(profile)),
 | 
|        pending_extension_manager_(*ALLOW_THIS_IN_INITIALIZER_LIST(this)),
 | 
|        install_directory_(install_directory),
 | 
| @@ -467,23 +469,29 @@ const ExtensionSet* ExtensionService::terminated_extensions() const {
 | 
|    return &terminated_extensions_;
 | 
|  }
 | 
|  
 | 
| -const ExtensionSet* ExtensionService::GenerateInstalledExtensionsSet() const {
 | 
| -  ExtensionSet* installed_extensions = new ExtensionSet();
 | 
| +const ExtensionSet* ExtensionService::blacklisted_extensions() const {
 | 
| +  return &blacklisted_extensions_;
 | 
| +}
 | 
| +
 | 
| +scoped_ptr<const ExtensionSet>
 | 
| +    ExtensionService::GenerateInstalledExtensionsSet() const {
 | 
| +  scoped_ptr<ExtensionSet> installed_extensions(new ExtensionSet());
 | 
|    installed_extensions->InsertAll(extensions_);
 | 
|    installed_extensions->InsertAll(disabled_extensions_);
 | 
|    installed_extensions->InsertAll(terminated_extensions_);
 | 
| -  return installed_extensions;
 | 
| +  installed_extensions->InsertAll(blacklisted_extensions_);
 | 
| +  return installed_extensions.PassAs<const ExtensionSet>();
 | 
|  }
 | 
|  
 | 
| -const ExtensionSet* ExtensionService::GetWipedOutExtensions() const {
 | 
| -  ExtensionSet* extension_set = new ExtensionSet();
 | 
| +scoped_ptr<const ExtensionSet> ExtensionService::GetWipedOutExtensions() const {
 | 
| +  scoped_ptr<ExtensionSet> extension_set(new ExtensionSet());
 | 
|    for (ExtensionSet::const_iterator iter = disabled_extensions_.begin();
 | 
|         iter != disabled_extensions_.end(); ++iter) {
 | 
|      int disabled_reason = extension_prefs_->GetDisableReasons((*iter)->id());
 | 
|      if ((disabled_reason & Extension::DISABLE_SIDELOAD_WIPEOUT) != 0)
 | 
|        extension_set->Insert(*iter);
 | 
|    }
 | 
| -  return extension_set;
 | 
| +  return extension_set.PassAs<const ExtensionSet>();
 | 
|  }
 | 
|  
 | 
|  extensions::PendingExtensionManager*
 | 
| @@ -579,9 +587,39 @@ void ExtensionService::Shutdown() {
 | 
|  const Extension* ExtensionService::GetExtensionById(
 | 
|      const std::string& id, bool include_disabled) const {
 | 
|    int include_mask = INCLUDE_ENABLED;
 | 
| -  if (include_disabled)
 | 
| -    include_mask |= INCLUDE_DISABLED;
 | 
| -  return GetExtensionByIdInternal(id, include_mask);
 | 
| +  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_mask |= INCLUDE_DISABLED | INCLUDE_BLACKLISTED;
 | 
| +  }
 | 
| +  return GetExtensionById(id, include_mask);
 | 
| +}
 | 
| +
 | 
| +const Extension* ExtensionService::GetExtensionById(
 | 
| +    const std::string& id, int include_mask) const {
 | 
| +  std::string lowercase_id = StringToLowerASCII(id);
 | 
| +  if (include_mask & INCLUDE_ENABLED) {
 | 
| +    const Extension* extension = extensions_.GetByID(lowercase_id);
 | 
| +    if (extension)
 | 
| +      return extension;
 | 
| +  }
 | 
| +  if (include_mask & INCLUDE_DISABLED) {
 | 
| +    const Extension* extension = disabled_extensions_.GetByID(lowercase_id);
 | 
| +    if (extension)
 | 
| +      return extension;
 | 
| +  }
 | 
| +  if (include_mask & INCLUDE_TERMINATED) {
 | 
| +    const Extension* extension = terminated_extensions_.GetByID(lowercase_id);
 | 
| +    if (extension)
 | 
| +      return extension;
 | 
| +  }
 | 
| +  if (include_mask & INCLUDE_BLACKLISTED) {
 | 
| +    const Extension* extension = blacklisted_extensions_.GetByID(lowercase_id);
 | 
| +    if (extension)
 | 
| +      return extension;
 | 
| +  }
 | 
| +  return NULL;
 | 
|  }
 | 
|  
 | 
|  void ExtensionService::Init() {
 | 
| @@ -637,9 +675,7 @@ bool ExtensionService::UpdateExtension(const std::string& id,
 | 
|    const extensions::PendingExtensionInfo* pending_extension_info =
 | 
|        pending_extension_manager()->GetById(id);
 | 
|  
 | 
| -  int include_mask = INCLUDE_ENABLED | INCLUDE_DISABLED;
 | 
| -  const Extension* extension =
 | 
| -      GetExtensionByIdInternal(id, include_mask);
 | 
| +  const Extension* extension = GetInstalledExtension(id);
 | 
|    if (!pending_extension_info && !extension) {
 | 
|      LOG(WARNING) << "Will not update extension " << id
 | 
|                   << " because it is not installed or pending";
 | 
| @@ -890,13 +926,15 @@ bool ExtensionService::IsExtensionEnabled(
 | 
|      return true;
 | 
|    }
 | 
|  
 | 
| -  if (disabled_extensions_.Contains(extension_id))
 | 
| +  if (disabled_extensions_.Contains(extension_id) ||
 | 
| +      blacklisted_extensions_.Contains(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) &&
 | 
| -      !extension_prefs_->IsExternalExtensionUninstalled(extension_id);
 | 
| +         !extension_prefs_->IsExternalExtensionUninstalled(extension_id);
 | 
|  }
 | 
|  
 | 
|  bool ExtensionService::IsExternalExtensionUninstalled(
 | 
| @@ -914,8 +952,7 @@ void ExtensionService::EnableExtension(const std::string& extension_id) {
 | 
|    extension_prefs_->SetExtensionState(extension_id, Extension::ENABLED);
 | 
|    extension_prefs_->ClearDisableReasons(extension_id);
 | 
|  
 | 
| -  const Extension* extension = GetExtensionByIdInternal(extension_id,
 | 
| -      INCLUDE_DISABLED);
 | 
| +  const Extension* extension = disabled_extensions_.GetByID(extension_id);
 | 
|    // This can happen if sync enables an extension that is not
 | 
|    // installed yet.
 | 
|    if (!extension)
 | 
| @@ -966,8 +1003,8 @@ void ExtensionService::DisableExtension(
 | 
|    extension_prefs_->SetExtensionState(extension_id, Extension::DISABLED);
 | 
|    extension_prefs_->AddDisableReason(extension_id, disable_reason);
 | 
|  
 | 
| -  int include_mask = INCLUDE_ENABLED | INCLUDE_TERMINATED;
 | 
| -  extension = GetExtensionByIdInternal(extension_id, include_mask);
 | 
| +  int include_mask = INCLUDE_EVERYTHING & ~INCLUDE_DISABLED;
 | 
| +  extension = GetExtensionById(extension_id, include_mask);
 | 
|    if (!extension)
 | 
|      return;
 | 
|  
 | 
| @@ -1263,6 +1300,7 @@ extensions::ExtensionUpdater* ExtensionService::updater() {
 | 
|  
 | 
|  void ExtensionService::CheckManagementPolicy() {
 | 
|    std::vector<std::string> to_be_removed;
 | 
| +
 | 
|    // Loop through extensions list, unload installed extensions.
 | 
|    for (ExtensionSet::const_iterator iter = extensions_.begin();
 | 
|         iter != extensions_.end(); ++iter) {
 | 
| @@ -1826,15 +1864,31 @@ void ExtensionService::IdentifyAlertableExtensions() {
 | 
|  bool ExtensionService::PopulateExtensionErrorUI(
 | 
|      ExtensionErrorUI* extension_error_ui) {
 | 
|    bool needs_alert = false;
 | 
| +
 | 
| +  // Extensions that are blacklisted.
 | 
| +  for (ExtensionSet::const_iterator it = blacklisted_extensions_.begin();
 | 
| +       it != blacklisted_extensions_.end(); ++it) {
 | 
| +    std::string id = (*it)->id();
 | 
| +    if (!extension_prefs_->IsBlacklistedExtensionAcknowledged(id)) {
 | 
| +      extension_error_ui->AddBlacklistedExtension(id);
 | 
| +      needs_alert = true;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
|    for (ExtensionSet::const_iterator iter = extensions_.begin();
 | 
|         iter != extensions_.end(); ++iter) {
 | 
|      const Extension* e = *iter;
 | 
| +
 | 
| +    // Extensions disabled by policy. Note: this no longer includes blacklisted
 | 
| +    // extensions, though we still show the same UI.
 | 
|      if (!system_->management_policy()->UserMayLoad(e, NULL)) {
 | 
|        if (!extension_prefs_->IsBlacklistedExtensionAcknowledged(e->id())) {
 | 
|          extension_error_ui->AddBlacklistedExtension(e->id());
 | 
|          needs_alert = true;
 | 
|        }
 | 
|      }
 | 
| +
 | 
| +    // Orphaned extensions.
 | 
|      if (extension_prefs_->IsExtensionOrphaned(e->id())) {
 | 
|        if (!extension_prefs_->IsOrphanedExtensionAcknowledged(e->id())) {
 | 
|          extension_error_ui->AddOrphanedExtension(e->id());
 | 
| @@ -1842,6 +1896,7 @@ bool ExtensionService::PopulateExtensionErrorUI(
 | 
|        }
 | 
|      }
 | 
|    }
 | 
| +
 | 
|    return needs_alert;
 | 
|  }
 | 
|  
 | 
| @@ -1921,9 +1976,9 @@ void ExtensionService::UnloadExtension(
 | 
|      const std::string& extension_id,
 | 
|      extension_misc::UnloadedExtensionReason reason) {
 | 
|    // Make sure the extension gets deleted after we return from this function.
 | 
| -  int include_mask = INCLUDE_ENABLED | INCLUDE_DISABLED;
 | 
| +  int include_mask = INCLUDE_EVERYTHING & ~INCLUDE_TERMINATED;
 | 
|    scoped_refptr<const Extension> extension(
 | 
| -      GetExtensionByIdInternal(extension_id, include_mask));
 | 
| +      GetExtensionById(extension_id, include_mask));
 | 
|  
 | 
|    // This method can be called via PostTask, so the extension may have been
 | 
|    // unloaded by the time this runs.
 | 
| @@ -2081,7 +2136,17 @@ void ExtensionService::AddExtension(const Extension* extension) {
 | 
|    // wipeout before, we might disable this extension here.
 | 
|    MaybeWipeout(extension);
 | 
|  
 | 
| -  if (extension_prefs_->IsExtensionDisabled(extension->id())) {
 | 
| +  // Communicated to the Blacklist.
 | 
| +  std::set<std::string> already_in_blacklist;
 | 
| +
 | 
| +  if (extension_prefs_->IsExtensionBlacklisted(extension->id())) {
 | 
| +    // Don't check the Blacklist yet because it's asynchronous (we do it at
 | 
| +    // the end). This pre-emptive check is because we will always store the
 | 
| +    // blacklisted state of *installed* extensions in prefs, and it's important
 | 
| +    // not to re-enable blacklisted extensions.
 | 
| +    blacklisted_extensions_.Insert(extension);
 | 
| +    already_in_blacklist.insert(extension->id());
 | 
| +  } else if (extension_prefs_->IsExtensionDisabled(extension->id())) {
 | 
|      disabled_extensions_.Insert(extension);
 | 
|      SyncExtensionChangeIfNeeded(*extension);
 | 
|      content::NotificationService::current()->Notify(
 | 
| @@ -2093,29 +2158,38 @@ void ExtensionService::AddExtension(const Extension* extension) {
 | 
|          Extension::DISABLE_PERMISSIONS_INCREASE) {
 | 
|        extensions::AddExtensionDisabledError(this, extension);
 | 
|      }
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // All apps that are displayed in the launcher are ordered by their ordinals
 | 
| -  // so we must ensure they have valid ordinals.
 | 
| -  if (extension->RequiresSortOrdinal()) {
 | 
| -    extension_prefs_->extension_sorting()->EnsureValidOrdinals(
 | 
| -        extension->id(), syncer::StringOrdinal());
 | 
| -  }
 | 
| +  } else {
 | 
| +    // All apps that are displayed in the launcher are ordered by their ordinals
 | 
| +    // so we must ensure they have valid ordinals.
 | 
| +    if (extension->RequiresSortOrdinal()) {
 | 
| +      extension_prefs_->extension_sorting()->EnsureValidOrdinals(
 | 
| +          extension->id(), syncer::StringOrdinal());
 | 
| +    }
 | 
|  
 | 
| -  extensions_.Insert(extension);
 | 
| -  SyncExtensionChangeIfNeeded(*extension);
 | 
| -  NotifyExtensionLoaded(extension);
 | 
| -  DoPostLoadTasks(extension);
 | 
| +    extensions_.Insert(extension);
 | 
| +    SyncExtensionChangeIfNeeded(*extension);
 | 
| +    NotifyExtensionLoaded(extension);
 | 
| +    DoPostLoadTasks(extension);
 | 
|  
 | 
|  #if defined(ENABLE_THEMES)
 | 
| -  if (extension->is_theme()) {
 | 
| -    // Now that the theme extension is visible from outside the
 | 
| -    // ExtensionService, notify the ThemeService about the
 | 
| -    // newly-installed theme.
 | 
| -    ThemeServiceFactory::GetForProfile(profile_)->SetTheme(extension);
 | 
| -  }
 | 
| +    if (extension->is_theme()) {
 | 
| +      // Now that the theme extension is visible from outside the
 | 
| +      // ExtensionService, notify the ThemeService about the
 | 
| +      // newly-installed theme.
 | 
| +      ThemeServiceFactory::GetForProfile(profile_)->SetTheme(extension);
 | 
| +    }
 | 
|  #endif
 | 
| +  }
 | 
| +
 | 
| +  // Lastly, begin the process for checking the blacklist status of extensions.
 | 
| +  // This may need to go to other threads so is asynchronous.
 | 
| +  std::set<std::string> id_set;
 | 
| +  id_set.insert(extension->id());
 | 
| +  blacklist_->GetBlacklistedIDs(
 | 
| +      id_set,
 | 
| +      base::Bind(&ExtensionService::ManageBlacklist,
 | 
| +                 AsWeakPtr(),
 | 
| +                 already_in_blacklist));
 | 
|  }
 | 
|  
 | 
|  void ExtensionService::AddComponentExtension(const Extension* extension) {
 | 
| @@ -2188,9 +2262,7 @@ void ExtensionService::InitializePermissions(const Extension* extension) {
 | 
|    // still remember that "omnibox" had been granted, so that if the
 | 
|    // extension once again includes "omnibox" in an upgrade, the extension
 | 
|    // can upgrade without requiring this user's approval.
 | 
| -  int include_mask = INCLUDE_ENABLED | INCLUDE_DISABLED;
 | 
| -  const Extension* old =
 | 
| -      GetExtensionByIdInternal(extension->id(), include_mask);
 | 
| +  const Extension* old = GetInstalledExtension(extension->id());
 | 
|    bool is_extension_upgrade = old != NULL;
 | 
|    bool is_privilege_increase = false;
 | 
|    bool previously_disabled = false;
 | 
| @@ -2371,8 +2443,7 @@ void ExtensionService::OnExtensionInstalled(
 | 
|      extension_prefs_->ClearDisableReasons(id);
 | 
|    }
 | 
|  
 | 
| -  int include_mask = INCLUDE_ENABLED | INCLUDE_DISABLED;
 | 
| -  if (!GetExtensionByIdInternal(extension->id(), include_mask)) {
 | 
| +  if (!GetInstalledExtension(extension->id())) {
 | 
|      UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType",
 | 
|                                extension->GetType(), 100);
 | 
|      UMA_HISTOGRAM_ENUMERATION("Extensions.InstallSource",
 | 
| @@ -2484,27 +2555,6 @@ const Extension* ExtensionService::GetPendingExtensionUpdate(
 | 
|    return pending_extension_updates_.GetByID(id);
 | 
|  }
 | 
|  
 | 
| -const Extension* ExtensionService::GetExtensionByIdInternal(
 | 
| -    const std::string& id, int include_mask) const {
 | 
| -  std::string lowercase_id = StringToLowerASCII(id);
 | 
| -  if (include_mask & INCLUDE_ENABLED) {
 | 
| -    const Extension* extension = extensions_.GetByID(lowercase_id);
 | 
| -    if (extension)
 | 
| -      return extension;
 | 
| -  }
 | 
| -  if (include_mask & INCLUDE_DISABLED) {
 | 
| -    const Extension* extension = disabled_extensions_.GetByID(lowercase_id);
 | 
| -    if (extension)
 | 
| -      return extension;
 | 
| -  }
 | 
| -  if (include_mask & INCLUDE_TERMINATED) {
 | 
| -    const Extension* extension = terminated_extensions_.GetByID(lowercase_id);
 | 
| -    if (extension)
 | 
| -      return extension;
 | 
| -  }
 | 
| -  return NULL;
 | 
| -}
 | 
| -
 | 
|  void ExtensionService::TrackTerminatedExtension(const Extension* extension) {
 | 
|    if (!terminated_extensions_.Contains(extension->id()))
 | 
|      terminated_extensions_.Insert(make_scoped_refptr(extension));
 | 
| @@ -2519,13 +2569,16 @@ void ExtensionService::UntrackTerminatedExtension(const std::string& id) {
 | 
|  
 | 
|  const Extension* ExtensionService::GetTerminatedExtension(
 | 
|      const std::string& id) const {
 | 
| -  return GetExtensionByIdInternal(id, INCLUDE_TERMINATED);
 | 
| +  return GetExtensionById(id, INCLUDE_TERMINATED);
 | 
|  }
 | 
|  
 | 
|  const Extension* ExtensionService::GetInstalledExtension(
 | 
|      const std::string& id) const {
 | 
| -  int include_mask = INCLUDE_ENABLED | INCLUDE_DISABLED | INCLUDE_TERMINATED;
 | 
| -  return GetExtensionByIdInternal(id, include_mask);
 | 
| +  int include_mask = INCLUDE_ENABLED |
 | 
| +                     INCLUDE_DISABLED |
 | 
| +                     INCLUDE_TERMINATED |
 | 
| +                     INCLUDE_BLACKLISTED;
 | 
| +  return GetExtensionById(id, include_mask);
 | 
|  }
 | 
|  
 | 
|  bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) {
 | 
| @@ -3017,9 +3070,7 @@ bool ExtensionService::ShouldDelayExtensionUpdate(
 | 
|    if (!install_updates_when_idle_ || !wait_for_idle)
 | 
|      return false;
 | 
|  
 | 
| -  int include_mask = INCLUDE_ENABLED | INCLUDE_DISABLED;
 | 
| -  const Extension* old =
 | 
| -      GetExtensionByIdInternal(extension_id, include_mask);
 | 
| +  const Extension* old = GetInstalledExtension(extension_id);
 | 
|    // If there is no old extension, this is not an update, so don't delay.
 | 
|    if (!old)
 | 
|      return false;
 | 
| @@ -3036,5 +3087,49 @@ bool ExtensionService::ShouldDelayExtensionUpdate(
 | 
|  }
 | 
|  
 | 
|  void ExtensionService::OnBlacklistUpdated() {
 | 
| -  CheckManagementPolicy();
 | 
| +  blacklist_->GetBlacklistedIDs(
 | 
| +      GenerateInstalledExtensionsSet()->GetIDs(),
 | 
| +      base::Bind(&ExtensionService::ManageBlacklist,
 | 
| +                 AsWeakPtr(),
 | 
| +                 blacklisted_extensions_.GetIDs()));
 | 
| +}
 | 
| +
 | 
| +void ExtensionService::ManageBlacklist(
 | 
| +    const std::set<std::string>& old_blacklisted_ids,
 | 
| +    const std::set<std::string>& new_blacklisted_ids) {
 | 
| +  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 | 
| +
 | 
| +  std::set<std::string> no_longer_blacklisted;
 | 
| +  std::set_difference(old_blacklisted_ids.begin(), old_blacklisted_ids.end(),
 | 
| +                      new_blacklisted_ids.begin(), new_blacklisted_ids.end(),
 | 
| +                      std::inserter(no_longer_blacklisted,
 | 
| +                                    no_longer_blacklisted.begin()));
 | 
| +  std::set<std::string> not_yet_blacklisted;
 | 
| +  std::set_difference(new_blacklisted_ids.begin(), new_blacklisted_ids.end(),
 | 
| +                      old_blacklisted_ids.begin(), old_blacklisted_ids.end(),
 | 
| +                      std::inserter(not_yet_blacklisted,
 | 
| +                                    not_yet_blacklisted.begin()));
 | 
| +
 | 
| +  for (std::set<std::string>::iterator it = no_longer_blacklisted.begin();
 | 
| +       it != no_longer_blacklisted.end(); ++it) {
 | 
| +    scoped_refptr<const Extension> extension =
 | 
| +        blacklisted_extensions_.GetByID(*it);
 | 
| +    DCHECK(extension);
 | 
| +    if (!extension)
 | 
| +      continue;
 | 
| +    blacklisted_extensions_.Remove(*it);
 | 
| +    AddExtension(extension);
 | 
| +  }
 | 
| +
 | 
| +  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);
 | 
| +    if (!extension)
 | 
| +      continue;
 | 
| +    blacklisted_extensions_.Insert(extension);
 | 
| +    UnloadExtension(*it, extension_misc::UNLOAD_REASON_BLACKLIST);
 | 
| +  }
 | 
| +
 | 
| +  IdentifyAlertableExtensions();
 | 
|  }
 | 
| 
 |