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