Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / installed_loader.cc
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
39 using base::UserMetricsAction;
40 using content::BrowserThread;
41
42 namespace extensions {
43
44 namespace errors = manifest_errors;
45
46 namespace {
47
48 // The following enumeration is used in histograms matching
49 // Extensions.ManifestReload*.
50 enum 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.
61 enum 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.
71 enum 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
85 bool 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
99 ManifestReloadReason 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
117 BackgroundPageType 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.
127 void 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
139 InstalledLoader::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
144 InstalledLoader::~InstalledLoader() {
145 }
146
147 void 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
207 void 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
547 int 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