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