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.
5 #include "chrome/browser/extensions/installed_loader.h"
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/trace_event/trace_event.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/extensions/extension_action_manager.h"
17 #include "chrome/browser/extensions/extension_error_reporter.h"
18 #include "chrome/browser/extensions/extension_service.h"
19 #include "chrome/browser/extensions/extension_util.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/extensions/api/supervised_user_private/supervised_user_handler.h"
23 #include "chrome/common/extensions/chrome_manifest_url_handlers.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/event_router.h"
28 #include "extensions/browser/extension_prefs.h"
29 #include "extensions/browser/extension_registry.h"
30 #include "extensions/browser/extension_system.h"
31 #include "extensions/browser/management_policy.h"
32 #include "extensions/common/extension.h"
33 #include "extensions/common/extension_l10n_util.h"
34 #include "extensions/common/extension_set.h"
35 #include "extensions/common/extension_urls.h"
36 #include "extensions/common/file_util.h"
37 #include "extensions/common/manifest.h"
38 #include "extensions/common/manifest_constants.h"
39 #include "extensions/common/manifest_handlers/background_info.h"
40 #include "extensions/common/manifest_url_handlers.h"
42 using base::UserMetricsAction
;
43 using content::BrowserThread
;
45 namespace extensions
{
47 namespace errors
= manifest_errors
;
51 // The following enumeration is used in histograms matching
52 // Extensions.ManifestReload*.
53 enum ManifestReloadReason
{
54 NOT_NEEDED
= 0, // Reload not needed.
55 UNPACKED_DIR
, // Unpacked directory.
56 NEEDS_RELOCALIZATION
, // The locale has changed since we read this extension.
57 CORRUPT_PREFERENCES
, // The manifest in the preferences is corrupt.
59 // New enum values must go above here.
60 NUM_MANIFEST_RELOAD_REASONS
63 // Used in histogram Extension.BackgroundPageType.
64 enum BackgroundPageType
{
65 NO_BACKGROUND_PAGE
= 0,
66 BACKGROUND_PAGE_PERSISTENT
,
69 // New enum values must go above here.
70 NUM_BACKGROUND_PAGE_TYPES
73 // Used in histogram Extensions.ExternalItemState.
74 enum ExternalItemState
{
75 DEPRECATED_EXTERNAL_ITEM_DISABLED
= 0,
76 DEPRECATED_EXTERNAL_ITEM_ENABLED
,
77 EXTERNAL_ITEM_WEBSTORE_DISABLED
,
78 EXTERNAL_ITEM_WEBSTORE_ENABLED
,
79 EXTERNAL_ITEM_NONWEBSTORE_DISABLED
,
80 EXTERNAL_ITEM_NONWEBSTORE_ENABLED
,
81 EXTERNAL_ITEM_WEBSTORE_UNINSTALLED
,
82 EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED
,
84 // New enum values must go above here.
85 EXTERNAL_ITEM_MAX_ITEMS
88 bool IsManifestCorrupt(const base::DictionaryValue
* manifest
) {
92 // Because of bug #272524 sometimes manifests got mangled in the preferences
93 // file, one particularly bad case resulting in having both a background page
94 // and background scripts values. In those situations we want to reload the
95 // manifest from the extension to fix this.
96 const base::Value
* background_page
;
97 const base::Value
* background_scripts
;
98 return manifest
->Get(manifest_keys::kBackgroundPage
, &background_page
) &&
99 manifest
->Get(manifest_keys::kBackgroundScripts
, &background_scripts
);
102 ManifestReloadReason
ShouldReloadExtensionManifest(const ExtensionInfo
& info
) {
103 // Always reload manifests of unpacked extensions, because they can change
104 // on disk independent of the manifest in our prefs.
105 if (Manifest::IsUnpackedLocation(info
.extension_location
))
108 // Reload the manifest if it needs to be relocalized.
109 if (extension_l10n_util::ShouldRelocalizeManifest(
110 info
.extension_manifest
.get()))
111 return NEEDS_RELOCALIZATION
;
113 // Reload if the copy of the manifest in the preferences is corrupt.
114 if (IsManifestCorrupt(info
.extension_manifest
.get()))
115 return CORRUPT_PREFERENCES
;
120 BackgroundPageType
GetBackgroundPageType(const Extension
* extension
) {
121 if (!BackgroundInfo::HasBackgroundPage(extension
))
122 return NO_BACKGROUND_PAGE
;
123 if (BackgroundInfo::HasPersistentBackgroundPage(extension
))
124 return BACKGROUND_PAGE_PERSISTENT
;
128 // Records the creation flags of an extension grouped by
129 // Extension::InitFromValueFlags.
130 void RecordCreationFlags(const Extension
* extension
) {
131 for (int i
= 0; i
< Extension::kInitFromValueFlagBits
; ++i
) {
133 if (extension
->creation_flags() & flag
) {
134 UMA_HISTOGRAM_ENUMERATION(
135 "Extensions.LoadCreationFlags", i
, Extension::kInitFromValueFlagBits
);
140 // Helper to record a single disable reason histogram value (see
141 // RecordDisableReasons below).
142 void RecordDisbleReasonHistogram(int reason
) {
143 UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.DisableReason", reason
);
146 // Records the disable reasons for a single extension grouped by
147 // Extension::DisableReason.
148 void RecordDisableReasons(int reasons
) {
149 // |reasons| is a bitmask with values from Extension::DisabledReason
150 // which are increasing powers of 2.
151 if (reasons
== Extension::DISABLE_NONE
) {
152 RecordDisbleReasonHistogram(Extension::DISABLE_NONE
);
155 for (int reason
= 1; reason
< Extension::DISABLE_REASON_LAST
; reason
<<= 1) {
156 if (reasons
& reason
)
157 RecordDisbleReasonHistogram(reason
);
163 InstalledLoader::InstalledLoader(ExtensionService
* extension_service
)
164 : extension_service_(extension_service
),
165 extension_registry_(ExtensionRegistry::Get(extension_service
->profile())),
166 extension_prefs_(ExtensionPrefs::Get(extension_service
->profile())) {}
168 InstalledLoader::~InstalledLoader() {
171 void InstalledLoader::Load(const ExtensionInfo
& info
, bool write_to_prefs
) {
173 scoped_refptr
<const Extension
> extension(NULL
);
174 if (info
.extension_manifest
) {
175 extension
= Extension::Create(
177 info
.extension_location
,
178 *info
.extension_manifest
,
179 GetCreationFlags(&info
),
182 error
= errors::kManifestUnreadable
;
185 // Once installed, non-unpacked extensions cannot change their IDs (e.g., by
186 // updating the 'key' field in their manifest).
187 // TODO(jstritar): migrate preferences when unpacked extensions change IDs.
188 if (extension
.get() && !Manifest::IsUnpackedLocation(extension
->location()) &&
189 info
.extension_id
!= extension
->id()) {
190 error
= errors::kCannotChangeExtensionID
;
194 // Check policy on every load in case an extension was blacklisted while
195 // Chrome was not running.
196 const ManagementPolicy
* policy
= extensions::ExtensionSystem::Get(
197 extension_service_
->profile())->management_policy();
198 if (extension
.get()) {
199 Extension::DisableReason disable_reason
= Extension::DISABLE_NONE
;
200 bool force_disabled
= false;
201 if (!policy
->UserMayLoad(extension
.get(), NULL
)) {
202 // The error message from UserMayInstall() often contains the extension ID
203 // and is therefore not well suited to this UI.
204 error
= errors::kDisabledByPolicy
;
206 } else if (!extension_prefs_
->IsExtensionDisabled(extension
->id()) &&
207 policy
->MustRemainDisabled(
208 extension
.get(), &disable_reason
, NULL
)) {
209 extension_prefs_
->SetExtensionState(extension
->id(), Extension::DISABLED
);
210 extension_prefs_
->AddDisableReason(extension
->id(), disable_reason
);
211 force_disabled
= true;
213 UMA_HISTOGRAM_BOOLEAN("ExtensionInstalledLoader.ForceDisabled",
217 if (!extension
.get()) {
218 ExtensionErrorReporter::GetInstance()->ReportLoadError(
221 extension_service_
->profile(),
227 extension_prefs_
->UpdateManifest(extension
.get());
229 extension_service_
->AddExtension(extension
.get());
232 void InstalledLoader::LoadAllExtensions() {
233 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
234 TRACE_EVENT0("browser,startup", "InstalledLoader::LoadAllExtensions");
235 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.LoadAllTime2");
236 base::TimeTicks start_time
= base::TimeTicks::Now();
238 Profile
* profile
= extension_service_
->profile();
239 scoped_ptr
<ExtensionPrefs::ExtensionsInfo
> extensions_info(
240 extension_prefs_
->GetInstalledExtensionsInfo());
242 std::vector
<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS
, 0);
243 bool should_write_prefs
= false;
245 for (size_t i
= 0; i
< extensions_info
->size(); ++i
) {
246 ExtensionInfo
* info
= extensions_info
->at(i
).get();
248 // Skip extensions that were loaded from the command-line because we don't
249 // want those to persist across browser restart.
250 if (info
->extension_location
== Manifest::COMMAND_LINE
)
253 ManifestReloadReason reload_reason
= ShouldReloadExtensionManifest(*info
);
254 ++reload_reason_counts
[reload_reason
];
256 if (reload_reason
!= NOT_NEEDED
) {
257 // Reloading an extension reads files from disk. We do this on the
258 // UI thread because reloads should be very rare, and the complexity
259 // added by delaying the time when the extensions service knows about
260 // all extensions is significant. See crbug.com/37548 for details.
261 // |allow_io| disables tests that file operations run on the file
263 base::ThreadRestrictions::ScopedAllowIO allow_io
;
266 scoped_refptr
<const Extension
> extension(
267 file_util::LoadExtension(info
->extension_path
,
268 info
->extension_location
,
269 GetCreationFlags(info
),
272 if (!extension
.get()) {
273 ExtensionErrorReporter::GetInstance()->ReportLoadError(
274 info
->extension_path
,
281 extensions_info
->at(i
)->extension_manifest
.reset(
282 static_cast<base::DictionaryValue
*>(
283 extension
->manifest()->value()->DeepCopy()));
284 should_write_prefs
= true;
288 for (size_t i
= 0; i
< extensions_info
->size(); ++i
) {
289 if (extensions_info
->at(i
)->extension_location
!= Manifest::COMMAND_LINE
)
290 Load(*extensions_info
->at(i
), should_write_prefs
);
293 extension_service_
->OnLoadedInstalledExtensions();
295 // The histograms Extensions.ManifestReload* allow us to validate
296 // the assumption that reloading manifest is a rare event.
297 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
298 reload_reason_counts
[NOT_NEEDED
]);
299 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
300 reload_reason_counts
[UNPACKED_DIR
]);
301 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
302 reload_reason_counts
[NEEDS_RELOCALIZATION
]);
304 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll",
305 extension_registry_
->enabled_extensions().size());
306 UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled",
307 extension_registry_
->disabled_extensions().size());
309 // TODO(rkaplow): Obsolete this when verified similar to LoadAllTime2.
310 UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
311 base::TimeTicks::Now() - start_time
);
312 RecordExtensionsMetrics();
315 void InstalledLoader::RecordExtensionsMetrics() {
316 Profile
* profile
= extension_service_
->profile();
318 int app_user_count
= 0;
319 int app_external_count
= 0;
320 int hosted_app_count
= 0;
321 int legacy_packaged_app_count
= 0;
322 int platform_app_count
= 0;
323 int user_script_count
= 0;
324 int content_pack_count
= 0;
325 int extension_user_count
= 0;
326 int extension_external_count
= 0;
328 int page_action_count
= 0;
329 int browser_action_count
= 0;
330 int disabled_for_permissions_count
= 0;
331 int non_webstore_ntp_override_count
= 0;
332 int incognito_allowed_count
= 0;
333 int incognito_not_allowed_count
= 0;
334 int file_access_allowed_count
= 0;
335 int file_access_not_allowed_count
= 0;
336 int eventless_event_pages_count
= 0;
338 const ExtensionSet
& extensions
= extension_registry_
->enabled_extensions();
339 ExtensionActionManager
* extension_action_manager
=
340 ExtensionActionManager::Get(profile
);
341 for (ExtensionSet::const_iterator iter
= extensions
.begin();
342 iter
!= extensions
.end();
344 const Extension
* extension
= iter
->get();
345 Manifest::Location location
= extension
->location();
346 Manifest::Type type
= extension
->GetType();
348 // For the first few metrics, include all extensions and apps (component,
349 // unpacked, etc). It's good to know these locations, and it doesn't
350 // muck up any of the stats. Later, though, we want to omit component and
351 // unpacked, as they are less interesting.
352 if (extension
->is_app())
353 UMA_HISTOGRAM_ENUMERATION(
354 "Extensions.AppLocation", location
, Manifest::NUM_LOCATIONS
);
355 else if (extension
->is_extension())
356 UMA_HISTOGRAM_ENUMERATION(
357 "Extensions.ExtensionLocation", location
, Manifest::NUM_LOCATIONS
);
359 if (!ManifestURL::UpdatesFromGallery(extension
)) {
360 UMA_HISTOGRAM_ENUMERATION(
361 "Extensions.NonWebstoreLocation", location
, Manifest::NUM_LOCATIONS
);
363 // Check for inconsistencies if the extension was supposedly installed
364 // from the webstore.
367 // This value was a mistake. Turns out sideloaded extensions can
368 // have the from_webstore bit if they update from the webstore.
369 DEPRECATED_IS_EXTERNAL
= 1,
371 if (extension
->from_webstore()) {
372 UMA_HISTOGRAM_ENUMERATION(
373 "Extensions.FromWebstoreInconsistency", BAD_UPDATE_URL
, 2);
377 if (Manifest::IsExternalLocation(location
)) {
378 // See loop below for DISABLED.
379 if (ManifestURL::UpdatesFromGallery(extension
)) {
380 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
381 EXTERNAL_ITEM_WEBSTORE_ENABLED
,
382 EXTERNAL_ITEM_MAX_ITEMS
);
384 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
385 EXTERNAL_ITEM_NONWEBSTORE_ENABLED
,
386 EXTERNAL_ITEM_MAX_ITEMS
);
390 // From now on, don't count component extensions, since they are only
391 // extensions as an implementation detail. Continue to count unpacked
392 // extensions for a few metrics.
393 if (location
== Manifest::COMPONENT
)
396 // Histogram for non-webstore extensions overriding new tab page should
397 // include unpacked extensions.
398 if (!extension
->from_webstore() &&
399 URLOverrides::GetChromeURLOverrides(extension
).count("newtab")) {
400 ++non_webstore_ntp_override_count
;
403 // Don't count unpacked extensions anymore, either.
404 if (Manifest::IsUnpackedLocation(location
))
407 UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestVersion",
408 extension
->manifest_version(),
409 10); // TODO(kalman): Why 10 manifest versions?
411 // We might have wanted to count legacy packaged apps here, too, since they
412 // are effectively extensions. Unfortunately, it's too late, as we don't
413 // want to mess up the existing stats.
414 if (type
== Manifest::TYPE_EXTENSION
) {
415 UMA_HISTOGRAM_ENUMERATION("Extensions.BackgroundPageType",
416 GetBackgroundPageType(extension
),
417 NUM_BACKGROUND_PAGE_TYPES
);
419 if (GetBackgroundPageType(extension
) == EVENT_PAGE
) {
420 // Count extension event pages with no registered events. Either the
421 // event page is badly designed, or there may be a bug where the event
422 // page failed to start after an update (crbug.com/469361).
423 if (EventRouter::Get(extension_service_
->profile())->
424 GetRegisteredEvents(extension
->id()).size() == 0) {
425 ++eventless_event_pages_count
;
426 VLOG(1) << "Event page without registered event listeners: "
427 << extension
->id() << " " << extension
->name();
432 // Using an enumeration shows us the total installed ratio across all users.
433 // Using the totals per user at each startup tells us the distribution of
434 // usage for each user (e.g. 40% of users have at least one app installed).
435 UMA_HISTOGRAM_ENUMERATION(
436 "Extensions.LoadType", type
, Manifest::NUM_LOAD_TYPES
);
438 case Manifest::TYPE_THEME
:
441 case Manifest::TYPE_USER_SCRIPT
:
444 case Manifest::TYPE_HOSTED_APP
:
446 if (Manifest::IsExternalLocation(location
)) {
447 ++app_external_count
;
452 case Manifest::TYPE_LEGACY_PACKAGED_APP
:
453 ++legacy_packaged_app_count
;
454 if (Manifest::IsExternalLocation(location
)) {
455 ++app_external_count
;
460 case Manifest::TYPE_PLATFORM_APP
:
461 ++platform_app_count
;
462 if (Manifest::IsExternalLocation(location
)) {
463 ++app_external_count
;
468 case Manifest::TYPE_EXTENSION
:
470 if (Manifest::IsExternalLocation(location
)) {
471 ++extension_external_count
;
473 ++extension_user_count
;
478 if (extension_action_manager
->GetPageAction(*extension
))
481 if (extension_action_manager
->GetBrowserAction(*extension
))
482 ++browser_action_count
;
484 if (SupervisedUserInfo::IsContentPack(extension
))
485 ++content_pack_count
;
487 RecordCreationFlags(extension
);
489 ExtensionService::RecordPermissionMessagesHistogram(
490 extension
, "Extensions.Permissions_Load2");
492 // For incognito and file access, skip anything that doesn't appear in
493 // settings. Also, policy-installed (and unpacked of course, checked above)
494 // extensions are boring.
495 if (extension
->ShouldDisplayInExtensionSettings() &&
496 !Manifest::IsPolicyLocation(extension
->location())) {
497 if (extension
->can_be_incognito_enabled()) {
498 if (util::IsIncognitoEnabled(extension
->id(), profile
))
499 ++incognito_allowed_count
;
501 ++incognito_not_allowed_count
;
503 if (extension
->wants_file_access()) {
504 if (util::AllowFileAccess(extension
->id(), profile
))
505 ++file_access_allowed_count
;
507 ++file_access_not_allowed_count
;
512 const ExtensionSet
& disabled_extensions
=
513 extension_registry_
->disabled_extensions();
515 for (ExtensionSet::const_iterator ex
= disabled_extensions
.begin();
516 ex
!= disabled_extensions
.end();
518 if (extension_prefs_
->DidExtensionEscalatePermissions((*ex
)->id())) {
519 ++disabled_for_permissions_count
;
521 RecordDisableReasons(extension_prefs_
->GetDisableReasons((*ex
)->id()));
522 if (Manifest::IsExternalLocation((*ex
)->location())) {
523 // See loop above for ENABLED.
524 if (ManifestURL::UpdatesFromGallery(ex
->get())) {
525 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
526 EXTERNAL_ITEM_WEBSTORE_DISABLED
,
527 EXTERNAL_ITEM_MAX_ITEMS
);
529 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
530 EXTERNAL_ITEM_NONWEBSTORE_DISABLED
,
531 EXTERNAL_ITEM_MAX_ITEMS
);
536 scoped_ptr
<ExtensionPrefs::ExtensionsInfo
> uninstalled_extensions_info(
537 extension_prefs_
->GetUninstalledExtensionsInfo());
538 for (size_t i
= 0; i
< uninstalled_extensions_info
->size(); ++i
) {
539 ExtensionInfo
* info
= uninstalled_extensions_info
->at(i
).get();
540 if (Manifest::IsExternalLocation(info
->extension_location
)) {
541 std::string update_url
;
542 if (info
->extension_manifest
->GetString("update_url", &update_url
) &&
543 extension_urls::IsWebstoreUpdateUrl(GURL(update_url
))) {
544 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
545 EXTERNAL_ITEM_WEBSTORE_UNINSTALLED
,
546 EXTERNAL_ITEM_MAX_ITEMS
);
548 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
549 EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED
,
550 EXTERNAL_ITEM_MAX_ITEMS
);
555 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp",
556 app_user_count
+ app_external_count
);
557 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppUser", app_user_count
);
558 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppExternal", app_external_count
);
559 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count
);
560 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp",
561 legacy_packaged_app_count
);
562 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPlatformApp", platform_app_count
);
563 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension",
564 extension_user_count
+ extension_external_count
);
565 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionUser",
566 extension_user_count
);
567 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionExternal",
568 extension_external_count
);
569 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count
);
570 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count
);
571 // Histogram name different for legacy reasons.
572 UMA_HISTOGRAM_COUNTS_100("PageActionController.ExtensionsWithPageActions",
574 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
575 browser_action_count
);
576 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadContentPack", content_pack_count
);
577 UMA_HISTOGRAM_COUNTS_100("Extensions.DisabledForPermissions",
578 disabled_for_permissions_count
);
579 UMA_HISTOGRAM_COUNTS_100("Extensions.NonWebStoreNewTabPageOverrides",
580 non_webstore_ntp_override_count
);
581 if (incognito_allowed_count
+ incognito_not_allowed_count
> 0) {
582 UMA_HISTOGRAM_COUNTS_100("Extensions.IncognitoAllowed",
583 incognito_allowed_count
);
584 UMA_HISTOGRAM_COUNTS_100("Extensions.IncognitoNotAllowed",
585 incognito_not_allowed_count
);
587 if (file_access_allowed_count
+ file_access_not_allowed_count
> 0) {
588 UMA_HISTOGRAM_COUNTS_100("Extensions.FileAccessAllowed",
589 file_access_allowed_count
);
590 UMA_HISTOGRAM_COUNTS_100("Extensions.FileAccessNotAllowed",
591 file_access_not_allowed_count
);
593 UMA_HISTOGRAM_COUNTS_100("Extensions.CorruptExtensionTotalDisables",
594 extension_prefs_
->GetCorruptedDisableCount());
595 UMA_HISTOGRAM_COUNTS_100("Extensions.EventlessEventPages",
596 eventless_event_pages_count
);
599 int InstalledLoader::GetCreationFlags(const ExtensionInfo
* info
) {
600 int flags
= extension_prefs_
->GetCreationFlags(info
->extension_id
);
601 if (!Manifest::IsUnpackedLocation(info
->extension_location
))
602 flags
|= Extension::REQUIRE_KEY
;
603 if (extension_prefs_
->AllowFileAccess(info
->extension_id
))
604 flags
|= Extension::ALLOW_FILE_ACCESS
;
608 } // namespace extensions