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