Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/installed_loader.h"
      6 
      7 #include "base/files/file_path.h"
      8 #include "base/metrics/histogram.h"
      9 #include "base/metrics/sparse_histogram.h"
     10 #include "base/strings/stringprintf.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "base/threading/thread_restrictions.h"
     13 #include "base/values.h"
     14 #include "chrome/browser/browser_process.h"
     15 #include "chrome/browser/extensions/extension_action_manager.h"
     16 #include "chrome/browser/extensions/extension_error_reporter.h"
     17 #include "chrome/browser/extensions/extension_service.h"
     18 #include "chrome/browser/extensions/extension_util.h"
     19 #include "chrome/browser/profiles/profile_manager.h"
     20 #include "chrome/common/chrome_switches.h"
     21 #include "chrome/common/extensions/api/supervised_user_private/supervised_user_handler.h"
     22 #include "chrome/common/extensions/manifest_url_handler.h"
     23 #include "chrome/common/pref_names.h"
     24 #include "content/public/browser/browser_thread.h"
     25 #include "content/public/browser/notification_service.h"
     26 #include "content/public/browser/user_metrics.h"
     27 #include "extensions/browser/extension_prefs.h"
     28 #include "extensions/browser/extension_registry.h"
     29 #include "extensions/browser/extension_system.h"
     30 #include "extensions/browser/management_policy.h"
     31 #include "extensions/common/extension.h"
     32 #include "extensions/common/extension_l10n_util.h"
     33 #include "extensions/common/extension_set.h"
     34 #include "extensions/common/extension_urls.h"
     35 #include "extensions/common/file_util.h"
     36 #include "extensions/common/manifest.h"
     37 #include "extensions/common/manifest_constants.h"
     38 #include "extensions/common/manifest_handlers/background_info.h"
     39 
     40 using base::UserMetricsAction;
     41 using content::BrowserThread;
     42 
     43 namespace extensions {
     44 
     45 namespace errors = manifest_errors;
     46 
     47 namespace {
     48 
     49 // The following enumeration is used in histograms matching
     50 // Extensions.ManifestReload*.
     51 enum ManifestReloadReason {
     52   NOT_NEEDED = 0,        // Reload not needed.
     53   UNPACKED_DIR,          // Unpacked directory.
     54   NEEDS_RELOCALIZATION,  // The locale has changed since we read this extension.
     55   CORRUPT_PREFERENCES,   // The manifest in the preferences is corrupt.
     56 
     57   // New enum values must go above here.
     58   NUM_MANIFEST_RELOAD_REASONS
     59 };
     60 
     61 // Used in histogram Extension.BackgroundPageType.
     62 enum BackgroundPageType {
     63   NO_BACKGROUND_PAGE = 0,
     64   BACKGROUND_PAGE_PERSISTENT,
     65   EVENT_PAGE,
     66 
     67   // New enum values must go above here.
     68   NUM_BACKGROUND_PAGE_TYPES
     69 };
     70 
     71 // Used in histogram Extensions.ExternalItemState.
     72 enum ExternalItemState {
     73   DEPRECATED_EXTERNAL_ITEM_DISABLED = 0,
     74   DEPRECATED_EXTERNAL_ITEM_ENABLED,
     75   EXTERNAL_ITEM_WEBSTORE_DISABLED,
     76   EXTERNAL_ITEM_WEBSTORE_ENABLED,
     77   EXTERNAL_ITEM_NONWEBSTORE_DISABLED,
     78   EXTERNAL_ITEM_NONWEBSTORE_ENABLED,
     79   EXTERNAL_ITEM_WEBSTORE_UNINSTALLED,
     80   EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED,
     81 
     82   // New enum values must go above here.
     83   EXTERNAL_ITEM_MAX_ITEMS
     84 };
     85 
     86 bool IsManifestCorrupt(const base::DictionaryValue* manifest) {
     87   if (!manifest)
     88     return false;
     89 
     90   // Because of bug #272524 sometimes manifests got mangled in the preferences
     91   // file, one particularly bad case resulting in having both a background page
     92   // and background scripts values. In those situations we want to reload the
     93   // manifest from the extension to fix this.
     94   const base::Value* background_page;
     95   const base::Value* background_scripts;
     96   return manifest->Get(manifest_keys::kBackgroundPage, &background_page) &&
     97       manifest->Get(manifest_keys::kBackgroundScripts, &background_scripts);
     98 }
     99 
    100 ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
    101   // Always reload manifests of unpacked extensions, because they can change
    102   // on disk independent of the manifest in our prefs.
    103   if (Manifest::IsUnpackedLocation(info.extension_location))
    104     return UNPACKED_DIR;
    105 
    106   // Reload the manifest if it needs to be relocalized.
    107   if (extension_l10n_util::ShouldRelocalizeManifest(
    108           info.extension_manifest.get()))
    109     return NEEDS_RELOCALIZATION;
    110 
    111   // Reload if the copy of the manifest in the preferences is corrupt.
    112   if (IsManifestCorrupt(info.extension_manifest.get()))
    113     return CORRUPT_PREFERENCES;
    114 
    115   return NOT_NEEDED;
    116 }
    117 
    118 BackgroundPageType GetBackgroundPageType(const Extension* extension) {
    119   if (!BackgroundInfo::HasBackgroundPage(extension))
    120     return NO_BACKGROUND_PAGE;
    121   if (BackgroundInfo::HasPersistentBackgroundPage(extension))
    122     return BACKGROUND_PAGE_PERSISTENT;
    123   return EVENT_PAGE;
    124 }
    125 
    126 // Records the creation flags of an extension grouped by
    127 // Extension::InitFromValueFlags.
    128 void RecordCreationFlags(const Extension* extension) {
    129   for (int i = 0; i < Extension::kInitFromValueFlagBits; ++i) {
    130     int flag = 1 << i;
    131     if (extension->creation_flags() & flag) {
    132       UMA_HISTOGRAM_ENUMERATION(
    133           "Extensions.LoadCreationFlags", i, Extension::kInitFromValueFlagBits);
    134     }
    135   }
    136 }
    137 
    138 // Helper to record a single disable reason histogram value (see
    139 // RecordDisableReasons below).
    140 void RecordDisbleReasonHistogram(int reason) {
    141   UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.DisableReason", reason);
    142 }
    143 
    144 // Records the disable reasons for a single extension grouped by
    145 // Extension::DisableReason.
    146 void RecordDisableReasons(int reasons) {
    147   // |reasons| is a bitmask with values from Extension::DisabledReason
    148   // which are increasing powers of 2.
    149   if (reasons == Extension::DISABLE_NONE) {
    150     RecordDisbleReasonHistogram(Extension::DISABLE_NONE);
    151     return;
    152   }
    153   for (int reason = 1; reason < Extension::DISABLE_REASON_LAST; reason <<= 1) {
    154     if (reasons & reason)
    155       RecordDisbleReasonHistogram(reason);
    156   }
    157 }
    158 
    159 }  // namespace
    160 
    161 InstalledLoader::InstalledLoader(ExtensionService* extension_service)
    162     : extension_service_(extension_service),
    163       extension_registry_(ExtensionRegistry::Get(extension_service->profile())),
    164       extension_prefs_(ExtensionPrefs::Get(extension_service->profile())) {}
    165 
    166 InstalledLoader::~InstalledLoader() {
    167 }
    168 
    169 void InstalledLoader::Load(const ExtensionInfo& info, bool write_to_prefs) {
    170   std::string error;
    171   scoped_refptr<const Extension> extension(NULL);
    172   if (info.extension_manifest) {
    173     extension = Extension::Create(
    174         info.extension_path,
    175         info.extension_location,
    176         *info.extension_manifest,
    177         GetCreationFlags(&info),
    178         &error);
    179   } else {
    180     error = errors::kManifestUnreadable;
    181   }
    182 
    183   // Once installed, non-unpacked extensions cannot change their IDs (e.g., by
    184   // updating the 'key' field in their manifest).
    185   // TODO(jstritar): migrate preferences when unpacked extensions change IDs.
    186   if (extension.get() && !Manifest::IsUnpackedLocation(extension->location()) &&
    187       info.extension_id != extension->id()) {
    188     error = errors::kCannotChangeExtensionID;
    189     extension = NULL;
    190   }
    191 
    192   // Check policy on every load in case an extension was blacklisted while
    193   // Chrome was not running.
    194   const ManagementPolicy* policy = extensions::ExtensionSystem::Get(
    195       extension_service_->profile())->management_policy();
    196   if (extension.get()) {
    197     Extension::DisableReason disable_reason = Extension::DISABLE_NONE;
    198     bool force_disabled = false;
    199     if (!policy->UserMayLoad(extension.get(), NULL)) {
    200       // The error message from UserMayInstall() often contains the extension ID
    201       // and is therefore not well suited to this UI.
    202       error = errors::kDisabledByPolicy;
    203       extension = NULL;
    204     } else if (!extension_prefs_->IsExtensionDisabled(extension->id()) &&
    205                policy->MustRemainDisabled(
    206                    extension.get(), &disable_reason, NULL)) {
    207       extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED);
    208       extension_prefs_->AddDisableReason(extension->id(), disable_reason);
    209       force_disabled = true;
    210     }
    211     UMA_HISTOGRAM_BOOLEAN("ExtensionInstalledLoader.ForceDisabled",
    212                           force_disabled);
    213   }
    214 
    215   if (!extension.get()) {
    216     ExtensionErrorReporter::GetInstance()->ReportLoadError(
    217         info.extension_path,
    218         error,
    219         extension_service_->profile(),
    220         false);  // Be quiet.
    221     return;
    222   }
    223 
    224   if (write_to_prefs)
    225     extension_prefs_->UpdateManifest(extension.get());
    226 
    227   extension_service_->AddExtension(extension.get());
    228 }
    229 
    230 void InstalledLoader::LoadAllExtensions() {
    231   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    232 
    233   base::TimeTicks start_time = base::TimeTicks::Now();
    234 
    235   Profile* profile = extension_service_->profile();
    236   scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
    237       extension_prefs_->GetInstalledExtensionsInfo());
    238 
    239   std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
    240   bool should_write_prefs = false;
    241 
    242   for (size_t i = 0; i < extensions_info->size(); ++i) {
    243     ExtensionInfo* info = extensions_info->at(i).get();
    244 
    245     // Skip extensions that were loaded from the command-line because we don't
    246     // want those to persist across browser restart.
    247     if (info->extension_location == Manifest::COMMAND_LINE)
    248       continue;
    249 
    250     ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
    251     ++reload_reason_counts[reload_reason];
    252 
    253     if (reload_reason != NOT_NEEDED) {
    254       // Reloading an extension reads files from disk.  We do this on the
    255       // UI thread because reloads should be very rare, and the complexity
    256       // added by delaying the time when the extensions service knows about
    257       // all extensions is significant.  See crbug.com/37548 for details.
    258       // |allow_io| disables tests that file operations run on the file
    259       // thread.
    260       base::ThreadRestrictions::ScopedAllowIO allow_io;
    261 
    262       std::string error;
    263       scoped_refptr<const Extension> extension(
    264           file_util::LoadExtension(info->extension_path,
    265                                    info->extension_location,
    266                                    GetCreationFlags(info),
    267                                    &error));
    268 
    269       if (!extension.get()) {
    270         ExtensionErrorReporter::GetInstance()->ReportLoadError(
    271             info->extension_path,
    272             error,
    273             profile,
    274             false);  // Be quiet.
    275         continue;
    276       }
    277 
    278       extensions_info->at(i)->extension_manifest.reset(
    279           static_cast<base::DictionaryValue*>(
    280               extension->manifest()->value()->DeepCopy()));
    281       should_write_prefs = true;
    282     }
    283   }
    284 
    285   for (size_t i = 0; i < extensions_info->size(); ++i) {
    286     if (extensions_info->at(i)->extension_location != Manifest::COMMAND_LINE)
    287       Load(*extensions_info->at(i), should_write_prefs);
    288   }
    289 
    290   extension_service_->OnLoadedInstalledExtensions();
    291 
    292   // The histograms Extensions.ManifestReload* allow us to validate
    293   // the assumption that reloading manifest is a rare event.
    294   UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
    295                            reload_reason_counts[NOT_NEEDED]);
    296   UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
    297                            reload_reason_counts[UNPACKED_DIR]);
    298   UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
    299                            reload_reason_counts[NEEDS_RELOCALIZATION]);
    300 
    301   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll",
    302                            extension_registry_->enabled_extensions().size());
    303   UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled",
    304                            extension_registry_->disabled_extensions().size());
    305 
    306   UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
    307                       base::TimeTicks::Now() - start_time);
    308 
    309   int app_user_count = 0;
    310   int app_external_count = 0;
    311   int hosted_app_count = 0;
    312   int legacy_packaged_app_count = 0;
    313   int platform_app_count = 0;
    314   int user_script_count = 0;
    315   int content_pack_count = 0;
    316   int extension_user_count = 0;
    317   int extension_external_count = 0;
    318   int theme_count = 0;
    319   int page_action_count = 0;
    320   int browser_action_count = 0;
    321   int disabled_for_permissions_count = 0;
    322   int non_webstore_ntp_override_count = 0;
    323   int incognito_allowed_count = 0;
    324   int incognito_not_allowed_count = 0;
    325   int file_access_allowed_count = 0;
    326   int file_access_not_allowed_count = 0;
    327 
    328   const ExtensionSet& extensions = extension_registry_->enabled_extensions();
    329   ExtensionActionManager* extension_action_manager =
    330       ExtensionActionManager::Get(profile);
    331   for (ExtensionSet::const_iterator iter = extensions.begin();
    332        iter != extensions.end();
    333        ++iter) {
    334     const Extension* extension = iter->get();
    335     Manifest::Location location = extension->location();
    336     Manifest::Type type = extension->GetType();
    337 
    338     // For the first few metrics, include all extensions and apps (component,
    339     // unpacked, etc). It's good to know these locations, and it doesn't
    340     // muck up any of the stats. Later, though, we want to omit component and
    341     // unpacked, as they are less interesting.
    342     if (extension->is_app())
    343       UMA_HISTOGRAM_ENUMERATION(
    344           "Extensions.AppLocation", location, Manifest::NUM_LOCATIONS);
    345     else if (extension->is_extension())
    346       UMA_HISTOGRAM_ENUMERATION(
    347           "Extensions.ExtensionLocation", location, Manifest::NUM_LOCATIONS);
    348 
    349     if (!ManifestURL::UpdatesFromGallery(extension)) {
    350       UMA_HISTOGRAM_ENUMERATION(
    351           "Extensions.NonWebstoreLocation", location, Manifest::NUM_LOCATIONS);
    352 
    353       // Check for inconsistencies if the extension was supposedly installed
    354       // from the webstore.
    355       enum {
    356         BAD_UPDATE_URL = 0,
    357         // This value was a mistake. Turns out sideloaded extensions can
    358         // have the from_webstore bit if they update from the webstore.
    359         DEPRECATED_IS_EXTERNAL = 1,
    360       };
    361       if (extension->from_webstore()) {
    362         UMA_HISTOGRAM_ENUMERATION(
    363             "Extensions.FromWebstoreInconsistency", BAD_UPDATE_URL, 2);
    364       }
    365     }
    366 
    367     if (Manifest::IsExternalLocation(location)) {
    368       // See loop below for DISABLED.
    369       if (ManifestURL::UpdatesFromGallery(extension)) {
    370         UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
    371                                   EXTERNAL_ITEM_WEBSTORE_ENABLED,
    372                                   EXTERNAL_ITEM_MAX_ITEMS);
    373       } else {
    374         UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
    375                                   EXTERNAL_ITEM_NONWEBSTORE_ENABLED,
    376                                   EXTERNAL_ITEM_MAX_ITEMS);
    377       }
    378     }
    379 
    380     // From now on, don't count component extensions, since they are only
    381     // extensions as an implementation detail. Continue to count unpacked
    382     // extensions for a few metrics.
    383     if (location == Manifest::COMPONENT)
    384       continue;
    385 
    386     // Histogram for non-webstore extensions overriding new tab page should
    387     // include unpacked extensions.
    388     if (!extension->from_webstore() &&
    389         URLOverrides::GetChromeURLOverrides(extension).count("newtab")) {
    390       ++non_webstore_ntp_override_count;
    391     }
    392 
    393     // Don't count unpacked extensions anymore, either.
    394     if (Manifest::IsUnpackedLocation(location))
    395       continue;
    396 
    397     UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestVersion",
    398                               extension->manifest_version(),
    399                               10);  // TODO(kalman): Why 10 manifest versions?
    400 
    401     // We might have wanted to count legacy packaged apps here, too, since they
    402     // are effectively extensions. Unfortunately, it's too late, as we don't
    403     // want to mess up the existing stats.
    404     if (type == Manifest::TYPE_EXTENSION) {
    405       UMA_HISTOGRAM_ENUMERATION("Extensions.BackgroundPageType",
    406                                 GetBackgroundPageType(extension),
    407                                 NUM_BACKGROUND_PAGE_TYPES);
    408     }
    409 
    410     // Using an enumeration shows us the total installed ratio across all users.
    411     // Using the totals per user at each startup tells us the distribution of
    412     // usage for each user (e.g. 40% of users have at least one app installed).
    413     UMA_HISTOGRAM_ENUMERATION(
    414         "Extensions.LoadType", type, Manifest::NUM_LOAD_TYPES);
    415     switch (type) {
    416       case Manifest::TYPE_THEME:
    417         ++theme_count;
    418         break;
    419       case Manifest::TYPE_USER_SCRIPT:
    420         ++user_script_count;
    421         break;
    422       case Manifest::TYPE_HOSTED_APP:
    423         ++hosted_app_count;
    424         if (Manifest::IsExternalLocation(location)) {
    425           ++app_external_count;
    426         } else {
    427           ++app_user_count;
    428         }
    429         break;
    430       case Manifest::TYPE_LEGACY_PACKAGED_APP:
    431         ++legacy_packaged_app_count;
    432         if (Manifest::IsExternalLocation(location)) {
    433           ++app_external_count;
    434         } else {
    435           ++app_user_count;
    436         }
    437         break;
    438       case Manifest::TYPE_PLATFORM_APP:
    439         ++platform_app_count;
    440         if (Manifest::IsExternalLocation(location)) {
    441           ++app_external_count;
    442         } else {
    443           ++app_user_count;
    444         }
    445         break;
    446       case Manifest::TYPE_EXTENSION:
    447       default:
    448         if (Manifest::IsExternalLocation(location)) {
    449           ++extension_external_count;
    450         } else {
    451           ++extension_user_count;
    452         }
    453         break;
    454     }
    455 
    456     if (extension_action_manager->GetPageAction(*extension))
    457       ++page_action_count;
    458 
    459     if (extension_action_manager->GetBrowserAction(*extension))
    460       ++browser_action_count;
    461 
    462     if (SupervisedUserInfo::IsContentPack(extension))
    463       ++content_pack_count;
    464 
    465     RecordCreationFlags(extension);
    466 
    467     ExtensionService::RecordPermissionMessagesHistogram(
    468         extension, "Extensions.Permissions_Load2");
    469 
    470     // For incognito and file access, skip anything that doesn't appear in
    471     // settings. Also, policy-installed (and unpacked of course, checked above)
    472     // extensions are boring.
    473     if (extension->ShouldDisplayInExtensionSettings() &&
    474         !Manifest::IsPolicyLocation(extension->location())) {
    475       if (extension->can_be_incognito_enabled()) {
    476         if (util::IsIncognitoEnabled(extension->id(), profile))
    477           ++incognito_allowed_count;
    478         else
    479           ++incognito_not_allowed_count;
    480       }
    481       if (extension->wants_file_access()) {
    482         if (util::AllowFileAccess(extension->id(), profile))
    483           ++file_access_allowed_count;
    484         else
    485           ++file_access_not_allowed_count;
    486       }
    487     }
    488   }
    489 
    490   const ExtensionSet& disabled_extensions =
    491       extension_registry_->disabled_extensions();
    492 
    493   for (ExtensionSet::const_iterator ex = disabled_extensions.begin();
    494        ex != disabled_extensions.end();
    495        ++ex) {
    496     if (extension_prefs_->DidExtensionEscalatePermissions((*ex)->id())) {
    497       ++disabled_for_permissions_count;
    498     }
    499     RecordDisableReasons(extension_prefs_->GetDisableReasons((*ex)->id()));
    500     if (Manifest::IsExternalLocation((*ex)->location())) {
    501       // See loop above for ENABLED.
    502       if (ManifestURL::UpdatesFromGallery(ex->get())) {
    503         UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
    504                                   EXTERNAL_ITEM_WEBSTORE_DISABLED,
    505                                   EXTERNAL_ITEM_MAX_ITEMS);
    506       } else {
    507         UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
    508                                   EXTERNAL_ITEM_NONWEBSTORE_DISABLED,
    509                                   EXTERNAL_ITEM_MAX_ITEMS);
    510       }
    511     }
    512   }
    513 
    514   scoped_ptr<ExtensionPrefs::ExtensionsInfo> uninstalled_extensions_info(
    515       extension_prefs_->GetUninstalledExtensionsInfo());
    516   for (size_t i = 0; i < uninstalled_extensions_info->size(); ++i) {
    517     ExtensionInfo* info = uninstalled_extensions_info->at(i).get();
    518     if (Manifest::IsExternalLocation(info->extension_location)) {
    519       std::string update_url;
    520       if (info->extension_manifest->GetString("update_url", &update_url) &&
    521           extension_urls::IsWebstoreUpdateUrl(GURL(update_url))) {
    522         UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
    523                                   EXTERNAL_ITEM_WEBSTORE_UNINSTALLED,
    524                                   EXTERNAL_ITEM_MAX_ITEMS);
    525       } else {
    526         UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
    527                                   EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED,
    528                                   EXTERNAL_ITEM_MAX_ITEMS);
    529       }
    530     }
    531   }
    532 
    533   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp",
    534                            app_user_count + app_external_count);
    535   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppUser", app_user_count);
    536   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppExternal", app_external_count);
    537   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
    538   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp",
    539                            legacy_packaged_app_count);
    540   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPlatformApp", platform_app_count);
    541   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension",
    542                            extension_user_count + extension_external_count);
    543   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionUser",
    544                            extension_user_count);
    545   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionExternal",
    546                            extension_external_count);
    547   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
    548   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
    549   // Histogram name different for legacy reasons.
    550   UMA_HISTOGRAM_COUNTS_100("PageActionController.ExtensionsWithPageActions",
    551                            page_action_count);
    552   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
    553                            browser_action_count);
    554   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadContentPack", content_pack_count);
    555   UMA_HISTOGRAM_COUNTS_100("Extensions.DisabledForPermissions",
    556                            disabled_for_permissions_count);
    557   UMA_HISTOGRAM_COUNTS_100("Extensions.NonWebStoreNewTabPageOverrides",
    558                            non_webstore_ntp_override_count);
    559   if (incognito_allowed_count + incognito_not_allowed_count > 0) {
    560     UMA_HISTOGRAM_COUNTS_100("Extensions.IncognitoAllowed",
    561                              incognito_allowed_count);
    562     UMA_HISTOGRAM_COUNTS_100("Extensions.IncognitoNotAllowed",
    563                              incognito_not_allowed_count);
    564   }
    565   if (file_access_allowed_count + file_access_not_allowed_count > 0) {
    566     UMA_HISTOGRAM_COUNTS_100("Extensions.FileAccessAllowed",
    567                              file_access_allowed_count);
    568     UMA_HISTOGRAM_COUNTS_100("Extensions.FileAccessNotAllowed",
    569                              file_access_not_allowed_count);
    570   }
    571   UMA_HISTOGRAM_COUNTS_100("Extensions.CorruptExtensionTotalDisables",
    572                            extension_prefs_->GetCorruptedDisableCount());
    573 }
    574 
    575 int InstalledLoader::GetCreationFlags(const ExtensionInfo* info) {
    576   int flags = extension_prefs_->GetCreationFlags(info->extension_id);
    577   if (!Manifest::IsUnpackedLocation(info->extension_location))
    578     flags |= Extension::REQUIRE_KEY;
    579   if (extension_prefs_->AllowFileAccess(info->extension_id))
    580     flags |= Extension::ALLOW_FILE_ACCESS;
    581   return flags;
    582 }
    583 
    584 }  // namespace extensions
    585