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