service_worker_task_queue.cc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  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/service_worker_task_queue.h"
  5. #include <memory>
  6. #include <type_traits>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/bind.h"
  10. #include "base/containers/contains.h"
  11. #include "base/metrics/histogram_macros.h"
  12. #include "base/strings/stringprintf.h"
  13. #include "base/strings/utf_string_conversions.h"
  14. #include "base/syslog_logging.h"
  15. #include "content/public/browser/browser_context.h"
  16. #include "content/public/browser/browser_task_traits.h"
  17. #include "content/public/browser/browser_thread.h"
  18. #include "content/public/browser/child_process_security_policy.h"
  19. #include "content/public/browser/console_message.h"
  20. #include "content/public/browser/render_process_host.h"
  21. #include "content/public/browser/service_worker_context.h"
  22. #include "content/public/browser/storage_partition.h"
  23. #include "extensions/browser/event_router.h"
  24. #include "extensions/browser/extension_error.h"
  25. #include "extensions/browser/extension_prefs.h"
  26. #include "extensions/browser/extension_registry.h"
  27. #include "extensions/browser/extension_util.h"
  28. #include "extensions/browser/extensions_browser_client.h"
  29. #include "extensions/browser/process_manager.h"
  30. #include "extensions/browser/renderer_startup_helper.h"
  31. #include "extensions/browser/service_worker_task_queue_factory.h"
  32. #include "extensions/common/constants.h"
  33. #include "extensions/common/manifest_constants.h"
  34. #include "extensions/common/manifest_handlers/background_info.h"
  35. #include "extensions/common/manifest_handlers/incognito_info.h"
  36. #include "third_party/blink/public/common/storage_key/storage_key.h"
  37. #include "third_party/blink/public/mojom/service_worker/service_worker_registration_options.mojom.h"
  38. #include "url/origin.h"
  39. using content::BrowserContext;
  40. namespace extensions {
  41. namespace {
  42. // A preference key storing the information about an extension that was
  43. // activated and has a registered worker based background page.
  44. const char kPrefServiceWorkerRegistrationInfo[] =
  45. "service_worker_registration_info";
  46. // The extension version of the registered service worker.
  47. const char kServiceWorkerVersion[] = "version";
  48. ServiceWorkerTaskQueue::TestObserver* g_test_observer = nullptr;
  49. // ServiceWorkerRegistration state of an activated extension.
  50. enum class RegistrationState {
  51. // Not registered.
  52. kNotRegistered,
  53. // Registration is inflight.
  54. kPending,
  55. // Registration is complete.
  56. kRegistered,
  57. };
  58. // Browser process worker state of an activated extension.
  59. enum class BrowserState {
  60. // Initial state, not started.
  61. kInitial,
  62. // Worker is in the process of starting from the browser process.
  63. kStarting,
  64. // Worker has completed starting (i.e. has seen DidStartWorkerForScope).
  65. kStarted,
  66. };
  67. // Render process worker state of an activated extension.
  68. enum class RendererState {
  69. // Initial state, neither started nor stopped.
  70. kInitial,
  71. // Worker thread has started.
  72. kStarted,
  73. // Worker thread has not started or has been stopped.
  74. kStopped,
  75. };
  76. } // namespace
  77. ServiceWorkerTaskQueue::ServiceWorkerTaskQueue(BrowserContext* browser_context)
  78. : browser_context_(browser_context) {}
  79. ServiceWorkerTaskQueue::~ServiceWorkerTaskQueue() {
  80. for (auto* const service_worker_context : observing_worker_contexts_)
  81. service_worker_context->RemoveObserver(this);
  82. }
  83. ServiceWorkerTaskQueue::TestObserver::TestObserver() {}
  84. ServiceWorkerTaskQueue::TestObserver::~TestObserver() {}
  85. // static
  86. ServiceWorkerTaskQueue* ServiceWorkerTaskQueue::Get(BrowserContext* context) {
  87. return ServiceWorkerTaskQueueFactory::GetForBrowserContext(context);
  88. }
  89. // The current worker related state of an activated extension.
  90. class ServiceWorkerTaskQueue::WorkerState {
  91. public:
  92. WorkerState() = default;
  93. WorkerState(const WorkerState&) = delete;
  94. WorkerState& operator=(const WorkerState&) = delete;
  95. void SetWorkerId(const WorkerId& worker_id, ProcessManager* process_manager) {
  96. if (worker_id_ && *worker_id_ != worker_id) {
  97. // Sanity check that the old worker is gone.
  98. DCHECK(!process_manager->HasServiceWorker(*worker_id_));
  99. // Clear stale renderer state if there's any.
  100. renderer_state_ = RendererState::kInitial;
  101. }
  102. worker_id_ = worker_id;
  103. }
  104. bool ready() const {
  105. return registration_state_ == RegistrationState::kRegistered &&
  106. browser_state_ == BrowserState::kStarted &&
  107. renderer_state_ == RendererState::kStarted && worker_id_.has_value();
  108. }
  109. bool has_pending_tasks() const { return !pending_tasks_.empty(); }
  110. private:
  111. friend class ServiceWorkerTaskQueue;
  112. RegistrationState registration_state_ = RegistrationState::kNotRegistered;
  113. BrowserState browser_state_ = BrowserState::kInitial;
  114. RendererState renderer_state_ = RendererState::kInitial;
  115. // Pending tasks that will be run once the worker becomes ready.
  116. std::vector<PendingTask> pending_tasks_;
  117. // Contains the worker's WorkerId associated with this WorkerState, once we
  118. // have discovered info about the worker.
  119. absl::optional<WorkerId> worker_id_;
  120. };
  121. void ServiceWorkerTaskQueue::DidStartWorkerForScope(
  122. const SequencedContextId& context_id,
  123. base::Time start_time,
  124. int64_t version_id,
  125. int process_id,
  126. int thread_id) {
  127. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  128. const ExtensionId& extension_id = context_id.first.extension_id();
  129. const ActivationSequence& sequence = context_id.second;
  130. if (!IsCurrentSequence(extension_id, sequence)) {
  131. // Extension run with |sequence| was already deactivated.
  132. // TODO(lazyboy): Add a DCHECK that the worker in question is actually
  133. // shutting down soon.
  134. DCHECK(!GetWorkerState(context_id));
  135. return;
  136. }
  137. // HACK: The service worker layer might invoke this callback with an ID for a
  138. // RenderProcessHost that has already terminated. This isn't the right fix for
  139. // this, because it results in the internal state here stalling out - we'll
  140. // wait on the browser side to be ready, which will never happen. This should
  141. // be cleaned up on the next activation sequence, but this still isn't good.
  142. // The proper fix here is that the service worker layer shouldn't be invoking
  143. // this callback with stale processes.
  144. // https://crbug.com/1335821.
  145. if (!content::RenderProcessHost::FromID(process_id)) {
  146. // NOTE: The following is an antipattern [1]. We have this as a temporary
  147. // hack to avoid crashing for stable users while the bug is addressed.
  148. // [1]
  149. // https://chromium.googlesource.com/chromium/src/+/HEAD/styleguide/c++/c++-dos-and-donts.md#guarding-with-dcheck_is_on
  150. NOTREACHED();
  151. return;
  152. }
  153. UMA_HISTOGRAM_BOOLEAN("Extensions.ServiceWorkerBackground.StartWorkerStatus",
  154. true);
  155. UMA_HISTOGRAM_TIMES("Extensions.ServiceWorkerBackground.StartWorkerTime",
  156. base::Time::Now() - start_time);
  157. WorkerState* worker_state = GetWorkerState(context_id);
  158. DCHECK(worker_state);
  159. const WorkerId worker_id = {extension_id, process_id, version_id, thread_id};
  160. // Note: If the worker has already stopped on worker thread
  161. // (DidStopServiceWorkerContext) before we got here (i.e. the browser has
  162. // finished starting the worker), then |worker_state_map_| will hold the
  163. // worker until deactivation.
  164. // TODO(lazyboy): We need to ensure that the worker is not stopped in the
  165. // renderer before we execute tasks in the browser process. This will also
  166. // avoid holding the worker in |worker_state_map_| until deactivation as noted
  167. // above.
  168. DCHECK_NE(BrowserState::kStarted, worker_state->browser_state_)
  169. << "Worker was already loaded";
  170. worker_state->SetWorkerId(worker_id, ProcessManager::Get(browser_context_));
  171. worker_state->browser_state_ = BrowserState::kStarted;
  172. RunPendingTasksIfWorkerReady(context_id);
  173. }
  174. void ServiceWorkerTaskQueue::DidStartWorkerFail(
  175. const SequencedContextId& context_id,
  176. blink::ServiceWorkerStatusCode status_code) {
  177. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  178. if (!IsCurrentSequence(context_id.first.extension_id(), context_id.second)) {
  179. // This can happen is when the registration got unregistered right before we
  180. // tried to start it. See crbug.com/999027 for details.
  181. DCHECK(!GetWorkerState(context_id));
  182. return;
  183. }
  184. UMA_HISTOGRAM_BOOLEAN("Extensions.ServiceWorkerBackground.StartWorkerStatus",
  185. false);
  186. WorkerState* worker_state = GetWorkerState(context_id);
  187. DCHECK(worker_state);
  188. if (g_test_observer) {
  189. g_test_observer->DidStartWorkerFail(context_id.first.extension_id(),
  190. worker_state->pending_tasks_.size(),
  191. status_code);
  192. }
  193. worker_state->pending_tasks_.clear();
  194. // TODO(https://crbug/1062936): Needs more thought: extension would be in
  195. // perma-broken state after this as the registration wouldn't be stored if
  196. // this happens.
  197. LOG(ERROR)
  198. << "DidStartWorkerFail " << context_id.first.extension_id() << ": "
  199. << static_cast<std::underlying_type_t<blink::ServiceWorkerStatusCode>>(
  200. status_code);
  201. }
  202. void ServiceWorkerTaskQueue::DidInitializeServiceWorkerContext(
  203. int render_process_id,
  204. const ExtensionId& extension_id,
  205. int64_t service_worker_version_id,
  206. int thread_id) {
  207. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  208. ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
  209. DCHECK(registry);
  210. const Extension* extension =
  211. registry->enabled_extensions().GetByID(extension_id);
  212. // The caller should have validated that the extension is still enabled.
  213. CHECK(extension);
  214. content::RenderProcessHost* process_host =
  215. content::RenderProcessHost::FromID(render_process_id);
  216. // The caller should have validated that the RenderProcessHost is still
  217. // active.
  218. CHECK(process_host);
  219. util::InitializeFileSchemeAccessForExtension(render_process_id, extension_id,
  220. browser_context_);
  221. ProcessManager::Get(browser_context_)
  222. ->RegisterServiceWorker({extension_id, render_process_id,
  223. service_worker_version_id, thread_id});
  224. RendererStartupHelperFactory::GetForBrowserContext(browser_context_)
  225. ->ActivateExtensionInProcess(*extension, process_host);
  226. }
  227. void ServiceWorkerTaskQueue::DidStartServiceWorkerContext(
  228. int render_process_id,
  229. const ExtensionId& extension_id,
  230. ActivationSequence activation_sequence,
  231. const GURL& service_worker_scope,
  232. int64_t service_worker_version_id,
  233. int thread_id) {
  234. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  235. if (!IsCurrentSequence(extension_id, activation_sequence))
  236. return;
  237. SequencedContextId context_id(
  238. LazyContextId(browser_context_, extension_id, service_worker_scope),
  239. activation_sequence);
  240. const WorkerId worker_id = {extension_id, render_process_id,
  241. service_worker_version_id, thread_id};
  242. WorkerState* worker_state = GetWorkerState(context_id);
  243. DCHECK(worker_state);
  244. // If |worker_state| had a worker running previously, for which we didn't
  245. // see DidStopServiceWorkerContext notification (typically happens on render
  246. // process shutdown), then we'd preserve stale state in |renderer_state_|.
  247. //
  248. // This isn't a problem because the next browser process readiness
  249. // (DidStartWorkerForScope) or the next renderer process readiness
  250. // (DidStartServiceWorkerContext) will clear the state, whichever happens
  251. // first.
  252. //
  253. // TODO(lazyboy): Update the renderer state in RenderProcessExited() and
  254. // uncomment the following DCHECK:
  255. // DCHECK_NE(RendererState::kStarted, worker_state->renderer_state_)
  256. // << "Worker already started";
  257. worker_state->SetWorkerId(worker_id, ProcessManager::Get(browser_context_));
  258. worker_state->renderer_state_ = RendererState::kStarted;
  259. RunPendingTasksIfWorkerReady(context_id);
  260. }
  261. void ServiceWorkerTaskQueue::DidStopServiceWorkerContext(
  262. int render_process_id,
  263. const ExtensionId& extension_id,
  264. ActivationSequence activation_sequence,
  265. const GURL& service_worker_scope,
  266. int64_t service_worker_version_id,
  267. int thread_id) {
  268. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  269. if (!IsCurrentSequence(extension_id, activation_sequence))
  270. return;
  271. const WorkerId worker_id = {extension_id, render_process_id,
  272. service_worker_version_id, thread_id};
  273. ProcessManager::Get(browser_context_)->UnregisterServiceWorker(worker_id);
  274. SequencedContextId context_id(
  275. LazyContextId(browser_context_, extension_id, service_worker_scope),
  276. activation_sequence);
  277. WorkerState* worker_state = GetWorkerState(context_id);
  278. DCHECK(worker_state);
  279. if (worker_state->worker_id_ != worker_id) {
  280. // We can see DidStopServiceWorkerContext right after DidInitialize and
  281. // without DidStartServiceWorkerContext.
  282. return;
  283. }
  284. DCHECK_NE(RendererState::kStopped, worker_state->renderer_state_);
  285. worker_state->renderer_state_ = RendererState::kStopped;
  286. worker_state->worker_id_ = absl::nullopt;
  287. }
  288. // static
  289. void ServiceWorkerTaskQueue::SetObserverForTest(TestObserver* observer) {
  290. g_test_observer = observer;
  291. }
  292. bool ServiceWorkerTaskQueue::ShouldEnqueueTask(BrowserContext* context,
  293. const Extension* extension) {
  294. // We call StartWorker every time we want to dispatch an event to an extension
  295. // Service worker.
  296. // TODO(lazyboy): Is that a problem?
  297. return true;
  298. }
  299. void ServiceWorkerTaskQueue::AddPendingTask(
  300. const LazyContextId& lazy_context_id,
  301. PendingTask task) {
  302. DCHECK(lazy_context_id.is_for_service_worker());
  303. // TODO(lazyboy): Do we need to handle incognito context?
  304. auto sequence = GetCurrentSequence(lazy_context_id.extension_id());
  305. DCHECK(sequence) << "Trying to add pending task to an inactive extension: "
  306. << lazy_context_id.extension_id();
  307. const SequencedContextId context_id(lazy_context_id, *sequence);
  308. WorkerState* worker_state = GetWorkerState(context_id);
  309. DCHECK(worker_state);
  310. auto& tasks = worker_state->pending_tasks_;
  311. bool needs_start_worker = tasks.empty();
  312. tasks.push_back(std::move(task));
  313. if (worker_state->registration_state_ != RegistrationState::kRegistered) {
  314. // If the worker hasn't finished registration, wait for it to complete.
  315. // DidRegisterServiceWorker will Start worker to run |task| later.
  316. return;
  317. }
  318. // Start worker if there isn't any request to start worker with |context_id|
  319. // is in progress.
  320. if (needs_start_worker)
  321. RunTasksAfterStartWorker(context_id);
  322. }
  323. void ServiceWorkerTaskQueue::ActivateExtension(const Extension* extension) {
  324. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  325. const ExtensionId extension_id = extension->id();
  326. ActivationSequence current_sequence(++next_activation_sequence_);
  327. activation_sequences_[extension_id] = current_sequence;
  328. SequencedContextId context_id(
  329. LazyContextId(browser_context_, extension_id, extension->url()),
  330. current_sequence);
  331. DCHECK(!base::Contains(worker_state_map_, context_id));
  332. WorkerState& worker_state = worker_state_map_[context_id];
  333. content::ServiceWorkerContext* service_worker_context =
  334. GetServiceWorkerContext(extension->id());
  335. StartObserving(service_worker_context);
  336. // Note: version.IsValid() = false implies we didn't have any prefs stored.
  337. base::Version version = RetrieveRegisteredServiceWorkerVersion(extension_id);
  338. const bool service_worker_already_registered =
  339. version.IsValid() && version == extension->version();
  340. if (g_test_observer) {
  341. g_test_observer->OnActivateExtension(extension_id,
  342. !service_worker_already_registered);
  343. }
  344. if (service_worker_already_registered) {
  345. worker_state.registration_state_ = RegistrationState::kRegistered;
  346. VerifyRegistration(service_worker_context, context_id, extension->url());
  347. return;
  348. }
  349. worker_state.registration_state_ = RegistrationState::kPending;
  350. RegisterServiceWorker(RegistrationReason::REGISTER_ON_EXTENSION_LOAD,
  351. context_id, *extension);
  352. }
  353. void ServiceWorkerTaskQueue::VerifyRegistration(
  354. content::ServiceWorkerContext* service_worker_context,
  355. const SequencedContextId& context_id,
  356. const GURL& scope) {
  357. service_worker_context->CheckHasServiceWorker(
  358. scope, blink::StorageKey(url::Origin::Create(scope)),
  359. base::BindOnce(&ServiceWorkerTaskQueue::DidVerifyRegistration,
  360. weak_factory_.GetWeakPtr(), context_id));
  361. }
  362. void ServiceWorkerTaskQueue::RegisterServiceWorker(
  363. RegistrationReason reason,
  364. const SequencedContextId& context_id,
  365. const Extension& extension) {
  366. GURL script_url = extension.GetResourceURL(
  367. BackgroundInfo::GetBackgroundServiceWorkerScript(&extension));
  368. blink::mojom::ServiceWorkerRegistrationOptions option;
  369. if (BackgroundInfo::GetBackgroundServiceWorkerType(&extension) ==
  370. BackgroundServiceWorkerType::kModule) {
  371. option.type = blink::mojom::ScriptType::kModule;
  372. }
  373. option.scope = extension.url();
  374. content::ServiceWorkerContext* service_worker_context =
  375. GetServiceWorkerContext(extension.id());
  376. service_worker_context->RegisterServiceWorker(
  377. script_url, blink::StorageKey(url::Origin::Create(option.scope)), option,
  378. base::BindOnce(&ServiceWorkerTaskQueue::DidRegisterServiceWorker,
  379. weak_factory_.GetWeakPtr(), context_id, reason,
  380. base::Time::Now()));
  381. }
  382. void ServiceWorkerTaskQueue::DeactivateExtension(const Extension* extension) {
  383. const ExtensionId extension_id = extension->id();
  384. RemoveRegisteredServiceWorkerInfo(extension_id);
  385. absl::optional<ActivationSequence> sequence =
  386. GetCurrentSequence(extension_id);
  387. // Extension was never activated, this happens in tests.
  388. if (!sequence)
  389. return;
  390. activation_sequences_.erase(extension_id);
  391. SequencedContextId context_id(
  392. LazyContextId(browser_context_, extension_id, extension->url()),
  393. *sequence);
  394. WorkerState* worker_state = GetWorkerState(context_id);
  395. DCHECK(worker_state);
  396. // TODO(lazyboy): Run orphaned tasks with nullptr ContextInfo.
  397. worker_state->pending_tasks_.clear();
  398. worker_state_map_.erase(context_id);
  399. content::ServiceWorkerContext* service_worker_context =
  400. GetServiceWorkerContext(extension->id());
  401. service_worker_context->UnregisterServiceWorker(
  402. extension->url(), blink::StorageKey(extension->origin()),
  403. base::BindOnce(&ServiceWorkerTaskQueue::DidUnregisterServiceWorker,
  404. weak_factory_.GetWeakPtr(), extension_id, *sequence));
  405. StopObserving(service_worker_context);
  406. }
  407. void ServiceWorkerTaskQueue::RunTasksAfterStartWorker(
  408. const SequencedContextId& context_id) {
  409. DCHECK(context_id.first.is_for_service_worker());
  410. const LazyContextId& lazy_context_id = context_id.first;
  411. if (lazy_context_id.browser_context() != browser_context_)
  412. return;
  413. WorkerState* worker_state = GetWorkerState(context_id);
  414. DCHECK_NE(BrowserState::kStarted, worker_state->browser_state_);
  415. content::StoragePartition* partition =
  416. util::GetStoragePartitionForExtensionId(
  417. lazy_context_id.extension_id(), lazy_context_id.browser_context());
  418. content::ServiceWorkerContext* service_worker_context =
  419. partition->GetServiceWorkerContext();
  420. const GURL& scope = context_id.first.service_worker_scope();
  421. service_worker_context->StartWorkerForScope(
  422. scope, blink::StorageKey(url::Origin::Create(scope)),
  423. base::BindOnce(&ServiceWorkerTaskQueue::DidStartWorkerForScope,
  424. weak_factory_.GetWeakPtr(), context_id, base::Time::Now()),
  425. base::BindOnce(&ServiceWorkerTaskQueue::DidStartWorkerFail,
  426. weak_factory_.GetWeakPtr(), context_id));
  427. }
  428. void ServiceWorkerTaskQueue::DidRegisterServiceWorker(
  429. const SequencedContextId& context_id,
  430. RegistrationReason reason,
  431. base::Time start_time,
  432. blink::ServiceWorkerStatusCode status_code) {
  433. ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
  434. const ExtensionId& extension_id = context_id.first.extension_id();
  435. DCHECK(registry);
  436. const Extension* extension =
  437. registry->enabled_extensions().GetByID(extension_id);
  438. if (!extension) {
  439. return;
  440. }
  441. if (!IsCurrentSequence(extension_id, context_id.second))
  442. return;
  443. WorkerState* worker_state = GetWorkerState(context_id);
  444. DCHECK(worker_state);
  445. const bool success = status_code == blink::ServiceWorkerStatusCode::kOk;
  446. UMA_HISTOGRAM_BOOLEAN("Extensions.ServiceWorkerBackground.RegistrationStatus",
  447. success);
  448. if (reason == RegistrationReason::RE_REGISTER_ON_STATE_MISMATCH) {
  449. UMA_HISTOGRAM_BOOLEAN(
  450. "Extensions.ServiceWorkerBackground.RegistrationMismatchMitigated",
  451. success);
  452. if (g_test_observer)
  453. g_test_observer->RegistrationMismatchMitigated(success);
  454. }
  455. if (!success) {
  456. std::string msg = base::StringPrintf(
  457. "Service worker registration failed. Status code: %d",
  458. static_cast<int>(status_code));
  459. auto error = std::make_unique<ManifestError>(
  460. extension_id, base::UTF8ToUTF16(msg),
  461. base::UTF8ToUTF16(manifest_keys::kBackground),
  462. base::UTF8ToUTF16(
  463. BackgroundInfo::GetBackgroundServiceWorkerScript(extension)));
  464. ExtensionsBrowserClient::Get()->ReportError(browser_context_,
  465. std::move(error));
  466. return;
  467. }
  468. UMA_HISTOGRAM_TIMES("Extensions.ServiceWorkerBackground.RegistrationTime",
  469. base::Time::Now() - start_time);
  470. worker_state->registration_state_ = RegistrationState::kRegistered;
  471. SetRegisteredServiceWorkerInfo(extension->id(), extension->version());
  472. if (worker_state->has_pending_tasks()) {
  473. // TODO(lazyboy): If worker for |context_id| is already running, consider
  474. // not calling StartWorker. This should be straightforward now that service
  475. // worker's internal state is on the UI thread rather than the IO thread.
  476. RunTasksAfterStartWorker(context_id);
  477. }
  478. }
  479. void ServiceWorkerTaskQueue::DidUnregisterServiceWorker(
  480. const ExtensionId& extension_id,
  481. ActivationSequence sequence,
  482. bool success) {
  483. // Extension run with |sequence| was already deactivated.
  484. if (!IsCurrentSequence(extension_id, sequence))
  485. return;
  486. // TODO(lazyboy): Handle success = false case.
  487. if (!success)
  488. LOG(ERROR) << "Failed to unregister service worker!";
  489. }
  490. base::Version ServiceWorkerTaskQueue::RetrieveRegisteredServiceWorkerVersion(
  491. const ExtensionId& extension_id) {
  492. if (browser_context_->IsOffTheRecord()) {
  493. auto it = off_the_record_registrations_.find(extension_id);
  494. return it != off_the_record_registrations_.end() ? it->second
  495. : base::Version();
  496. }
  497. const base::DictionaryValue* info = nullptr;
  498. ExtensionPrefs::Get(browser_context_)
  499. ->ReadPrefAsDictionary(extension_id, kPrefServiceWorkerRegistrationInfo,
  500. &info);
  501. if (!info) {
  502. return base::Version();
  503. }
  504. if (const std::string* version_string =
  505. info->FindStringKey(kServiceWorkerVersion)) {
  506. return base::Version(*version_string);
  507. }
  508. return base::Version();
  509. }
  510. void ServiceWorkerTaskQueue::SetRegisteredServiceWorkerInfo(
  511. const ExtensionId& extension_id,
  512. const base::Version& version) {
  513. DCHECK(version.IsValid());
  514. if (browser_context_->IsOffTheRecord()) {
  515. off_the_record_registrations_[extension_id] = version;
  516. } else {
  517. auto info = std::make_unique<base::DictionaryValue>();
  518. info->SetStringKey(kServiceWorkerVersion, version.GetString());
  519. ExtensionPrefs::Get(browser_context_)
  520. ->UpdateExtensionPref(extension_id, kPrefServiceWorkerRegistrationInfo,
  521. std::move(info));
  522. }
  523. }
  524. void ServiceWorkerTaskQueue::RemoveRegisteredServiceWorkerInfo(
  525. const ExtensionId& extension_id) {
  526. if (browser_context_->IsOffTheRecord()) {
  527. off_the_record_registrations_.erase(extension_id);
  528. } else {
  529. ExtensionPrefs::Get(browser_context_)
  530. ->UpdateExtensionPref(extension_id, kPrefServiceWorkerRegistrationInfo,
  531. nullptr);
  532. }
  533. }
  534. void ServiceWorkerTaskQueue::RunPendingTasksIfWorkerReady(
  535. const SequencedContextId& context_id) {
  536. WorkerState* worker_state = GetWorkerState(context_id);
  537. DCHECK(worker_state);
  538. if (!worker_state->ready()) {
  539. // Worker isn't ready yet, wait for next event and run the tasks then.
  540. return;
  541. }
  542. // Running |pending_tasks_[context_id]| marks the completion of
  543. // DidStartWorkerForScope, clean up |browser_ready| state of the worker so
  544. // that new tasks can be queued up.
  545. worker_state->browser_state_ = BrowserState::kInitial;
  546. DCHECK(worker_state->has_pending_tasks())
  547. << "Worker ready, but no tasks to run!";
  548. std::vector<PendingTask> tasks;
  549. std::swap(worker_state->pending_tasks_, tasks);
  550. DCHECK(worker_state->worker_id_);
  551. const auto& worker_id = *worker_state->worker_id_;
  552. for (auto& task : tasks) {
  553. auto context_info = std::make_unique<LazyContextTaskQueue::ContextInfo>(
  554. context_id.first.extension_id(),
  555. content::RenderProcessHost::FromID(worker_id.render_process_id),
  556. worker_id.version_id, worker_id.thread_id,
  557. context_id.first.service_worker_scope());
  558. std::move(task).Run(std::move(context_info));
  559. }
  560. }
  561. bool ServiceWorkerTaskQueue::IsCurrentSequence(
  562. const ExtensionId& extension_id,
  563. ActivationSequence sequence) const {
  564. auto current_sequence = GetCurrentSequence(extension_id);
  565. return current_sequence == sequence;
  566. }
  567. absl::optional<ActivationSequence> ServiceWorkerTaskQueue::GetCurrentSequence(
  568. const ExtensionId& extension_id) const {
  569. auto iter = activation_sequences_.find(extension_id);
  570. if (iter == activation_sequences_.end())
  571. return absl::nullopt;
  572. return iter->second;
  573. }
  574. void ServiceWorkerTaskQueue::OnReportConsoleMessage(
  575. int64_t version_id,
  576. const GURL& scope,
  577. const content::ConsoleMessage& message) {
  578. if (message.message_level != blink::mojom::ConsoleMessageLevel::kError) {
  579. // We don't report certain low-severity errors.
  580. return;
  581. }
  582. auto error_instance = std::make_unique<RuntimeError>(
  583. scope.host(), browser_context_->IsOffTheRecord(),
  584. base::UTF8ToUTF16(content::MessageSourceToString(message.source)),
  585. message.message,
  586. StackTrace(1, StackFrame(message.line_number, 1,
  587. base::UTF8ToUTF16(message.source_url.spec()),
  588. u"")) /* Construct a trace to contain
  589. one frame with the error */
  590. ,
  591. message.source_url,
  592. content::ConsoleMessageLevelToLogSeverity(message.message_level),
  593. -1 /* a service worker does not have a render_view_id */,
  594. -1 /* TODO(crbug.com/1218812): Retrieve render_process_id */);
  595. ExtensionsBrowserClient::Get()->ReportError(browser_context_,
  596. std::move(error_instance));
  597. }
  598. void ServiceWorkerTaskQueue::OnDestruct(
  599. content::ServiceWorkerContext* context) {
  600. StopObserving(context);
  601. }
  602. size_t ServiceWorkerTaskQueue::GetNumPendingTasksForTest(
  603. const LazyContextId& lazy_context_id) {
  604. auto current_sequence = GetCurrentSequence(lazy_context_id.extension_id());
  605. if (!current_sequence)
  606. return 0u;
  607. const SequencedContextId context_id(lazy_context_id, *current_sequence);
  608. WorkerState* worker_state = GetWorkerState(context_id);
  609. return worker_state ? worker_state->pending_tasks_.size() : 0u;
  610. }
  611. ServiceWorkerTaskQueue::WorkerState* ServiceWorkerTaskQueue::GetWorkerState(
  612. const SequencedContextId& context_id) {
  613. auto worker_iter = worker_state_map_.find(context_id);
  614. return worker_iter == worker_state_map_.end() ? nullptr
  615. : &worker_iter->second;
  616. }
  617. content::ServiceWorkerContext* ServiceWorkerTaskQueue::GetServiceWorkerContext(
  618. const ExtensionId& extension_id) {
  619. return util::GetStoragePartitionForExtensionId(extension_id, browser_context_)
  620. ->GetServiceWorkerContext();
  621. }
  622. void ServiceWorkerTaskQueue::StartObserving(
  623. content::ServiceWorkerContext* service_worker_context) {
  624. if (observing_worker_contexts_.count(service_worker_context) == 0u)
  625. service_worker_context->AddObserver(this);
  626. observing_worker_contexts_.insert(service_worker_context);
  627. }
  628. void ServiceWorkerTaskQueue::StopObserving(
  629. content::ServiceWorkerContext* service_worker_context) {
  630. auto iter_pair =
  631. observing_worker_contexts_.equal_range(service_worker_context);
  632. DCHECK(iter_pair.first != observing_worker_contexts_.end());
  633. if (std::distance(iter_pair.first, iter_pair.second) == 1)
  634. service_worker_context->RemoveObserver(this);
  635. observing_worker_contexts_.erase(iter_pair.first);
  636. }
  637. void ServiceWorkerTaskQueue::DidVerifyRegistration(
  638. const SequencedContextId& context_id,
  639. content::ServiceWorkerCapability capability) {
  640. const bool is_registered =
  641. capability != content::ServiceWorkerCapability::NO_SERVICE_WORKER;
  642. UMA_HISTOGRAM_BOOLEAN(
  643. "Extensions.ServiceWorkerBackground.RegistrationWhenExpected",
  644. is_registered);
  645. if (is_registered)
  646. return;
  647. // We expected a SW registration (as ExtensionPrefs said so), but there isn't
  648. // one. Re-register SW script if the extension is still installed (it's
  649. // possible it was uninstalled while we were checking).
  650. const ExtensionId& extension_id = context_id.first.extension_id();
  651. ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
  652. DCHECK(registry);
  653. const Extension* extension =
  654. registry->enabled_extensions().GetByID(extension_id);
  655. if (!extension)
  656. return;
  657. UMA_HISTOGRAM_ENUMERATION(
  658. "Extensions.ServiceWorkerBackground.RegistrationMismatchLocation",
  659. extension->location());
  660. RegisterServiceWorker(RegistrationReason::RE_REGISTER_ON_STATE_MISMATCH,
  661. context_id, *extension);
  662. }
  663. void ServiceWorkerTaskQueue::ActivateIncognitoSplitModeExtensions(
  664. ServiceWorkerTaskQueue* other) {
  665. DCHECK(browser_context_->IsOffTheRecord())
  666. << "Only need to activate split mode extensions for an OTR context";
  667. for (const auto& activated : other->activation_sequences_) {
  668. ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
  669. DCHECK(registry);
  670. const Extension* extension =
  671. registry->enabled_extensions().GetByID(activated.first);
  672. if (extension && IncognitoInfo::IsSplitMode(extension))
  673. ActivateExtension(extension);
  674. }
  675. }
  676. } // namespace extensions