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/time/time.h"
16 #include "base/trace_event/trace_event.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/pdf/pdf_extension_util.h"
19 #include "chrome/browser/search/hotword_service.h"
20 #include "chrome/browser/search/hotword_service_factory.h"
21 #include "chrome/common/chrome_paths.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/chrome_version_info.h"
24 #include "chrome/common/extensions/extension_constants.h"
25 #include "chrome/grit/generated_resources.h"
26 #include "components/crx_file/id_util.h"
27 #include "content/public/browser/browser_context.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/plugin_service.h"
30 #include "extensions/common/extension.h"
31 #include "extensions/common/extension_l10n_util.h"
32 #include "extensions/common/file_util.h"
33 #include "extensions/common/manifest_constants.h"
34 #include "grit/browser_resources.h"
35 #include "ui/base/l10n/l10n_util.h"
36 #include "ui/base/resource/resource_bundle.h"
38 #if defined(OS_CHROMEOS)
39 #include "components/user_manager/user_manager.h"
40 #include "grit/keyboard_resources.h"
41 #include "ui/file_manager/grit/file_manager_resources.h"
42 #include "ui/keyboard/keyboard_util.h"
45 #if defined(GOOGLE_CHROME_BUILD)
46 #include "chrome/browser/defaults.h"
49 #if defined(OS_CHROMEOS)
50 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
51 #include "chromeos/chromeos_switches.h"
52 #include "content/public/browser/site_instance.h"
53 #include "content/public/browser/storage_partition.h"
54 #include "extensions/browser/extensions_browser_client.h"
55 #include "storage/browser/fileapi/file_system_context.h"
58 #if defined(ENABLE_APP_LIST)
59 #include "chrome/grit/chromium_strings.h"
62 #if defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
63 #include "chrome/browser/ui/app_list/google_now_extension.h"
66 using content::BrowserThread
;
68 namespace extensions
{
72 static bool enable_background_extensions_during_testing
= false;
74 std::string
GenerateId(const base::DictionaryValue
* manifest
,
75 const base::FilePath
& path
) {
78 CHECK(manifest
->GetString(manifest_keys::kPublicKey
, &raw_key
));
79 CHECK(Extension::ParsePEMKeyBytes(raw_key
, &id_input
));
80 std::string id
= crx_file::id_util::GenerateId(id_input
);
84 #if defined(OS_CHROMEOS)
85 scoped_ptr
<base::DictionaryValue
>
86 LoadManifestOnFileThread(
87 const base::FilePath
& chromevox_path
, const char* manifest_filename
) {
88 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
90 scoped_ptr
<base::DictionaryValue
> manifest(
91 file_util::LoadManifest(chromevox_path
, manifest_filename
, &error
));
92 CHECK(manifest
) << error
;
93 bool localized
= extension_l10n_util::LocalizeExtension(
94 chromevox_path
, manifest
.get(), &error
);
95 CHECK(localized
) << error
;
96 return manifest
.Pass();
99 bool IsNormalSession() {
100 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
101 chromeos::switches::kGuestSession
) &&
102 user_manager::UserManager::IsInitialized() &&
103 user_manager::UserManager::Get()->IsUserLoggedIn();
105 #endif // defined(OS_CHROMEOS)
109 ComponentLoader::ComponentExtensionInfo::ComponentExtensionInfo(
110 const base::DictionaryValue
* manifest
, const base::FilePath
& directory
)
111 : manifest(manifest
),
112 root_directory(directory
) {
113 if (!root_directory
.IsAbsolute()) {
114 CHECK(PathService::Get(chrome::DIR_RESOURCES
, &root_directory
));
115 root_directory
= root_directory
.Append(directory
);
117 extension_id
= GenerateId(manifest
, root_directory
);
120 ComponentLoader::ComponentLoader(ExtensionServiceInterface
* extension_service
,
121 PrefService
* profile_prefs
,
122 PrefService
* local_state
,
123 content::BrowserContext
* browser_context
)
124 : profile_prefs_(profile_prefs
),
125 local_state_(local_state
),
126 browser_context_(browser_context
),
127 extension_service_(extension_service
),
128 weak_factory_(this) {}
130 ComponentLoader::~ComponentLoader() {
131 ClearAllRegistered();
134 void ComponentLoader::LoadAll() {
135 TRACE_EVENT0("browser,startup", "ComponentLoader::LoadAll");
136 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.LoadAllComponentTime");
138 for (RegisteredComponentExtensions::iterator it
=
139 component_extensions_
.begin();
140 it
!= component_extensions_
.end(); ++it
) {
145 base::DictionaryValue
* ComponentLoader::ParseManifest(
146 const std::string
& manifest_contents
) const {
147 JSONStringValueDeserializer
deserializer(manifest_contents
);
148 scoped_ptr
<base::Value
> manifest(deserializer
.Deserialize(NULL
, NULL
));
150 if (!manifest
.get() || !manifest
->IsType(base::Value::TYPE_DICTIONARY
)) {
151 LOG(ERROR
) << "Failed to parse extension manifest.";
154 // Transfer ownership to the caller.
155 return static_cast<base::DictionaryValue
*>(manifest
.release());
158 void ComponentLoader::ClearAllRegistered() {
159 for (RegisteredComponentExtensions::iterator it
=
160 component_extensions_
.begin();
161 it
!= component_extensions_
.end(); ++it
) {
165 component_extensions_
.clear();
168 std::string
ComponentLoader::GetExtensionID(
169 int manifest_resource_id
,
170 const base::FilePath
& root_directory
) {
171 std::string manifest_contents
= ResourceBundle::GetSharedInstance().
172 GetRawDataResource(manifest_resource_id
).as_string();
173 base::DictionaryValue
* manifest
= ParseManifest(manifest_contents
);
175 return std::string();
177 ComponentExtensionInfo
info(manifest
, root_directory
);
178 return info
.extension_id
;
181 std::string
ComponentLoader::Add(int manifest_resource_id
,
182 const base::FilePath
& root_directory
) {
183 std::string manifest_contents
=
184 ResourceBundle::GetSharedInstance().GetRawDataResource(
185 manifest_resource_id
).as_string();
186 return Add(manifest_contents
, root_directory
);
189 std::string
ComponentLoader::Add(const std::string
& manifest_contents
,
190 const base::FilePath
& root_directory
) {
191 // The Value is kept for the lifetime of the ComponentLoader. This is
192 // required in case LoadAll() is called again.
193 base::DictionaryValue
* manifest
= ParseManifest(manifest_contents
);
195 return Add(manifest
, root_directory
);
196 return std::string();
199 std::string
ComponentLoader::Add(const base::DictionaryValue
* parsed_manifest
,
200 const base::FilePath
& root_directory
) {
201 ComponentExtensionInfo
info(parsed_manifest
, root_directory
);
202 component_extensions_
.push_back(info
);
203 if (extension_service_
->is_ready())
205 return info
.extension_id
;
208 std::string
ComponentLoader::AddOrReplace(const base::FilePath
& path
) {
209 base::FilePath absolute_path
= base::MakeAbsoluteFilePath(path
);
211 scoped_ptr
<base::DictionaryValue
> manifest(
212 file_util::LoadManifest(absolute_path
, &error
));
214 LOG(ERROR
) << "Could not load extension from '" <<
215 absolute_path
.value() << "'. " << error
;
216 return std::string();
218 Remove(GenerateId(manifest
.get(), absolute_path
));
220 return Add(manifest
.release(), absolute_path
);
223 void ComponentLoader::Reload(const std::string
& extension_id
) {
224 for (RegisteredComponentExtensions::iterator it
=
225 component_extensions_
.begin(); it
!= component_extensions_
.end();
227 if (it
->extension_id
== extension_id
) {
234 void ComponentLoader::Load(const ComponentExtensionInfo
& info
) {
235 // TODO(abarth): We should REQUIRE_MODERN_MANIFEST_VERSION once we've updated
236 // our component extensions to the new manifest version.
237 int flags
= Extension::REQUIRE_KEY
;
241 scoped_refptr
<const Extension
> extension(Extension::Create(
247 if (!extension
.get()) {
252 CHECK_EQ(info
.extension_id
, extension
->id()) << extension
->name();
253 extension_service_
->AddComponentExtension(extension
.get());
256 void ComponentLoader::Remove(const base::FilePath
& root_directory
) {
257 // Find the ComponentExtensionInfo for the extension.
258 RegisteredComponentExtensions::iterator it
= component_extensions_
.begin();
259 for (; it
!= component_extensions_
.end(); ++it
) {
260 if (it
->root_directory
== root_directory
) {
261 Remove(GenerateId(it
->manifest
, root_directory
));
267 void ComponentLoader::Remove(const std::string
& id
) {
268 RegisteredComponentExtensions::iterator it
= component_extensions_
.begin();
269 for (; it
!= component_extensions_
.end(); ++it
) {
270 if (it
->extension_id
== id
) {
271 UnloadComponent(&(*it
));
272 it
= component_extensions_
.erase(it
);
278 bool ComponentLoader::Exists(const std::string
& id
) const {
279 RegisteredComponentExtensions::const_iterator it
=
280 component_extensions_
.begin();
281 for (; it
!= component_extensions_
.end(); ++it
)
282 if (it
->extension_id
== id
)
287 void ComponentLoader::AddFileManagerExtension() {
288 #if defined(OS_CHROMEOS)
290 const base::CommandLine
* command_line
=
291 base::CommandLine::ForCurrentProcess();
292 if (command_line
->HasSwitch(switches::kFileManagerExtensionPath
)) {
293 base::FilePath
filemgr_extension_path(
294 command_line
->GetSwitchValuePath(switches::kFileManagerExtensionPath
));
295 AddWithNameAndDescription(IDR_FILEMANAGER_MANIFEST
,
296 filemgr_extension_path
,
297 IDS_FILEMANAGER_APP_NAME
,
298 IDS_FILEMANAGER_APP_DESCRIPTION
);
302 AddWithNameAndDescription(IDR_FILEMANAGER_MANIFEST
,
303 base::FilePath(FILE_PATH_LITERAL("file_manager")),
304 IDS_FILEMANAGER_APP_NAME
,
305 IDS_FILEMANAGER_APP_DESCRIPTION
);
306 #endif // defined(OS_CHROMEOS)
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)
316 void ComponentLoader::AddAudioPlayerExtension() {
317 #if defined(OS_CHROMEOS)
318 Add(IDR_AUDIO_PLAYER_MANIFEST
,
319 base::FilePath(FILE_PATH_LITERAL("audio_player")));
320 #endif // defined(OS_CHROMEOS)
323 void ComponentLoader::AddGalleryExtension() {
324 #if defined(OS_CHROMEOS)
325 Add(IDR_GALLERY_MANIFEST
, base::FilePath(FILE_PATH_LITERAL("gallery")));
329 void ComponentLoader::AddHangoutServicesExtension() {
330 #if defined(GOOGLE_CHROME_BUILD) || defined(ENABLE_HANGOUT_SERVICES_EXTENSION)
331 Add(IDR_HANGOUT_SERVICES_MANIFEST
,
332 base::FilePath(FILE_PATH_LITERAL("hangout_services")));
336 void ComponentLoader::AddHotwordAudioVerificationApp() {
337 if (HotwordServiceFactory::IsAlwaysOnAvailable()) {
338 Add(IDR_HOTWORD_AUDIO_VERIFICATION_MANIFEST
,
339 base::FilePath(FILE_PATH_LITERAL("hotword_audio_verification")));
343 void ComponentLoader::AddHotwordHelperExtension() {
344 if (HotwordServiceFactory::IsHotwordAllowed(browser_context_
)) {
345 Add(IDR_HOTWORD_MANIFEST
,
346 base::FilePath(FILE_PATH_LITERAL("hotword")));
350 void ComponentLoader::AddImageLoaderExtension() {
351 #if defined(IMAGE_LOADER_EXTENSION)
352 Add(IDR_IMAGE_LOADER_MANIFEST
,
353 base::FilePath(FILE_PATH_LITERAL("image_loader")));
354 #endif // defined(IMAGE_LOADER_EXTENSION)
357 void ComponentLoader::AddNetworkSpeechSynthesisExtension() {
358 Add(IDR_NETWORK_SPEECH_SYNTHESIS_MANIFEST
,
359 base::FilePath(FILE_PATH_LITERAL("network_speech_synthesis")));
362 #if defined(OS_CHROMEOS)
363 void ComponentLoader::AddChromeVoxExtension(
364 const base::Closure
& done_cb
) {
365 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
366 base::FilePath resources_path
;
367 PathService::Get(chrome::DIR_RESOURCES
, &resources_path
);
369 base::FilePath chromevox_path
=
370 resources_path
.Append(extension_misc::kChromeVoxExtensionPath
);
372 const char* manifest_filename
=
373 IsNormalSession() ? extension_misc::kChromeVoxManifestFilename
374 : extension_misc::kChromeVoxGuestManifestFilename
;
376 BrowserThread::PostTaskAndReplyWithResult(
379 base::Bind(&LoadManifestOnFileThread
, chromevox_path
, manifest_filename
),
380 base::Bind(&ComponentLoader::AddChromeVoxExtensionWithManifest
,
381 weak_factory_
.GetWeakPtr(),
386 void ComponentLoader::AddChromeVoxExtensionWithManifest(
387 const base::FilePath
& chromevox_path
,
388 const base::Closure
& done_cb
,
389 scoped_ptr
<base::DictionaryValue
> manifest
) {
390 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
391 std::string extension_id
= Add(manifest
.release(), chromevox_path
);
392 CHECK_EQ(extension_misc::kChromeVoxExtensionId
, extension_id
);
393 if (!done_cb
.is_null())
397 std::string
ComponentLoader::AddChromeOsSpeechSynthesisExtension() {
398 int idr
= IsNormalSession() ? IDR_SPEECH_SYNTHESIS_MANIFEST
399 : IDR_SPEECH_SYNTHESIS_GUEST_MANIFEST
;
400 std::string id
= Add(idr
,
401 base::FilePath(extension_misc::kSpeechSynthesisExtensionPath
));
402 EnableFileSystemInGuestMode(id
);
407 void ComponentLoader::AddWithNameAndDescription(
408 int manifest_resource_id
,
409 const base::FilePath
& root_directory
,
411 int description_string_id
) {
412 std::string manifest_contents
=
413 ResourceBundle::GetSharedInstance().GetRawDataResource(
414 manifest_resource_id
).as_string();
416 // The Value is kept for the lifetime of the ComponentLoader. This is
417 // required in case LoadAll() is called again.
418 base::DictionaryValue
* manifest
= ParseManifest(manifest_contents
);
421 manifest
->SetString(manifest_keys::kName
,
422 l10n_util::GetStringUTF8(name_string_id
));
423 manifest
->SetString(manifest_keys::kDescription
,
424 l10n_util::GetStringUTF8(description_string_id
));
425 Add(manifest
, root_directory
);
429 void ComponentLoader::AddChromeApp() {
430 #if defined(ENABLE_APP_LIST)
431 AddWithNameAndDescription(IDR_CHROME_APP_MANIFEST
,
432 base::FilePath(FILE_PATH_LITERAL("chrome_app")),
433 IDS_SHORT_PRODUCT_NAME
,
434 IDS_CHROME_SHORTCUT_DESCRIPTION
);
438 void ComponentLoader::AddKeyboardApp() {
439 #if defined(OS_CHROMEOS)
440 Add(IDR_KEYBOARD_MANIFEST
, base::FilePath(FILE_PATH_LITERAL("keyboard")));
444 void ComponentLoader::AddWebStoreApp() {
445 #if defined(OS_CHROMEOS)
446 if (!IsNormalSession())
450 AddWithNameAndDescription(IDR_WEBSTORE_MANIFEST
,
451 base::FilePath(FILE_PATH_LITERAL("web_store")),
452 IDS_WEBSTORE_NAME_STORE
,
453 IDS_WEBSTORE_APP_DESCRIPTION
);
457 void ComponentLoader::EnableBackgroundExtensionsForTesting() {
458 enable_background_extensions_during_testing
= true;
461 void ComponentLoader::AddDefaultComponentExtensions(
462 bool skip_session_components
) {
463 // Do not add component extensions that have background pages here -- add them
464 // to AddDefaultComponentExtensionsWithBackgroundPages.
465 #if defined(OS_CHROMEOS)
466 Add(IDR_MOBILE_MANIFEST
,
467 base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile")));
469 #if defined(GOOGLE_CHROME_BUILD)
470 if (browser_defaults::enable_help_app
) {
471 Add(IDR_HELP_MANIFEST
, base::FilePath(FILE_PATH_LITERAL(
472 "/usr/share/chromeos-assets/helpapp")));
476 // Skip all other extensions that require user session presence.
477 if (!skip_session_components
) {
478 const base::CommandLine
* command_line
=
479 base::CommandLine::ForCurrentProcess();
480 if (!command_line
->HasSwitch(chromeos::switches::kGuestSession
))
481 Add(IDR_BOOKMARKS_MANIFEST
,
482 base::FilePath(FILE_PATH_LITERAL("bookmark_manager")));
484 Add(IDR_CROSH_BUILTIN_MANIFEST
, base::FilePath(FILE_PATH_LITERAL(
485 "/usr/share/chromeos-assets/crosh_builtin")));
487 #else // !defined(OS_CHROMEOS)
488 DCHECK(!skip_session_components
);
489 Add(IDR_BOOKMARKS_MANIFEST
,
490 base::FilePath(FILE_PATH_LITERAL("bookmark_manager")));
491 // Cloud Print component app. Not required on Chrome OS.
492 Add(IDR_CLOUDPRINT_MANIFEST
,
493 base::FilePath(FILE_PATH_LITERAL("cloud_print")));
496 if (!skip_session_components
) {
503 AddDefaultComponentExtensionsWithBackgroundPages(skip_session_components
);
506 void ComponentLoader::AddDefaultComponentExtensionsForKioskMode(
507 bool skip_session_components
) {
508 // No component extension for kiosk app launch splash screen.
509 if (skip_session_components
)
512 // Component extensions needed for kiosk apps.
513 AddFileManagerExtension();
515 // Add virtual keyboard.
519 void ComponentLoader::AddDefaultComponentExtensionsWithBackgroundPages(
520 bool skip_session_components
) {
521 const base::CommandLine
* command_line
=
522 base::CommandLine::ForCurrentProcess();
524 // Component extensions with background pages are not enabled during tests
525 // because they generate a lot of background behavior that can interfere.
526 if (!enable_background_extensions_during_testing
&&
527 (command_line
->HasSwitch(switches::kTestType
) ||
528 command_line
->HasSwitch(
529 switches::kDisableComponentExtensionsWithBackgroundPages
))) {
533 #if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
534 // Since this is a v2 app it has a background page.
535 AddWithNameAndDescription(IDR_GENIUS_APP_MANIFEST
,
536 base::FilePath(FILE_PATH_LITERAL(
537 "/usr/share/chromeos-assets/genius_app")),
539 IDS_GENIUS_APP_DESCRIPTION
);
542 if (!skip_session_components
) {
543 AddVideoPlayerExtension();
544 AddAudioPlayerExtension();
545 AddFileManagerExtension();
546 AddGalleryExtension();
548 AddHangoutServicesExtension();
549 AddHotwordAudioVerificationApp();
550 AddHotwordHelperExtension();
551 AddImageLoaderExtension();
553 bool install_feedback
= enable_background_extensions_during_testing
;
554 #if defined(GOOGLE_CHROME_BUILD)
555 install_feedback
= true;
556 #endif // defined(GOOGLE_CHROME_BUILD)
557 if (install_feedback
)
558 Add(IDR_FEEDBACK_MANIFEST
, base::FilePath(FILE_PATH_LITERAL("feedback")));
560 #if defined(ENABLE_SETTINGS_APP)
561 Add(IDR_SETTINGS_APP_MANIFEST
,
562 base::FilePath(FILE_PATH_LITERAL("settings_app")));
566 #if defined(OS_CHROMEOS)
567 if (!skip_session_components
) {
568 #if defined(GOOGLE_CHROME_BUILD)
569 if (!command_line
->HasSwitch(
570 chromeos::switches::kDisableOfficeEditingComponentApp
)) {
571 std::string id
= Add(IDR_QUICKOFFICE_MANIFEST
, base::FilePath(
572 FILE_PATH_LITERAL("/usr/share/chromeos-assets/quickoffice")));
573 EnableFileSystemInGuestMode(id
);
575 #endif // defined(GOOGLE_CHROME_BUILD)
577 Add(IDR_ECHO_MANIFEST
,
578 base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/echo")));
580 if (!command_line
->HasSwitch(chromeos::switches::kGuestSession
)) {
581 Add(IDR_WALLPAPERMANAGER_MANIFEST
,
582 base::FilePath(FILE_PATH_LITERAL("chromeos/wallpaper_manager")));
585 Add(IDR_FIRST_RUN_DIALOG_MANIFEST
,
586 base::FilePath(FILE_PATH_LITERAL("chromeos/first_run/app")));
588 Add(IDR_NETWORK_CONFIGURATION_MANIFEST
,
589 base::FilePath(FILE_PATH_LITERAL("chromeos/network_configuration")));
591 Add(IDR_CONNECTIVITY_DIAGNOSTICS_MANIFEST
,
592 base::FilePath(extension_misc::kConnectivityDiagnosticsPath
));
593 Add(IDR_CONNECTIVITY_DIAGNOSTICS_LAUNCHER_MANIFEST
,
594 base::FilePath(extension_misc::kConnectivityDiagnosticsLauncherPath
));
597 // Load ChromeVox extension now if spoken feedback is enabled.
598 if (chromeos::AccessibilityManager::Get() &&
599 chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) {
600 AddChromeVoxExtension(base::Closure());
602 #endif // defined(OS_CHROMEOS)
604 #if defined(ENABLE_GOOGLE_NOW)
605 const char kEnablePrefix
[] = "Enable";
606 const char kFieldTrialName
[] = "GoogleNow";
607 std::string
enable_prefix(kEnablePrefix
);
608 std::string field_trial_result
=
609 base::FieldTrialList::FindFullName(kFieldTrialName
);
611 bool enabled_via_field_trial
=
612 field_trial_result
.compare(0, enable_prefix
.length(), enable_prefix
) == 0;
614 // Enable the feature on trybots and trunk builds.
615 bool enabled_via_trunk_build
=
616 chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_UNKNOWN
;
618 bool enabled
= enabled_via_field_trial
|| enabled_via_trunk_build
;
620 #if defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
621 // Don't load if newer trial is running (== new extension id is available).
622 std::string ignored_extension_id
;
623 if (GetGoogleNowExtensionId(&ignored_extension_id
)) {
628 if (!skip_session_components
&& enabled
) {
629 Add(IDR_GOOGLE_NOW_MANIFEST
,
630 base::FilePath(FILE_PATH_LITERAL("google_now")));
634 #if defined(GOOGLE_CHROME_BUILD)
635 #if !defined(OS_CHROMEOS) // http://crbug.com/314799
636 AddNetworkSpeechSynthesisExtension();
639 #endif // defined(GOOGLE_CHROME_BUILD)
641 #if defined(ENABLE_PLUGINS)
642 if (switches::OutOfProcessPdfEnabled()) {
643 Add(pdf_extension_util::GetManifest(),
644 base::FilePath(FILE_PATH_LITERAL("pdf")));
648 Add(IDR_CRYPTOTOKEN_MANIFEST
,
649 base::FilePath(FILE_PATH_LITERAL("cryptotoken")));
652 void ComponentLoader::UnloadComponent(ComponentExtensionInfo
* component
) {
653 delete component
->manifest
;
654 if (extension_service_
->is_ready()) {
656 RemoveComponentExtension(component
->extension_id
);
660 void ComponentLoader::EnableFileSystemInGuestMode(const std::string
& id
) {
661 #if defined(OS_CHROMEOS)
662 if (!IsNormalSession()) {
663 // TODO(dpolukhin): Hack to enable HTML5 temporary file system for
664 // the extension. Some component extensions don't work without temporary
665 // file system access. Make sure temporary file system is enabled in the off
666 // the record browser context (as that is the one used in guest session).
667 content::BrowserContext
* off_the_record_context
=
668 ExtensionsBrowserClient::Get()->GetOffTheRecordContext(
670 GURL site
= content::SiteInstance::GetSiteForURL(
671 off_the_record_context
, Extension::GetBaseURLFromExtensionId(id
));
672 storage::FileSystemContext
* file_system_context
=
673 content::BrowserContext::GetStoragePartitionForSite(
674 off_the_record_context
, site
)->GetFileSystemContext();
675 file_system_context
->EnableTemporaryFileSystemInIncognito();
680 } // namespace extensions