shell_extension_loader.cc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // Copyright 2018 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. #include "extensions/shell/browser/shell_extension_loader.h"
  5. #include "apps/launcher.h"
  6. #include "base/auto_reset.h"
  7. #include "base/bind.h"
  8. #include "base/files/file_path.h"
  9. #include "base/files/file_util.h"
  10. #include "base/logging.h"
  11. #include "base/task/sequenced_task_runner.h"
  12. #include "base/task/task_runner_util.h"
  13. #include "components/services/app_service/public/mojom/types.mojom-shared.h"
  14. #include "extensions/browser/extension_file_task_runner.h"
  15. #include "extensions/browser/extension_prefs.h"
  16. #include "extensions/browser/extension_registry.h"
  17. #include "extensions/common/file_util.h"
  18. namespace extensions {
  19. using LoadErrorBehavior = ExtensionRegistrar::LoadErrorBehavior;
  20. namespace {
  21. scoped_refptr<const Extension> LoadUnpacked(
  22. const base::FilePath& extension_dir) {
  23. // app_shell only supports unpacked extensions.
  24. // NOTE: If you add packed extension support consider removing the flag
  25. // FOLLOW_SYMLINKS_ANYWHERE below. Packed extensions should not have symlinks.
  26. if (!base::DirectoryExists(extension_dir)) {
  27. LOG(ERROR) << "Extension directory not found: "
  28. << extension_dir.AsUTF8Unsafe();
  29. return nullptr;
  30. }
  31. int load_flags = Extension::FOLLOW_SYMLINKS_ANYWHERE;
  32. std::string load_error;
  33. scoped_refptr<Extension> extension = file_util::LoadExtension(
  34. extension_dir, mojom::ManifestLocation::kCommandLine, load_flags,
  35. &load_error);
  36. if (!extension.get()) {
  37. LOG(ERROR) << "Loading extension at " << extension_dir.value()
  38. << " failed with: " << load_error;
  39. return nullptr;
  40. }
  41. // Log warnings.
  42. if (extension->install_warnings().size()) {
  43. LOG(WARNING) << "Warnings loading extension at " << extension_dir.value()
  44. << ":";
  45. for (const auto& warning : extension->install_warnings())
  46. LOG(WARNING) << warning.message;
  47. }
  48. return extension;
  49. }
  50. } // namespace
  51. ShellExtensionLoader::ShellExtensionLoader(
  52. content::BrowserContext* browser_context)
  53. : browser_context_(browser_context),
  54. extension_registrar_(browser_context, this),
  55. keep_alive_requester_(browser_context) {}
  56. ShellExtensionLoader::~ShellExtensionLoader() = default;
  57. const Extension* ShellExtensionLoader::LoadExtension(
  58. const base::FilePath& extension_dir) {
  59. scoped_refptr<const Extension> extension = LoadUnpacked(extension_dir);
  60. if (extension)
  61. extension_registrar_.AddExtension(extension);
  62. return extension.get();
  63. }
  64. void ShellExtensionLoader::ReloadExtension(ExtensionId extension_id) {
  65. const Extension* extension = ExtensionRegistry::Get(browser_context_)
  66. ->GetInstalledExtension(extension_id);
  67. // We shouldn't be trying to reload extensions that haven't been added.
  68. DCHECK(extension);
  69. // This should always start false since it's only set here, or in
  70. // LoadExtensionForReload() as a result of the call below.
  71. DCHECK_EQ(false, did_schedule_reload_);
  72. base::AutoReset<bool> reset_did_schedule_reload(&did_schedule_reload_, false);
  73. // Set up a keep-alive while the extension reloads. Do this before starting
  74. // the reload so that the first step, disabling the extension, doesn't release
  75. // the last remaining keep-alive and shut down the application.
  76. keep_alive_requester_.StartTrackingReload(extension);
  77. extension_registrar_.ReloadExtension(extension_id, LoadErrorBehavior::kQuiet);
  78. if (did_schedule_reload_)
  79. return;
  80. // ExtensionRegistrar didn't invoke us to schedule the reload, so the reload
  81. // wasn't actually started. Clear the keep-alive so we don't wait forever.
  82. keep_alive_requester_.StopTrackingReload(extension_id);
  83. }
  84. void ShellExtensionLoader::FinishExtensionReload(
  85. const ExtensionId old_extension_id,
  86. scoped_refptr<const Extension> extension) {
  87. if (extension) {
  88. extension_registrar_.AddExtension(extension);
  89. // If the extension is a platform app, adding it above caused
  90. // ShellKeepAliveRequester to create a new keep-alive to wait for the app to
  91. // open its first window.
  92. // Launch the app now.
  93. if (extension->is_platform_app())
  94. apps::LaunchPlatformApp(browser_context_, extension.get(),
  95. AppLaunchSource::kSourceReload);
  96. }
  97. // Whether or not the reload succeeded, we should stop waiting for it.
  98. keep_alive_requester_.StopTrackingReload(old_extension_id);
  99. }
  100. void ShellExtensionLoader::PreAddExtension(const Extension* extension,
  101. const Extension* old_extension) {
  102. if (old_extension)
  103. return;
  104. // The extension might be disabled if a previous reload attempt failed. In
  105. // that case, we want to remove that disable reason.
  106. ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_);
  107. if (extension_prefs->IsExtensionDisabled(extension->id()) &&
  108. extension_prefs->HasDisableReason(extension->id(),
  109. disable_reason::DISABLE_RELOAD)) {
  110. extension_prefs->RemoveDisableReason(extension->id(),
  111. disable_reason::DISABLE_RELOAD);
  112. // Only re-enable the extension if there are no other disable reasons.
  113. if (extension_prefs->GetDisableReasons(extension->id()) ==
  114. disable_reason::DISABLE_NONE) {
  115. extension_prefs->SetExtensionEnabled(extension->id());
  116. }
  117. }
  118. }
  119. void ShellExtensionLoader::PostActivateExtension(
  120. scoped_refptr<const Extension> extension) {}
  121. void ShellExtensionLoader::PostDeactivateExtension(
  122. scoped_refptr<const Extension> extension) {}
  123. void ShellExtensionLoader::LoadExtensionForReload(
  124. const ExtensionId& extension_id,
  125. const base::FilePath& path,
  126. LoadErrorBehavior load_error_behavior) {
  127. CHECK(!path.empty());
  128. base::PostTaskAndReplyWithResult(
  129. GetExtensionFileTaskRunner().get(), FROM_HERE,
  130. base::BindOnce(&LoadUnpacked, path),
  131. base::BindOnce(&ShellExtensionLoader::FinishExtensionReload,
  132. weak_factory_.GetWeakPtr(), extension_id));
  133. did_schedule_reload_ = true;
  134. }
  135. bool ShellExtensionLoader::CanEnableExtension(const Extension* extension) {
  136. return true;
  137. }
  138. bool ShellExtensionLoader::CanDisableExtension(const Extension* extension) {
  139. // Extensions cannot be disabled by the user.
  140. return false;
  141. }
  142. bool ShellExtensionLoader::ShouldBlockExtension(const Extension* extension) {
  143. return false;
  144. }
  145. } // namespace extensions