• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
LookupWebstoreName()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 
GenerateId(const base::DictionaryValue * manifest,const base::FilePath & path)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>
LoadManifestOnFileThread(const base::FilePath & chromevox_path,const char * manifest_filename)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 
ComponentExtensionInfo(const base::DictionaryValue * manifest,const base::FilePath & directory)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 
ComponentLoader(ExtensionServiceInterface * extension_service,PrefService * profile_prefs,PrefService * local_state,content::BrowserContext * browser_context)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 
~ComponentLoader()139 ComponentLoader::~ComponentLoader() {
140   ClearAllRegistered();
141 }
142 
LoadAll()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 
ParseManifest(const std::string & manifest_contents) const151 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 
ClearAllRegistered()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 
GetExtensionID(int manifest_resource_id,const base::FilePath & root_directory)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 
Add(int manifest_resource_id,const base::FilePath & root_directory)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 
Add(const std::string & manifest_contents,const base::FilePath & root_directory)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 
Add(const base::DictionaryValue * parsed_manifest,const base::FilePath & root_directory)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 
AddOrReplace(const base::FilePath & path)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 
Reload(const std::string & extension_id)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 
Load(const ComponentExtensionInfo & info)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 
Remove(const base::FilePath & root_directory)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 
Remove(const std::string & id)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 
Exists(const std::string & id) const284 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 
AddFileManagerExtension()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 
AddVideoPlayerExtension()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 
AddGalleryExtension()316 void ComponentLoader::AddGalleryExtension() {
317 #if defined(OS_CHROMEOS)
318   Add(IDR_GALLERY_MANIFEST, base::FilePath(FILE_PATH_LITERAL("gallery")));
319 #endif
320 }
321 
AddHangoutServicesExtension()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 
AddHotwordHelperExtension()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 
AddImageLoaderExtension()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 
AddNetworkSpeechSynthesisExtension()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)
AddChromeVoxExtension(const base::Closure & done_cb)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 
AddChromeVoxExtensionWithManifest(const base::FilePath & chromevox_path,const base::Closure & done_cb,scoped_ptr<base::DictionaryValue> manifest)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 
AddChromeOsSpeechSynthesisExtension()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 
AddWithName(int manifest_resource_id,const base::FilePath & root_directory,const std::string & name)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 
AddChromeApp()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 
AddKeyboardApp()420 void ComponentLoader::AddKeyboardApp() {
421 #if defined(OS_CHROMEOS)
422   Add(IDR_KEYBOARD_MANIFEST, base::FilePath(FILE_PATH_LITERAL("keyboard")));
423 #endif
424 }
425 
AddWebStoreApp()426 void ComponentLoader::AddWebStoreApp() {
427   AddWithName(IDR_WEBSTORE_MANIFEST,
428               base::FilePath(FILE_PATH_LITERAL("web_store")),
429               LookupWebstoreName());
430 }
431 
432 // static
EnableBackgroundExtensionsForTesting()433 void ComponentLoader::EnableBackgroundExtensionsForTesting() {
434   enable_background_extensions_during_testing = true;
435 }
436 
AddDefaultComponentExtensions(bool skip_session_components)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 
AddDefaultComponentExtensionsForKioskMode(bool skip_session_components)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 
AddDefaultComponentExtensionsWithBackgroundPages(bool skip_session_components)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 
UnloadComponent(ComponentExtensionInfo * component)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 
EnableFileSystemInGuestMode(const std::string & id)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