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/component_loader.h" 6 7 #include <map> 8 #include <string> 9 10 #include "base/command_line.h" 11 #include "base/file_util.h" 12 #include "base/json/json_string_value_serializer.h" 13 #include "base/metrics/field_trial.h" 14 #include "base/path_service.h" 15 #include "base/prefs/pref_change_registrar.h" 16 #include "chrome/browser/chrome_notification_types.h" 17 #include "chrome/browser/extensions/extension_service.h" 18 #include "chrome/browser/search/hotword_service_factory.h" 19 #include "chrome/common/chrome_paths.h" 20 #include "chrome/common/chrome_switches.h" 21 #include "chrome/common/chrome_version_info.h" 22 #include "chrome/common/extensions/extension_constants.h" 23 #include "chrome/common/pref_names.h" 24 #include "content/public/browser/browser_thread.h" 25 #include "content/public/browser/notification_details.h" 26 #include "content/public/browser/notification_source.h" 27 #include "content/public/browser/plugin_service.h" 28 #include "extensions/common/extension.h" 29 #include "extensions/common/file_util.h" 30 #include "extensions/common/id_util.h" 31 #include "extensions/common/manifest_constants.h" 32 #include "grit/browser_resources.h" 33 #include "grit/generated_resources.h" 34 #include "ui/base/l10n/l10n_util.h" 35 #include "ui/base/resource/resource_bundle.h" 36 37 #if defined(OS_CHROMEOS) 38 #include "grit/keyboard_resources.h" 39 #include "ui/file_manager/grit/file_manager_resources.h" 40 #include "ui/keyboard/keyboard_util.h" 41 #endif 42 43 #if defined(GOOGLE_CHROME_BUILD) 44 #include "chrome/browser/defaults.h" 45 #endif 46 47 #if defined(OS_CHROMEOS) 48 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" 49 #include "chrome/browser/chromeos/login/users/user_manager.h" 50 #include "chromeos/chromeos_switches.h" 51 #include "content/public/browser/site_instance.h" 52 #include "content/public/browser/storage_partition.h" 53 #include "extensions/browser/extensions_browser_client.h" 54 #include "webkit/browser/fileapi/file_system_context.h" 55 #endif 56 57 #if defined(ENABLE_APP_LIST) 58 #include "grit/chromium_strings.h" 59 #endif 60 61 using content::BrowserThread; 62 63 namespace extensions { 64 65 namespace { 66 67 static bool enable_background_extensions_during_testing = false; 68 69 std::string LookupWebstoreName() { 70 const char kWebStoreNameFieldTrialName[] = "WebStoreName"; 71 const char kStoreControl[] = "StoreControl"; 72 const char kWebStore[] = "WebStore"; 73 const char kGetApps[] = "GetApps"; 74 const char kAddApps[] = "AddApps"; 75 const char kMoreApps[] = "MoreApps"; 76 77 typedef std::map<std::string, int> NameMap; 78 CR_DEFINE_STATIC_LOCAL(NameMap, names, ()); 79 if (names.empty()) { 80 names.insert(std::make_pair(kStoreControl, IDS_WEBSTORE_NAME_STORE)); 81 names.insert(std::make_pair(kWebStore, IDS_WEBSTORE_NAME_WEBSTORE)); 82 names.insert(std::make_pair(kGetApps, IDS_WEBSTORE_NAME_GET_APPS)); 83 names.insert(std::make_pair(kAddApps, IDS_WEBSTORE_NAME_ADD_APPS)); 84 names.insert(std::make_pair(kMoreApps, IDS_WEBSTORE_NAME_MORE_APPS)); 85 } 86 std::string field_trial_name = 87 base::FieldTrialList::FindFullName(kWebStoreNameFieldTrialName); 88 NameMap::iterator it = names.find(field_trial_name); 89 int string_id = it == names.end() ? names[kStoreControl] : it->second; 90 return l10n_util::GetStringUTF8(string_id); 91 } 92 93 std::string GenerateId(const base::DictionaryValue* manifest, 94 const base::FilePath& path) { 95 std::string raw_key; 96 std::string id_input; 97 CHECK(manifest->GetString(manifest_keys::kPublicKey, &raw_key)); 98 CHECK(Extension::ParsePEMKeyBytes(raw_key, &id_input)); 99 std::string id = id_util::GenerateId(id_input); 100 return id; 101 } 102 103 #if defined(OS_CHROMEOS) 104 scoped_ptr<base::DictionaryValue> 105 LoadManifestOnFileThread( 106 const base::FilePath& chromevox_path, const char* manifest_filename) { 107 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); 108 std::string error; 109 scoped_ptr<base::DictionaryValue> manifest( 110 file_util::LoadManifest(chromevox_path, manifest_filename, &error)); 111 CHECK(manifest) << error; 112 return manifest.Pass(); 113 } 114 #endif // defined(OS_CHROMEOS) 115 116 } // namespace 117 118 ComponentLoader::ComponentExtensionInfo::ComponentExtensionInfo( 119 const base::DictionaryValue* manifest, const base::FilePath& directory) 120 : manifest(manifest), 121 root_directory(directory) { 122 if (!root_directory.IsAbsolute()) { 123 CHECK(PathService::Get(chrome::DIR_RESOURCES, &root_directory)); 124 root_directory = root_directory.Append(directory); 125 } 126 extension_id = GenerateId(manifest, root_directory); 127 } 128 129 ComponentLoader::ComponentLoader(ExtensionServiceInterface* extension_service, 130 PrefService* profile_prefs, 131 PrefService* local_state, 132 content::BrowserContext* browser_context) 133 : profile_prefs_(profile_prefs), 134 local_state_(local_state), 135 browser_context_(browser_context), 136 extension_service_(extension_service), 137 weak_factory_(this) {} 138 139 ComponentLoader::~ComponentLoader() { 140 ClearAllRegistered(); 141 } 142 143 void ComponentLoader::LoadAll() { 144 for (RegisteredComponentExtensions::iterator it = 145 component_extensions_.begin(); 146 it != component_extensions_.end(); ++it) { 147 Load(*it); 148 } 149 } 150 151 base::DictionaryValue* ComponentLoader::ParseManifest( 152 const std::string& manifest_contents) const { 153 JSONStringValueSerializer serializer(manifest_contents); 154 scoped_ptr<base::Value> manifest(serializer.Deserialize(NULL, NULL)); 155 156 if (!manifest.get() || !manifest->IsType(base::Value::TYPE_DICTIONARY)) { 157 LOG(ERROR) << "Failed to parse extension manifest."; 158 return NULL; 159 } 160 // Transfer ownership to the caller. 161 return static_cast<base::DictionaryValue*>(manifest.release()); 162 } 163 164 void ComponentLoader::ClearAllRegistered() { 165 for (RegisteredComponentExtensions::iterator it = 166 component_extensions_.begin(); 167 it != component_extensions_.end(); ++it) { 168 delete it->manifest; 169 } 170 171 component_extensions_.clear(); 172 } 173 174 std::string ComponentLoader::GetExtensionID( 175 int manifest_resource_id, 176 const base::FilePath& root_directory) { 177 std::string manifest_contents = ResourceBundle::GetSharedInstance(). 178 GetRawDataResource(manifest_resource_id).as_string(); 179 base::DictionaryValue* manifest = ParseManifest(manifest_contents); 180 if (!manifest) 181 return std::string(); 182 183 ComponentExtensionInfo info(manifest, root_directory); 184 return info.extension_id; 185 } 186 187 std::string ComponentLoader::Add(int manifest_resource_id, 188 const base::FilePath& root_directory) { 189 std::string manifest_contents = 190 ResourceBundle::GetSharedInstance().GetRawDataResource( 191 manifest_resource_id).as_string(); 192 return Add(manifest_contents, root_directory); 193 } 194 195 std::string ComponentLoader::Add(const std::string& manifest_contents, 196 const base::FilePath& root_directory) { 197 // The Value is kept for the lifetime of the ComponentLoader. This is 198 // required in case LoadAll() is called again. 199 base::DictionaryValue* manifest = ParseManifest(manifest_contents); 200 if (manifest) 201 return Add(manifest, root_directory); 202 return std::string(); 203 } 204 205 std::string ComponentLoader::Add(const base::DictionaryValue* parsed_manifest, 206 const base::FilePath& root_directory) { 207 ComponentExtensionInfo info(parsed_manifest, root_directory); 208 component_extensions_.push_back(info); 209 if (extension_service_->is_ready()) 210 Load(info); 211 return info.extension_id; 212 } 213 214 std::string ComponentLoader::AddOrReplace(const base::FilePath& path) { 215 base::FilePath absolute_path = base::MakeAbsoluteFilePath(path); 216 std::string error; 217 scoped_ptr<base::DictionaryValue> manifest( 218 file_util::LoadManifest(absolute_path, &error)); 219 if (!manifest) { 220 LOG(ERROR) << "Could not load extension from '" << 221 absolute_path.value() << "'. " << error; 222 return std::string(); 223 } 224 Remove(GenerateId(manifest.get(), absolute_path)); 225 226 return Add(manifest.release(), absolute_path); 227 } 228 229 void ComponentLoader::Reload(const std::string& extension_id) { 230 for (RegisteredComponentExtensions::iterator it = 231 component_extensions_.begin(); it != component_extensions_.end(); 232 ++it) { 233 if (it->extension_id == extension_id) { 234 Load(*it); 235 break; 236 } 237 } 238 } 239 240 void ComponentLoader::Load(const ComponentExtensionInfo& info) { 241 // TODO(abarth): We should REQUIRE_MODERN_MANIFEST_VERSION once we've updated 242 // our component extensions to the new manifest version. 243 int flags = Extension::REQUIRE_KEY; 244 245 std::string error; 246 247 scoped_refptr<const Extension> extension(Extension::Create( 248 info.root_directory, 249 Manifest::COMPONENT, 250 *info.manifest, 251 flags, 252 &error)); 253 if (!extension.get()) { 254 LOG(ERROR) << error; 255 return; 256 } 257 258 CHECK_EQ(info.extension_id, extension->id()) << extension->name(); 259 extension_service_->AddComponentExtension(extension.get()); 260 } 261 262 void ComponentLoader::Remove(const base::FilePath& root_directory) { 263 // Find the ComponentExtensionInfo for the extension. 264 RegisteredComponentExtensions::iterator it = component_extensions_.begin(); 265 for (; it != component_extensions_.end(); ++it) { 266 if (it->root_directory == root_directory) { 267 Remove(GenerateId(it->manifest, root_directory)); 268 break; 269 } 270 } 271 } 272 273 void ComponentLoader::Remove(const std::string& id) { 274 RegisteredComponentExtensions::iterator it = component_extensions_.begin(); 275 for (; it != component_extensions_.end(); ++it) { 276 if (it->extension_id == id) { 277 UnloadComponent(&(*it)); 278 it = component_extensions_.erase(it); 279 break; 280 } 281 } 282 } 283 284 bool ComponentLoader::Exists(const std::string& id) const { 285 RegisteredComponentExtensions::const_iterator it = 286 component_extensions_.begin(); 287 for (; it != component_extensions_.end(); ++it) 288 if (it->extension_id == id) 289 return true; 290 return false; 291 } 292 293 void ComponentLoader::AddFileManagerExtension() { 294 #if defined(OS_CHROMEOS) 295 #ifndef NDEBUG 296 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 297 if (command_line->HasSwitch(switches::kFileManagerExtensionPath)) { 298 base::FilePath filemgr_extension_path( 299 command_line->GetSwitchValuePath(switches::kFileManagerExtensionPath)); 300 Add(IDR_FILEMANAGER_MANIFEST, filemgr_extension_path); 301 return; 302 } 303 #endif // NDEBUG 304 Add(IDR_FILEMANAGER_MANIFEST, 305 base::FilePath(FILE_PATH_LITERAL("file_manager"))); 306 #endif // defined(OS_CHROMEOS) 307 } 308 309 void ComponentLoader::AddVideoPlayerExtension() { 310 #if defined(OS_CHROMEOS) 311 Add(IDR_VIDEO_PLAYER_MANIFEST, 312 base::FilePath(FILE_PATH_LITERAL("video_player"))); 313 #endif // defined(OS_CHROMEOS) 314 } 315 316 void ComponentLoader::AddGalleryExtension() { 317 #if defined(OS_CHROMEOS) 318 Add(IDR_GALLERY_MANIFEST, base::FilePath(FILE_PATH_LITERAL("gallery"))); 319 #endif 320 } 321 322 void ComponentLoader::AddHangoutServicesExtension() { 323 #if defined(GOOGLE_CHROME_BUILD) || defined(ENABLE_HANGOUT_SERVICES_EXTENSION) 324 Add(IDR_HANGOUT_SERVICES_MANIFEST, 325 base::FilePath(FILE_PATH_LITERAL("hangout_services"))); 326 #endif 327 } 328 329 void ComponentLoader::AddHotwordHelperExtension() { 330 if (HotwordServiceFactory::IsHotwordAllowed(browser_context_)) { 331 Add(IDR_HOTWORD_HELPER_MANIFEST, 332 base::FilePath(FILE_PATH_LITERAL("hotword_helper"))); 333 } 334 } 335 336 void ComponentLoader::AddImageLoaderExtension() { 337 #if defined(IMAGE_LOADER_EXTENSION) 338 Add(IDR_IMAGE_LOADER_MANIFEST, 339 base::FilePath(FILE_PATH_LITERAL("image_loader"))); 340 #endif // defined(IMAGE_LOADER_EXTENSION) 341 } 342 343 void ComponentLoader::AddNetworkSpeechSynthesisExtension() { 344 Add(IDR_NETWORK_SPEECH_SYNTHESIS_MANIFEST, 345 base::FilePath(FILE_PATH_LITERAL("network_speech_synthesis"))); 346 } 347 348 #if defined(OS_CHROMEOS) 349 void ComponentLoader::AddChromeVoxExtension( 350 const base::Closure& done_cb) { 351 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 352 base::FilePath resources_path; 353 PathService::Get(chrome::DIR_RESOURCES, &resources_path); 354 base::FilePath chromevox_path = 355 resources_path.Append(extension_misc::kChromeVoxExtensionPath); 356 357 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 358 const char* manifest_filename = 359 command_line->HasSwitch(chromeos::switches::kGuestSession) ? 360 extension_misc::kChromeVoxGuestManifestFilename : 361 extension_misc::kChromeVoxManifestFilename; 362 BrowserThread::PostTaskAndReplyWithResult( 363 BrowserThread::FILE, 364 FROM_HERE, 365 base::Bind(&LoadManifestOnFileThread, chromevox_path, manifest_filename), 366 base::Bind(&ComponentLoader::AddChromeVoxExtensionWithManifest, 367 weak_factory_.GetWeakPtr(), 368 chromevox_path, 369 done_cb)); 370 } 371 372 void ComponentLoader::AddChromeVoxExtensionWithManifest( 373 const base::FilePath& chromevox_path, 374 const base::Closure& done_cb, 375 scoped_ptr<base::DictionaryValue> manifest) { 376 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 377 std::string extension_id = Add(manifest.release(), chromevox_path); 378 CHECK_EQ(extension_misc::kChromeVoxExtensionId, extension_id); 379 if (!done_cb.is_null()) 380 done_cb.Run(); 381 } 382 383 std::string ComponentLoader::AddChromeOsSpeechSynthesisExtension() { 384 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 385 int idr = command_line->HasSwitch(chromeos::switches::kGuestSession) ? 386 IDR_SPEECH_SYNTHESIS_GUEST_MANIFEST : IDR_SPEECH_SYNTHESIS_MANIFEST; 387 std::string id = Add(idr, 388 base::FilePath(extension_misc::kSpeechSynthesisExtensionPath)); 389 EnableFileSystemInGuestMode(id); 390 return id; 391 } 392 #endif 393 394 void ComponentLoader::AddWithName(int manifest_resource_id, 395 const base::FilePath& root_directory, 396 const std::string& name) { 397 std::string manifest_contents = 398 ResourceBundle::GetSharedInstance().GetRawDataResource( 399 manifest_resource_id).as_string(); 400 401 // The Value is kept for the lifetime of the ComponentLoader. This is 402 // required in case LoadAll() is called again. 403 base::DictionaryValue* manifest = ParseManifest(manifest_contents); 404 405 if (manifest) { 406 // Update manifest to use a proper name. 407 manifest->SetString(manifest_keys::kName, name); 408 Add(manifest, root_directory); 409 } 410 } 411 412 void ComponentLoader::AddChromeApp() { 413 #if defined(ENABLE_APP_LIST) 414 AddWithName(IDR_CHROME_APP_MANIFEST, 415 base::FilePath(FILE_PATH_LITERAL("chrome_app")), 416 l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME)); 417 #endif 418 } 419 420 void ComponentLoader::AddKeyboardApp() { 421 #if defined(OS_CHROMEOS) 422 Add(IDR_KEYBOARD_MANIFEST, base::FilePath(FILE_PATH_LITERAL("keyboard"))); 423 #endif 424 } 425 426 void ComponentLoader::AddWebStoreApp() { 427 AddWithName(IDR_WEBSTORE_MANIFEST, 428 base::FilePath(FILE_PATH_LITERAL("web_store")), 429 LookupWebstoreName()); 430 } 431 432 // static 433 void ComponentLoader::EnableBackgroundExtensionsForTesting() { 434 enable_background_extensions_during_testing = true; 435 } 436 437 void ComponentLoader::AddDefaultComponentExtensions( 438 bool skip_session_components) { 439 // Do not add component extensions that have background pages here -- add them 440 // to AddDefaultComponentExtensionsWithBackgroundPages. 441 #if defined(OS_CHROMEOS) 442 Add(IDR_MOBILE_MANIFEST, 443 base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile"))); 444 445 #if defined(GOOGLE_CHROME_BUILD) 446 if (browser_defaults::enable_help_app) { 447 Add(IDR_HELP_MANIFEST, base::FilePath(FILE_PATH_LITERAL( 448 "/usr/share/chromeos-assets/helpapp"))); 449 } 450 #endif 451 452 // Skip all other extensions that require user session presence. 453 if (!skip_session_components) { 454 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 455 if (!command_line->HasSwitch(chromeos::switches::kGuestSession)) 456 Add(IDR_BOOKMARKS_MANIFEST, 457 base::FilePath(FILE_PATH_LITERAL("bookmark_manager"))); 458 459 Add(IDR_CROSH_BUILTIN_MANIFEST, base::FilePath(FILE_PATH_LITERAL( 460 "/usr/share/chromeos-assets/crosh_builtin"))); 461 } 462 #else // !defined(OS_CHROMEOS) 463 DCHECK(!skip_session_components); 464 Add(IDR_BOOKMARKS_MANIFEST, 465 base::FilePath(FILE_PATH_LITERAL("bookmark_manager"))); 466 // Cloud Print component app. Not required on Chrome OS. 467 Add(IDR_CLOUDPRINT_MANIFEST, 468 base::FilePath(FILE_PATH_LITERAL("cloud_print"))); 469 #endif 470 471 if (!skip_session_components) { 472 AddWebStoreApp(); 473 AddChromeApp(); 474 } 475 476 AddKeyboardApp(); 477 478 AddDefaultComponentExtensionsWithBackgroundPages(skip_session_components); 479 } 480 481 void ComponentLoader::AddDefaultComponentExtensionsForKioskMode( 482 bool skip_session_components) { 483 // No component extension for kiosk app launch splash screen. 484 if (skip_session_components) 485 return; 486 487 // Component extensions needed for kiosk apps. 488 AddVideoPlayerExtension(); 489 AddFileManagerExtension(); 490 AddGalleryExtension(); 491 492 // Add virtual keyboard. 493 AddKeyboardApp(); 494 } 495 496 void ComponentLoader::AddDefaultComponentExtensionsWithBackgroundPages( 497 bool skip_session_components) { 498 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 499 500 // Component extensions with background pages are not enabled during tests 501 // because they generate a lot of background behavior that can interfere. 502 if (!enable_background_extensions_during_testing && 503 (command_line->HasSwitch(switches::kTestType) || 504 command_line->HasSwitch( 505 switches::kDisableComponentExtensionsWithBackgroundPages))) { 506 return; 507 } 508 509 #if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD) 510 // Since this is a v2 app it has a background page. 511 if (!command_line->HasSwitch(chromeos::switches::kDisableGeniusApp)) { 512 AddWithName(IDR_GENIUS_APP_MANIFEST, 513 base::FilePath(FILE_PATH_LITERAL( 514 "/usr/share/chromeos-assets/genius_app")), 515 l10n_util::GetStringUTF8(IDS_GENIUS_APP_NAME)); 516 } 517 #endif 518 519 if (!skip_session_components) { 520 AddVideoPlayerExtension(); 521 AddFileManagerExtension(); 522 AddGalleryExtension(); 523 524 AddHangoutServicesExtension(); 525 AddHotwordHelperExtension(); 526 AddImageLoaderExtension(); 527 528 #if defined(ENABLE_SETTINGS_APP) 529 Add(IDR_SETTINGS_APP_MANIFEST, 530 base::FilePath(FILE_PATH_LITERAL("settings_app"))); 531 #endif 532 } 533 534 // If (!enable_background_extensions_during_testing || this isn't a test) 535 // install_feedback = false; 536 bool install_feedback = enable_background_extensions_during_testing; 537 #if defined(GOOGLE_CHROME_BUILD) 538 install_feedback = true; 539 #endif // defined(GOOGLE_CHROME_BUILD) 540 if (install_feedback) 541 Add(IDR_FEEDBACK_MANIFEST, base::FilePath(FILE_PATH_LITERAL("feedback"))); 542 543 #if defined(OS_CHROMEOS) 544 if (!skip_session_components) { 545 #if defined(GOOGLE_CHROME_BUILD) 546 if (!command_line->HasSwitch( 547 chromeos::switches::kDisableQuickofficeComponentApp)) { 548 std::string id = Add(IDR_QUICKOFFICE_MANIFEST, base::FilePath( 549 FILE_PATH_LITERAL("/usr/share/chromeos-assets/quickoffice"))); 550 EnableFileSystemInGuestMode(id); 551 } 552 #endif // defined(GOOGLE_CHROME_BUILD) 553 554 Add(IDR_ECHO_MANIFEST, 555 base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/echo"))); 556 557 if (!command_line->HasSwitch(chromeos::switches::kGuestSession)) { 558 Add(IDR_WALLPAPERMANAGER_MANIFEST, 559 base::FilePath(FILE_PATH_LITERAL("chromeos/wallpaper_manager"))); 560 } 561 562 Add(IDR_FIRST_RUN_DIALOG_MANIFEST, 563 base::FilePath(FILE_PATH_LITERAL("chromeos/first_run/app"))); 564 565 Add(IDR_NETWORK_CONFIGURATION_MANIFEST, 566 base::FilePath(FILE_PATH_LITERAL("chromeos/network_configuration"))); 567 568 Add(IDR_CONNECTIVITY_DIAGNOSTICS_MANIFEST, 569 base::FilePath(extension_misc::kConnectivityDiagnosticsPath)); 570 Add(IDR_CONNECTIVITY_DIAGNOSTICS_LAUNCHER_MANIFEST, 571 base::FilePath(extension_misc::kConnectivityDiagnosticsLauncherPath)); 572 } 573 574 // Load ChromeVox extension now if spoken feedback is enabled. 575 if (chromeos::AccessibilityManager::Get() && 576 chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) { 577 AddChromeVoxExtension(base::Closure()); 578 } 579 #endif // defined(OS_CHROMEOS) 580 581 #if defined(ENABLE_GOOGLE_NOW) 582 const char kEnablePrefix[] = "Enable"; 583 const char kFieldTrialName[] = "GoogleNow"; 584 std::string enable_prefix(kEnablePrefix); 585 std::string field_trial_result = 586 base::FieldTrialList::FindFullName(kFieldTrialName); 587 588 bool enabled_via_field_trial = 589 field_trial_result.compare(0, enable_prefix.length(), enable_prefix) == 0; 590 591 // Enable the feature on trybots and trunk builds. 592 bool enabled_via_trunk_build = 593 chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_UNKNOWN; 594 595 bool enabled = enabled_via_field_trial || enabled_via_trunk_build; 596 597 if (!skip_session_components && enabled) { 598 Add(IDR_GOOGLE_NOW_MANIFEST, 599 base::FilePath(FILE_PATH_LITERAL("google_now"))); 600 } 601 #endif 602 603 #if defined(GOOGLE_CHROME_BUILD) 604 #if !defined(OS_CHROMEOS) // http://crbug.com/314799 605 AddNetworkSpeechSynthesisExtension(); 606 #endif 607 608 if (!skip_session_components && 609 command_line->HasSwitch(switches::kEnableEasyUnlock)) { 610 if (command_line->HasSwitch(switches::kEasyUnlockAppPath)) { 611 base::FilePath easy_unlock_path( 612 command_line->GetSwitchValuePath(switches::kEasyUnlockAppPath)); 613 Add(IDR_EASY_UNLOCK_MANIFEST, easy_unlock_path); 614 } else { 615 #if defined(OS_CHROMEOS) 616 Add(IDR_EASY_UNLOCK_MANIFEST, 617 base::FilePath( 618 FILE_PATH_LITERAL("/usr/share/chromeos-assets/easy_unlock"))); 619 #endif 620 } 621 } 622 #endif // defined(GOOGLE_CHROME_BUILD) 623 624 #if defined(ENABLE_PLUGINS) 625 base::FilePath pdf_path; 626 content::PluginService* plugin_service = 627 content::PluginService::GetInstance(); 628 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kOutOfProcessPdf) && 629 PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path) && 630 plugin_service->GetRegisteredPpapiPluginInfo(pdf_path)) { 631 Add(IDR_PDF_MANIFEST, base::FilePath(FILE_PATH_LITERAL("pdf"))); 632 } 633 #endif 634 635 Add(IDR_CRYPTOTOKEN_MANIFEST, 636 base::FilePath(FILE_PATH_LITERAL("cryptotoken"))); 637 } 638 639 void ComponentLoader::UnloadComponent(ComponentExtensionInfo* component) { 640 delete component->manifest; 641 if (extension_service_->is_ready()) { 642 extension_service_-> 643 RemoveComponentExtension(component->extension_id); 644 } 645 } 646 647 void ComponentLoader::EnableFileSystemInGuestMode(const std::string& id) { 648 #if defined(OS_CHROMEOS) 649 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 650 if (command_line->HasSwitch(chromeos::switches::kGuestSession)) { 651 // TODO(dpolukhin): Hack to enable HTML5 temporary file system for 652 // the extension. Some component extensions don't work without temporary 653 // file system access. Make sure temporary file system is enabled in the off 654 // the record browser context (as that is the one used in guest session). 655 content::BrowserContext* off_the_record_context = 656 ExtensionsBrowserClient::Get()->GetOffTheRecordContext( 657 browser_context_); 658 GURL site = content::SiteInstance::GetSiteForURL( 659 off_the_record_context, Extension::GetBaseURLFromExtensionId(id)); 660 fileapi::FileSystemContext* file_system_context = 661 content::BrowserContext::GetStoragePartitionForSite( 662 off_the_record_context, site)->GetFileSystemContext(); 663 file_system_context->EnableTemporaryFileSystemInIncognito(); 664 } 665 #endif 666 } 667 668 } // namespace extensions 669