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"
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/data_deleter.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/pdf/pdf_extension_util.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/search/hotword_service.h"
24 #include "chrome/browser/search/hotword_service_factory.h"
25 #include "chrome/browser/signin/signin_manager_factory.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/chrome_version_info.h"
29 #include "chrome/common/extensions/extension_constants.h"
30 #include "chrome/grit/generated_resources.h"
31 #include "components/crx_file/id_util.h"
32 #include "components/signin/core/browser/signin_manager.h"
33 #include "components/signin/core/browser/signin_manager_base.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/plugin_service.h"
36 #include "extensions/common/constants.h"
37 #include "extensions/common/extension.h"
38 #include "extensions/common/extension_l10n_util.h"
39 #include "extensions/common/file_util.h"
40 #include "extensions/common/manifest_constants.h"
41 #include "grit/browser_resources.h"
42 #include "ui/base/l10n/l10n_util.h"
43 #include "ui/base/resource/resource_bundle.h"
45 #if defined(OS_CHROMEOS)
46 #include "ash/system/chromeos/devicetype_utils.h"
47 #include "components/chrome_apps/grit/chrome_apps_resources.h"
48 #include "components/user_manager/user_manager.h"
49 #include "grit/keyboard_resources.h"
50 #include "ui/file_manager/grit/file_manager_resources.h"
51 #include "ui/keyboard/keyboard_util.h"
54 #if defined(GOOGLE_CHROME_BUILD)
55 #include "chrome/browser/defaults.h"
58 #if defined(OS_CHROMEOS)
59 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
60 #include "chromeos/chromeos_switches.h"
61 #include "content/public/browser/site_instance.h"
62 #include "content/public/browser/storage_partition.h"
63 #include "extensions/browser/extensions_browser_client.h"
64 #include "storage/browser/fileapi/file_system_context.h"
67 #if defined(ENABLE_APP_LIST)
68 #include "chrome/grit/chromium_strings.h"
71 #if defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
72 #include "chrome/browser/ui/app_list/google_now_extension.h"
75 using content::BrowserThread
;
77 namespace extensions
{
81 static bool enable_background_extensions_during_testing
= false;
83 std::string
GenerateId(const base::DictionaryValue
* manifest
,
84 const base::FilePath
& path
) {
87 CHECK(manifest
->GetString(manifest_keys::kPublicKey
, &raw_key
));
88 CHECK(Extension::ParsePEMKeyBytes(raw_key
, &id_input
));
89 std::string id
= crx_file::id_util::GenerateId(id_input
);
93 #if defined(OS_CHROMEOS)
94 scoped_ptr
<base::DictionaryValue
>
95 LoadManifestOnFileThread(
96 const base::FilePath
& root_directory
,
97 const base::FilePath::CharType
* manifest_filename
) {
98 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
100 scoped_ptr
<base::DictionaryValue
> manifest(
101 file_util::LoadManifest(root_directory
, manifest_filename
, &error
));
103 LOG(ERROR
) << "Can't load "
104 << root_directory
.Append(manifest_filename
).AsUTF8Unsafe()
108 bool localized
= extension_l10n_util::LocalizeExtension(
109 root_directory
, manifest
.get(), &error
);
110 CHECK(localized
) << error
;
111 return manifest
.Pass();
114 bool IsNormalSession() {
115 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
116 chromeos::switches::kGuestSession
) &&
117 user_manager::UserManager::IsInitialized() &&
118 user_manager::UserManager::Get()->IsUserLoggedIn();
120 #endif // defined(OS_CHROMEOS)
124 ComponentLoader::ComponentExtensionInfo::ComponentExtensionInfo(
125 const base::DictionaryValue
* manifest
, const base::FilePath
& directory
)
126 : manifest(manifest
),
127 root_directory(directory
) {
128 if (!root_directory
.IsAbsolute()) {
129 CHECK(PathService::Get(chrome::DIR_RESOURCES
, &root_directory
));
130 root_directory
= root_directory
.Append(directory
);
132 extension_id
= GenerateId(manifest
, root_directory
);
135 ComponentLoader::ComponentLoader(ExtensionServiceInterface
* extension_service
,
136 PrefService
* profile_prefs
,
137 PrefService
* local_state
,
139 : profile_prefs_(profile_prefs
),
140 local_state_(local_state
),
142 extension_service_(extension_service
),
143 ignore_whitelist_for_testing_(false),
144 weak_factory_(this) {}
146 ComponentLoader::~ComponentLoader() {
147 ClearAllRegistered();
150 void ComponentLoader::LoadAll() {
151 TRACE_EVENT0("browser,startup", "ComponentLoader::LoadAll");
152 TRACK_SCOPED_REGION("Startup", "ComponentLoader::LoadAll");
153 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.LoadAllComponentTime");
155 for (RegisteredComponentExtensions::iterator it
=
156 component_extensions_
.begin();
157 it
!= component_extensions_
.end(); ++it
) {
162 base::DictionaryValue
* ComponentLoader::ParseManifest(
163 const std::string
& manifest_contents
) const {
164 JSONStringValueDeserializer
deserializer(manifest_contents
);
165 scoped_ptr
<base::Value
> manifest(deserializer
.Deserialize(NULL
, NULL
));
167 if (!manifest
.get() || !manifest
->IsType(base::Value::TYPE_DICTIONARY
)) {
168 LOG(ERROR
) << "Failed to parse extension manifest.";
171 // Transfer ownership to the caller.
172 return static_cast<base::DictionaryValue
*>(manifest
.release());
175 void ComponentLoader::ClearAllRegistered() {
176 for (RegisteredComponentExtensions::iterator it
=
177 component_extensions_
.begin();
178 it
!= component_extensions_
.end(); ++it
) {
182 component_extensions_
.clear();
185 std::string
ComponentLoader::GetExtensionID(
186 int manifest_resource_id
,
187 const base::FilePath
& root_directory
) {
188 std::string manifest_contents
= ResourceBundle::GetSharedInstance().
189 GetRawDataResource(manifest_resource_id
).as_string();
190 base::DictionaryValue
* manifest
= ParseManifest(manifest_contents
);
192 return std::string();
194 ComponentExtensionInfo
info(manifest
, root_directory
);
195 return info
.extension_id
;
198 std::string
ComponentLoader::Add(int manifest_resource_id
,
199 const base::FilePath
& root_directory
) {
200 if (!ignore_whitelist_for_testing_
&&
201 !IsComponentExtensionWhitelisted(manifest_resource_id
))
202 return std::string();
204 std::string manifest_contents
=
205 ResourceBundle::GetSharedInstance().GetRawDataResource(
206 manifest_resource_id
).as_string();
207 return Add(manifest_contents
, root_directory
, true);
210 std::string
ComponentLoader::Add(const std::string
& manifest_contents
,
211 const base::FilePath
& root_directory
) {
212 return Add(manifest_contents
, root_directory
, false);
215 std::string
ComponentLoader::Add(const std::string
& manifest_contents
,
216 const base::FilePath
& root_directory
,
217 bool skip_whitelist
) {
218 // The Value is kept for the lifetime of the ComponentLoader. This is
219 // required in case LoadAll() is called again.
220 base::DictionaryValue
* manifest
= ParseManifest(manifest_contents
);
222 return Add(manifest
, root_directory
, skip_whitelist
);
223 return std::string();
226 std::string
ComponentLoader::Add(const base::DictionaryValue
* parsed_manifest
,
227 const base::FilePath
& root_directory
,
228 bool skip_whitelist
) {
229 ComponentExtensionInfo
info(parsed_manifest
, root_directory
);
230 if (!ignore_whitelist_for_testing_
&&
232 !IsComponentExtensionWhitelisted(info
.extension_id
))
233 return std::string();
235 component_extensions_
.push_back(info
);
236 if (extension_service_
->is_ready())
238 return info
.extension_id
;
241 std::string
ComponentLoader::AddOrReplace(const base::FilePath
& path
) {
242 base::FilePath absolute_path
= base::MakeAbsoluteFilePath(path
);
244 scoped_ptr
<base::DictionaryValue
> manifest(
245 file_util::LoadManifest(absolute_path
, &error
));
247 LOG(ERROR
) << "Could not load extension from '" <<
248 absolute_path
.value() << "'. " << error
;
249 return std::string();
251 Remove(GenerateId(manifest
.get(), absolute_path
));
253 // We don't check component extensions loaded by path because this is only
254 // used by developers for testing.
255 return Add(manifest
.release(), absolute_path
, true);
258 void ComponentLoader::Reload(const std::string
& extension_id
) {
259 for (RegisteredComponentExtensions::iterator it
=
260 component_extensions_
.begin(); it
!= component_extensions_
.end();
262 if (it
->extension_id
== extension_id
) {
269 void ComponentLoader::Load(const ComponentExtensionInfo
& info
) {
271 scoped_refptr
<const Extension
> extension(CreateExtension(info
, &error
));
272 if (!extension
.get()) {
277 CHECK_EQ(info
.extension_id
, extension
->id()) << extension
->name();
278 extension_service_
->AddComponentExtension(extension
.get());
281 void ComponentLoader::Remove(const base::FilePath
& root_directory
) {
282 // Find the ComponentExtensionInfo for the extension.
283 RegisteredComponentExtensions::iterator it
= component_extensions_
.begin();
284 for (; it
!= component_extensions_
.end(); ++it
) {
285 if (it
->root_directory
== root_directory
) {
286 Remove(GenerateId(it
->manifest
, root_directory
));
292 void ComponentLoader::Remove(const std::string
& id
) {
293 RegisteredComponentExtensions::iterator it
= component_extensions_
.begin();
294 for (; it
!= component_extensions_
.end(); ++it
) {
295 if (it
->extension_id
== id
) {
296 UnloadComponent(&(*it
));
297 it
= component_extensions_
.erase(it
);
303 bool ComponentLoader::Exists(const std::string
& id
) const {
304 RegisteredComponentExtensions::const_iterator it
=
305 component_extensions_
.begin();
306 for (; it
!= component_extensions_
.end(); ++it
)
307 if (it
->extension_id
== id
)
312 void ComponentLoader::AddFileManagerExtension() {
313 #if defined(OS_CHROMEOS)
314 AddWithNameAndDescription(
315 IDR_FILEMANAGER_MANIFEST
,
316 base::FilePath(FILE_PATH_LITERAL("file_manager")),
317 l10n_util::GetStringUTF8(IDS_FILEMANAGER_APP_NAME
),
318 l10n_util::GetStringUTF8(IDS_FILEMANAGER_APP_DESCRIPTION
));
319 #endif // defined(OS_CHROMEOS)
322 void ComponentLoader::AddVideoPlayerExtension() {
323 #if defined(OS_CHROMEOS)
324 Add(IDR_VIDEO_PLAYER_MANIFEST
,
325 base::FilePath(FILE_PATH_LITERAL("video_player")));
326 #endif // defined(OS_CHROMEOS)
329 void ComponentLoader::AddAudioPlayerExtension() {
330 #if defined(OS_CHROMEOS)
331 Add(IDR_AUDIO_PLAYER_MANIFEST
,
332 base::FilePath(FILE_PATH_LITERAL("audio_player")));
333 #endif // defined(OS_CHROMEOS)
336 void ComponentLoader::AddGalleryExtension() {
337 #if defined(OS_CHROMEOS)
338 Add(IDR_GALLERY_MANIFEST
, base::FilePath(FILE_PATH_LITERAL("gallery")));
342 void ComponentLoader::AddWebstoreWidgetExtension() {
343 #if defined(OS_CHROMEOS)
344 AddWithNameAndDescription(
345 IDR_CHROME_APPS_WEBSTORE_WIDGET_MANIFEST
,
346 base::FilePath(FILE_PATH_LITERAL("webstore_widget")),
347 l10n_util::GetStringUTF8(IDS_WEBSTORE_WIDGET_APP_NAME
),
348 l10n_util::GetStringUTF8(IDS_WEBSTORE_WIDGET_APP_DESC
));
352 void ComponentLoader::AddHangoutServicesExtension() {
353 #if defined(GOOGLE_CHROME_BUILD) || defined(ENABLE_HANGOUT_SERVICES_EXTENSION)
354 Add(IDR_HANGOUT_SERVICES_MANIFEST
,
355 base::FilePath(FILE_PATH_LITERAL("hangout_services")));
359 void ComponentLoader::AddHotwordAudioVerificationApp() {
360 if (HotwordServiceFactory::IsAlwaysOnAvailable()) {
361 Add(IDR_HOTWORD_AUDIO_VERIFICATION_MANIFEST
,
362 base::FilePath(FILE_PATH_LITERAL("hotword_audio_verification")));
366 void ComponentLoader::AddHotwordHelperExtension() {
367 if (HotwordServiceFactory::IsHotwordAllowed(profile_
)) {
368 Add(IDR_HOTWORD_MANIFEST
,
369 base::FilePath(FILE_PATH_LITERAL("hotword")));
373 void ComponentLoader::AddImageLoaderExtension() {
374 #if defined(IMAGE_LOADER_EXTENSION)
375 Add(IDR_IMAGE_LOADER_MANIFEST
,
376 base::FilePath(FILE_PATH_LITERAL("image_loader")));
377 #endif // defined(IMAGE_LOADER_EXTENSION)
380 void ComponentLoader::AddNetworkSpeechSynthesisExtension() {
381 Add(IDR_NETWORK_SPEECH_SYNTHESIS_MANIFEST
,
382 base::FilePath(FILE_PATH_LITERAL("network_speech_synthesis")));
385 void ComponentLoader::AddGoogleNowExtension() {
386 #if defined(ENABLE_GOOGLE_NOW)
387 const char kEnablePrefix
[] = "Enable";
388 const char kFieldTrialName
[] = "GoogleNow";
389 std::string
enable_prefix(kEnablePrefix
);
390 std::string field_trial_result
=
391 base::FieldTrialList::FindFullName(kFieldTrialName
);
393 bool enabled_via_field_trial
=
394 field_trial_result
.compare(0, enable_prefix
.length(), enable_prefix
) == 0;
396 // Enable the feature on trybots and trunk builds.
397 bool enabled_via_trunk_build
=
398 chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_UNKNOWN
;
400 bool is_authenticated
=
401 SigninManagerFactory::GetForProfile(profile_
)->IsAuthenticated();
404 (enabled_via_field_trial
&& is_authenticated
) || enabled_via_trunk_build
;
406 #if defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
407 // Don't load if newer trial is running (== new extension id is available).
408 std::string ignored_extension_id
;
409 if (GetGoogleNowExtensionId(&ignored_extension_id
)) {
412 #endif // defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
414 const int google_now_manifest_id
= IDR_GOOGLE_NOW_MANIFEST
;
415 const base::FilePath root_directory
=
416 base::FilePath(FILE_PATH_LITERAL("google_now"));
418 Add(google_now_manifest_id
, root_directory
);
420 DeleteData(google_now_manifest_id
, root_directory
);
422 #endif // defined(ENABLE_GOOGLE_NOW)
425 #if defined(OS_CHROMEOS)
426 void ComponentLoader::AddChromeVoxExtension(
427 const base::Closure
& done_cb
) {
428 base::FilePath resources_path
;
429 CHECK(PathService::Get(chrome::DIR_RESOURCES
, &resources_path
));
431 base::FilePath chromevox_path
=
432 resources_path
.Append(extension_misc::kChromeVoxExtensionPath
);
434 const base::FilePath::CharType
* manifest_filename
=
435 IsNormalSession() ? extensions::kManifestFilename
436 : extension_misc::kGuestManifestFilename
;
440 extension_misc::kChromeVoxExtensionId
,
444 void ComponentLoader::AddChromeOsSpeechSynthesisExtension() {
445 const base::FilePath::CharType
* manifest_filename
=
446 IsNormalSession() ? extensions::kManifestFilename
447 : extension_misc::kGuestManifestFilename
;
450 base::FilePath(extension_misc::kSpeechSynthesisExtensionPath
),
451 extension_misc::kSpeechSynthesisExtensionId
,
452 base::Bind(&ComponentLoader::EnableFileSystemInGuestMode
,
453 weak_factory_
.GetWeakPtr(),
454 extension_misc::kChromeVoxExtensionId
));
458 void ComponentLoader::AddWithNameAndDescription(
459 int manifest_resource_id
,
460 const base::FilePath
& root_directory
,
461 const std::string
& name_string
,
462 const std::string
& description_string
) {
463 if (!ignore_whitelist_for_testing_
&&
464 !IsComponentExtensionWhitelisted(manifest_resource_id
))
467 std::string manifest_contents
=
468 ResourceBundle::GetSharedInstance().GetRawDataResource(
469 manifest_resource_id
).as_string();
471 // The Value is kept for the lifetime of the ComponentLoader. This is
472 // required in case LoadAll() is called again.
473 base::DictionaryValue
* manifest
= ParseManifest(manifest_contents
);
476 manifest
->SetString(manifest_keys::kName
, name_string
);
477 manifest
->SetString(manifest_keys::kDescription
, description_string
);
478 Add(manifest
, root_directory
, true);
482 void ComponentLoader::AddChromeApp() {
483 #if defined(ENABLE_APP_LIST)
484 AddWithNameAndDescription(
485 IDR_CHROME_APP_MANIFEST
, base::FilePath(FILE_PATH_LITERAL("chrome_app")),
486 l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME
),
487 l10n_util::GetStringUTF8(IDS_CHROME_SHORTCUT_DESCRIPTION
));
491 void ComponentLoader::AddKeyboardApp() {
492 #if defined(OS_CHROMEOS)
493 Add(IDR_KEYBOARD_MANIFEST
, base::FilePath(FILE_PATH_LITERAL("keyboard")));
497 void ComponentLoader::AddWebStoreApp() {
498 #if defined(OS_CHROMEOS)
499 if (!IsNormalSession())
503 AddWithNameAndDescription(
504 IDR_WEBSTORE_MANIFEST
, base::FilePath(FILE_PATH_LITERAL("web_store")),
505 l10n_util::GetStringUTF8(IDS_WEBSTORE_NAME_STORE
),
506 l10n_util::GetStringUTF8(IDS_WEBSTORE_APP_DESCRIPTION
));
509 scoped_refptr
<const Extension
> ComponentLoader::CreateExtension(
510 const ComponentExtensionInfo
& info
, std::string
* utf8_error
) {
511 // TODO(abarth): We should REQUIRE_MODERN_MANIFEST_VERSION once we've updated
512 // our component extensions to the new manifest version.
513 int flags
= Extension::REQUIRE_KEY
;
514 return Extension::Create(
523 void ComponentLoader::EnableBackgroundExtensionsForTesting() {
524 enable_background_extensions_during_testing
= true;
527 void ComponentLoader::AddDefaultComponentExtensions(
528 bool skip_session_components
) {
529 // Do not add component extensions that have background pages here -- add them
530 // to AddDefaultComponentExtensionsWithBackgroundPages.
531 #if defined(OS_CHROMEOS)
532 Add(IDR_MOBILE_MANIFEST
,
533 base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile")));
535 #if defined(GOOGLE_CHROME_BUILD)
536 if (browser_defaults::enable_help_app
) {
537 Add(IDR_HELP_MANIFEST
, base::FilePath(FILE_PATH_LITERAL(
538 "/usr/share/chromeos-assets/helpapp")));
542 // Skip all other extensions that require user session presence.
543 if (!skip_session_components
) {
544 const base::CommandLine
* command_line
=
545 base::CommandLine::ForCurrentProcess();
546 if (!command_line
->HasSwitch(chromeos::switches::kGuestSession
))
547 Add(IDR_BOOKMARKS_MANIFEST
,
548 base::FilePath(FILE_PATH_LITERAL("bookmark_manager")));
550 Add(IDR_CROSH_BUILTIN_MANIFEST
, base::FilePath(FILE_PATH_LITERAL(
551 "/usr/share/chromeos-assets/crosh_builtin")));
553 #else // !defined(OS_CHROMEOS)
554 DCHECK(!skip_session_components
);
555 Add(IDR_BOOKMARKS_MANIFEST
,
556 base::FilePath(FILE_PATH_LITERAL("bookmark_manager")));
557 // Cloud Print component app. Not required on Chrome OS.
558 Add(IDR_CLOUDPRINT_MANIFEST
,
559 base::FilePath(FILE_PATH_LITERAL("cloud_print")));
562 if (!skip_session_components
) {
569 AddDefaultComponentExtensionsWithBackgroundPages(skip_session_components
);
571 #if defined(ENABLE_PLUGINS)
572 Add(pdf_extension_util::GetManifest(),
573 base::FilePath(FILE_PATH_LITERAL("pdf")));
577 void ComponentLoader::AddDefaultComponentExtensionsForKioskMode(
578 bool skip_session_components
) {
579 // No component extension for kiosk app launch splash screen.
580 if (skip_session_components
)
583 // Component extensions needed for kiosk apps.
584 AddFileManagerExtension();
586 // Add virtual keyboard.
589 #if defined(ENABLE_PLUGINS)
590 Add(pdf_extension_util::GetManifest(),
591 base::FilePath(FILE_PATH_LITERAL("pdf")));
595 void ComponentLoader::AddDefaultComponentExtensionsWithBackgroundPages(
596 bool skip_session_components
) {
597 const base::CommandLine
* command_line
=
598 base::CommandLine::ForCurrentProcess();
600 // Component extensions with background pages are not enabled during tests
601 // because they generate a lot of background behavior that can interfere.
602 if (!enable_background_extensions_during_testing
&&
603 (command_line
->HasSwitch(switches::kTestType
) ||
604 command_line
->HasSwitch(
605 switches::kDisableComponentExtensionsWithBackgroundPages
))) {
609 #if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
610 // Since this is a v2 app it has a background page.
611 AddWithNameAndDescription(
612 IDR_GENIUS_APP_MANIFEST
, base::FilePath(FILE_PATH_LITERAL(
613 "/usr/share/chromeos-assets/genius_app")),
614 l10n_util::GetStringUTF8(IDS_GENIUS_APP_NAME
),
615 l10n_util::GetStringFUTF8(IDS_GENIUS_APP_DESCRIPTION
,
616 ash::GetChromeOSDeviceName()));
619 if (!skip_session_components
) {
620 AddVideoPlayerExtension();
621 AddAudioPlayerExtension();
622 AddFileManagerExtension();
623 AddGalleryExtension();
624 AddWebstoreWidgetExtension();
626 AddHangoutServicesExtension();
627 AddHotwordAudioVerificationApp();
628 AddHotwordHelperExtension();
629 AddImageLoaderExtension();
630 AddGoogleNowExtension();
632 bool install_feedback
= enable_background_extensions_during_testing
;
633 #if defined(GOOGLE_CHROME_BUILD)
634 install_feedback
= true;
635 #endif // defined(GOOGLE_CHROME_BUILD)
636 if (install_feedback
)
637 Add(IDR_FEEDBACK_MANIFEST
, base::FilePath(FILE_PATH_LITERAL("feedback")));
639 #if defined(ENABLE_SETTINGS_APP)
640 Add(IDR_SETTINGS_APP_MANIFEST
,
641 base::FilePath(FILE_PATH_LITERAL("settings_app")));
645 #if defined(OS_CHROMEOS)
646 if (!skip_session_components
) {
647 #if defined(GOOGLE_CHROME_BUILD)
648 if (!command_line
->HasSwitch(
649 chromeos::switches::kDisableOfficeEditingComponentApp
)) {
650 std::string id
= Add(IDR_QUICKOFFICE_MANIFEST
, base::FilePath(
651 FILE_PATH_LITERAL("/usr/share/chromeos-assets/quickoffice")));
652 EnableFileSystemInGuestMode(id
);
654 #endif // defined(GOOGLE_CHROME_BUILD)
656 Add(IDR_ECHO_MANIFEST
,
657 base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/echo")));
659 if (!command_line
->HasSwitch(chromeos::switches::kGuestSession
)) {
660 Add(IDR_WALLPAPERMANAGER_MANIFEST
,
661 base::FilePath(FILE_PATH_LITERAL("chromeos/wallpaper_manager")));
664 Add(IDR_FIRST_RUN_DIALOG_MANIFEST
,
665 base::FilePath(FILE_PATH_LITERAL("chromeos/first_run/app")));
667 Add(IDR_NETWORK_CONFIGURATION_MANIFEST
,
668 base::FilePath(FILE_PATH_LITERAL("chromeos/network_configuration")));
670 Add(IDR_CONNECTIVITY_DIAGNOSTICS_MANIFEST
,
671 base::FilePath(extension_misc::kConnectivityDiagnosticsPath
));
672 Add(IDR_CONNECTIVITY_DIAGNOSTICS_LAUNCHER_MANIFEST
,
673 base::FilePath(extension_misc::kConnectivityDiagnosticsLauncherPath
));
676 // Load ChromeVox extension now if spoken feedback is enabled.
677 if (chromeos::AccessibilityManager::Get() &&
678 chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) {
679 AddChromeVoxExtension(base::Closure());
681 #endif // defined(OS_CHROMEOS)
683 #if defined(GOOGLE_CHROME_BUILD)
684 #if !defined(OS_CHROMEOS) // http://crbug.com/314799
685 AddNetworkSpeechSynthesisExtension();
688 #endif // defined(GOOGLE_CHROME_BUILD)
690 Add(IDR_CRYPTOTOKEN_MANIFEST
,
691 base::FilePath(FILE_PATH_LITERAL("cryptotoken")));
694 void ComponentLoader::DeleteData(int manifest_resource_id
,
695 const base::FilePath
& root_directory
) {
696 std::string manifest_contents
=
697 ResourceBundle::GetSharedInstance().GetRawDataResource(
698 manifest_resource_id
).as_string();
699 base::DictionaryValue
* manifest
= ParseManifest(manifest_contents
);
703 ComponentExtensionInfo
info(manifest
, root_directory
);
705 scoped_refptr
<const Extension
> extension(CreateExtension(info
, &error
));
706 if (!extension
.get()) {
711 DataDeleter::StartDeleting(
712 profile_
, extension
.get(), base::Bind(base::DoNothing
));
715 void ComponentLoader::UnloadComponent(ComponentExtensionInfo
* component
) {
716 delete component
->manifest
;
717 if (extension_service_
->is_ready()) {
719 RemoveComponentExtension(component
->extension_id
);
723 void ComponentLoader::EnableFileSystemInGuestMode(const std::string
& id
) {
724 #if defined(OS_CHROMEOS)
725 if (!IsNormalSession()) {
726 // TODO(dpolukhin): Hack to enable HTML5 temporary file system for
727 // the extension. Some component extensions don't work without temporary
728 // file system access. Make sure temporary file system is enabled in the off
729 // the record browser context (as that is the one used in guest session).
730 content::BrowserContext
* off_the_record_context
=
731 ExtensionsBrowserClient::Get()->GetOffTheRecordContext(profile_
);
732 GURL site
= content::SiteInstance::GetSiteForURL(
733 off_the_record_context
, Extension::GetBaseURLFromExtensionId(id
));
734 storage::FileSystemContext
* file_system_context
=
735 content::BrowserContext::GetStoragePartitionForSite(
736 off_the_record_context
, site
)->GetFileSystemContext();
737 file_system_context
->EnableTemporaryFileSystemInIncognito();
742 #if defined(OS_CHROMEOS)
743 void ComponentLoader::AddWithManifestFile(
744 const base::FilePath::CharType
* manifest_filename
,
745 const base::FilePath
& root_directory
,
746 const char* extension_id
,
747 const base::Closure
& done_cb
) {
748 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
749 BrowserThread::PostTaskAndReplyWithResult(
752 base::Bind(&LoadManifestOnFileThread
, root_directory
, manifest_filename
),
753 base::Bind(&ComponentLoader::FinishAddWithManifestFile
,
754 weak_factory_
.GetWeakPtr(),
760 void ComponentLoader::FinishAddWithManifestFile(
761 const base::FilePath
& root_directory
,
762 const char* extension_id
,
763 const base::Closure
& done_cb
,
764 scoped_ptr
<base::DictionaryValue
> manifest
) {
765 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
767 return; // Error already logged.
768 std::string actual_extension_id
= Add(
772 CHECK_EQ(extension_id
, actual_extension_id
);
773 if (!done_cb
.is_null())
778 } // namespace extensions