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