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 557