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 <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