Remove keyboard_ui.css and manifest_keyboard.json
[chromium-blink-merge.git] / chrome / browser / extensions / component_loader.cc
blobce26c96a4e9ea642f3aa8d02829f42e30247c87d
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.
5 #include "chrome/browser/extensions/component_loader.h"
7 #include <string>
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/metrics/histogram_macros.h"
14 #include "base/path_service.h"
15 #include "base/profiler/scoped_profile.h"
16 #include "base/time/time.h"
17 #include "base/trace_event/trace_event.h"
18 #include "chrome/browser/extensions/component_extensions_whitelist/whitelist.h"
19 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/pdf/pdf_extension_util.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/search/hotword_service.h"
23 #include "chrome/browser/search/hotword_service_factory.h"
24 #include "chrome/browser/signin/signin_manager_factory.h"
25 #include "chrome/common/chrome_paths.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/chrome_version_info.h"
28 #include "chrome/common/extensions/extension_constants.h"
29 #include "chrome/grit/generated_resources.h"
30 #include "components/crx_file/id_util.h"
31 #include "components/signin/core/browser/signin_manager.h"
32 #include "components/signin/core/browser/signin_manager_base.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/plugin_service.h"
35 #include "extensions/common/constants.h"
36 #include "extensions/common/extension.h"
37 #include "extensions/common/extension_l10n_util.h"
38 #include "extensions/common/file_util.h"
39 #include "extensions/common/manifest_constants.h"
40 #include "grit/browser_resources.h"
41 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/base/resource/resource_bundle.h"
44 #if defined(OS_CHROMEOS)
45 #include "components/chrome_apps/grit/chrome_apps_resources.h"
46 #include "components/user_manager/user_manager.h"
47 #include "grit/keyboard_resources.h"
48 #include "ui/file_manager/grit/file_manager_resources.h"
49 #include "ui/keyboard/keyboard_util.h"
50 #endif
52 #if defined(GOOGLE_CHROME_BUILD)
53 #include "chrome/browser/defaults.h"
54 #endif
56 #if defined(OS_CHROMEOS)
57 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
58 #include "chromeos/chromeos_switches.h"
59 #include "content/public/browser/site_instance.h"
60 #include "content/public/browser/storage_partition.h"
61 #include "extensions/browser/extensions_browser_client.h"
62 #include "storage/browser/fileapi/file_system_context.h"
63 #endif
65 #if defined(ENABLE_APP_LIST)
66 #include "chrome/grit/chromium_strings.h"
67 #endif
69 #if defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
70 #include "chrome/browser/ui/app_list/google_now_extension.h"
71 #endif
73 using content::BrowserThread;
75 namespace extensions {
77 namespace {
79 static bool enable_background_extensions_during_testing = false;
81 std::string GenerateId(const base::DictionaryValue* manifest,
82 const base::FilePath& path) {
83 std::string raw_key;
84 std::string id_input;
85 CHECK(manifest->GetString(manifest_keys::kPublicKey, &raw_key));
86 CHECK(Extension::ParsePEMKeyBytes(raw_key, &id_input));
87 std::string id = crx_file::id_util::GenerateId(id_input);
88 return id;
91 #if defined(OS_CHROMEOS)
92 scoped_ptr<base::DictionaryValue>
93 LoadManifestOnFileThread(
94 const base::FilePath& root_directory,
95 const base::FilePath::CharType* manifest_filename) {
96 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
97 std::string error;
98 scoped_ptr<base::DictionaryValue> manifest(
99 file_util::LoadManifest(root_directory, manifest_filename, &error));
100 if (!manifest) {
101 LOG(ERROR) << "Can't load "
102 << root_directory.Append(manifest_filename).AsUTF8Unsafe()
103 << ": " << error;
104 return nullptr;
106 bool localized = extension_l10n_util::LocalizeExtension(
107 root_directory, manifest.get(), &error);
108 CHECK(localized) << error;
109 return manifest.Pass();
112 bool IsNormalSession() {
113 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
114 chromeos::switches::kGuestSession) &&
115 user_manager::UserManager::IsInitialized() &&
116 user_manager::UserManager::Get()->IsUserLoggedIn();
118 #endif // defined(OS_CHROMEOS)
120 } // namespace
122 ComponentLoader::ComponentExtensionInfo::ComponentExtensionInfo(
123 const base::DictionaryValue* manifest, const base::FilePath& directory)
124 : manifest(manifest),
125 root_directory(directory) {
126 if (!root_directory.IsAbsolute()) {
127 CHECK(PathService::Get(chrome::DIR_RESOURCES, &root_directory));
128 root_directory = root_directory.Append(directory);
130 extension_id = GenerateId(manifest, root_directory);
133 ComponentLoader::ComponentLoader(ExtensionServiceInterface* extension_service,
134 PrefService* profile_prefs,
135 PrefService* local_state,
136 Profile* profile)
137 : profile_prefs_(profile_prefs),
138 local_state_(local_state),
139 profile_(profile),
140 extension_service_(extension_service),
141 ignore_whitelist_for_testing_(false),
142 weak_factory_(this) {}
144 ComponentLoader::~ComponentLoader() {
145 ClearAllRegistered();
148 void ComponentLoader::LoadAll() {
149 TRACE_EVENT0("browser,startup", "ComponentLoader::LoadAll");
150 TRACK_SCOPED_REGION("Startup", "ComponentLoader::LoadAll");
151 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.LoadAllComponentTime");
153 for (RegisteredComponentExtensions::iterator it =
154 component_extensions_.begin();
155 it != component_extensions_.end(); ++it) {
156 Load(*it);
160 base::DictionaryValue* ComponentLoader::ParseManifest(
161 const std::string& manifest_contents) const {
162 JSONStringValueDeserializer deserializer(manifest_contents);
163 scoped_ptr<base::Value> manifest(deserializer.Deserialize(NULL, NULL));
165 if (!manifest.get() || !manifest->IsType(base::Value::TYPE_DICTIONARY)) {
166 LOG(ERROR) << "Failed to parse extension manifest.";
167 return NULL;
169 // Transfer ownership to the caller.
170 return static_cast<base::DictionaryValue*>(manifest.release());
173 void ComponentLoader::ClearAllRegistered() {
174 for (RegisteredComponentExtensions::iterator it =
175 component_extensions_.begin();
176 it != component_extensions_.end(); ++it) {
177 delete it->manifest;
180 component_extensions_.clear();
183 std::string ComponentLoader::GetExtensionID(
184 int manifest_resource_id,
185 const base::FilePath& root_directory) {
186 std::string manifest_contents = ResourceBundle::GetSharedInstance().
187 GetRawDataResource(manifest_resource_id).as_string();
188 base::DictionaryValue* manifest = ParseManifest(manifest_contents);
189 if (!manifest)
190 return std::string();
192 ComponentExtensionInfo info(manifest, root_directory);
193 return info.extension_id;
196 std::string ComponentLoader::Add(int manifest_resource_id,
197 const base::FilePath& root_directory) {
198 if (!ignore_whitelist_for_testing_ &&
199 !IsComponentExtensionWhitelisted(manifest_resource_id))
200 return std::string();
202 std::string manifest_contents =
203 ResourceBundle::GetSharedInstance().GetRawDataResource(
204 manifest_resource_id).as_string();
205 return Add(manifest_contents, root_directory, true);
208 std::string ComponentLoader::Add(const std::string& manifest_contents,
209 const base::FilePath& root_directory) {
210 return Add(manifest_contents, root_directory, false);
213 std::string ComponentLoader::Add(const std::string& manifest_contents,
214 const base::FilePath& root_directory,
215 bool skip_whitelist) {
216 // The Value is kept for the lifetime of the ComponentLoader. This is
217 // required in case LoadAll() is called again.
218 base::DictionaryValue* manifest = ParseManifest(manifest_contents);
219 if (manifest)
220 return Add(manifest, root_directory, skip_whitelist);
221 return std::string();
224 std::string ComponentLoader::Add(const base::DictionaryValue* parsed_manifest,
225 const base::FilePath& root_directory,
226 bool skip_whitelist) {
227 ComponentExtensionInfo info(parsed_manifest, root_directory);
228 if (!ignore_whitelist_for_testing_ &&
229 !skip_whitelist &&
230 !IsComponentExtensionWhitelisted(info.extension_id))
231 return std::string();
233 component_extensions_.push_back(info);
234 if (extension_service_->is_ready())
235 Load(info);
236 return info.extension_id;
239 std::string ComponentLoader::AddOrReplace(const base::FilePath& path) {
240 base::FilePath absolute_path = base::MakeAbsoluteFilePath(path);
241 std::string error;
242 scoped_ptr<base::DictionaryValue> manifest(
243 file_util::LoadManifest(absolute_path, &error));
244 if (!manifest) {
245 LOG(ERROR) << "Could not load extension from '" <<
246 absolute_path.value() << "'. " << error;
247 return std::string();
249 Remove(GenerateId(manifest.get(), absolute_path));
251 // We don't check component extensions loaded by path because this is only
252 // used by developers for testing.
253 return Add(manifest.release(), absolute_path, true);
256 void ComponentLoader::Reload(const std::string& extension_id) {
257 for (RegisteredComponentExtensions::iterator it =
258 component_extensions_.begin(); it != component_extensions_.end();
259 ++it) {
260 if (it->extension_id == extension_id) {
261 Load(*it);
262 break;
267 void ComponentLoader::Load(const ComponentExtensionInfo& info) {
268 // TODO(abarth): We should REQUIRE_MODERN_MANIFEST_VERSION once we've updated
269 // our component extensions to the new manifest version.
270 int flags = Extension::REQUIRE_KEY;
272 std::string error;
274 scoped_refptr<const Extension> extension(Extension::Create(
275 info.root_directory,
276 Manifest::COMPONENT,
277 *info.manifest,
278 flags,
279 &error));
280 if (!extension.get()) {
281 LOG(ERROR) << error;
282 return;
285 CHECK_EQ(info.extension_id, extension->id()) << extension->name();
286 extension_service_->AddComponentExtension(extension.get());
289 void ComponentLoader::Remove(const base::FilePath& root_directory) {
290 // Find the ComponentExtensionInfo for the extension.
291 RegisteredComponentExtensions::iterator it = component_extensions_.begin();
292 for (; it != component_extensions_.end(); ++it) {
293 if (it->root_directory == root_directory) {
294 Remove(GenerateId(it->manifest, root_directory));
295 break;
300 void ComponentLoader::Remove(const std::string& id) {
301 RegisteredComponentExtensions::iterator it = component_extensions_.begin();
302 for (; it != component_extensions_.end(); ++it) {
303 if (it->extension_id == id) {
304 UnloadComponent(&(*it));
305 it = component_extensions_.erase(it);
306 break;
311 bool ComponentLoader::Exists(const std::string& id) const {
312 RegisteredComponentExtensions::const_iterator it =
313 component_extensions_.begin();
314 for (; it != component_extensions_.end(); ++it)
315 if (it->extension_id == id)
316 return true;
317 return false;
320 void ComponentLoader::AddFileManagerExtension() {
321 #if defined(OS_CHROMEOS)
322 AddWithNameAndDescription(IDR_FILEMANAGER_MANIFEST,
323 base::FilePath(FILE_PATH_LITERAL("file_manager")),
324 IDS_FILEMANAGER_APP_NAME,
325 IDS_FILEMANAGER_APP_DESCRIPTION);
326 #endif // defined(OS_CHROMEOS)
329 void ComponentLoader::AddVideoPlayerExtension() {
330 #if defined(OS_CHROMEOS)
331 Add(IDR_VIDEO_PLAYER_MANIFEST,
332 base::FilePath(FILE_PATH_LITERAL("video_player")));
333 #endif // defined(OS_CHROMEOS)
336 void ComponentLoader::AddAudioPlayerExtension() {
337 #if defined(OS_CHROMEOS)
338 Add(IDR_AUDIO_PLAYER_MANIFEST,
339 base::FilePath(FILE_PATH_LITERAL("audio_player")));
340 #endif // defined(OS_CHROMEOS)
343 void ComponentLoader::AddGalleryExtension() {
344 #if defined(OS_CHROMEOS)
345 Add(IDR_GALLERY_MANIFEST, base::FilePath(FILE_PATH_LITERAL("gallery")));
346 #endif
349 void ComponentLoader::AddWebstoreWidgetExtension() {
350 #if defined(OS_CHROMEOS)
351 AddWithNameAndDescription(
352 IDR_CHROME_APPS_WEBSTORE_WIDGET_MANIFEST,
353 base::FilePath(FILE_PATH_LITERAL("webstore_widget")),
354 IDS_WEBSTORE_WIDGET_APP_NAME,
355 IDS_WEBSTORE_WIDGET_APP_DESC);
356 #endif
359 void ComponentLoader::AddHangoutServicesExtension() {
360 #if defined(GOOGLE_CHROME_BUILD) || defined(ENABLE_HANGOUT_SERVICES_EXTENSION)
361 Add(IDR_HANGOUT_SERVICES_MANIFEST,
362 base::FilePath(FILE_PATH_LITERAL("hangout_services")));
363 #endif
366 void ComponentLoader::AddHotwordAudioVerificationApp() {
367 if (HotwordServiceFactory::IsAlwaysOnAvailable()) {
368 Add(IDR_HOTWORD_AUDIO_VERIFICATION_MANIFEST,
369 base::FilePath(FILE_PATH_LITERAL("hotword_audio_verification")));
373 void ComponentLoader::AddHotwordHelperExtension() {
374 if (HotwordServiceFactory::IsHotwordAllowed(profile_)) {
375 Add(IDR_HOTWORD_MANIFEST,
376 base::FilePath(FILE_PATH_LITERAL("hotword")));
380 void ComponentLoader::AddImageLoaderExtension() {
381 #if defined(IMAGE_LOADER_EXTENSION)
382 Add(IDR_IMAGE_LOADER_MANIFEST,
383 base::FilePath(FILE_PATH_LITERAL("image_loader")));
384 #endif // defined(IMAGE_LOADER_EXTENSION)
387 void ComponentLoader::AddNetworkSpeechSynthesisExtension() {
388 Add(IDR_NETWORK_SPEECH_SYNTHESIS_MANIFEST,
389 base::FilePath(FILE_PATH_LITERAL("network_speech_synthesis")));
392 void ComponentLoader::AddGoogleNowExtension() {
393 #if defined(ENABLE_GOOGLE_NOW)
394 const char kEnablePrefix[] = "Enable";
395 const char kFieldTrialName[] = "GoogleNow";
396 std::string enable_prefix(kEnablePrefix);
397 std::string field_trial_result =
398 base::FieldTrialList::FindFullName(kFieldTrialName);
400 bool enabled_via_field_trial =
401 field_trial_result.compare(0, enable_prefix.length(), enable_prefix) == 0;
403 // Enable the feature on trybots and trunk builds.
404 bool enabled_via_trunk_build =
405 chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_UNKNOWN;
407 bool is_authenticated =
408 SigninManagerFactory::GetForProfile(profile_)->IsAuthenticated();
410 bool enabled =
411 (enabled_via_field_trial && is_authenticated) || enabled_via_trunk_build;
413 #if defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
414 // Don't load if newer trial is running (== new extension id is available).
415 std::string ignored_extension_id;
416 if (GetGoogleNowExtensionId(&ignored_extension_id)) {
417 enabled = false;
419 #endif // defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
421 if (enabled) {
422 Add(IDR_GOOGLE_NOW_MANIFEST,
423 base::FilePath(FILE_PATH_LITERAL("google_now")));
425 #endif // defined(ENABLE_GOOGLE_NOW)
428 #if defined(OS_CHROMEOS)
429 void ComponentLoader::AddChromeVoxExtension(
430 const base::Closure& done_cb) {
431 base::FilePath resources_path;
432 CHECK(PathService::Get(chrome::DIR_RESOURCES, &resources_path));
434 base::FilePath chromevox_path =
435 resources_path.Append(extension_misc::kChromeVoxExtensionPath);
437 const base::FilePath::CharType* manifest_filename =
438 IsNormalSession() ? extensions::kManifestFilename
439 : extension_misc::kGuestManifestFilename;
440 AddWithManifestFile(
441 manifest_filename,
442 chromevox_path,
443 extension_misc::kChromeVoxExtensionId,
444 done_cb);
447 void ComponentLoader::AddChromeOsSpeechSynthesisExtension() {
448 const base::FilePath::CharType* manifest_filename =
449 IsNormalSession() ? extensions::kManifestFilename
450 : extension_misc::kGuestManifestFilename;
451 AddWithManifestFile(
452 manifest_filename,
453 base::FilePath(extension_misc::kSpeechSynthesisExtensionPath),
454 extension_misc::kSpeechSynthesisExtensionId,
455 base::Bind(&ComponentLoader::EnableFileSystemInGuestMode,
456 weak_factory_.GetWeakPtr(),
457 extension_misc::kChromeVoxExtensionId));
459 #endif
461 void ComponentLoader::AddWithNameAndDescription(
462 int manifest_resource_id,
463 const base::FilePath& root_directory,
464 int name_string_id,
465 int description_string_id) {
466 if (!ignore_whitelist_for_testing_ &&
467 !IsComponentExtensionWhitelisted(manifest_resource_id))
468 return;
470 std::string manifest_contents =
471 ResourceBundle::GetSharedInstance().GetRawDataResource(
472 manifest_resource_id).as_string();
474 // The Value is kept for the lifetime of the ComponentLoader. This is
475 // required in case LoadAll() is called again.
476 base::DictionaryValue* manifest = ParseManifest(manifest_contents);
478 if (manifest) {
479 manifest->SetString(manifest_keys::kName,
480 l10n_util::GetStringUTF8(name_string_id));
481 manifest->SetString(manifest_keys::kDescription,
482 l10n_util::GetStringUTF8(description_string_id));
483 Add(manifest, root_directory, true);
487 void ComponentLoader::AddChromeApp() {
488 #if defined(ENABLE_APP_LIST)
489 AddWithNameAndDescription(IDR_CHROME_APP_MANIFEST,
490 base::FilePath(FILE_PATH_LITERAL("chrome_app")),
491 IDS_SHORT_PRODUCT_NAME,
492 IDS_CHROME_SHORTCUT_DESCRIPTION);
493 #endif
496 void ComponentLoader::AddKeyboardApp() {
497 #if defined(OS_CHROMEOS)
498 Add(IDR_KEYBOARD_MANIFEST, base::FilePath(FILE_PATH_LITERAL("keyboard")));
499 #endif
502 void ComponentLoader::AddWebStoreApp() {
503 #if defined(OS_CHROMEOS)
504 if (!IsNormalSession())
505 return;
506 #endif
508 AddWithNameAndDescription(IDR_WEBSTORE_MANIFEST,
509 base::FilePath(FILE_PATH_LITERAL("web_store")),
510 IDS_WEBSTORE_NAME_STORE,
511 IDS_WEBSTORE_APP_DESCRIPTION);
514 // static
515 void ComponentLoader::EnableBackgroundExtensionsForTesting() {
516 enable_background_extensions_during_testing = true;
519 void ComponentLoader::AddDefaultComponentExtensions(
520 bool skip_session_components) {
521 // Do not add component extensions that have background pages here -- add them
522 // to AddDefaultComponentExtensionsWithBackgroundPages.
523 #if defined(OS_CHROMEOS)
524 Add(IDR_MOBILE_MANIFEST,
525 base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile")));
527 #if defined(GOOGLE_CHROME_BUILD)
528 if (browser_defaults::enable_help_app) {
529 Add(IDR_HELP_MANIFEST, base::FilePath(FILE_PATH_LITERAL(
530 "/usr/share/chromeos-assets/helpapp")));
532 #endif
534 // Skip all other extensions that require user session presence.
535 if (!skip_session_components) {
536 const base::CommandLine* command_line =
537 base::CommandLine::ForCurrentProcess();
538 if (!command_line->HasSwitch(chromeos::switches::kGuestSession))
539 Add(IDR_BOOKMARKS_MANIFEST,
540 base::FilePath(FILE_PATH_LITERAL("bookmark_manager")));
542 Add(IDR_CROSH_BUILTIN_MANIFEST, base::FilePath(FILE_PATH_LITERAL(
543 "/usr/share/chromeos-assets/crosh_builtin")));
545 #else // !defined(OS_CHROMEOS)
546 DCHECK(!skip_session_components);
547 Add(IDR_BOOKMARKS_MANIFEST,
548 base::FilePath(FILE_PATH_LITERAL("bookmark_manager")));
549 // Cloud Print component app. Not required on Chrome OS.
550 Add(IDR_CLOUDPRINT_MANIFEST,
551 base::FilePath(FILE_PATH_LITERAL("cloud_print")));
552 #endif
554 if (!skip_session_components) {
555 AddWebStoreApp();
556 AddChromeApp();
559 AddKeyboardApp();
561 AddDefaultComponentExtensionsWithBackgroundPages(skip_session_components);
563 #if defined(ENABLE_PLUGINS)
564 Add(pdf_extension_util::GetManifest(),
565 base::FilePath(FILE_PATH_LITERAL("pdf")));
566 #endif
569 void ComponentLoader::AddDefaultComponentExtensionsForKioskMode(
570 bool skip_session_components) {
571 // No component extension for kiosk app launch splash screen.
572 if (skip_session_components)
573 return;
575 // Component extensions needed for kiosk apps.
576 AddFileManagerExtension();
578 // Add virtual keyboard.
579 AddKeyboardApp();
581 #if defined(ENABLE_PLUGINS)
582 Add(pdf_extension_util::GetManifest(),
583 base::FilePath(FILE_PATH_LITERAL("pdf")));
584 #endif
587 void ComponentLoader::AddDefaultComponentExtensionsWithBackgroundPages(
588 bool skip_session_components) {
589 const base::CommandLine* command_line =
590 base::CommandLine::ForCurrentProcess();
592 // Component extensions with background pages are not enabled during tests
593 // because they generate a lot of background behavior that can interfere.
594 if (!enable_background_extensions_during_testing &&
595 (command_line->HasSwitch(switches::kTestType) ||
596 command_line->HasSwitch(
597 switches::kDisableComponentExtensionsWithBackgroundPages))) {
598 return;
601 #if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
602 // Since this is a v2 app it has a background page.
603 AddWithNameAndDescription(IDR_GENIUS_APP_MANIFEST,
604 base::FilePath(FILE_PATH_LITERAL(
605 "/usr/share/chromeos-assets/genius_app")),
606 IDS_GENIUS_APP_NAME,
607 IDS_GENIUS_APP_DESCRIPTION);
608 #endif
610 if (!skip_session_components) {
611 AddVideoPlayerExtension();
612 AddAudioPlayerExtension();
613 AddFileManagerExtension();
614 AddGalleryExtension();
615 AddWebstoreWidgetExtension();
617 AddHangoutServicesExtension();
618 AddHotwordAudioVerificationApp();
619 AddHotwordHelperExtension();
620 AddImageLoaderExtension();
621 AddGoogleNowExtension();
623 bool install_feedback = enable_background_extensions_during_testing;
624 #if defined(GOOGLE_CHROME_BUILD)
625 install_feedback = true;
626 #endif // defined(GOOGLE_CHROME_BUILD)
627 if (install_feedback)
628 Add(IDR_FEEDBACK_MANIFEST, base::FilePath(FILE_PATH_LITERAL("feedback")));
630 #if defined(ENABLE_SETTINGS_APP)
631 Add(IDR_SETTINGS_APP_MANIFEST,
632 base::FilePath(FILE_PATH_LITERAL("settings_app")));
633 #endif
636 #if defined(OS_CHROMEOS)
637 if (!skip_session_components) {
638 #if defined(GOOGLE_CHROME_BUILD)
639 if (!command_line->HasSwitch(
640 chromeos::switches::kDisableOfficeEditingComponentApp)) {
641 std::string id = Add(IDR_QUICKOFFICE_MANIFEST, base::FilePath(
642 FILE_PATH_LITERAL("/usr/share/chromeos-assets/quickoffice")));
643 EnableFileSystemInGuestMode(id);
645 #endif // defined(GOOGLE_CHROME_BUILD)
647 Add(IDR_ECHO_MANIFEST,
648 base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/echo")));
650 if (!command_line->HasSwitch(chromeos::switches::kGuestSession)) {
651 Add(IDR_WALLPAPERMANAGER_MANIFEST,
652 base::FilePath(FILE_PATH_LITERAL("chromeos/wallpaper_manager")));
655 Add(IDR_FIRST_RUN_DIALOG_MANIFEST,
656 base::FilePath(FILE_PATH_LITERAL("chromeos/first_run/app")));
658 Add(IDR_NETWORK_CONFIGURATION_MANIFEST,
659 base::FilePath(FILE_PATH_LITERAL("chromeos/network_configuration")));
661 Add(IDR_CONNECTIVITY_DIAGNOSTICS_MANIFEST,
662 base::FilePath(extension_misc::kConnectivityDiagnosticsPath));
663 Add(IDR_CONNECTIVITY_DIAGNOSTICS_LAUNCHER_MANIFEST,
664 base::FilePath(extension_misc::kConnectivityDiagnosticsLauncherPath));
667 // Load ChromeVox extension now if spoken feedback is enabled.
668 if (chromeos::AccessibilityManager::Get() &&
669 chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) {
670 AddChromeVoxExtension(base::Closure());
672 #endif // defined(OS_CHROMEOS)
674 #if defined(GOOGLE_CHROME_BUILD)
675 #if !defined(OS_CHROMEOS) // http://crbug.com/314799
676 AddNetworkSpeechSynthesisExtension();
677 #endif
679 #endif // defined(GOOGLE_CHROME_BUILD)
681 Add(IDR_CRYPTOTOKEN_MANIFEST,
682 base::FilePath(FILE_PATH_LITERAL("cryptotoken")));
685 void ComponentLoader::UnloadComponent(ComponentExtensionInfo* component) {
686 delete component->manifest;
687 if (extension_service_->is_ready()) {
688 extension_service_->
689 RemoveComponentExtension(component->extension_id);
693 void ComponentLoader::EnableFileSystemInGuestMode(const std::string& id) {
694 #if defined(OS_CHROMEOS)
695 if (!IsNormalSession()) {
696 // TODO(dpolukhin): Hack to enable HTML5 temporary file system for
697 // the extension. Some component extensions don't work without temporary
698 // file system access. Make sure temporary file system is enabled in the off
699 // the record browser context (as that is the one used in guest session).
700 content::BrowserContext* off_the_record_context =
701 ExtensionsBrowserClient::Get()->GetOffTheRecordContext(profile_);
702 GURL site = content::SiteInstance::GetSiteForURL(
703 off_the_record_context, Extension::GetBaseURLFromExtensionId(id));
704 storage::FileSystemContext* file_system_context =
705 content::BrowserContext::GetStoragePartitionForSite(
706 off_the_record_context, site)->GetFileSystemContext();
707 file_system_context->EnableTemporaryFileSystemInIncognito();
709 #endif
712 #if defined(OS_CHROMEOS)
713 void ComponentLoader::AddWithManifestFile(
714 const base::FilePath::CharType* manifest_filename,
715 const base::FilePath& root_directory,
716 const char* extension_id,
717 const base::Closure& done_cb) {
718 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
719 BrowserThread::PostTaskAndReplyWithResult(
720 BrowserThread::FILE,
721 FROM_HERE,
722 base::Bind(&LoadManifestOnFileThread, root_directory, manifest_filename),
723 base::Bind(&ComponentLoader::FinishAddWithManifestFile,
724 weak_factory_.GetWeakPtr(),
725 root_directory,
726 extension_id,
727 done_cb));
730 void ComponentLoader::FinishAddWithManifestFile(
731 const base::FilePath& root_directory,
732 const char* extension_id,
733 const base::Closure& done_cb,
734 scoped_ptr<base::DictionaryValue> manifest) {
735 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
736 if (!manifest)
737 return; // Error already logged.
738 std::string actual_extension_id = Add(
739 manifest.release(),
740 root_directory,
741 false);
742 CHECK_EQ(extension_id, actual_extension_id);
743 if (!done_cb.is_null())
744 done_cb.Run();
746 #endif
748 } // namespace extensions