extension_registrar.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. // Copyright 2017 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/browser/extension_registrar.h"
  5. #include "base/bind.h"
  6. #include "base/callback_helpers.h"
  7. #include "base/check_op.h"
  8. #include "base/containers/contains.h"
  9. #include "base/metrics/histogram_macros.h"
  10. #include "base/notreached.h"
  11. #include "build/chromeos_buildflags.h"
  12. #include "content/public/browser/browser_context.h"
  13. #include "content/public/browser/browser_thread.h"
  14. #include "content/public/browser/devtools_agent_host.h"
  15. #include "content/public/browser/storage_partition.h"
  16. #include "extensions/browser/app_sorting.h"
  17. #include "extensions/browser/blocklist_extension_prefs.h"
  18. #include "extensions/browser/extension_host.h"
  19. #include "extensions/browser/extension_prefs.h"
  20. #include "extensions/browser/extension_registry.h"
  21. #include "extensions/browser/extension_system.h"
  22. #include "extensions/browser/extension_util.h"
  23. #include "extensions/browser/lazy_context_id.h"
  24. #include "extensions/browser/lazy_context_task_queue.h"
  25. #include "extensions/browser/process_manager.h"
  26. #include "extensions/browser/renderer_startup_helper.h"
  27. #include "extensions/browser/service_worker_task_queue.h"
  28. #include "extensions/browser/task_queue_util.h"
  29. #include "extensions/common/manifest_handlers/background_info.h"
  30. #include "extensions/common/permissions/permissions_data.h"
  31. #if BUILDFLAG(IS_CHROMEOS_ASH)
  32. #include "chrome/browser/ash/crosapi/browser_util.h"
  33. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  34. using content::DevToolsAgentHost;
  35. namespace extensions {
  36. ExtensionRegistrar::ExtensionRegistrar(content::BrowserContext* browser_context,
  37. Delegate* delegate)
  38. : browser_context_(browser_context),
  39. delegate_(delegate),
  40. extension_system_(ExtensionSystem::Get(browser_context)),
  41. extension_prefs_(ExtensionPrefs::Get(browser_context)),
  42. registry_(ExtensionRegistry::Get(browser_context)),
  43. renderer_helper_(
  44. RendererStartupHelperFactory::GetForBrowserContext(browser_context)) {
  45. // ExtensionRegistrar is created by ExtensionSystem via ExtensionService, and
  46. // ExtensionSystemFactory depends on ProcessManager, so this should be safe.
  47. auto* process_manager = ProcessManager::Get(browser_context_);
  48. DCHECK(process_manager);
  49. process_manager_observation_.Observe(process_manager);
  50. }
  51. ExtensionRegistrar::~ExtensionRegistrar() = default;
  52. void ExtensionRegistrar::AddExtension(
  53. scoped_refptr<const Extension> extension) {
  54. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  55. bool is_extension_loaded = false;
  56. const Extension* old = registry_->GetInstalledExtension(extension->id());
  57. if (old) {
  58. is_extension_loaded = true;
  59. int version_compare_result = extension->version().CompareTo(old->version());
  60. // Other than for unpacked extensions, we should not be downgrading.
  61. if (!Manifest::IsUnpackedLocation(extension->location()) &&
  62. version_compare_result < 0) {
  63. UMA_HISTOGRAM_ENUMERATION(
  64. "Extensions.AttemptedToDowngradeVersionLocation",
  65. extension->location());
  66. // TODO(https://crbug.com/810799): It would be awfully nice to CHECK this,
  67. // but that's caused problems. There are apparently times when this
  68. // happens that we aren't accounting for. We should track those down and
  69. // fix them, but it can be tricky.
  70. NOTREACHED() << "Attempted to downgrade extension."
  71. << "\nID: " << extension->id()
  72. << "\nOld Version: " << old->version()
  73. << "\nNew Version: " << extension->version()
  74. << "\nLocation: " << extension->location();
  75. return;
  76. }
  77. }
  78. // If the extension was disabled for a reload, we will enable it.
  79. bool was_reloading = reloading_extensions_.erase(extension->id()) > 0;
  80. // The extension is now loaded; remove its data from unloaded extension map.
  81. unloaded_extension_paths_.erase(extension->id());
  82. // If a terminated extension is loaded, remove it from the terminated list.
  83. UntrackTerminatedExtension(extension->id());
  84. // Notify the delegate we will add the extension.
  85. delegate_->PreAddExtension(extension.get(), old);
  86. if (was_reloading) {
  87. failed_to_reload_unpacked_extensions_.erase(extension->path());
  88. ReplaceReloadedExtension(extension);
  89. } else {
  90. if (is_extension_loaded) {
  91. // To upgrade an extension in place, remove the old one and then activate
  92. // the new one. ReloadExtension disables the extension, which is
  93. // sufficient.
  94. RemoveExtension(extension->id(), UnloadedExtensionReason::UPDATE);
  95. }
  96. AddNewExtension(extension);
  97. }
  98. }
  99. void ExtensionRegistrar::AddNewExtension(
  100. scoped_refptr<const Extension> extension) {
  101. if (blocklist_prefs::IsExtensionBlocklisted(extension->id(),
  102. extension_prefs_)) {
  103. DCHECK(!Manifest::IsComponentLocation(extension->location()));
  104. // Only prefs is checked for the blocklist. We rely on callers to check the
  105. // blocklist before calling into here, e.g. CrxInstaller checks before
  106. // installation then threads through the install and pending install flow
  107. // of this class, and ExtensionService checks when loading installed
  108. // extensions.
  109. registry_->AddBlocklisted(extension);
  110. } else if (delegate_->ShouldBlockExtension(extension.get())) {
  111. DCHECK(!Manifest::IsComponentLocation(extension->location()));
  112. registry_->AddBlocked(extension);
  113. } else if (extension_prefs_->IsExtensionDisabled(extension->id())) {
  114. registry_->AddDisabled(extension);
  115. } else { // Extension should be enabled.
  116. // All apps that are displayed in the launcher are ordered by their ordinals
  117. // so we must ensure they have valid ordinals.
  118. if (extension->RequiresSortOrdinal()) {
  119. AppSorting* app_sorting = extension_system_->app_sorting();
  120. app_sorting->SetExtensionVisible(extension->id(),
  121. extension->ShouldDisplayInNewTabPage());
  122. app_sorting->EnsureValidOrdinals(extension->id(),
  123. syncer::StringOrdinal());
  124. }
  125. registry_->AddEnabled(extension);
  126. ActivateExtension(extension.get(), true);
  127. }
  128. }
  129. void ExtensionRegistrar::RemoveExtension(const ExtensionId& extension_id,
  130. UnloadedExtensionReason reason) {
  131. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  132. int include_mask = ExtensionRegistry::ENABLED | ExtensionRegistry::DISABLED |
  133. ExtensionRegistry::TERMINATED;
  134. scoped_refptr<const Extension> extension(
  135. registry_->GetExtensionById(extension_id, include_mask));
  136. // If the extension is blocked/blocklisted, no need to notify again.
  137. if (!extension)
  138. return;
  139. if (registry_->terminated_extensions().Contains(extension_id)) {
  140. // The extension was already deactivated from the call to
  141. // TerminateExtension(), which also should have added it to
  142. // unloaded_extension_paths_ if necessary.
  143. registry_->RemoveTerminated(extension->id());
  144. return;
  145. }
  146. // Keep information about the extension so that we can reload it later
  147. // even if it's not permanently installed.
  148. unloaded_extension_paths_[extension->id()] = extension->path();
  149. // Stop tracking whether the extension was meant to be enabled after a reload.
  150. reloading_extensions_.erase(extension->id());
  151. if (registry_->enabled_extensions().Contains(extension_id)) {
  152. registry_->RemoveEnabled(extension_id);
  153. DeactivateExtension(extension.get(), reason);
  154. } else {
  155. // The extension was already deactivated from the call to
  156. // DisableExtension().
  157. bool removed = registry_->RemoveDisabled(extension->id());
  158. DCHECK(removed);
  159. }
  160. }
  161. void ExtensionRegistrar::EnableExtension(const ExtensionId& extension_id) {
  162. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  163. // If the extension is currently reloading, it will be enabled once the reload
  164. // is complete.
  165. if (reloading_extensions_.count(extension_id) > 0)
  166. return;
  167. // First, check that the extension can be enabled.
  168. if (IsExtensionEnabled(extension_id) ||
  169. blocklist_prefs::IsExtensionBlocklisted(extension_id, extension_prefs_) ||
  170. registry_->blocked_extensions().Contains(extension_id)) {
  171. return;
  172. }
  173. const Extension* extension =
  174. registry_->disabled_extensions().GetByID(extension_id);
  175. if (extension && !delegate_->CanEnableExtension(extension))
  176. return;
  177. // Now that we know the extension can be enabled, update the prefs.
  178. extension_prefs_->SetExtensionEnabled(extension_id);
  179. // This can happen if sync enables an extension that is not installed yet.
  180. if (!extension)
  181. return;
  182. // Actually enable the extension.
  183. registry_->AddEnabled(extension);
  184. registry_->RemoveDisabled(extension->id());
  185. ActivateExtension(extension, false);
  186. }
  187. void ExtensionRegistrar::DisableExtension(const ExtensionId& extension_id,
  188. int disable_reasons) {
  189. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  190. DCHECK_NE(disable_reason::DISABLE_NONE, disable_reasons);
  191. scoped_refptr<const Extension> extension =
  192. registry_->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
  193. bool is_controlled_extension =
  194. !delegate_->CanDisableExtension(extension.get());
  195. if (is_controlled_extension) {
  196. // Remove disallowed disable reasons.
  197. // Certain disable reasons are always allowed, since they are more internal
  198. // to the browser (rather than the user choosing to disable the extension).
  199. int internal_disable_reason_mask =
  200. extensions::disable_reason::DISABLE_RELOAD |
  201. extensions::disable_reason::DISABLE_CORRUPTED |
  202. extensions::disable_reason::DISABLE_UPDATE_REQUIRED_BY_POLICY |
  203. extensions::disable_reason::DISABLE_BLOCKED_BY_POLICY |
  204. extensions::disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED |
  205. extensions::disable_reason::DISABLE_REINSTALL;
  206. #if BUILDFLAG(IS_CHROMEOS_ASH)
  207. // For controlled extensions, only allow disabling not ash-keeplisted
  208. // extensions if Lacros is the only browser.
  209. if (!crosapi::browser_util::IsAshWebBrowserEnabled()) {
  210. internal_disable_reason_mask |=
  211. extensions::disable_reason::DISABLE_NOT_ASH_KEEPLISTED;
  212. }
  213. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  214. disable_reasons &= internal_disable_reason_mask;
  215. if (disable_reasons == disable_reason::DISABLE_NONE)
  216. return;
  217. }
  218. // The extension may have been disabled already. Just add the disable reasons.
  219. if (!IsExtensionEnabled(extension_id)) {
  220. extension_prefs_->AddDisableReasons(extension_id, disable_reasons);
  221. return;
  222. }
  223. extension_prefs_->SetExtensionDisabled(extension_id, disable_reasons);
  224. int include_mask =
  225. ExtensionRegistry::EVERYTHING & ~ExtensionRegistry::DISABLED;
  226. extension = registry_->GetExtensionById(extension_id, include_mask);
  227. if (!extension)
  228. return;
  229. // The extension is either enabled or terminated.
  230. DCHECK(registry_->enabled_extensions().Contains(extension->id()) ||
  231. registry_->terminated_extensions().Contains(extension->id()));
  232. // Move the extension to the disabled list.
  233. registry_->AddDisabled(extension);
  234. if (registry_->enabled_extensions().Contains(extension->id())) {
  235. registry_->RemoveEnabled(extension->id());
  236. DeactivateExtension(extension.get(), UnloadedExtensionReason::DISABLE);
  237. } else {
  238. // The extension must have been terminated. Don't send additional
  239. // notifications for it being disabled.
  240. bool removed = registry_->RemoveTerminated(extension->id());
  241. DCHECK(removed);
  242. }
  243. }
  244. namespace {
  245. std::vector<scoped_refptr<DevToolsAgentHost>> GetDevToolsAgentHostsFor(
  246. ProcessManager* process_manager,
  247. const Extension* extension) {
  248. std::vector<scoped_refptr<DevToolsAgentHost>> result;
  249. if (!BackgroundInfo::IsServiceWorkerBased(extension)) {
  250. ExtensionHost* host =
  251. process_manager->GetBackgroundHostForExtension(extension->id());
  252. if (host && content::DevToolsAgentHost::HasFor(host->host_contents())) {
  253. result.push_back(
  254. content::DevToolsAgentHost::GetOrCreateFor(host->host_contents()));
  255. }
  256. } else {
  257. content::ServiceWorkerContext* context =
  258. util::GetStoragePartitionForExtensionId(
  259. extension->id(), process_manager->browser_context())
  260. ->GetServiceWorkerContext();
  261. std::vector<WorkerId> service_worker_ids =
  262. process_manager->GetServiceWorkersForExtension(extension->id());
  263. for (const auto& worker_id : service_worker_ids) {
  264. auto devtools_host =
  265. DevToolsAgentHost::GetForServiceWorker(context, worker_id.version_id);
  266. if (devtools_host)
  267. result.push_back(std::move(devtools_host));
  268. }
  269. }
  270. return result;
  271. }
  272. } // namespace
  273. void ExtensionRegistrar::ReloadExtension(
  274. const ExtensionId extension_id, // Passed by value because reloading can
  275. // invalidate a reference to the ID.
  276. LoadErrorBehavior load_error_behavior) {
  277. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  278. base::FilePath path;
  279. const Extension* disabled_extension =
  280. registry_->disabled_extensions().GetByID(extension_id);
  281. if (disabled_extension) {
  282. path = disabled_extension->path();
  283. }
  284. // If the extension is already reloading, don't reload again.
  285. if (extension_prefs_->HasDisableReason(extension_id,
  286. disable_reason::DISABLE_RELOAD)) {
  287. DCHECK(disabled_extension);
  288. // If an unpacked extension previously failed to reload, it will still be
  289. // marked as disabled, but we can try to reload it again - the developer
  290. // may have fixed the issue.
  291. if (failed_to_reload_unpacked_extensions_.count(path) == 0)
  292. return;
  293. failed_to_reload_unpacked_extensions_.erase(path);
  294. }
  295. // Ignore attempts to reload a blocklisted or blocked extension. Sometimes
  296. // this can happen in a convoluted reload sequence triggered by the
  297. // termination of a blocklisted or blocked extension and a naive attempt to
  298. // reload it. For an example see http://crbug.com/373842.
  299. if (registry_->blocklisted_extensions().Contains(extension_id) ||
  300. registry_->blocked_extensions().Contains(extension_id)) {
  301. return;
  302. }
  303. const Extension* enabled_extension =
  304. registry_->enabled_extensions().GetByID(extension_id);
  305. // Disable the extension if it's loaded. It might not be loaded if it crashed.
  306. if (enabled_extension) {
  307. // If the extension has an inspector open for its background page, detach
  308. // the inspector and hang onto a cookie for it, so that we can reattach
  309. // later.
  310. // TODO(yoz): this is not incognito-safe!
  311. ProcessManager* manager = ProcessManager::Get(browser_context_);
  312. auto agent_hosts = GetDevToolsAgentHostsFor(manager, enabled_extension);
  313. if (!agent_hosts.empty()) {
  314. for (auto& host : agent_hosts) {
  315. // Let DevTools know we'll be back once extension is reloaded.
  316. // TODO(caseq): this should rather be called Disconnect().
  317. host->DisconnectWebContents();
  318. }
  319. // Retain DevToolsAgentHosts for the extension being reloaded to prevent
  320. // client disconnecting. We will re-attach later, when the extension is
  321. // loaded.
  322. // TODO(crbug.com/1246530): clean up upon failure to reload.
  323. orphaned_dev_tools_[extension_id] = std::move(agent_hosts);
  324. }
  325. path = enabled_extension->path();
  326. DisableExtension(extension_id, disable_reason::DISABLE_RELOAD);
  327. DCHECK(registry_->disabled_extensions().Contains(extension_id));
  328. reloading_extensions_.insert(extension_id);
  329. } else if (!disabled_extension) {
  330. std::map<ExtensionId, base::FilePath>::const_iterator iter =
  331. unloaded_extension_paths_.find(extension_id);
  332. if (iter == unloaded_extension_paths_.end()) {
  333. return;
  334. }
  335. path = unloaded_extension_paths_[extension_id];
  336. }
  337. delegate_->LoadExtensionForReload(extension_id, path, load_error_behavior);
  338. }
  339. void ExtensionRegistrar::OnUnpackedExtensionReloadFailed(
  340. const base::FilePath& path) {
  341. failed_to_reload_unpacked_extensions_.insert(path);
  342. }
  343. void ExtensionRegistrar::TerminateExtension(const ExtensionId& extension_id) {
  344. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  345. scoped_refptr<const Extension> extension =
  346. registry_->enabled_extensions().GetByID(extension_id);
  347. if (!extension)
  348. return;
  349. // Keep information about the extension so that we can reload it later
  350. // even if it's not permanently installed.
  351. unloaded_extension_paths_[extension->id()] = extension->path();
  352. DCHECK(!base::Contains(reloading_extensions_, extension->id()))
  353. << "Enabled extension shouldn't be marked for reloading";
  354. registry_->AddTerminated(extension);
  355. registry_->RemoveEnabled(extension_id);
  356. DeactivateExtension(extension.get(), UnloadedExtensionReason::TERMINATE);
  357. }
  358. void ExtensionRegistrar::UntrackTerminatedExtension(
  359. const ExtensionId& extension_id) {
  360. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  361. scoped_refptr<const Extension> extension =
  362. registry_->terminated_extensions().GetByID(extension_id);
  363. if (!extension)
  364. return;
  365. registry_->RemoveTerminated(extension_id);
  366. }
  367. bool ExtensionRegistrar::IsExtensionEnabled(
  368. const ExtensionId& extension_id) const {
  369. if (registry_->enabled_extensions().Contains(extension_id) ||
  370. registry_->terminated_extensions().Contains(extension_id)) {
  371. return true;
  372. }
  373. if (registry_->disabled_extensions().Contains(extension_id) ||
  374. registry_->blocklisted_extensions().Contains(extension_id) ||
  375. registry_->blocked_extensions().Contains(extension_id)) {
  376. return false;
  377. }
  378. if (delegate_->ShouldBlockExtension(nullptr))
  379. return false;
  380. // If the extension hasn't been loaded yet, check the prefs for it. Assume
  381. // enabled unless otherwise noted.
  382. return !extension_prefs_->IsExtensionDisabled(extension_id) &&
  383. !blocklist_prefs::IsExtensionBlocklisted(extension_id,
  384. extension_prefs_) &&
  385. !extension_prefs_->IsExternalExtensionUninstalled(extension_id);
  386. }
  387. void ExtensionRegistrar::DidCreateMainFrameForBackgroundPage(
  388. ExtensionHost* host) {
  389. auto iter = orphaned_dev_tools_.find(host->extension_id());
  390. if (iter == orphaned_dev_tools_.end())
  391. return;
  392. // Keepalive count is reset on extension reload. This re-establishes the
  393. // keepalive that was added when the DevTools agent was initially attached.
  394. ProcessManager::Get(browser_context_)
  395. ->IncrementLazyKeepaliveCount(host->extension(), Activity::DEV_TOOLS,
  396. std::string());
  397. DCHECK_GE(1u, iter->second.size());
  398. // TODO(caseq): do we need to handle the case when the extension changed
  399. // from SW-based to WC-based during reload?
  400. iter->second[0]->ConnectWebContents(host->host_contents());
  401. orphaned_dev_tools_.erase(iter);
  402. }
  403. void ExtensionRegistrar::ActivateExtension(const Extension* extension,
  404. bool is_newly_added) {
  405. // The URLRequestContexts need to be first to know that the extension
  406. // was loaded. Otherwise a race can arise where a renderer that is created
  407. // for the extension may try to load an extension URL with an extension id
  408. // that the request context doesn't yet know about. The BrowserContext should
  409. // ensure its URLRequestContexts appropriately discover the loaded extension.
  410. extension_system_->RegisterExtensionWithRequestContexts(
  411. extension,
  412. base::BindOnce(
  413. &ExtensionRegistrar::OnExtensionRegisteredWithRequestContexts,
  414. weak_factory_.GetWeakPtr(), WrapRefCounted(extension)));
  415. // Activate the extension before calling
  416. // RendererStartupHelper::OnExtensionLoaded() below, so that we have
  417. // activation information ready while we send ExtensionMsg_Load IPC.
  418. //
  419. // TODO(lazyboy): We should move all logic that is required to start up an
  420. // extension to a separate class, instead of calling adhoc methods like
  421. // service worker ones below.
  422. ActivateTaskQueueForExtension(browser_context_, extension);
  423. renderer_helper_->OnExtensionLoaded(*extension);
  424. // Tell subsystems that use the ExtensionRegistryObserver::OnExtensionLoaded
  425. // about the new extension.
  426. //
  427. // NOTE: It is important that this happen after notifying the renderers about
  428. // the new extensions so that if we navigate to an extension URL in
  429. // ExtensionRegistryObserver::OnExtensionLoaded the renderer is guaranteed to
  430. // know about it.
  431. registry_->TriggerOnLoaded(extension);
  432. delegate_->PostActivateExtension(extension);
  433. // When an extension is activated, and it is either event page-based or
  434. // service worker-based, it may be necessary to spin up its context.
  435. if (BackgroundInfo::HasLazyContext(extension))
  436. MaybeSpinUpLazyContext(extension, is_newly_added);
  437. }
  438. void ExtensionRegistrar::DeactivateExtension(const Extension* extension,
  439. UnloadedExtensionReason reason) {
  440. registry_->TriggerOnUnloaded(extension, reason);
  441. renderer_helper_->OnExtensionUnloaded(*extension);
  442. extension_system_->UnregisterExtensionWithRequestContexts(extension->id());
  443. DeactivateTaskQueueForExtension(browser_context_, extension);
  444. delegate_->PostDeactivateExtension(extension);
  445. }
  446. bool ExtensionRegistrar::ReplaceReloadedExtension(
  447. scoped_refptr<const Extension> extension) {
  448. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  449. // The extension must already be disabled, and the original extension has
  450. // been unloaded.
  451. CHECK(registry_->disabled_extensions().Contains(extension->id()));
  452. if (!delegate_->CanEnableExtension(extension.get()))
  453. return false;
  454. // TODO(michaelpg): Other disable reasons might have been added after the
  455. // reload started. We may want to keep the extension disabled and just remove
  456. // the DISABLE_RELOAD reason in that case.
  457. extension_prefs_->SetExtensionEnabled(extension->id());
  458. // Move it over to the enabled list.
  459. CHECK(registry_->RemoveDisabled(extension->id()));
  460. CHECK(registry_->AddEnabled(extension));
  461. ActivateExtension(extension.get(), false);
  462. return true;
  463. }
  464. void ExtensionRegistrar::OnExtensionRegisteredWithRequestContexts(
  465. scoped_refptr<const Extension> extension) {
  466. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  467. registry_->AddReady(extension);
  468. if (registry_->enabled_extensions().Contains(extension->id()))
  469. registry_->TriggerOnReady(extension.get());
  470. }
  471. void ExtensionRegistrar::MaybeSpinUpLazyContext(const Extension* extension,
  472. bool is_newly_added) {
  473. DCHECK(BackgroundInfo::HasLazyContext(extension));
  474. // For orphaned devtools, we will reconnect devtools to it later in
  475. // DidCreateMainFrameForBackgroundPage().
  476. bool has_orphaned_dev_tools =
  477. base::Contains(orphaned_dev_tools_, extension->id());
  478. // Reloading component extension does not trigger install, so RuntimeAPI won't
  479. // be able to detect its loading. Therefore, we need to spin up its lazy
  480. // background page.
  481. bool is_component_extension =
  482. Manifest::IsComponentLocation(extension->location());
  483. // TODO(crbug.com/1024211): This is either a workaround or something
  484. // that will be part of the permanent solution for service worker-
  485. // based extensions.
  486. // We spin up extensions with the webRequest permission so their
  487. // listeners are reconstructed on load.
  488. bool has_web_request_permission =
  489. extension->permissions_data()->HasAPIPermission(
  490. mojom::APIPermissionID::kWebRequest);
  491. // Event page-based extension cannot have the webRequest permission.
  492. DCHECK(!has_web_request_permission ||
  493. BackgroundInfo::IsServiceWorkerBased(extension));
  494. // If there aren't any special cases, we're done.
  495. if (!has_orphaned_dev_tools && !is_component_extension &&
  496. !has_web_request_permission) {
  497. return;
  498. }
  499. // If the extension's not being reloaded (|is_newly_added| = true),
  500. // only wake it up if it has the webRequest permission.
  501. if (is_newly_added && !has_web_request_permission)
  502. return;
  503. // Wake up the extension by posting a dummy task. In the case of a service
  504. // worker-based extension with the webRequest permission that's being newly
  505. // installed, this will result in a no-op task that's not necessary, since
  506. // this is really only needed for a previously-installed extension. However,
  507. // that cost is minimal, since the worker is already active.
  508. const LazyContextId context_id(browser_context_, extension);
  509. context_id.GetTaskQueue()->AddPendingTask(context_id, base::DoNothing());
  510. }
  511. void ExtensionRegistrar::OnServiceWorkerRegistered(const WorkerId& worker_id) {
  512. // Just release the host. We only get here when the new worker has been
  513. // attached and resumed by the DevTools, and all we need in case of service
  514. // worker-based extensions is to keep the host around for the target
  515. // auto-attacher to do its job.
  516. orphaned_dev_tools_.erase(worker_id.extension_id);
  517. }
  518. } // namespace extensions