Home | History | Annotate | Download | only in extensions
      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