Extensions cleanup: Merge IsSyncableApp+Extension, ShouldSyncApp+Extension
[chromium-blink-merge.git] / chrome / browser / extensions / component_loader.cc
blob666a2639c2b477c879198c0c5289aedb8b9a71da
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/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"
52 #endif
54 #if defined(GOOGLE_CHROME_BUILD)
55 #include "chrome/browser/defaults.h"
56 #endif
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"
65 #endif
67 #if defined(ENABLE_APP_LIST)
68 #include "chrome/grit/chromium_strings.h"
69 #endif
71 #if defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
72 #include "chrome/browser/ui/app_list/google_now_extension.h"
73 #endif
75 using content::BrowserThread;
77 namespace extensions {
79 namespace {
81 static bool enable_background_extensions_during_testing = false;
83 std::string GenerateId(const base::DictionaryValue* manifest,
84 const base::FilePath& path) {
85 std::string raw_key;
86 std::string id_input;
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);
90 return id;
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);
99 std::string error;
100 scoped_ptr<base::DictionaryValue> manifest(
101 file_util::LoadManifest(root_directory, manifest_filename, &error));
102 if (!manifest) {
103 LOG(ERROR) << "Can't load "
104 << root_directory.Append(manifest_filename).AsUTF8Unsafe()
105 << ": " << error;
106 return nullptr;
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)
122 } // namespace
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,
138 Profile* profile)
139 : profile_prefs_(profile_prefs),
140 local_state_(local_state),
141 profile_(profile),
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) {
158 Load(*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.";
169 return NULL;
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) {
179 delete it->manifest;
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);
191 if (!manifest)
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);
221 if (manifest)
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_ &&
231 !skip_whitelist &&
232 !IsComponentExtensionWhitelisted(info.extension_id))
233 return std::string();
235 component_extensions_.push_back(info);
236 if (extension_service_->is_ready())
237 Load(info);
238 return info.extension_id;
241 std::string ComponentLoader::AddOrReplace(const base::FilePath& path) {
242 base::FilePath absolute_path = base::MakeAbsoluteFilePath(path);
243 std::string error;
244 scoped_ptr<base::DictionaryValue> manifest(
245 file_util::LoadManifest(absolute_path, &error));
246 if (!manifest) {
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();
261 ++it) {
262 if (it->extension_id == extension_id) {
263 Load(*it);
264 break;
269 void ComponentLoader::Load(const ComponentExtensionInfo& info) {
270 std::string error;
271 scoped_refptr<const Extension> extension(CreateExtension(info, &error));
272 if (!extension.get()) {
273 LOG(ERROR) << error;
274 return;
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));
287 break;
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);
298 break;
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)
308 return true;
309 return false;
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")));
339 #endif
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));
349 #endif
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")));
356 #endif
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();
403 bool enabled =
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)) {
410 enabled = false;
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"));
417 if (enabled) {
418 Add(google_now_manifest_id, root_directory);
419 } else {
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;
437 AddWithManifestFile(
438 manifest_filename,
439 chromevox_path,
440 extension_misc::kChromeVoxExtensionId,
441 done_cb);
444 void ComponentLoader::AddChromeOsSpeechSynthesisExtension() {
445 const base::FilePath::CharType* manifest_filename =
446 IsNormalSession() ? extensions::kManifestFilename
447 : extension_misc::kGuestManifestFilename;
448 AddWithManifestFile(
449 manifest_filename,
450 base::FilePath(extension_misc::kSpeechSynthesisExtensionPath),
451 extension_misc::kSpeechSynthesisExtensionId,
452 base::Bind(&ComponentLoader::EnableFileSystemInGuestMode,
453 weak_factory_.GetWeakPtr(),
454 extension_misc::kChromeVoxExtensionId));
456 #endif
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))
465 return;
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);
475 if (manifest) {
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));
488 #endif
491 void ComponentLoader::AddKeyboardApp() {
492 #if defined(OS_CHROMEOS)
493 Add(IDR_KEYBOARD_MANIFEST, base::FilePath(FILE_PATH_LITERAL("keyboard")));
494 #endif
497 void ComponentLoader::AddWebStoreApp() {
498 #if defined(OS_CHROMEOS)
499 if (!IsNormalSession())
500 return;
501 #endif
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(
515 info.root_directory,
516 Manifest::COMPONENT,
517 *info.manifest,
518 flags,
519 utf8_error);
522 // static
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")));
540 #endif
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")));
560 #endif
562 if (!skip_session_components) {
563 AddWebStoreApp();
564 AddChromeApp();
567 AddKeyboardApp();
569 AddDefaultComponentExtensionsWithBackgroundPages(skip_session_components);
571 #if defined(ENABLE_PLUGINS)
572 Add(pdf_extension_util::GetManifest(),
573 base::FilePath(FILE_PATH_LITERAL("pdf")));
574 #endif
577 void ComponentLoader::AddDefaultComponentExtensionsForKioskMode(
578 bool skip_session_components) {
579 // No component extension for kiosk app launch splash screen.
580 if (skip_session_components)
581 return;
583 // Component extensions needed for kiosk apps.
584 AddFileManagerExtension();
586 // Add virtual keyboard.
587 AddKeyboardApp();
589 #if defined(ENABLE_PLUGINS)
590 Add(pdf_extension_util::GetManifest(),
591 base::FilePath(FILE_PATH_LITERAL("pdf")));
592 #endif
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))) {
606 return;
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()));
617 #endif
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")));
642 #endif
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();
686 #endif
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);
700 if (!manifest)
701 return;
703 ComponentExtensionInfo info(manifest, root_directory);
704 std::string error;
705 scoped_refptr<const Extension> extension(CreateExtension(info, &error));
706 if (!extension.get()) {
707 LOG(ERROR) << error;
708 return;
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()) {
718 extension_service_->
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();
739 #endif
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(
750 BrowserThread::FILE,
751 FROM_HERE,
752 base::Bind(&LoadManifestOnFileThread, root_directory, manifest_filename),
753 base::Bind(&ComponentLoader::FinishAddWithManifestFile,
754 weak_factory_.GetWeakPtr(),
755 root_directory,
756 extension_id,
757 done_cb));
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);
766 if (!manifest)
767 return; // Error already logged.
768 std::string actual_extension_id = Add(
769 manifest.release(),
770 root_directory,
771 false);
772 CHECK_EQ(extension_id, actual_extension_id);
773 if (!done_cb.is_null())
774 done_cb.Run();
776 #endif
778 } // namespace extensions