blob: b97fba12ce389864e559277627ce98babb537115 [file] [log] [blame]
[email protected]9fe42042013-10-29 21:13:331// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]b6536df2012-03-16 18:55:232// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]9fe42042013-10-29 21:13:335#include "extensions/browser/lazy_background_task_queue.h"
[email protected]b6536df2012-03-16 18:55:236
7#include "base/callback.h"
Karan Bhatia019bc702017-11-10 21:30:238#include "base/logging.h"
[email protected]9fe42042013-10-29 21:13:339#include "content/public/browser/browser_context.h"
[email protected]b6536df2012-03-16 18:55:2310#include "content/public/browser/notification_service.h"
11#include "content/public/browser/render_process_host.h"
12#include "content/public/browser/render_view_host.h"
13#include "content/public/browser/site_instance.h"
14#include "content/public/browser/web_contents.h"
[email protected]22401dc2014-03-21 01:38:5715#include "extensions/browser/extension_host.h"
[email protected]9fe42042013-10-29 21:13:3316#include "extensions/browser/extensions_browser_client.h"
juncai07ea53872015-05-20 22:20:1317#include "extensions/browser/lazy_background_task_queue_factory.h"
lazyboy63b994a2017-06-30 21:20:2318#include "extensions/browser/lazy_context_id.h"
[email protected]adf5a102014-07-31 12:44:0619#include "extensions/browser/notification_types.h"
[email protected]98b6d942013-11-10 00:34:0720#include "extensions/browser/process_manager.h"
[email protected]50de9aa22013-11-14 06:30:3421#include "extensions/browser/process_map.h"
[email protected]e4452d32013-11-15 23:07:4122#include "extensions/common/extension.h"
[email protected]558878cc82013-11-09 01:25:5123#include "extensions/common/manifest_handlers/background_info.h"
[email protected]cb2edf22013-04-01 20:25:2324#include "extensions/common/view_type.h"
[email protected]b6536df2012-03-16 18:55:2325
[email protected]83055ea72012-04-05 18:56:3626namespace extensions {
27
lazyboy63b994a2017-06-30 21:20:2328namespace {
29
Derek Cheng86c3f0e2018-05-21 18:14:3230// Attempts to create a background host for a lazy background page. Returns true
31// if the background host is created.
32bool CreateLazyBackgroundHost(ProcessManager* pm, const Extension* extension) {
David Bertoni3e1e9fa2018-08-29 20:39:3033 pm->IncrementLazyKeepaliveCount(extension, Activity::LIFECYCLE_MANAGEMENT,
34 Activity::kCreatePage);
Derek Cheng86c3f0e2018-05-21 18:14:3235 // Creating the background host may fail, e.g. if the extension isn't enabled
36 // in incognito mode.
37 return pm->CreateBackgroundHost(extension,
38 BackgroundInfo::GetBackgroundURL(extension));
39}
40
lazyboy63b994a2017-06-30 21:20:2341} // namespace
42
[email protected]9fe42042013-10-29 21:13:3343LazyBackgroundTaskQueue::LazyBackgroundTaskQueue(
44 content::BrowserContext* browser_context)
Evan Stade922f3f1f2019-09-04 21:05:1345 : browser_context_(browser_context) {
[email protected]adf5a102014-07-31 12:44:0646 registrar_.Add(this,
kalmanfd474fa2015-03-16 22:30:5747 extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD,
[email protected]b6536df2012-03-16 18:55:2348 content::NotificationService::AllBrowserContextsAndSources());
[email protected]adf5a102014-07-31 12:44:0649 registrar_.Add(this,
50 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
[email protected]76a383e2012-04-13 18:46:0151 content::NotificationService::AllBrowserContextsAndSources());
[email protected]c3bb7182014-07-16 21:15:1852
53 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context));
[email protected]b6536df2012-03-16 18:55:2354}
55
56LazyBackgroundTaskQueue::~LazyBackgroundTaskQueue() {
57}
58
juncai07ea53872015-05-20 22:20:1359// static
60LazyBackgroundTaskQueue* LazyBackgroundTaskQueue::Get(
61 content::BrowserContext* browser_context) {
62 return LazyBackgroundTaskQueueFactory::GetForBrowserContext(browser_context);
63}
64
[email protected]d79e3ab2012-04-03 18:28:3665bool LazyBackgroundTaskQueue::ShouldEnqueueTask(
[email protected]9fe42042013-10-29 21:13:3366 content::BrowserContext* browser_context,
67 const Extension* extension) {
[email protected]9fc5bdc82014-08-03 23:49:2668 // Note: browser_context may not be the same as browser_context_ for incognito
69 // extension tasks.
[email protected]d79e3ab2012-04-03 18:28:3670 DCHECK(extension);
[email protected]9367eabc2013-03-01 01:29:2971 if (BackgroundInfo::HasBackgroundPage(extension)) {
reillyg0ea3fa902014-10-28 15:30:2372 ProcessManager* pm = ProcessManager::Get(browser_context);
[email protected]d79e3ab2012-04-03 18:28:3673 ExtensionHost* background_host =
74 pm->GetBackgroundHostForExtension(extension->id());
kalmanfd474fa2015-03-16 22:30:5775 if (!background_host || !background_host->has_loaded_once())
[email protected]d79e3ab2012-04-03 18:28:3676 return true;
[email protected]0d475e072012-07-26 02:30:4277 if (pm->IsBackgroundHostClosing(extension->id()))
78 pm->CancelSuspend(extension);
[email protected]d79e3ab2012-04-03 18:28:3679 }
80
81 return false;
82}
83
David Bertoni8269a092018-12-19 15:55:4284void LazyBackgroundTaskQueue::AddPendingTask(const LazyContextId& context_id,
85 PendingTask task) {
[email protected]9fe42042013-10-29 21:13:3386 if (ExtensionsBrowserClient::Get()->IsShuttingDown()) {
Istiaque Ahmedb7f0e2fd92017-10-11 17:37:4287 std::move(task).Run(nullptr);
[email protected]09510772013-09-05 00:08:4788 return;
89 }
David Bertoni8269a092018-12-19 15:55:4290 const ExtensionId& extension_id = context_id.extension_id();
91 content::BrowserContext* const browser_context = context_id.browser_context();
Istiaque Ahmedb7f0e2fd92017-10-11 17:37:4292 PendingTasksList* tasks_list = nullptr;
David Bertoni64786432018-12-21 23:10:1293 auto it = pending_tasks_.find(context_id);
[email protected]b6536df2012-03-16 18:55:2394 if (it == pending_tasks_.end()) {
Derek Cheng86c3f0e2018-05-21 18:14:3295 const Extension* extension = ExtensionRegistry::Get(browser_context)
96 ->enabled_extensions()
97 .GetByID(extension_id);
[email protected]9367eabc2013-03-01 01:29:2998 if (extension && BackgroundInfo::HasLazyBackgroundPage(extension)) {
[email protected]546fc9d2012-08-18 04:10:0699 // If this is the first enqueued task, and we're not waiting for the
100 // background page to unload, ensure the background page is loaded.
Derek Cheng86c3f0e2018-05-21 18:14:32101 if (!CreateLazyBackgroundHost(ProcessManager::Get(browser_context),
102 extension)) {
Istiaque Ahmedb7f0e2fd92017-10-11 17:37:42103 std::move(task).Run(nullptr);
[email protected]61aa8c62013-10-01 00:43:07104 return;
105 }
[email protected]546fc9d2012-08-18 04:10:06106 }
Derek Cheng86c3f0e2018-05-21 18:14:32107 auto tasks_list_tmp = std::make_unique<PendingTasksList>();
108 tasks_list = tasks_list_tmp.get();
David Bertoni64786432018-12-21 23:10:12109 pending_tasks_[context_id] = std::move(tasks_list_tmp);
[email protected]b6536df2012-03-16 18:55:23110 } else {
111 tasks_list = it->second.get();
112 }
113
Istiaque Ahmedb7f0e2fd92017-10-11 17:37:42114 tasks_list->push_back(std::move(task));
[email protected]b6536df2012-03-16 18:55:23115}
116
[email protected]1ad12ef2012-04-16 19:26:22117void LazyBackgroundTaskQueue::ProcessPendingTasks(
118 ExtensionHost* host,
[email protected]9fe42042013-10-29 21:13:33119 content::BrowserContext* browser_context,
[email protected]1ad12ef2012-04-16 19:26:22120 const Extension* extension) {
Karan Bhatia019bc702017-11-10 21:30:23121 DCHECK(extension);
122
[email protected]9fe42042013-10-29 21:13:33123 if (!ExtensionsBrowserClient::Get()->IsSameContext(browser_context,
124 browser_context_))
[email protected]1ad12ef2012-04-16 19:26:22125 return;
126
[email protected]9fe42042013-10-29 21:13:33127 PendingTasksKey key(browser_context, extension->id());
jdoerriea1e1598b2018-10-10 09:10:37128 auto map_it = pending_tasks_.find(key);
[email protected]b6536df2012-03-16 18:55:23129 if (map_it == pending_tasks_.end()) {
[email protected]9367eabc2013-03-01 01:29:29130 if (BackgroundInfo::HasLazyBackgroundPage(extension))
[email protected]546fc9d2012-08-18 04:10:06131 CHECK(!host); // lazy page should not load without any pending tasks
[email protected]b6536df2012-03-16 18:55:23132 return;
133 }
134
[email protected]b49fd0bdb2012-07-25 20:30:56135 // Swap the pending tasks to a temporary, to avoid problems if the task
136 // list is modified during processing.
137 PendingTasksList tasks;
138 tasks.swap(*map_it->second);
Istiaque Ahmedb7f0e2fd92017-10-11 17:37:42139 for (auto& task : tasks)
David Bertoni643f6a942018-12-17 16:50:07140 std::move(task).Run(host ? std::make_unique<ContextInfo>(host) : nullptr);
[email protected]b6536df2012-03-16 18:55:23141
[email protected]b49fd0bdb2012-07-25 20:30:56142 pending_tasks_.erase(key);
[email protected]b6536df2012-03-16 18:55:23143
Derek Cheng86c3f0e2018-05-21 18:14:32144 // Balance the keepalive in CreateLazyBackgroundHost. Note we don't do this on
145 // a failure to load, because the keepalive count is reset in that case.
[email protected]9367eabc2013-03-01 01:29:29146 if (host && BackgroundInfo::HasLazyBackgroundPage(extension)) {
reillyg0ea3fa902014-10-28 15:30:23147 ProcessManager::Get(browser_context)
David Bertoni3e1e9fa2018-08-29 20:39:30148 ->DecrementLazyKeepaliveCount(extension, Activity::LIFECYCLE_MANAGEMENT,
149 Activity::kCreatePage);
[email protected]1ad12ef2012-04-16 19:26:22150 }
[email protected]b6536df2012-03-16 18:55:23151}
152
Derek Cheng86c3f0e2018-05-21 18:14:32153void LazyBackgroundTaskQueue::NotifyTasksExtensionFailedToLoad(
154 content::BrowserContext* browser_context,
155 const Extension* extension) {
156 ProcessPendingTasks(nullptr, browser_context, extension);
157 // If this extension is also running in an off-the-record context, notify that
158 // task queue as well.
159 ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get();
160 if (browser_client->HasOffTheRecordContext(browser_context)) {
161 ProcessPendingTasks(nullptr,
162 browser_client->GetOffTheRecordContext(browser_context),
163 extension);
164 }
165}
166
[email protected]b6536df2012-03-16 18:55:23167void LazyBackgroundTaskQueue::Observe(
168 int type,
169 const content::NotificationSource& source,
170 const content::NotificationDetails& details) {
171 switch (type) {
kalmanfd474fa2015-03-16 22:30:57172 case extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD: {
[email protected]b6536df2012-03-16 18:55:23173 // If an on-demand background page finished loading, dispatch queued up
174 // events for it.
[email protected]3a1dc572012-07-31 22:25:13175 ExtensionHost* host =
176 content::Details<ExtensionHost>(details).ptr();
[email protected]cb2edf22013-04-01 20:25:23177 if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
kalmanfd474fa2015-03-16 22:30:57178 CHECK(host->has_loaded_once());
[email protected]9fe42042013-10-29 21:13:33179 ProcessPendingTasks(host, host->browser_context(), host->extension());
[email protected]b6536df2012-03-16 18:55:23180 }
181 break;
182 }
[email protected]adf5a102014-07-31 12:44:06183 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
[email protected]ed78d3fd2012-08-09 03:59:57184 // Notify consumers about the load failure when the background host dies.
185 // This can happen if the extension crashes. This is not strictly
186 // necessary, since we also unload the extension in that case (which
187 // dispatches the tasks below), but is a good extra precaution.
[email protected]9fe42042013-10-29 21:13:33188 content::BrowserContext* browser_context =
189 content::Source<content::BrowserContext>(source).ptr();
[email protected]3a1dc572012-07-31 22:25:13190 ExtensionHost* host =
191 content::Details<ExtensionHost>(details).ptr();
Karan Bhatia019bc702017-11-10 21:30:23192 if (host->extension() &&
193 host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
[email protected]9fe42042013-10-29 21:13:33194 ProcessPendingTasks(NULL, browser_context, host->extension());
[email protected]76a383e2012-04-13 18:46:01195 }
196 break;
197 }
[email protected]b6536df2012-03-16 18:55:23198 default:
199 NOTREACHED();
200 break;
201 }
202}
[email protected]83055ea72012-04-05 18:56:36203
Derek Cheng86c3f0e2018-05-21 18:14:32204void LazyBackgroundTaskQueue::OnExtensionLoaded(
205 content::BrowserContext* browser_context,
206 const Extension* extension) {
207 // If there are pending tasks for a lazy background page, and its background
208 // host has not been created yet, then create it. This can happen if a pending
209 // task was added while the extension is not yet enabled (e.g., component
210 // extension crashed and waiting to reload, https://crbug.com/835017).
211 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
212 return;
213
214 CreateLazyBackgroundHostOnExtensionLoaded(browser_context, extension);
215
216 // Also try to create the background host for the off-the-record context.
217 ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get();
218 if (browser_client->HasOffTheRecordContext(browser_context)) {
219 CreateLazyBackgroundHostOnExtensionLoaded(
220 browser_client->GetOffTheRecordContext(browser_context), extension);
221 }
222}
223
[email protected]c3bb7182014-07-16 21:15:18224void LazyBackgroundTaskQueue::OnExtensionUnloaded(
225 content::BrowserContext* browser_context,
226 const Extension* extension,
limasdf0deef2042017-05-03 19:17:17227 UnloadedExtensionReason reason) {
Derek Cheng86c3f0e2018-05-21 18:14:32228 NotifyTasksExtensionFailedToLoad(browser_context, extension);
229}
230
231void LazyBackgroundTaskQueue::CreateLazyBackgroundHostOnExtensionLoaded(
232 content::BrowserContext* browser_context,
233 const Extension* extension) {
234 PendingTasksKey key(browser_context, extension->id());
Jan Wilken Dörrie0fd53a22019-06-07 09:55:46235 if (!base::Contains(pending_tasks_, key))
Derek Cheng86c3f0e2018-05-21 18:14:32236 return;
237
238 ProcessManager* pm = ProcessManager::Get(browser_context);
239
240 // Background host already created, just wait for it to finish loading.
241 if (pm->GetBackgroundHostForExtension(extension->id()))
242 return;
243
244 if (!CreateLazyBackgroundHost(pm, extension))
245 ProcessPendingTasks(nullptr, browser_context, extension);
[email protected]c3bb7182014-07-16 21:15:18246}
247
[email protected]83055ea72012-04-05 18:56:36248} // namespace extensions