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