1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/component_loader.h"
6
7#include <string>
8
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/path_service.h"
14#include "chrome/browser/extensions/extension_service.h"
15#include "chrome/browser/search/hotword_service_factory.h"
16#include "chrome/common/chrome_paths.h"
17#include "chrome/common/chrome_switches.h"
18#include "chrome/common/chrome_version_info.h"
19#include "chrome/common/extensions/extension_constants.h"
20#include "chrome/grit/generated_resources.h"
21#include "components/crx_file/id_util.h"
22#include "content/public/browser/browser_context.h"
23#include "content/public/browser/browser_thread.h"
24#include "content/public/browser/plugin_service.h"
25#include "extensions/common/extension.h"
26#include "extensions/common/file_util.h"
27#include "extensions/common/manifest_constants.h"
28#include "grit/browser_resources.h"
29#include "ui/base/l10n/l10n_util.h"
30#include "ui/base/resource/resource_bundle.h"
31
32#if defined(OS_CHROMEOS)
33#include "grit/keyboard_resources.h"
34#include "ui/file_manager/grit/file_manager_resources.h"
35#include "ui/keyboard/keyboard_util.h"
36#endif
37
38#if defined(GOOGLE_CHROME_BUILD)
39#include "chrome/browser/defaults.h"
40#endif
41
42#if defined(OS_CHROMEOS)
43#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
44#include "chromeos/chromeos_switches.h"
45#include "content/public/browser/site_instance.h"
46#include "content/public/browser/storage_partition.h"
47#include "extensions/browser/extensions_browser_client.h"
48#include "storage/browser/fileapi/file_system_context.h"
49#endif
50
51#if defined(ENABLE_APP_LIST)
52#include "chrome/grit/chromium_strings.h"
53#endif
54
55using content::BrowserThread;
56
57namespace extensions {
58
59namespace {
60
61static bool enable_background_extensions_during_testing = false;
62
63std::string GenerateId(const base::DictionaryValue* manifest,
64                       const base::FilePath& path) {
65  std::string raw_key;
66  std::string id_input;
67  CHECK(manifest->GetString(manifest_keys::kPublicKey, &raw_key));
68  CHECK(Extension::ParsePEMKeyBytes(raw_key, &id_input));
69  std::string id = crx_file::id_util::GenerateId(id_input);
70  return id;
71}
72
73#if defined(OS_CHROMEOS)
74scoped_ptr<base::DictionaryValue>
75LoadManifestOnFileThread(
76    const base::FilePath& chromevox_path, const char* manifest_filename) {
77  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
78  std::string error;
79  scoped_ptr<base::DictionaryValue> manifest(
80      file_util::LoadManifest(chromevox_path, manifest_filename, &error));
81  CHECK(manifest) << error;
82  return manifest.Pass();
83}
84#endif  // defined(OS_CHROMEOS)
85
86}  // namespace
87
88ComponentLoader::ComponentExtensionInfo::ComponentExtensionInfo(
89    const base::DictionaryValue* manifest, const base::FilePath& directory)
90    : manifest(manifest),
91      root_directory(directory) {
92  if (!root_directory.IsAbsolute()) {
93    CHECK(PathService::Get(chrome::DIR_RESOURCES, &root_directory));
94    root_directory = root_directory.Append(directory);
95  }
96  extension_id = GenerateId(manifest, root_directory);
97}
98
99ComponentLoader::ComponentLoader(ExtensionServiceInterface* extension_service,
100                                 PrefService* profile_prefs,
101                                 PrefService* local_state,
102                                 content::BrowserContext* browser_context)
103    : profile_prefs_(profile_prefs),
104      local_state_(local_state),
105      browser_context_(browser_context),
106      extension_service_(extension_service),
107      weak_factory_(this) {}
108
109ComponentLoader::~ComponentLoader() {
110  ClearAllRegistered();
111}
112
113void ComponentLoader::LoadAll() {
114  for (RegisteredComponentExtensions::iterator it =
115          component_extensions_.begin();
116      it != component_extensions_.end(); ++it) {
117    Load(*it);
118  }
119}
120
121base::DictionaryValue* ComponentLoader::ParseManifest(
122    const std::string& manifest_contents) const {
123  JSONStringValueSerializer serializer(manifest_contents);
124  scoped_ptr<base::Value> manifest(serializer.Deserialize(NULL, NULL));
125
126  if (!manifest.get() || !manifest->IsType(base::Value::TYPE_DICTIONARY)) {
127    LOG(ERROR) << "Failed to parse extension manifest.";
128    return NULL;
129  }
130  // Transfer ownership to the caller.
131  return static_cast<base::DictionaryValue*>(manifest.release());
132}
133
134void ComponentLoader::ClearAllRegistered() {
135  for (RegisteredComponentExtensions::iterator it =
136          component_extensions_.begin();
137      it != component_extensions_.end(); ++it) {
138      delete it->manifest;
139  }
140
141  component_extensions_.clear();
142}
143
144std::string ComponentLoader::GetExtensionID(
145    int manifest_resource_id,
146    const base::FilePath& root_directory) {
147  std::string manifest_contents = ResourceBundle::GetSharedInstance().
148      GetRawDataResource(manifest_resource_id).as_string();
149  base::DictionaryValue* manifest = ParseManifest(manifest_contents);
150  if (!manifest)
151    return std::string();
152
153  ComponentExtensionInfo info(manifest, root_directory);
154  return info.extension_id;
155}
156
157std::string ComponentLoader::Add(int manifest_resource_id,
158                                 const base::FilePath& root_directory) {
159  std::string manifest_contents =
160      ResourceBundle::GetSharedInstance().GetRawDataResource(
161          manifest_resource_id).as_string();
162  return Add(manifest_contents, root_directory);
163}
164
165std::string ComponentLoader::Add(const std::string& manifest_contents,
166                                 const base::FilePath& root_directory) {
167  // The Value is kept for the lifetime of the ComponentLoader. This is
168  // required in case LoadAll() is called again.
169  base::DictionaryValue* manifest = ParseManifest(manifest_contents);
170  if (manifest)
171    return Add(manifest, root_directory);
172  return std::string();
173}
174
175std::string ComponentLoader::Add(const base::DictionaryValue* parsed_manifest,
176                                 const base::FilePath& root_directory) {
177  ComponentExtensionInfo info(parsed_manifest, root_directory);
178  component_extensions_.push_back(info);
179  if (extension_service_->is_ready())
180    Load(info);
181  return info.extension_id;
182}
183
184std::string ComponentLoader::AddOrReplace(const base::FilePath& path) {
185  base::FilePath absolute_path = base::MakeAbsoluteFilePath(path);
186  std::string error;
187  scoped_ptr<base::DictionaryValue> manifest(
188      file_util::LoadManifest(absolute_path, &error));
189  if (!manifest) {
190    LOG(ERROR) << "Could not load extension from '" <<
191                  absolute_path.value() << "'. " << error;
192    return std::string();
193  }
194  Remove(GenerateId(manifest.get(), absolute_path));
195
196  return Add(manifest.release(), absolute_path);
197}
198
199void ComponentLoader::Reload(const std::string& extension_id) {
200  for (RegisteredComponentExtensions::iterator it =
201         component_extensions_.begin(); it != component_extensions_.end();
202         ++it) {
203    if (it->extension_id == extension_id) {
204      Load(*it);
205      break;
206    }
207  }
208}
209
210void ComponentLoader::Load(const ComponentExtensionInfo& info) {
211  // TODO(abarth): We should REQUIRE_MODERN_MANIFEST_VERSION once we've updated
212  //               our component extensions to the new manifest version.
213  int flags = Extension::REQUIRE_KEY;
214
215  std::string error;
216
217  scoped_refptr<const Extension> extension(Extension::Create(
218      info.root_directory,
219      Manifest::COMPONENT,
220      *info.manifest,
221      flags,
222      &error));
223  if (!extension.get()) {
224    LOG(ERROR) << error;
225    return;
226  }
227
228  CHECK_EQ(info.extension_id, extension->id()) << extension->name();
229  extension_service_->AddComponentExtension(extension.get());
230}
231
232void ComponentLoader::Remove(const base::FilePath& root_directory) {
233  // Find the ComponentExtensionInfo for the extension.
234  RegisteredComponentExtensions::iterator it = component_extensions_.begin();
235  for (; it != component_extensions_.end(); ++it) {
236    if (it->root_directory == root_directory) {
237      Remove(GenerateId(it->manifest, root_directory));
238      break;
239    }
240  }
241}
242
243void ComponentLoader::Remove(const std::string& id) {
244  RegisteredComponentExtensions::iterator it = component_extensions_.begin();
245  for (; it != component_extensions_.end(); ++it) {
246    if (it->extension_id == id) {
247      UnloadComponent(&(*it));
248      it = component_extensions_.erase(it);
249      break;
250    }
251  }
252}
253
254bool ComponentLoader::Exists(const std::string& id) const {
255  RegisteredComponentExtensions::const_iterator it =
256      component_extensions_.begin();
257  for (; it != component_extensions_.end(); ++it)
258    if (it->extension_id == id)
259      return true;
260  return false;
261}
262
263void ComponentLoader::AddFileManagerExtension() {
264#if defined(OS_CHROMEOS)
265#ifndef NDEBUG
266  const CommandLine* command_line = CommandLine::ForCurrentProcess();
267  if (command_line->HasSwitch(switches::kFileManagerExtensionPath)) {
268    base::FilePath filemgr_extension_path(
269        command_line->GetSwitchValuePath(switches::kFileManagerExtensionPath));
270    AddWithNameAndDescription(IDR_FILEMANAGER_MANIFEST,
271                              filemgr_extension_path,
272                              IDS_FILEMANAGER_APP_NAME,
273                              IDS_FILEMANAGER_APP_DESCRIPTION);
274    return;
275  }
276#endif  // NDEBUG
277  AddWithNameAndDescription(IDR_FILEMANAGER_MANIFEST,
278                            base::FilePath(FILE_PATH_LITERAL("file_manager")),
279                            IDS_FILEMANAGER_APP_NAME,
280                            IDS_FILEMANAGER_APP_DESCRIPTION);
281#endif  // defined(OS_CHROMEOS)
282}
283
284void ComponentLoader::AddVideoPlayerExtension() {
285#if defined(OS_CHROMEOS)
286  Add(IDR_VIDEO_PLAYER_MANIFEST,
287      base::FilePath(FILE_PATH_LITERAL("video_player")));
288#endif  // defined(OS_CHROMEOS)
289}
290
291void ComponentLoader::AddGalleryExtension() {
292#if defined(OS_CHROMEOS)
293  Add(IDR_GALLERY_MANIFEST, base::FilePath(FILE_PATH_LITERAL("gallery")));
294#endif
295}
296
297void ComponentLoader::AddHangoutServicesExtension() {
298#if defined(GOOGLE_CHROME_BUILD) || defined(ENABLE_HANGOUT_SERVICES_EXTENSION)
299  Add(IDR_HANGOUT_SERVICES_MANIFEST,
300      base::FilePath(FILE_PATH_LITERAL("hangout_services")));
301#endif
302}
303
304void ComponentLoader::AddHotwordAudioVerificationApp() {
305  CommandLine* command_line = CommandLine::ForCurrentProcess();
306  if (command_line->HasSwitch(switches::kEnableExperimentalHotwording)) {
307    Add(IDR_HOTWORD_AUDIO_VERIFICATION_MANIFEST,
308        base::FilePath(FILE_PATH_LITERAL("hotword_audio_verification")));
309  }
310}
311
312void ComponentLoader::AddHotwordHelperExtension() {
313  if (HotwordServiceFactory::IsHotwordAllowed(browser_context_)) {
314    CommandLine* command_line = CommandLine::ForCurrentProcess();
315    if (command_line->HasSwitch(switches::kEnableExperimentalHotwording)) {
316      Add(IDR_HOTWORD_MANIFEST,
317          base::FilePath(FILE_PATH_LITERAL("hotword")));
318    } else {
319      Add(IDR_HOTWORD_HELPER_MANIFEST,
320          base::FilePath(FILE_PATH_LITERAL("hotword_helper")));
321    }
322  }
323}
324
325void ComponentLoader::AddImageLoaderExtension() {
326#if defined(IMAGE_LOADER_EXTENSION)
327  Add(IDR_IMAGE_LOADER_MANIFEST,
328      base::FilePath(FILE_PATH_LITERAL("image_loader")));
329#endif  // defined(IMAGE_LOADER_EXTENSION)
330}
331
332void ComponentLoader::AddNetworkSpeechSynthesisExtension() {
333  Add(IDR_NETWORK_SPEECH_SYNTHESIS_MANIFEST,
334      base::FilePath(FILE_PATH_LITERAL("network_speech_synthesis")));
335}
336
337#if defined(OS_CHROMEOS)
338void ComponentLoader::AddChromeVoxExtension(
339    const base::Closure& done_cb) {
340  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
341  base::FilePath resources_path;
342  PathService::Get(chrome::DIR_RESOURCES, &resources_path);
343
344  base::FilePath chromevox_path =
345      resources_path.Append(extension_misc::kChromeVoxExtensionPath);
346
347  const CommandLine* command_line = CommandLine::ForCurrentProcess();
348  bool is_chromevox_next =
349      command_line->HasSwitch(chromeos::switches::kEnableChromeVoxNext);
350  bool is_guest = command_line->HasSwitch(chromeos::switches::kGuestSession);
351  const char* manifest_filename;
352  if (is_chromevox_next) {
353    manifest_filename =
354        is_guest ? extension_misc::kChromeVoxNextGuestManifestFilename
355                 : extension_misc::kChromeVoxNextManifestFilename;
356  } else {
357    manifest_filename =
358        is_guest ? extension_misc::kChromeVoxGuestManifestFilename
359                 : extension_misc::kChromeVoxManifestFilename;
360  }
361  BrowserThread::PostTaskAndReplyWithResult(
362      BrowserThread::FILE,
363      FROM_HERE,
364      base::Bind(&LoadManifestOnFileThread, chromevox_path, manifest_filename),
365      base::Bind(&ComponentLoader::AddChromeVoxExtensionWithManifest,
366                 weak_factory_.GetWeakPtr(),
367                 chromevox_path,
368                 done_cb));
369}
370
371void ComponentLoader::AddChromeVoxExtensionWithManifest(
372    const base::FilePath& chromevox_path,
373    const base::Closure& done_cb,
374    scoped_ptr<base::DictionaryValue> manifest) {
375  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
376  std::string extension_id = Add(manifest.release(), chromevox_path);
377  CHECK_EQ(extension_misc::kChromeVoxExtensionId, extension_id);
378  if (!done_cb.is_null())
379    done_cb.Run();
380}
381
382std::string ComponentLoader::AddChromeOsSpeechSynthesisExtension() {
383  const CommandLine* command_line = CommandLine::ForCurrentProcess();
384  int idr = command_line->HasSwitch(chromeos::switches::kGuestSession) ?
385      IDR_SPEECH_SYNTHESIS_GUEST_MANIFEST : IDR_SPEECH_SYNTHESIS_MANIFEST;
386  std::string id = Add(idr,
387      base::FilePath(extension_misc::kSpeechSynthesisExtensionPath));
388  EnableFileSystemInGuestMode(id);
389  return id;
390}
391#endif
392
393void ComponentLoader::AddWithNameAndDescription(
394    int manifest_resource_id,
395    const base::FilePath& root_directory,
396    int name_string_id,
397    int description_string_id) {
398  std::string manifest_contents =
399      ResourceBundle::GetSharedInstance().GetRawDataResource(
400          manifest_resource_id).as_string();
401
402  // The Value is kept for the lifetime of the ComponentLoader. This is
403  // required in case LoadAll() is called again.
404  base::DictionaryValue* manifest = ParseManifest(manifest_contents);
405
406  if (manifest) {
407    manifest->SetString(manifest_keys::kName,
408                        l10n_util::GetStringUTF8(name_string_id));
409    manifest->SetString(manifest_keys::kDescription,
410                        l10n_util::GetStringUTF8(description_string_id));
411    Add(manifest, root_directory);
412  }
413}
414
415void ComponentLoader::AddChromeApp() {
416#if defined(ENABLE_APP_LIST)
417  AddWithNameAndDescription(IDR_CHROME_APP_MANIFEST,
418                            base::FilePath(FILE_PATH_LITERAL("chrome_app")),
419                            IDS_SHORT_PRODUCT_NAME,
420                            IDS_CHROME_SHORTCUT_DESCRIPTION);
421#endif
422}
423
424void ComponentLoader::AddKeyboardApp() {
425#if defined(OS_CHROMEOS)
426  Add(IDR_KEYBOARD_MANIFEST, base::FilePath(FILE_PATH_LITERAL("keyboard")));
427#endif
428}
429
430void ComponentLoader::AddWebStoreApp() {
431  AddWithNameAndDescription(IDR_WEBSTORE_MANIFEST,
432                            base::FilePath(FILE_PATH_LITERAL("web_store")),
433                            IDS_WEBSTORE_NAME_STORE,
434                            IDS_WEBSTORE_APP_DESCRIPTION);
435}
436
437// static
438void ComponentLoader::EnableBackgroundExtensionsForTesting() {
439  enable_background_extensions_during_testing = true;
440}
441
442void ComponentLoader::AddDefaultComponentExtensions(
443    bool skip_session_components) {
444  // Do not add component extensions that have background pages here -- add them
445  // to AddDefaultComponentExtensionsWithBackgroundPages.
446#if defined(OS_CHROMEOS)
447  Add(IDR_MOBILE_MANIFEST,
448      base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile")));
449
450#if defined(GOOGLE_CHROME_BUILD)
451  if (browser_defaults::enable_help_app) {
452    Add(IDR_HELP_MANIFEST, base::FilePath(FILE_PATH_LITERAL(
453                               "/usr/share/chromeos-assets/helpapp")));
454  }
455#endif
456
457  // Skip all other extensions that require user session presence.
458  if (!skip_session_components) {
459    const CommandLine* command_line = CommandLine::ForCurrentProcess();
460    if (!command_line->HasSwitch(chromeos::switches::kGuestSession))
461      Add(IDR_BOOKMARKS_MANIFEST,
462          base::FilePath(FILE_PATH_LITERAL("bookmark_manager")));
463
464    Add(IDR_CROSH_BUILTIN_MANIFEST, base::FilePath(FILE_PATH_LITERAL(
465        "/usr/share/chromeos-assets/crosh_builtin")));
466  }
467#else  // !defined(OS_CHROMEOS)
468  DCHECK(!skip_session_components);
469  Add(IDR_BOOKMARKS_MANIFEST,
470      base::FilePath(FILE_PATH_LITERAL("bookmark_manager")));
471  // Cloud Print component app. Not required on Chrome OS.
472  Add(IDR_CLOUDPRINT_MANIFEST,
473      base::FilePath(FILE_PATH_LITERAL("cloud_print")));
474#endif
475
476  if (!skip_session_components) {
477    AddWebStoreApp();
478    AddChromeApp();
479  }
480
481  AddKeyboardApp();
482
483  AddDefaultComponentExtensionsWithBackgroundPages(skip_session_components);
484}
485
486void ComponentLoader::AddDefaultComponentExtensionsForKioskMode(
487    bool skip_session_components) {
488  // No component extension for kiosk app launch splash screen.
489  if (skip_session_components)
490    return;
491
492  // Component extensions needed for kiosk apps.
493  AddFileManagerExtension();
494
495  // Add virtual keyboard.
496  AddKeyboardApp();
497}
498
499void ComponentLoader::AddDefaultComponentExtensionsWithBackgroundPages(
500    bool skip_session_components) {
501  const CommandLine* command_line = CommandLine::ForCurrentProcess();
502
503  // Component extensions with background pages are not enabled during tests
504  // because they generate a lot of background behavior that can interfere.
505  if (!enable_background_extensions_during_testing &&
506      (command_line->HasSwitch(switches::kTestType) ||
507          command_line->HasSwitch(
508              switches::kDisableComponentExtensionsWithBackgroundPages))) {
509    return;
510  }
511
512#if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
513  // Since this is a v2 app it has a background page.
514  AddWithNameAndDescription(IDR_GENIUS_APP_MANIFEST,
515                            base::FilePath(FILE_PATH_LITERAL(
516                                "/usr/share/chromeos-assets/genius_app")),
517                            IDS_GENIUS_APP_NAME,
518                            IDS_GENIUS_APP_DESCRIPTION);
519#endif
520
521  if (!skip_session_components) {
522    AddVideoPlayerExtension();
523    AddFileManagerExtension();
524    AddGalleryExtension();
525
526    AddHangoutServicesExtension();
527    AddHotwordAudioVerificationApp();
528    AddHotwordHelperExtension();
529    AddImageLoaderExtension();
530
531#if defined(ENABLE_SETTINGS_APP)
532    Add(IDR_SETTINGS_APP_MANIFEST,
533        base::FilePath(FILE_PATH_LITERAL("settings_app")));
534#endif
535  }
536
537  // If (!enable_background_extensions_during_testing || this isn't a test)
538  //   install_feedback = false;
539  bool install_feedback = enable_background_extensions_during_testing;
540#if defined(GOOGLE_CHROME_BUILD)
541  install_feedback = true;
542#endif  // defined(GOOGLE_CHROME_BUILD)
543  if (install_feedback)
544    Add(IDR_FEEDBACK_MANIFEST, base::FilePath(FILE_PATH_LITERAL("feedback")));
545
546#if defined(OS_CHROMEOS)
547  if (!skip_session_components) {
548#if defined(GOOGLE_CHROME_BUILD)
549    if (!command_line->HasSwitch(
550            chromeos::switches::kDisableOfficeEditingComponentApp)) {
551      std::string id = Add(IDR_QUICKOFFICE_MANIFEST, base::FilePath(
552          FILE_PATH_LITERAL("/usr/share/chromeos-assets/quickoffice")));
553      EnableFileSystemInGuestMode(id);
554    }
555#endif  // defined(GOOGLE_CHROME_BUILD)
556
557    Add(IDR_ECHO_MANIFEST,
558        base::FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/echo")));
559
560    if (!command_line->HasSwitch(chromeos::switches::kGuestSession)) {
561      Add(IDR_WALLPAPERMANAGER_MANIFEST,
562          base::FilePath(FILE_PATH_LITERAL("chromeos/wallpaper_manager")));
563    }
564
565    Add(IDR_FIRST_RUN_DIALOG_MANIFEST,
566        base::FilePath(FILE_PATH_LITERAL("chromeos/first_run/app")));
567
568    Add(IDR_NETWORK_CONFIGURATION_MANIFEST,
569        base::FilePath(FILE_PATH_LITERAL("chromeos/network_configuration")));
570
571    Add(IDR_CONNECTIVITY_DIAGNOSTICS_MANIFEST,
572        base::FilePath(extension_misc::kConnectivityDiagnosticsPath));
573    Add(IDR_CONNECTIVITY_DIAGNOSTICS_LAUNCHER_MANIFEST,
574        base::FilePath(extension_misc::kConnectivityDiagnosticsLauncherPath));
575  }
576
577  // Load ChromeVox extension now if spoken feedback is enabled.
578  if (chromeos::AccessibilityManager::Get() &&
579      chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) {
580    AddChromeVoxExtension(base::Closure());
581  }
582#endif  // defined(OS_CHROMEOS)
583
584#if defined(ENABLE_GOOGLE_NOW)
585  const char kEnablePrefix[] = "Enable";
586  const char kFieldTrialName[] = "GoogleNow";
587  std::string enable_prefix(kEnablePrefix);
588  std::string field_trial_result =
589      base::FieldTrialList::FindFullName(kFieldTrialName);
590
591  bool enabled_via_field_trial =
592      field_trial_result.compare(0, enable_prefix.length(), enable_prefix) == 0;
593
594  // Enable the feature on trybots and trunk builds.
595  bool enabled_via_trunk_build =
596      chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_UNKNOWN;
597
598  bool enabled = enabled_via_field_trial || enabled_via_trunk_build;
599
600  if (!skip_session_components && enabled) {
601    Add(IDR_GOOGLE_NOW_MANIFEST,
602        base::FilePath(FILE_PATH_LITERAL("google_now")));
603  }
604#endif
605
606#if defined(GOOGLE_CHROME_BUILD)
607#if !defined(OS_CHROMEOS)  // http://crbug.com/314799
608  AddNetworkSpeechSynthesisExtension();
609#endif
610
611#endif  // defined(GOOGLE_CHROME_BUILD)
612
613#if defined(ENABLE_PLUGINS)
614  base::FilePath pdf_path;
615  content::PluginService* plugin_service =
616      content::PluginService::GetInstance();
617  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kOutOfProcessPdf) &&
618      PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path) &&
619      plugin_service->GetRegisteredPpapiPluginInfo(pdf_path)) {
620    Add(IDR_PDF_MANIFEST, base::FilePath(FILE_PATH_LITERAL("pdf")));
621  }
622#endif
623
624  Add(IDR_CRYPTOTOKEN_MANIFEST,
625      base::FilePath(FILE_PATH_LITERAL("cryptotoken")));
626}
627
628void ComponentLoader::UnloadComponent(ComponentExtensionInfo* component) {
629  delete component->manifest;
630  if (extension_service_->is_ready()) {
631    extension_service_->
632        RemoveComponentExtension(component->extension_id);
633  }
634}
635
636void ComponentLoader::EnableFileSystemInGuestMode(const std::string& id) {
637#if defined(OS_CHROMEOS)
638  const CommandLine* command_line = CommandLine::ForCurrentProcess();
639  if (command_line->HasSwitch(chromeos::switches::kGuestSession)) {
640    // TODO(dpolukhin): Hack to enable HTML5 temporary file system for
641    // the extension. Some component extensions don't work without temporary
642    // file system access. Make sure temporary file system is enabled in the off
643    // the record browser context (as that is the one used in guest session).
644    content::BrowserContext* off_the_record_context =
645        ExtensionsBrowserClient::Get()->GetOffTheRecordContext(
646            browser_context_);
647    GURL site = content::SiteInstance::GetSiteForURL(
648        off_the_record_context, Extension::GetBaseURLFromExtensionId(id));
649    storage::FileSystemContext* file_system_context =
650        content::BrowserContext::GetStoragePartitionForSite(
651            off_the_record_context, site)->GetFileSystemContext();
652    file_system_context->EnableTemporaryFileSystemInIncognito();
653  }
654#endif
655}
656
657}  // namespace extensions
658