This source file includes following definitions.
- IsManifestCorrupt
 
- ShouldReloadExtensionManifest
 
- GetBackgroundPageType
 
- extension_prefs_
 
- LoadAllExtensions
 
- GetCreationFlags
 
#include "chrome/browser/extensions/installed_loader.h"
#include "base/files/file_path.h"
#include "base/metrics/histogram.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/runtime/runtime_api.h"
#include "chrome/browser/extensions/extension_action_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/api/managed_mode_private/managed_mode_handler.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_l10n_util.h"
#include "chrome/common/extensions/manifest_url_handler.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/user_metrics.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/management_policy.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/background_info.h"
using base::UserMetricsAction;
using content::BrowserThread;
namespace extensions {
namespace errors = manifest_errors;
namespace {
enum ManifestReloadReason {
  NOT_NEEDED = 0,  
  UNPACKED_DIR,  
  NEEDS_RELOCALIZATION,  
  CORRUPT_PREFERENCES,  
  NUM_MANIFEST_RELOAD_REASONS
};
enum BackgroundPageType {
  NO_BACKGROUND_PAGE = 0,
  BACKGROUND_PAGE_PERSISTENT = 1,
  EVENT_PAGE = 2,
};
enum ExternalItemState {
  DEPRECATED_EXTERNAL_ITEM_DISABLED = 0,
  DEPRECATED_EXTERNAL_ITEM_ENABLED = 1,
  EXTERNAL_ITEM_WEBSTORE_DISABLED = 2,
  EXTERNAL_ITEM_WEBSTORE_ENABLED = 3,
  EXTERNAL_ITEM_NONWEBSTORE_DISABLED = 4,
  EXTERNAL_ITEM_NONWEBSTORE_ENABLED = 5,
  EXTERNAL_ITEM_WEBSTORE_UNINSTALLED = 6,
  EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED = 7,
  EXTERNAL_ITEM_MAX_ITEMS = 8
};
bool IsManifestCorrupt(const base::DictionaryValue* manifest) {
  if (!manifest)
    return false;
  
  
  
  
  const base::Value* background_page;
  const base::Value* background_scripts;
  return manifest->Get(manifest_keys::kBackgroundPage, &background_page) &&
      manifest->Get(manifest_keys::kBackgroundScripts, &background_scripts);
}
ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
  
  
  if (Manifest::IsUnpackedLocation(info.extension_location))
    return UNPACKED_DIR;
  
  if (extension_l10n_util::ShouldRelocalizeManifest(
          info.extension_manifest.get()))
    return NEEDS_RELOCALIZATION;
  
  if (IsManifestCorrupt(info.extension_manifest.get()))
    return CORRUPT_PREFERENCES;
  return NOT_NEEDED;
}
BackgroundPageType GetBackgroundPageType(const Extension* extension) {
  if (!BackgroundInfo::HasBackgroundPage(extension))
    return NO_BACKGROUND_PAGE;
  if (BackgroundInfo::HasPersistentBackgroundPage(extension))
    return BACKGROUND_PAGE_PERSISTENT;
  return EVENT_PAGE;
}
}  
InstalledLoader::InstalledLoader(ExtensionService* extension_service)
    : extension_service_(extension_service),
      extension_registry_(ExtensionRegistry::Get(extension_service->profile())),
      extension_prefs_(ExtensionPrefs::Get(extension_service->profile())) {}
InstalledLoader::~InstalledLoader() {
}
void InstalledLoader::Load(const ExtensionInfo& info, bool write_to_prefs) {
  std::string error;
  scoped_refptr<const Extension> extension(NULL);
  if (info.extension_manifest) {
    extension = Extension::Create(
        info.extension_path,
        info.extension_location,
        *info.extension_manifest,
        GetCreationFlags(&info),
        &error);
  } else {
    error = errors::kManifestUnreadable;
  }
  
  
  
  if (extension.get() && !Manifest::IsUnpackedLocation(extension->location()) &&
      info.extension_id != extension->id()) {
    error = errors::kCannotChangeExtensionID;
    extension = NULL;
    content::RecordAction(UserMetricsAction("Extensions.IDChangedError"));
  }
  
  
  const ManagementPolicy* policy = extensions::ExtensionSystem::Get(
      extension_service_->profile())->management_policy();
  if (extension.get()) {
    Extension::DisableReason disable_reason = Extension::DISABLE_NONE;
    bool force_disabled = false;
    if (!policy->UserMayLoad(extension.get(), NULL)) {
      
      
      error = errors::kDisabledByPolicy;
      extension = NULL;
    } else if (!extension_prefs_->IsExtensionDisabled(extension->id()) &&
               policy->MustRemainDisabled(extension, &disable_reason, NULL)) {
      extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED);
      extension_prefs_->AddDisableReason(extension->id(), disable_reason);
      force_disabled = true;
    }
    UMA_HISTOGRAM_BOOLEAN("ExtensionInstalledLoader.ForceDisabled",
                          force_disabled);
  }
  if (!extension.get()) {
    extension_service_->ReportExtensionLoadError(
        info.extension_path, error, false);
    return;
  }
  if (write_to_prefs)
    extension_prefs_->UpdateManifest(extension.get());
  extension_service_->AddExtension(extension.get());
}
void InstalledLoader::LoadAllExtensions() {
  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  base::TimeTicks start_time = base::TimeTicks::Now();
  scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
      extension_prefs_->GetInstalledExtensionsInfo());
  std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
  bool should_write_prefs = false;
  for (size_t i = 0; i < extensions_info->size(); ++i) {
    ExtensionInfo* info = extensions_info->at(i).get();
    
    
    if (info->extension_location == Manifest::COMMAND_LINE)
      continue;
    ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
    ++reload_reason_counts[reload_reason];
    UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
                              reload_reason, 100);
    if (reload_reason != NOT_NEEDED) {
      
      
      
      
      
      
      base::ThreadRestrictions::ScopedAllowIO allow_io;
      std::string error;
      scoped_refptr<const Extension> extension(
          extension_file_util::LoadExtension(
              info->extension_path,
              info->extension_location,
              GetCreationFlags(info),
              &error));
      if (!extension.get()) {
        extension_service_->ReportExtensionLoadError(
            info->extension_path, error, false);
        continue;
      }
      extensions_info->at(i)->extension_manifest.reset(
          static_cast<base::DictionaryValue*>(
              extension->manifest()->value()->DeepCopy()));
      should_write_prefs = true;
    }
  }
  for (size_t i = 0; i < extensions_info->size(); ++i) {
    if (extensions_info->at(i)->extension_location == Manifest::COMMAND_LINE)
      continue;
    Load(*extensions_info->at(i), should_write_prefs);
  }
  extension_service_->OnLoadedInstalledExtensions();
  
  
  UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
                           reload_reason_counts[NOT_NEEDED]);
  UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
                           reload_reason_counts[UNPACKED_DIR]);
  UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
                           reload_reason_counts[NEEDS_RELOCALIZATION]);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll",
                           extension_registry_->enabled_extensions().size());
  UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled",
                           extension_registry_->disabled_extensions().size());
  UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
                      base::TimeTicks::Now() - start_time);
  int app_user_count = 0;
  int app_external_count = 0;
  int hosted_app_count = 0;
  int legacy_packaged_app_count = 0;
  int platform_app_count = 0;
  int user_script_count = 0;
  int content_pack_count = 0;
  int extension_user_count = 0;
  int extension_external_count = 0;
  int theme_count = 0;
  int page_action_count = 0;
  int browser_action_count = 0;
  int disabled_for_permissions_count = 0;
  int item_user_count = 0;
  int non_webstore_ntp_override_count = 0;
  const ExtensionSet& extensions = extension_registry_->enabled_extensions();
  ExtensionSet::const_iterator ex;
  for (ex = extensions.begin(); ex != extensions.end(); ++ex) {
    Manifest::Location location = (*ex)->location();
    Manifest::Type type = (*ex)->GetType();
    if ((*ex)->is_app()) {
      UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
                                location, 100);
    } else if (type == Manifest::TYPE_EXTENSION) {
      UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
                                location, 100);
    }
    if (!ManifestURL::UpdatesFromGallery(*ex)) {
      UMA_HISTOGRAM_ENUMERATION("Extensions.NonWebstoreLocation",
                                location, 100);
    }
    if (Manifest::IsExternalLocation(location)) {
      
      if (ManifestURL::UpdatesFromGallery(*ex)) {
        UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
                                  EXTERNAL_ITEM_WEBSTORE_ENABLED,
                                  EXTERNAL_ITEM_MAX_ITEMS);
      } else {
        UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
                                  EXTERNAL_ITEM_NONWEBSTORE_ENABLED,
                                  EXTERNAL_ITEM_MAX_ITEMS);
      }
    }
    if ((*ex)->from_webstore()) {
      
      
      enum {
        BAD_UPDATE_URL = 0,
        
        
        DEPRECATED_IS_EXTERNAL = 1,
      };
      if (!ManifestURL::UpdatesFromGallery(*ex)) {
        UMA_HISTOGRAM_ENUMERATION("Extensions.FromWebstoreInconsistency",
                                  BAD_UPDATE_URL, 2);
      }
    }
    
    
    if (location == Manifest::COMPONENT)
      continue;
    
    
    if (!(*ex)->from_webstore()) {
      const extensions::URLOverrides::URLOverrideMap& override_map =
          extensions::URLOverrides::GetChromeURLOverrides(ex->get());
      if (override_map.find("newtab") != override_map.end()) {
        ++non_webstore_ntp_override_count;
      }
    }
    
    
    if (Manifest::IsUnpackedLocation(location))
      continue;
    UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestVersion",
                              (*ex)->manifest_version(), 10);
    if (type == Manifest::TYPE_EXTENSION) {
      BackgroundPageType background_page_type =
          GetBackgroundPageType(ex->get());
      UMA_HISTOGRAM_ENUMERATION(
          "Extensions.BackgroundPageType", background_page_type, 10);
    }
    
    
    
    UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
    switch (type) {
      case Manifest::TYPE_THEME:
        ++theme_count;
        break;
      case Manifest::TYPE_USER_SCRIPT:
        ++user_script_count;
        break;
      case Manifest::TYPE_HOSTED_APP:
        ++hosted_app_count;
        if (Manifest::IsExternalLocation(location)) {
          ++app_external_count;
        } else {
          ++app_user_count;
        }
        break;
      case Manifest::TYPE_LEGACY_PACKAGED_APP:
        ++legacy_packaged_app_count;
        if (Manifest::IsExternalLocation(location)) {
          ++app_external_count;
        } else {
          ++app_user_count;
        }
        break;
      case Manifest::TYPE_PLATFORM_APP:
        ++platform_app_count;
        if (Manifest::IsExternalLocation(location)) {
          ++app_external_count;
        } else {
          ++app_user_count;
        }
        break;
      case Manifest::TYPE_EXTENSION:
      default:
        if (Manifest::IsExternalLocation(location)) {
          ++extension_external_count;
        } else {
          ++extension_user_count;
        }
        break;
    }
    if (!Manifest::IsExternalLocation((*ex)->location()))
      ++item_user_count;
    ExtensionActionManager* extension_action_manager =
        ExtensionActionManager::Get(extension_service_->profile());
    if (extension_action_manager->GetPageAction(*ex->get()))
      ++page_action_count;
    if (extension_action_manager->GetBrowserAction(*ex->get()))
      ++browser_action_count;
    if (extensions::ManagedModeInfo::IsContentPack(ex->get()))
      ++content_pack_count;
    extension_service_->RecordPermissionMessagesHistogram(
        ex->get(), "Extensions.Permissions_Load");
  }
  const ExtensionSet& disabled_extensions =
      extension_registry_->disabled_extensions();
  for (ex = disabled_extensions.begin(); ex != disabled_extensions.end();
       ++ex) {
    if (extension_prefs_->DidExtensionEscalatePermissions((*ex)->id())) {
      ++disabled_for_permissions_count;
    }
    if (Manifest::IsExternalLocation((*ex)->location())) {
      
      if (ManifestURL::UpdatesFromGallery(*ex)) {
        UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
                                  EXTERNAL_ITEM_WEBSTORE_DISABLED,
                                  EXTERNAL_ITEM_MAX_ITEMS);
      } else {
        UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
                                  EXTERNAL_ITEM_NONWEBSTORE_DISABLED,
                                  EXTERNAL_ITEM_MAX_ITEMS);
      }
    }
  }
  scoped_ptr<ExtensionPrefs::ExtensionsInfo> uninstalled_extensions_info(
      extension_prefs_->GetUninstalledExtensionsInfo());
  for (size_t i = 0; i < uninstalled_extensions_info->size(); ++i) {
    ExtensionInfo* info = uninstalled_extensions_info->at(i).get();
    if (Manifest::IsExternalLocation(info->extension_location)) {
      std::string update_url;
      if (info->extension_manifest->GetString("update_url", &update_url) &&
          extension_urls::IsWebstoreUpdateUrl(GURL(update_url))) {
        UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
                                  EXTERNAL_ITEM_WEBSTORE_UNINSTALLED,
                                  EXTERNAL_ITEM_MAX_ITEMS);
      } else {
        UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
                                  EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED,
                                  EXTERNAL_ITEM_MAX_ITEMS);
      }
    }
  }
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAllUser", item_user_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp",
                           app_user_count + app_external_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppUser", app_user_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppExternal", app_external_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp",
                           legacy_packaged_app_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPlatformApp", platform_app_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension",
                           extension_user_count + extension_external_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionUser",
                           extension_user_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionExternal",
                           extension_external_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
                           browser_action_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadContentPack", content_pack_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.DisabledForPermissions",
                           disabled_for_permissions_count);
  UMA_HISTOGRAM_COUNTS_100("Extensions.NonWebStoreNewTabPageOverrides",
                           non_webstore_ntp_override_count);
}
int InstalledLoader::GetCreationFlags(const ExtensionInfo* info) {
  int flags = extension_prefs_->GetCreationFlags(info->extension_id);
  if (!Manifest::IsUnpackedLocation(info->extension_location))
    flags |= Extension::REQUIRE_KEY;
  if (extension_prefs_->AllowFileAccess(info->extension_id))
    flags |= Extension::ALLOW_FILE_ACCESS;
  return flags;
}
}