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 <stddef.h>
8 #include <memory>
9 #include <string>
10 #include <vector>
11
12 #include "base/files/file_path.h"
13 #include "base/metrics/histogram_functions.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/threading/thread_restrictions.h"
17 #include "base/trace_event/trace_event.h"
18 #include "base/values.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_util.h"
22 #include "chrome/browser/extensions/load_error_reporter.h"
23 #include "chrome/browser/extensions/scripting_permissions_modifier.h"
24 #include "chrome/browser/profiles/profile_manager.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/extensions/chrome_manifest_url_handlers.h"
27 #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/notification_service.h"
30 #include "content/public/common/url_constants.h"
31 #include "extensions/browser/event_router.h"
32 #include "extensions/browser/extension_prefs.h"
33 #include "extensions/browser/extension_registry.h"
34 #include "extensions/browser/extension_system.h"
35 #include "extensions/browser/extension_util.h"
36 #include "extensions/browser/management_policy.h"
37 #include "extensions/browser/pref_types.h"
38 #include "extensions/browser/ui_util.h"
39 #include "extensions/common/extension.h"
40 #include "extensions/common/extension_l10n_util.h"
41 #include "extensions/common/extension_set.h"
42 #include "extensions/common/extension_urls.h"
43 #include "extensions/common/file_util.h"
44 #include "extensions/common/manifest.h"
45 #include "extensions/common/manifest_constants.h"
46 #include "extensions/common/manifest_handlers/background_info.h"
47 #include "extensions/common/manifest_url_handlers.h"
48 #include "extensions/common/permissions/api_permission.h"
49 #include "extensions/common/permissions/permissions_data.h"
50
51 using content::BrowserThread;
52
53 namespace extensions {
54
55 namespace {
56
57 // The following enumeration is used in histograms matching
58 // Extensions.ManifestReload*.
59 enum ManifestReloadReason {
60 NOT_NEEDED = 0, // Reload not needed.
61 UNPACKED_DIR, // Unpacked directory.
62 NEEDS_RELOCALIZATION, // The locale has changed since we read this extension.
63 CORRUPT_PREFERENCES, // The manifest in the preferences is corrupt.
64
65 // New enum values must go above here.
66 NUM_MANIFEST_RELOAD_REASONS
67 };
68
69 // Used in histogram Extensions.BackgroundPageType.
70 enum BackgroundPageType {
71 NO_BACKGROUND_PAGE = 0,
72 BACKGROUND_PAGE_PERSISTENT,
73 EVENT_PAGE,
74 SERVICE_WORKER,
75
76 // New enum values must go above here.
77 NUM_BACKGROUND_PAGE_TYPES
78 };
79
80 // Used in histogram Extensions.ExternalItemState.
81 enum ExternalItemState {
82 DEPRECATED_EXTERNAL_ITEM_DISABLED = 0,
83 DEPRECATED_EXTERNAL_ITEM_ENABLED,
84 EXTERNAL_ITEM_WEBSTORE_DISABLED,
85 EXTERNAL_ITEM_WEBSTORE_ENABLED,
86 EXTERNAL_ITEM_NONWEBSTORE_DISABLED,
87 EXTERNAL_ITEM_NONWEBSTORE_ENABLED,
88 EXTERNAL_ITEM_WEBSTORE_UNINSTALLED,
89 EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED,
90
91 // New enum values must go above here.
92 EXTERNAL_ITEM_MAX_ITEMS
93 };
94
IsManifestCorrupt(const base::DictionaryValue * manifest)95 bool IsManifestCorrupt(const base::DictionaryValue* manifest) {
96 if (!manifest)
97 return false;
98
99 // Because of bug #272524 sometimes manifests got mangled in the preferences
100 // file, one particularly bad case resulting in having both a background page
101 // and background scripts values. In those situations we want to reload the
102 // manifest from the extension to fix this.
103 const base::Value* background_page;
104 const base::Value* background_scripts;
105 return manifest->Get(manifest_keys::kBackgroundPage, &background_page) &&
106 manifest->Get(manifest_keys::kBackgroundScripts, &background_scripts);
107 }
108
ShouldReloadExtensionManifest(const ExtensionInfo & info)109 ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
110 // Always reload manifests of unpacked extensions, because they can change
111 // on disk independent of the manifest in our prefs.
112 if (Manifest::IsUnpackedLocation(info.extension_location))
113 return UNPACKED_DIR;
114
115 // Reload the manifest if it needs to be relocalized.
116 if (extension_l10n_util::ShouldRelocalizeManifest(
117 info.extension_manifest.get()))
118 return NEEDS_RELOCALIZATION;
119
120 // Reload if the copy of the manifest in the preferences is corrupt.
121 if (IsManifestCorrupt(info.extension_manifest.get()))
122 return CORRUPT_PREFERENCES;
123
124 return NOT_NEEDED;
125 }
126
GetBackgroundPageType(const Extension * extension)127 BackgroundPageType GetBackgroundPageType(const Extension* extension) {
128 if (!BackgroundInfo::HasBackgroundPage(extension))
129 return NO_BACKGROUND_PAGE;
130 if (BackgroundInfo::HasPersistentBackgroundPage(extension))
131 return BACKGROUND_PAGE_PERSISTENT;
132 if (BackgroundInfo::IsServiceWorkerBased(extension))
133 return SERVICE_WORKER;
134 return EVENT_PAGE;
135 }
136
137 // Records the creation flags of an extension grouped by
138 // Extension::InitFromValueFlags.
RecordCreationFlags(const Extension * extension)139 void RecordCreationFlags(const Extension* extension) {
140 for (int i = 0; i < Extension::kInitFromValueFlagBits; ++i) {
141 int flag = 1 << i;
142 if (extension->creation_flags() & flag) {
143 UMA_HISTOGRAM_EXACT_LINEAR("Extensions.LoadCreationFlags", i,
144 Extension::kInitFromValueFlagBits);
145 }
146 }
147 }
148
149 // Helper to record a single disable reason histogram value (see
150 // RecordDisableReasons below).
RecordDisbleReasonHistogram(int reason)151 void RecordDisbleReasonHistogram(int reason) {
152 base::UmaHistogramSparse("Extensions.DisableReason", reason);
153 }
154
155 // Records the disable reasons for a single extension grouped by
156 // disable_reason::DisableReason.
RecordDisableReasons(int reasons)157 void RecordDisableReasons(int reasons) {
158 // |reasons| is a bitmask with values from ExtensionDisabledReason
159 // which are increasing powers of 2.
160 if (reasons == disable_reason::DISABLE_NONE) {
161 RecordDisbleReasonHistogram(disable_reason::DISABLE_NONE);
162 return;
163 }
164 for (int reason = 1; reason < disable_reason::DISABLE_REASON_LAST;
165 reason <<= 1) {
166 if (reasons & reason)
167 RecordDisbleReasonHistogram(reason);
168 }
169 }
170
171 } // namespace
172
InstalledLoader(ExtensionService * extension_service)173 InstalledLoader::InstalledLoader(ExtensionService* extension_service)
174 : extension_service_(extension_service),
175 extension_registry_(ExtensionRegistry::Get(extension_service->profile())),
176 extension_prefs_(ExtensionPrefs::Get(extension_service->profile())) {}
177
~InstalledLoader()178 InstalledLoader::~InstalledLoader() {
179 }
180
Load(const ExtensionInfo & info,bool write_to_prefs)181 void InstalledLoader::Load(const ExtensionInfo& info, bool write_to_prefs) {
182 // TODO(asargent): add a test to confirm that we can't load extensions if
183 // their ID in preferences does not match the extension's actual ID.
184 if (invalid_extensions_.find(info.extension_path) !=
185 invalid_extensions_.end())
186 return;
187
188 std::string error;
189 scoped_refptr<const Extension> extension;
190 if (info.extension_manifest) {
191 extension = Extension::Create(
192 info.extension_path,
193 info.extension_location,
194 *info.extension_manifest,
195 GetCreationFlags(&info),
196 &error);
197 } else {
198 error = manifest_errors::kManifestUnreadable;
199 }
200
201 // Once installed, non-unpacked extensions cannot change their IDs (e.g., by
202 // updating the 'key' field in their manifest).
203 // TODO(jstritar): migrate preferences when unpacked extensions change IDs.
204 if (extension.get() && !Manifest::IsUnpackedLocation(extension->location()) &&
205 info.extension_id != extension->id()) {
206 error = manifest_errors::kCannotChangeExtensionID;
207 extension = nullptr;
208 }
209
210 if (!extension.get()) {
211 LoadErrorReporter::GetInstance()->ReportLoadError(
212 info.extension_path, error, extension_service_->profile(),
213 false); // Be quiet.
214 return;
215 }
216
217 const ManagementPolicy* policy = extensions::ExtensionSystem::Get(
218 extension_service_->profile())->management_policy();
219
220 if (extension_prefs_->IsExtensionDisabled(extension->id())) {
221 int disable_reasons = extension_prefs_->GetDisableReasons(extension->id());
222
223 // Update the extension prefs to reflect if the extension is no longer
224 // blocked due to admin policy.
225 if ((disable_reasons & disable_reason::DISABLE_BLOCKED_BY_POLICY) &&
226 !policy->MustRemainDisabled(extension.get(), nullptr, nullptr)) {
227 disable_reasons &= (~disable_reason::DISABLE_BLOCKED_BY_POLICY);
228 extension_prefs_->ReplaceDisableReasons(extension->id(), disable_reasons);
229 if (disable_reasons == disable_reason::DISABLE_NONE)
230 extension_prefs_->SetExtensionEnabled(extension->id());
231 }
232
233 if ((disable_reasons & disable_reason::DISABLE_CORRUPTED) &&
234 policy->MustRemainEnabled(extension.get(), nullptr)) {
235 // This extension must have been disabled due to corruption on a
236 // previous run of chrome, and for some reason we weren't successful in
237 // auto-reinstalling it. So we want to notify the
238 // PendingExtensionManager that we'd still like to keep attempt to
239 // re-download and reinstall it whenever the ExtensionService checks for
240 // external updates.
241 PendingExtensionManager* pending_manager =
242 extension_service_->pending_extension_manager();
243 pending_manager->ExpectPolicyReinstallForCorruption(
244 extension->id(), PendingExtensionManager::PolicyReinstallReason::
245 CORRUPTION_DETECTED_IN_PRIOR_SESSION);
246 }
247 } else {
248 // Extension is enabled. Check management policy to verify if it should
249 // remain so.
250 disable_reason::DisableReason disable_reason = disable_reason::DISABLE_NONE;
251 if (policy->MustRemainDisabled(extension.get(), &disable_reason, nullptr)) {
252 extension_prefs_->SetExtensionDisabled(extension->id(), disable_reason);
253 }
254 }
255
256 if (write_to_prefs)
257 extension_prefs_->UpdateManifest(extension.get());
258
259 extension_service_->AddExtension(extension.get());
260 }
261
LoadAllExtensions()262 void InstalledLoader::LoadAllExtensions() {
263 DCHECK_CURRENTLY_ON(BrowserThread::UI);
264 TRACE_EVENT0("browser,startup", "InstalledLoader::LoadAllExtensions");
265 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.LoadAllTime2");
266
267 Profile* profile = extension_service_->profile();
268 std::unique_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
269 extension_prefs_->GetInstalledExtensionsInfo());
270
271 std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
272 bool should_write_prefs = false;
273
274 for (size_t i = 0; i < extensions_info->size(); ++i) {
275 ExtensionInfo* info = extensions_info->at(i).get();
276
277 // Skip extensions that were loaded from the command-line because we don't
278 // want those to persist across browser restart.
279 if (info->extension_location == Manifest::COMMAND_LINE)
280 continue;
281
282 ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
283 ++reload_reason_counts[reload_reason];
284
285 if (reload_reason != NOT_NEEDED) {
286 // Reloading an extension reads files from disk. We do this on the
287 // UI thread because reloads should be very rare, and the complexity
288 // added by delaying the time when the extensions service knows about
289 // all extensions is significant. See crbug.com/37548 for details.
290 // |allow_io| disables tests that file operations run on the file
291 // thread.
292 base::ThreadRestrictions::ScopedAllowIO allow_io;
293
294 std::string error;
295 scoped_refptr<const Extension> extension(
296 file_util::LoadExtension(info->extension_path,
297 info->extension_location,
298 GetCreationFlags(info),
299 &error));
300
301 if (!extension.get() || extension->id() != info->extension_id) {
302 invalid_extensions_.insert(info->extension_path);
303 LoadErrorReporter::GetInstance()->ReportLoadError(info->extension_path,
304 error, profile,
305 false); // Be quiet.
306 continue;
307 }
308
309 extensions_info->at(i)->extension_manifest.reset(
310 static_cast<base::DictionaryValue*>(
311 extension->manifest()->value()->DeepCopy()));
312 should_write_prefs = true;
313 }
314 }
315
316 for (size_t i = 0; i < extensions_info->size(); ++i) {
317 if (extensions_info->at(i)->extension_location != Manifest::COMMAND_LINE)
318 Load(*extensions_info->at(i), should_write_prefs);
319 }
320
321 // The histograms Extensions.ManifestReload* allow us to validate
322 // the assumption that reloading manifest is a rare event.
323 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
324 reload_reason_counts[NOT_NEEDED]);
325 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
326 reload_reason_counts[UNPACKED_DIR]);
327 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
328 reload_reason_counts[NEEDS_RELOCALIZATION]);
329
330 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll",
331 extension_registry_->enabled_extensions().size());
332 UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled",
333 extension_registry_->disabled_extensions().size());
334
335 RecordExtensionsMetrics();
336 }
337
RecordExtensionsMetricsForTesting()338 void InstalledLoader::RecordExtensionsMetricsForTesting() {
339 RecordExtensionsMetrics();
340 }
341
RecordExtensionsMetrics()342 void InstalledLoader::RecordExtensionsMetrics() {
343 Profile* profile = extension_service_->profile();
344
345 int app_user_count = 0;
346 int app_external_count = 0;
347 int hosted_app_count = 0;
348 int legacy_packaged_app_count = 0;
349 int platform_app_count = 0;
350 int user_script_count = 0;
351 int extension_user_count = 0;
352 int extension_external_count = 0;
353 int theme_count = 0;
354 int page_action_count = 0;
355 int browser_action_count = 0;
356 int no_action_count = 0;
357 int disabled_for_permissions_count = 0;
358 int non_webstore_ntp_override_count = 0;
359 int ntp_override_count = 0;
360 int homepage_override_count = 0;
361 int search_engine_override_count = 0;
362 int startup_pages_override_count = 0;
363 int incognito_allowed_count = 0;
364 int incognito_not_allowed_count = 0;
365 int file_access_allowed_count = 0;
366 int file_access_not_allowed_count = 0;
367 int eventless_event_pages_count = 0;
368 int off_store_item_count = 0;
369 int web_request_blocking_count = 0;
370 int web_request_count = 0;
371
372 const ExtensionSet& extensions = extension_registry_->enabled_extensions();
373 for (ExtensionSet::const_iterator iter = extensions.begin();
374 iter != extensions.end();
375 ++iter) {
376 const Extension* extension = iter->get();
377 Manifest::Location location = extension->location();
378 Manifest::Type type = extension->GetType();
379
380 // For the first few metrics, include all extensions and apps (component,
381 // unpacked, etc). It's good to know these locations, and it doesn't
382 // muck up any of the stats. Later, though, we want to omit component and
383 // unpacked, as they are less interesting.
384 if (extension->is_app())
385 UMA_HISTOGRAM_ENUMERATION(
386 "Extensions.AppLocation", location, Manifest::NUM_LOCATIONS);
387 else if (extension->is_extension())
388 UMA_HISTOGRAM_ENUMERATION(
389 "Extensions.ExtensionLocation", location, Manifest::NUM_LOCATIONS);
390
391 if (!ManifestURL::UpdatesFromGallery(extension)) {
392 UMA_HISTOGRAM_ENUMERATION(
393 "Extensions.NonWebstoreLocation", location, Manifest::NUM_LOCATIONS);
394
395 // Check for inconsistencies if the extension was supposedly installed
396 // from the webstore.
397 enum {
398 BAD_UPDATE_URL = 0,
399 // This value was a mistake. Turns out sideloaded extensions can
400 // have the from_webstore bit if they update from the webstore.
401 DEPRECATED_IS_EXTERNAL = 1,
402 };
403 if (extension->from_webstore()) {
404 UMA_HISTOGRAM_ENUMERATION(
405 "Extensions.FromWebstoreInconsistency", BAD_UPDATE_URL, 2);
406 }
407 }
408
409 if (Manifest::IsExternalLocation(location)) {
410 // See loop below for DISABLED.
411 if (ManifestURL::UpdatesFromGallery(extension)) {
412 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
413 EXTERNAL_ITEM_WEBSTORE_ENABLED,
414 EXTERNAL_ITEM_MAX_ITEMS);
415 } else {
416 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
417 EXTERNAL_ITEM_NONWEBSTORE_ENABLED,
418 EXTERNAL_ITEM_MAX_ITEMS);
419 }
420 }
421
422 if (extension->permissions_data()->HasAPIPermission(
423 APIPermission::kWebRequestBlocking)) {
424 web_request_blocking_count++;
425 }
426
427 if (extension->permissions_data()->HasAPIPermission(
428 APIPermission::kWebRequest)) {
429 web_request_count++;
430 }
431
432 // From now on, don't count component extensions, since they are only
433 // extensions as an implementation detail. Continue to count unpacked
434 // extensions for a few metrics.
435 if (Manifest::IsComponentLocation(location))
436 continue;
437
438 // Histogram for extensions overriding the new tab page should include
439 // unpacked extensions.
440 if (URLOverrides::GetChromeURLOverrides(extension).count("newtab")) {
441 ++ntp_override_count;
442 if (!extension->from_webstore()) {
443 ++non_webstore_ntp_override_count;
444 }
445 }
446
447 // Histogram for extensions with settings overrides.
448 const SettingsOverrides* settings = SettingsOverrides::Get(extension);
449 if (settings) {
450 if (settings->search_engine)
451 ++search_engine_override_count;
452 if (!settings->startup_pages.empty())
453 ++startup_pages_override_count;
454 if (settings->homepage)
455 ++homepage_override_count;
456 }
457
458 // Don't count unpacked extensions anymore, either.
459 if (Manifest::IsUnpackedLocation(location))
460 continue;
461
462 UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestVersion",
463 extension->manifest_version(),
464 10); // TODO(kalman): Why 10 manifest versions?
465
466 // We might have wanted to count legacy packaged apps here, too, since they
467 // are effectively extensions. Unfortunately, it's too late, as we don't
468 // want to mess up the existing stats.
469 if (type == Manifest::TYPE_EXTENSION) {
470 UMA_HISTOGRAM_ENUMERATION("Extensions.BackgroundPageType",
471 GetBackgroundPageType(extension),
472 NUM_BACKGROUND_PAGE_TYPES);
473
474 if (GetBackgroundPageType(extension) == EVENT_PAGE) {
475 // Count extension event pages with no registered events. Either the
476 // event page is badly designed, or there may be a bug where the event
477 // page failed to start after an update (crbug.com/469361).
478 if (!EventRouter::Get(extension_service_->profile())
479 ->HasRegisteredEvents(extension->id())) {
480 ++eventless_event_pages_count;
481 VLOG(1) << "Event page without registered event listeners: "
482 << extension->id() << " " << extension->name();
483 }
484 }
485 }
486
487 // Using an enumeration shows us the total installed ratio across all users.
488 // Using the totals per user at each startup tells us the distribution of
489 // usage for each user (e.g. 40% of users have at least one app installed).
490 UMA_HISTOGRAM_ENUMERATION(
491 "Extensions.LoadType", type, Manifest::NUM_LOAD_TYPES);
492 switch (type) {
493 case Manifest::TYPE_THEME:
494 ++theme_count;
495 break;
496 case Manifest::TYPE_USER_SCRIPT:
497 ++user_script_count;
498 break;
499 case Manifest::TYPE_HOSTED_APP:
500 ++hosted_app_count;
501 if (Manifest::IsExternalLocation(location)) {
502 ++app_external_count;
503 } else {
504 ++app_user_count;
505 }
506 break;
507 case Manifest::TYPE_LEGACY_PACKAGED_APP:
508 ++legacy_packaged_app_count;
509 if (Manifest::IsExternalLocation(location)) {
510 ++app_external_count;
511 } else {
512 ++app_user_count;
513 }
514 break;
515 case Manifest::TYPE_PLATFORM_APP:
516 ++platform_app_count;
517 if (Manifest::IsExternalLocation(location)) {
518 ++app_external_count;
519 } else {
520 ++app_user_count;
521 }
522 break;
523 case Manifest::TYPE_EXTENSION:
524 default:
525 if (Manifest::IsExternalLocation(location)) {
526 ++extension_external_count;
527 } else {
528 ++extension_user_count;
529 }
530 break;
531 }
532
533 // We check the manifest key (instead of the ExtensionActionManager) because
534 // we want to know how many extensions have a given type of action as part
535 // of their code, rather than as part of the extension action redesign
536 // (which gives each extension an action).
537 if (extension->manifest()->HasKey(manifest_keys::kPageAction))
538 ++page_action_count;
539 else if (extension->manifest()->HasKey(manifest_keys::kBrowserAction))
540 ++browser_action_count;
541 else
542 ++no_action_count;
543
544 RecordCreationFlags(extension);
545
546 ExtensionService::RecordPermissionMessagesHistogram(extension, "Load");
547
548 // For incognito and file access, skip anything that doesn't appear in
549 // settings. Also, policy-installed (and unpacked of course, checked above)
550 // extensions are boring.
551 if (ui_util::ShouldDisplayInExtensionSettings(*extension) &&
552 !Manifest::IsPolicyLocation(extension->location())) {
553 if (util::CanBeIncognitoEnabled(extension)) {
554 if (util::IsIncognitoEnabled(extension->id(), profile))
555 ++incognito_allowed_count;
556 else
557 ++incognito_not_allowed_count;
558 }
559 if (extension->wants_file_access()) {
560 if (util::AllowFileAccess(extension->id(), profile))
561 ++file_access_allowed_count;
562 else
563 ++file_access_not_allowed_count;
564 }
565 }
566
567 if (!ManifestURL::UpdatesFromGallery(extension))
568 ++off_store_item_count;
569
570 ScriptingPermissionsModifier scripting_modifier(profile, extension);
571 // NOTE: CanAffectExtension() returns false in all cases when the
572 // RuntimeHostPermissions feature is disabled.
573 if (scripting_modifier.CanAffectExtension()) {
574 bool extension_has_withheld_hosts =
575 scripting_modifier.HasWithheldHostPermissions();
576 UMA_HISTOGRAM_BOOLEAN(
577 "Extensions.RuntimeHostPermissions.ExtensionHasWithheldHosts",
578 extension_has_withheld_hosts);
579 if (extension_has_withheld_hosts) {
580 // Record the number of granted hosts if and only if the extension
581 // has withheld host permissions. This lets us equate "0" granted
582 // hosts to "on click only".
583 size_t num_granted_hosts = 0;
584 for (const auto& pattern : extension->permissions_data()
585 ->active_permissions()
586 .effective_hosts()) {
587 // Ignore chrome:-scheme patterns (like chrome://favicon); these
588 // aren't withheld, and thus shouldn't be considered "granted".
589 if (pattern.scheme() != content::kChromeUIScheme)
590 ++num_granted_hosts;
591 }
592 // TODO(devlin): This only takes into account the granted hosts that
593 // were also requested by the extension (because it looks at the active
594 // permissions). We could potentially also record the granted hosts that
595 // were explicitly not requested.
596 UMA_HISTOGRAM_COUNTS_100(
597 "Extensions.RuntimeHostPermissions.GrantedHostCount",
598 num_granted_hosts);
599 }
600 }
601 }
602
603 const ExtensionSet& disabled_extensions =
604 extension_registry_->disabled_extensions();
605
606 for (ExtensionSet::const_iterator ex = disabled_extensions.begin();
607 ex != disabled_extensions.end();
608 ++ex) {
609 if (extension_prefs_->DidExtensionEscalatePermissions((*ex)->id())) {
610 ++disabled_for_permissions_count;
611 }
612 RecordDisableReasons(extension_prefs_->GetDisableReasons((*ex)->id()));
613 if (Manifest::IsExternalLocation((*ex)->location())) {
614 // See loop above for ENABLED.
615 if (ManifestURL::UpdatesFromGallery(ex->get())) {
616 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
617 EXTERNAL_ITEM_WEBSTORE_DISABLED,
618 EXTERNAL_ITEM_MAX_ITEMS);
619 } else {
620 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
621 EXTERNAL_ITEM_NONWEBSTORE_DISABLED,
622 EXTERNAL_ITEM_MAX_ITEMS);
623 }
624 }
625 }
626
627 base::UmaHistogramCounts100("Extensions.LoadApp",
628 app_user_count + app_external_count);
629 base::UmaHistogramCounts100("Extensions.LoadAppUser", app_user_count);
630 base::UmaHistogramCounts100("Extensions.LoadAppExternal", app_external_count);
631 base::UmaHistogramCounts100("Extensions.LoadHostedApp", hosted_app_count);
632 base::UmaHistogramCounts100("Extensions.LoadPackagedApp",
633 legacy_packaged_app_count);
634 base::UmaHistogramCounts100("Extensions.LoadPlatformApp", platform_app_count);
635 base::UmaHistogramCounts100("Extensions.LoadExtension",
636 extension_user_count + extension_external_count);
637 base::UmaHistogramCounts100("Extensions.LoadExtensionUser",
638 extension_user_count);
639 base::UmaHistogramCounts100("Extensions.LoadExtensionExternal",
640 extension_external_count);
641 base::UmaHistogramCounts100("Extensions.LoadUserScript", user_script_count);
642 base::UmaHistogramCounts100("Extensions.LoadTheme", theme_count);
643 // Histogram name different for legacy reasons.
644 base::UmaHistogramCounts100("PageActionController.ExtensionsWithPageActions",
645 page_action_count);
646 base::UmaHistogramCounts100("Extensions.LoadBrowserAction",
647 browser_action_count);
648 base::UmaHistogramCounts100("Extensions.LoadNoExtensionAction",
649 no_action_count);
650 base::UmaHistogramCounts100("Extensions.DisabledForPermissions",
651 disabled_for_permissions_count);
652 // TODO(kelvinjiang): Remove this histogram if it's not used anymore.
653 base::UmaHistogramCounts100("Extensions.NonWebStoreNewTabPageOverrides",
654 non_webstore_ntp_override_count);
655 base::UmaHistogramCounts100("Extensions.NewTabPageOverrides",
656 ntp_override_count);
657 base::UmaHistogramCounts100("Extensions.SearchEngineOverrides",
658 search_engine_override_count);
659 base::UmaHistogramCounts100("Extensions.StartupPagesOverrides",
660 startup_pages_override_count);
661 base::UmaHistogramCounts100("Extensions.HomepageOverrides",
662 homepage_override_count);
663 if (incognito_allowed_count + incognito_not_allowed_count > 0) {
664 base::UmaHistogramCounts100("Extensions.IncognitoAllowed",
665 incognito_allowed_count);
666 base::UmaHistogramCounts100("Extensions.IncognitoNotAllowed",
667 incognito_not_allowed_count);
668 }
669 if (file_access_allowed_count + file_access_not_allowed_count > 0) {
670 base::UmaHistogramCounts100("Extensions.FileAccessAllowed",
671 file_access_allowed_count);
672 base::UmaHistogramCounts100("Extensions.FileAccessNotAllowed",
673 file_access_not_allowed_count);
674 }
675 base::UmaHistogramCounts100(
676 "Extensions.CorruptExtensionTotalDisables",
677 extension_prefs_->GetPrefAsInteger(kCorruptedDisableCount));
678 base::UmaHistogramCounts100("Extensions.EventlessEventPages",
679 eventless_event_pages_count);
680 base::UmaHistogramCounts100("Extensions.LoadOffStoreItems",
681 off_store_item_count);
682 base::UmaHistogramCounts100("Extensions.WebRequestBlockingCount",
683 web_request_blocking_count);
684 base::UmaHistogramCounts100("Extensions.WebRequestCount", web_request_count);
685 }
686
GetCreationFlags(const ExtensionInfo * info)687 int InstalledLoader::GetCreationFlags(const ExtensionInfo* info) {
688 int flags = extension_prefs_->GetCreationFlags(info->extension_id);
689 if (!Manifest::IsUnpackedLocation(info->extension_location))
690 flags |= Extension::REQUIRE_KEY;
691 if (extension_prefs_->AllowFileAccess(info->extension_id))
692 flags |= Extension::ALLOW_FILE_ACCESS;
693 return flags;
694 }
695
696 } // namespace extensions
697