blob: e3220c480f15324ae74b3192a65149d56412534d [file] [log] [blame]
[email protected]98b6d942013-11-10 00:34:071// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]481e1a42009-05-06 20:56:052// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]98b6d942013-11-10 00:34:075#include "extensions/browser/process_manager.h"
[email protected]cb2edf22013-04-01 20:25:236
Jiaquan Hee057f67d2017-12-12 18:55:057#include <memory>
David Bertoni3e1e9fa2018-08-29 20:39:308#include <unordered_set>
kmarshall24b29b22015-04-29 01:41:479#include <vector>
10
[email protected]8add5412011-10-01 21:02:1411#include "base/bind.h"
Istiaque Ahmedb744ecf2019-02-06 00:23:3212#include "base/guid.h"
fdoraye6609ac82016-06-06 19:21:4013#include "base/location.h"
[email protected]0d475e072012-07-26 02:30:4214#include "base/logging.h"
avic9cec102015-12-23 00:39:2615#include "base/macros.h"
yoz1c99cbef2015-02-06 19:03:5616#include "base/metrics/histogram_macros.h"
Christopher Lamebb90202019-04-04 03:42:3617#include "base/one_shot_event.h"
fdoraye6609ac82016-06-06 19:21:4018#include "base/single_thread_task_runner.h"
David Bertoni3e1e9fa2018-08-29 20:39:3019#include "base/strings/string_number_conversions.h"
Istiaque Ahmedb744ecf2019-02-06 00:23:3220#include "base/task/post_task.h"
fdoraye6609ac82016-06-06 19:21:4021#include "base/threading/thread_task_runner_handle.h"
[email protected]41a17c52013-06-28 00:27:5322#include "base/time/time.h"
[email protected]94de8cb2013-11-07 06:29:2123#include "content/public/browser/browser_context.h"
Istiaque Ahmedb744ecf2019-02-06 00:23:3224#include "content/public/browser/browser_task_traits.h"
[email protected]a23f62e2013-04-26 13:13:0225#include "content/public/browser/devtools_agent_host.h"
Devlin Cronin7a282e32017-08-10 01:54:1026#include "content/public/browser/navigation_controller.h"
27#include "content/public/browser/navigation_entry.h"
[email protected]ad50def52011-10-19 23:17:0728#include "content/public/browser/notification_service.h"
[email protected]9dfed872013-12-30 23:08:5629#include "content/public/browser/render_frame_host.h"
[email protected]9c1662b2012-03-06 15:44:3330#include "content/public/browser/render_view_host.h"
Istiaque Ahmedb744ecf2019-02-06 00:23:3231#include "content/public/browser/service_worker_context.h"
Matt Falkenhagen1d69a342019-09-10 23:28:5732#include "content/public/browser/service_worker_external_request_result.h"
[email protected]b6583592012-01-25 19:52:3333#include "content/public/browser/site_instance.h"
Istiaque Ahmedb744ecf2019-02-06 00:23:3234#include "content/public/browser/storage_partition.h"
[email protected]4ca15302012-01-03 05:53:2035#include "content/public/browser/web_contents.h"
[email protected]6703c15d2014-04-03 19:03:4536#include "content/public/common/url_constants.h"
[email protected]22401dc2014-03-21 01:38:5737#include "extensions/browser/extension_host.h"
[email protected]5fdfa562013-12-27 17:43:5938#include "extensions/browser/extension_registry.h"
[email protected]59b0e602014-01-30 00:41:2439#include "extensions/browser/extension_system.h"
[email protected]7f474212013-11-05 04:26:1640#include "extensions/browser/extensions_browser_client.h"
David Bertoni8269a092018-12-19 15:55:4241#include "extensions/browser/lazy_context_id.h"
David Bertoni641e3ce02019-01-11 20:35:1242#include "extensions/browser/lazy_context_task_queue.h"
[email protected]adf5a102014-07-31 12:44:0643#include "extensions/browser/notification_types.h"
[email protected]6b54fda2014-07-22 02:13:4744#include "extensions/browser/process_manager_delegate.h"
reillyg0ea3fa902014-10-28 15:30:2345#include "extensions/browser/process_manager_factory.h"
[email protected]08d469b22014-03-31 00:51:2446#include "extensions/browser/process_manager_observer.h"
[email protected]cb2edf22013-04-01 20:25:2347#include "extensions/browser/view_type_utils.h"
[email protected]6703c15d2014-04-03 19:03:4548#include "extensions/common/constants.h"
[email protected]e4452d32013-11-15 23:07:4149#include "extensions/common/extension.h"
[email protected]fb820c02014-03-13 15:07:0850#include "extensions/common/extension_messages.h"
[email protected]558878cc82013-11-09 01:25:5151#include "extensions/common/manifest_handlers/background_info.h"
[email protected]1f7de252013-11-06 22:02:0052#include "extensions/common/manifest_handlers/incognito_info.h"
[email protected]bc535ee52010-08-31 18:40:3253
[email protected]7f474212013-11-05 04:26:1654using content::BrowserContext;
[email protected]98b6d942013-11-10 00:34:0755
56namespace extensions {
[email protected]7b1aa0e2013-10-16 22:57:3757
[email protected]bc535ee52010-08-31 18:40:3258namespace {
59
yoza9bf5602014-09-19 02:03:3160// The time to delay between an extension becoming idle and
61// sending a ShouldSuspend message.
yoza9bf5602014-09-19 02:03:3162unsigned g_event_page_idle_time_msec = 10000;
63
64// The time to delay between sending a ShouldSuspend message and
65// sending a Suspend message.
66unsigned g_event_page_suspending_time_msec = 5000;
67
rdevlin.cronin6ae04a012015-04-03 20:19:4068std::string GetExtensionIdForSiteInstance(
69 content::SiteInstance* site_instance) {
[email protected]6703c15d2014-04-03 19:03:4570 if (!site_instance)
[email protected]007b3f82013-04-09 08:46:4571 return std::string();
[email protected]d1fe1352012-04-26 00:47:3272
rdevlin.cronin6ae04a012015-04-03 20:19:4073 // This works for both apps and extensions because the site has been
74 // normalized to the extension URL for hosted apps.
[email protected]6703c15d2014-04-03 19:03:4575 const GURL& site_url = site_instance->GetSiteURL();
76
77 if (!site_url.SchemeIs(kExtensionScheme) &&
78 !site_url.SchemeIs(content::kGuestScheme))
79 return std::string();
80
81 return site_url.host();
[email protected]6baff0b52012-03-06 01:30:1882}
83
rdevlin.cronin6ae04a012015-04-03 20:19:4084std::string GetExtensionID(content::RenderFrameHost* render_frame_host) {
85 CHECK(render_frame_host);
86 return GetExtensionIdForSiteInstance(render_frame_host->GetSiteInstance());
[email protected]9dfed872013-12-30 23:08:5687}
88
89bool IsFrameInExtensionHost(ExtensionHost* extension_host,
90 content::RenderFrameHost* render_frame_host) {
rdevlin.cronin6ae04a012015-04-03 20:19:4091 return content::WebContents::FromRenderFrameHost(render_frame_host) ==
[email protected]9dfed872013-12-30 23:08:5692 extension_host->host_contents();
93}
94
[email protected]bc535ee52010-08-31 18:40:3295// Incognito profiles use this process manager. It is mostly a shim that decides
[email protected]98b6d942013-11-10 00:34:0796// whether to fall back on the original profile's ProcessManager based
[email protected]bc535ee52010-08-31 18:40:3297// on whether a given extension uses "split" or "spanning" incognito behavior.
rdevlin.cronin6ae04a012015-04-03 20:19:4098// TODO(devlin): Given how little this does and the amount of cruft it adds to
99// the .h file (in the form of protected members), we should consider just
100// moving the incognito logic into the base class.
[email protected]98b6d942013-11-10 00:34:07101class IncognitoProcessManager : public ProcessManager {
[email protected]bc535ee52010-08-31 18:40:32102 public:
[email protected]98b6d942013-11-10 00:34:07103 IncognitoProcessManager(BrowserContext* incognito_context,
[email protected]b9f6ba32014-03-10 18:34:08104 BrowserContext* original_context,
[email protected]6b54fda2014-07-22 02:13:47105 ExtensionRegistry* extension_registry);
dcheng9168b2f2014-10-21 12:38:24106 ~IncognitoProcessManager() override {}
107 bool CreateBackgroundHost(const Extension* extension,
108 const GURL& url) override;
rdevlin.cronin6ae04a012015-04-03 20:19:40109 scoped_refptr<content::SiteInstance> GetSiteInstanceForURL(const GURL& url)
110 override;
[email protected]bc535ee52010-08-31 18:40:32111
112 private:
[email protected]98b6d942013-11-10 00:34:07113 DISALLOW_COPY_AND_ASSIGN(IncognitoProcessManager);
[email protected]bc535ee52010-08-31 18:40:32114};
[email protected]481e1a42009-05-06 20:56:05115
[email protected]f72d0c62011-08-31 16:27:44116static void CreateBackgroundHostForExtensionLoad(
[email protected]98b6d942013-11-10 00:34:07117 ProcessManager* manager, const Extension* extension) {
[email protected]9367eabc2013-03-01 01:29:29118 if (BackgroundInfo::HasPersistentBackgroundPage(extension))
119 manager->CreateBackgroundHost(extension,
120 BackgroundInfo::GetBackgroundURL(extension));
[email protected]ae09ca62009-08-21 19:46:46121}
122
David Bertoni643f6a942018-12-17 16:50:07123void PropagateExtensionWakeResult(
124 base::OnceCallback<void(bool)> callback,
125 std::unique_ptr<LazyContextTaskQueue::ContextInfo> context_info) {
126 std::move(callback).Run(context_info != nullptr);
kmarshall24b29b22015-04-29 01:41:47127}
128
Istiaque Ahmedb744ecf2019-02-06 00:23:32129void StartServiceWorkerExternalRequest(content::ServiceWorkerContext* context,
130 int64_t service_worker_version_id,
131 const std::string& request_uuid) {
Matt Falkenhagend55b9282019-09-10 23:53:35132 DCHECK_CURRENTLY_ON(content::ServiceWorkerContext::GetCoreThreadId());
Istiaque Ahmedb744ecf2019-02-06 00:23:32133 context->StartingExternalRequest(service_worker_version_id, request_uuid);
134}
135
136void FinishServiceWorkerExternalRequest(content::ServiceWorkerContext* context,
137 int64_t service_worker_version_id,
138 const std::string& request_uuid) {
Matt Falkenhagend55b9282019-09-10 23:53:35139 DCHECK_CURRENTLY_ON(content::ServiceWorkerContext::GetCoreThreadId());
Matt Falkenhagen1d69a342019-09-10 23:28:57140 content::ServiceWorkerExternalRequestResult result =
Istiaque Ahmedb744ecf2019-02-06 00:23:32141 context->FinishedExternalRequest(service_worker_version_id, request_uuid);
Matt Falkenhagen1d69a342019-09-10 23:28:57142 DCHECK_EQ(result, content::ServiceWorkerExternalRequestResult::kOk);
Istiaque Ahmedb744ecf2019-02-06 00:23:32143}
144
[email protected]bc535ee52010-08-31 18:40:32145} // namespace
146
[email protected]98b6d942013-11-10 00:34:07147struct ProcessManager::BackgroundPageData {
[email protected]103f19f2012-04-02 19:30:12148 // The count of things keeping the lazy background page alive.
David Bertoni3e1e9fa2018-08-29 20:39:30149 // TODO(crbug.com://695711): Work on a plan to remove this and rely
150 // on activities.size() instead.
wezd6be2802017-03-27 01:49:28151 int lazy_keepalive_count = 0;
[email protected]388770152013-12-03 01:25:32152
[email protected]584e6572013-02-16 07:02:33153 // True if the page responded to the ShouldSuspend message and is currently
154 // dispatching the suspend event. During this time any events that arrive will
155 // cancel the suspend process and an onSuspendCanceled event will be
156 // dispatched to the page.
wezd6be2802017-03-27 01:49:28157 bool is_closing = false;
[email protected]103f19f2012-04-02 19:30:12158
[email protected]77a538f2014-07-14 22:25:37159 // Stores the value of the incremented
160 // ProcessManager::last_background_close_sequence_id_ whenever the extension
161 // is active. A copy of the ID is also passed in the callbacks and IPC
162 // messages leading up to CloseLazyBackgroundPageNow. The process is aborted
163 // if the IDs ever differ due to new activity.
wezd6be2802017-03-27 01:49:28164 uint64_t close_sequence_id = 0ull;
[email protected]77a538f2014-07-14 22:25:37165
[email protected]584e6572013-02-16 07:02:33166 // Keeps track of when this page was last suspended. Used for perf metrics.
lazyboyf33109d2016-08-31 00:37:08167 std::unique_ptr<base::ElapsedTimer> since_suspended;
David Bertoni3e1e9fa2018-08-29 20:39:30168
169 ActivitiesMultiset activities;
[email protected]103f19f2012-04-02 19:30:12170};
171
rdevlin.cronin6ae04a012015-04-03 20:19:40172// Data of a RenderFrameHost associated with an extension.
173struct ProcessManager::ExtensionRenderFrameData {
hashimoto5bca2272014-11-04 07:35:18174 // The type of the view.
wezd6be2802017-03-27 01:49:28175 extensions::ViewType view_type = VIEW_TYPE_INVALID;
hashimoto5bca2272014-11-04 07:35:18176
177 // Whether the view is keeping the lazy background page alive or not.
wezd6be2802017-03-27 01:49:28178 bool has_keepalive = false;
hashimoto5bca2272014-11-04 07:35:18179
180 // Returns whether the view can keep the lazy background page alive or not.
181 bool CanKeepalive() const {
182 switch (view_type) {
183 case VIEW_TYPE_APP_WINDOW:
184 case VIEW_TYPE_BACKGROUND_CONTENTS:
dmazzoni5ba638d2016-01-07 22:58:54185 case VIEW_TYPE_COMPONENT:
hashimoto5bca2272014-11-04 07:35:18186 case VIEW_TYPE_EXTENSION_DIALOG:
robcdcc4b82015-12-06 12:39:45187 case VIEW_TYPE_EXTENSION_GUEST:
hashimoto5bca2272014-11-04 07:35:18188 case VIEW_TYPE_EXTENSION_POPUP:
hashimoto5bca2272014-11-04 07:35:18189 case VIEW_TYPE_TAB_CONTENTS:
hashimoto5bca2272014-11-04 07:35:18190 return true;
191
192 case VIEW_TYPE_INVALID:
193 case VIEW_TYPE_EXTENSION_BACKGROUND_PAGE:
194 return false;
195 }
196 NOTREACHED();
197 return false;
198 }
199};
200
[email protected]bc535ee52010-08-31 18:40:32201//
[email protected]98b6d942013-11-10 00:34:07202// ProcessManager
[email protected]bc535ee52010-08-31 18:40:32203//
204
205// static
reillyg0ea3fa902014-10-28 15:30:23206ProcessManager* ProcessManager::Get(BrowserContext* context) {
207 return ProcessManagerFactory::GetForBrowserContext(context);
208}
209
210// static
[email protected]98b6d942013-11-10 00:34:07211ProcessManager* ProcessManager::Create(BrowserContext* context) {
[email protected]6b54fda2014-07-22 02:13:47212 ExtensionRegistry* extension_registry = ExtensionRegistry::Get(context);
[email protected]d012be2b2014-03-03 17:02:47213 ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get();
214 if (client->IsGuestSession(context)) {
215 // In the guest session, there is a single off-the-record context. Unlike
216 // a regular incognito mode, background pages of extensions must be
217 // created regardless of whether extensions use "spanning" or "split"
218 // incognito behavior.
219 BrowserContext* original_context = client->GetOriginalContext(context);
[email protected]6b54fda2014-07-22 02:13:47220 return new ProcessManager(context, original_context, extension_registry);
[email protected]d012be2b2014-03-03 17:02:47221 }
222
[email protected]7f474212013-11-05 04:26:16223 if (context->IsOffTheRecord()) {
[email protected]d012be2b2014-03-03 17:02:47224 BrowserContext* original_context = client->GetOriginalContext(context);
[email protected]b9f6ba32014-03-10 18:34:08225 return new IncognitoProcessManager(
reillyg0ea3fa902014-10-28 15:30:23226 context, original_context, extension_registry);
[email protected]7f474212013-11-05 04:26:16227 }
[email protected]d012be2b2014-03-03 17:02:47228
[email protected]6b54fda2014-07-22 02:13:47229 return new ProcessManager(context, context, extension_registry);
230}
231
232// static
233ProcessManager* ProcessManager::CreateForTesting(
234 BrowserContext* context,
235 ExtensionRegistry* extension_registry) {
236 DCHECK(!context->IsOffTheRecord());
237 return new ProcessManager(context, context, extension_registry);
[email protected]bc535ee52010-08-31 18:40:32238}
239
[email protected]b9f6ba32014-03-10 18:34:08240// static
241ProcessManager* ProcessManager::CreateIncognitoForTesting(
242 BrowserContext* incognito_context,
243 BrowserContext* original_context,
[email protected]6b54fda2014-07-22 02:13:47244 ExtensionRegistry* extension_registry) {
[email protected]b9f6ba32014-03-10 18:34:08245 DCHECK(incognito_context->IsOffTheRecord());
246 DCHECK(!original_context->IsOffTheRecord());
[email protected]6b54fda2014-07-22 02:13:47247 return new IncognitoProcessManager(incognito_context,
248 original_context,
[email protected]6b54fda2014-07-22 02:13:47249 extension_registry);
[email protected]b9f6ba32014-03-10 18:34:08250}
251
[email protected]98b6d942013-11-10 00:34:07252ProcessManager::ProcessManager(BrowserContext* context,
[email protected]6b54fda2014-07-22 02:13:47253 BrowserContext* original_context,
254 ExtensionRegistry* extension_registry)
rdevlin.cronin6ae04a012015-04-03 20:19:40255 : extension_registry_(extension_registry),
256 site_instance_(content::SiteInstance::Create(context)),
257 browser_context_(context),
Sami Kyostilafc646682019-08-08 05:19:56258 worker_task_runner_(
259 base::CreateSingleThreadTaskRunner({content::BrowserThread::IO})),
[email protected]77a538f2014-07-14 22:25:37260 startup_background_hosts_created_(false),
Evan Stade922f3f1f2019-09-04 21:05:13261 last_background_close_sequence_id_(0) {
[email protected]6b54fda2014-07-22 02:13:47262 // ExtensionRegistry is shared between incognito and regular contexts.
263 DCHECK_EQ(original_context, extension_registry_->browser_context());
limasdfe0f061b2015-02-27 00:35:06264 extension_registry_->AddObserver(this);
rdevlin.cronin6ae04a012015-04-03 20:19:40265
266 if (!context->IsOffTheRecord()) {
267 // Only the original profile needs to listen for ready to create background
268 // pages for all spanning extensions.
269 registrar_.Add(this,
[email protected]adf5a102014-07-31 12:44:06270 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
[email protected]7f474212013-11-05 04:26:16271 content::Source<BrowserContext>(original_context));
rdevlin.cronin6ae04a012015-04-03 20:19:40272 }
[email protected]49e7741e2014-07-21 01:57:42273 registrar_.Add(this,
[email protected]adf5a102014-07-31 12:44:06274 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
[email protected]7f474212013-11-05 04:26:16275 content::Source<BrowserContext>(context));
[email protected]adf5a102014-07-31 12:44:06276 registrar_.Add(this,
277 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
[email protected]7f474212013-11-05 04:26:16278 content::Source<BrowserContext>(context));
dgozman47679eb12016-10-17 17:30:18279 content::DevToolsAgentHost::AddObserver(this);
[email protected]481e1a42009-05-06 20:56:05280}
281
lazyboyf70b2eb92017-04-25 20:42:09282ProcessManager::~ProcessManager() {
283 content::DevToolsAgentHost::RemoveObserver(this);
284}
sense383ce0f2017-03-24 04:06:43285
286void ProcessManager::Shutdown() {
limasdfe0f061b2015-02-27 00:35:06287 extension_registry_->RemoveObserver(this);
[email protected]a95631cb2009-12-10 01:59:11288 CloseBackgroundHosts();
[email protected]ae5497f2009-11-05 00:39:46289 DCHECK(background_hosts_.empty());
dgozman47679eb12016-10-17 17:30:18290 content::DevToolsAgentHost::RemoveObserver(this);
sense383ce0f2017-03-24 04:06:43291 site_instance_ = nullptr;
[email protected]481e1a42009-05-06 20:56:05292}
293
rdevlin.cronin6ae04a012015-04-03 20:19:40294void ProcessManager::RegisterRenderFrameHost(
295 content::WebContents* web_contents,
296 content::RenderFrameHost* render_frame_host,
297 const Extension* extension) {
Karan Bhatiaad3b7272017-12-20 21:14:36298 DCHECK(render_frame_host->IsRenderFrameLive());
rdevlin.cronin6ae04a012015-04-03 20:19:40299 ExtensionRenderFrameData* data = &all_extension_frames_[render_frame_host];
300 data->view_type = GetViewType(web_contents);
301
302 // Keep the lazy background page alive as long as any non-background-page
303 // extension views are visible. Keepalive count balanced in
304 // UnregisterRenderFrame.
305 AcquireLazyKeepaliveCountForFrame(render_frame_host);
306
ericwilligersd1e28152016-10-17 22:53:14307 for (auto& observer : observer_list_)
308 observer.OnExtensionFrameRegistered(extension->id(), render_frame_host);
rdevlin.cronin6ae04a012015-04-03 20:19:40309}
310
311void ProcessManager::UnregisterRenderFrameHost(
312 content::RenderFrameHost* render_frame_host) {
jdoerriea1e1598b2018-10-10 09:10:37313 auto frame = all_extension_frames_.find(render_frame_host);
rdevlin.cronin6ae04a012015-04-03 20:19:40314
315 if (frame != all_extension_frames_.end()) {
316 std::string extension_id = GetExtensionID(render_frame_host);
317 // Keepalive count, balanced in RegisterRenderFrame.
318 ReleaseLazyKeepaliveCountForFrame(render_frame_host);
319 all_extension_frames_.erase(frame);
320
ericwilligersd1e28152016-10-17 22:53:14321 for (auto& observer : observer_list_)
322 observer.OnExtensionFrameUnregistered(extension_id, render_frame_host);
[email protected]63503462012-10-30 22:14:31323 }
rdevlin.cronin6ae04a012015-04-03 20:19:40324}
325
326scoped_refptr<content::SiteInstance> ProcessManager::GetSiteInstanceForURL(
327 const GURL& url) {
dchengbccd6b82016-03-30 16:24:19328 return site_instance_->GetRelatedSiteInstance(url);
rdevlin.cronin6ae04a012015-04-03 20:19:40329}
330
331const ProcessManager::FrameSet ProcessManager::GetAllFrames() const {
332 FrameSet result;
333 for (const auto& key_value : all_extension_frames_)
334 result.insert(key_value.first);
335 return result;
336}
337
338ProcessManager::FrameSet ProcessManager::GetRenderFrameHostsForExtension(
339 const std::string& extension_id) {
340 FrameSet result;
rdevlin.cronin6ae04a012015-04-03 20:19:40341 for (const auto& key_value : all_extension_frames_) {
robcdcc4b82015-12-06 12:39:45342 if (GetExtensionID(key_value.first) == extension_id)
rdevlin.cronin6ae04a012015-04-03 20:19:40343 result.insert(key_value.first);
344 }
[email protected]63503462012-10-30 22:14:31345 return result;
346}
347
robcdcc4b82015-12-06 12:39:45348bool ProcessManager::IsRenderFrameHostRegistered(
349 content::RenderFrameHost* render_frame_host) {
350 return all_extension_frames_.find(render_frame_host) !=
351 all_extension_frames_.end();
352}
353
[email protected]08d469b22014-03-31 00:51:24354void ProcessManager::AddObserver(ProcessManagerObserver* observer) {
355 observer_list_.AddObserver(observer);
356}
357
358void ProcessManager::RemoveObserver(ProcessManagerObserver* observer) {
359 observer_list_.RemoveObserver(observer);
360}
361
[email protected]6ad9cdf72014-02-27 13:12:41362bool ProcessManager::CreateBackgroundHost(const Extension* extension,
363 const GURL& url) {
Istiaque Ahmedccb444022018-06-19 02:11:12364 DCHECK(!BackgroundInfo::IsServiceWorkerBased(extension))
365 << "CreateBackgroundHostForExtensionLoad called for service worker based"
366 "background page";
[email protected]41619a9a2011-04-13 20:07:32367 // Hosted apps are taken care of from BackgroundContentsService. Ignore them
368 // here.
[email protected]6b54fda2014-07-22 02:13:47369 if (extension->is_hosted_app())
[email protected]6ad9cdf72014-02-27 13:12:41370 return false;
[email protected]6b54fda2014-07-22 02:13:47371
372 // Don't create hosts if the embedder doesn't allow it.
373 ProcessManagerDelegate* delegate =
374 ExtensionsBrowserClient::Get()->GetProcessManagerDelegate();
achuithd3da4f02017-03-23 20:05:29375 if (delegate &&
376 !delegate->IsExtensionBackgroundPageAllowed(browser_context_, *extension))
[email protected]6b54fda2014-07-22 02:13:47377 return false;
[email protected]41619a9a2011-04-13 20:07:32378
[email protected]bc535ee52010-08-31 18:40:32379 // Don't create multiple background hosts for an extension.
[email protected]6ad9cdf72014-02-27 13:12:41380 if (GetBackgroundHostForExtension(extension->id()))
381 return true; // TODO(kalman): return false here? It might break things...
[email protected]bc535ee52010-08-31 18:40:32382
achuithd3da4f02017-03-23 20:05:29383 DVLOG(1) << "CreateBackgroundHost " << extension->id();
[email protected]ab4eaf782009-06-10 00:11:24384 ExtensionHost* host =
rdevlin.cronin3d4261522015-02-10 00:48:15385 new ExtensionHost(extension, GetSiteInstanceForURL(url).get(), url,
[email protected]98b6d942013-11-10 00:34:07386 VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
[email protected]952a68e2011-11-17 00:36:10387 host->CreateRenderViewSoon();
[email protected]94de8cb2013-11-07 06:29:21388 OnBackgroundHostCreated(host);
[email protected]6ad9cdf72014-02-27 13:12:41389 return true;
[email protected]481e1a42009-05-06 20:56:05390}
391
rdevlin.cronin6ae04a012015-04-03 20:19:40392void ProcessManager::MaybeCreateStartupBackgroundHosts() {
393 if (startup_background_hosts_created_)
394 return;
395
396 // The embedder might disallow background pages entirely.
397 ProcessManagerDelegate* delegate =
398 ExtensionsBrowserClient::Get()->GetProcessManagerDelegate();
achuithd3da4f02017-03-23 20:05:29399 if (delegate &&
400 !delegate->AreBackgroundPagesAllowedForContext(browser_context_))
rdevlin.cronin6ae04a012015-04-03 20:19:40401 return;
402
403 // The embedder might want to defer background page loading. For example,
404 // Chrome defers background page loading when it is launched to show the app
405 // list, then triggers a load later when a browser window opens.
406 if (delegate &&
407 delegate->DeferCreatingStartupBackgroundHosts(browser_context_))
408 return;
409
410 CreateStartupBackgroundHosts();
411 startup_background_hosts_created_ = true;
412
413 // Background pages should only be loaded once. To prevent any further loads
414 // occurring, we remove the notification listeners.
415 BrowserContext* original_context =
416 ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context_);
417 if (registrar_.IsRegistered(
418 this,
419 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
420 content::Source<BrowserContext>(original_context))) {
421 registrar_.Remove(this,
422 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
423 content::Source<BrowserContext>(original_context));
424 }
425}
426
[email protected]98b6d942013-11-10 00:34:07427ExtensionHost* ProcessManager::GetBackgroundHostForExtension(
[email protected]06024c62011-10-20 20:57:12428 const std::string& extension_id) {
rdevlin.cronin6ae04a012015-04-03 20:19:40429 for (ExtensionHost* host : background_hosts_) {
[email protected]06024c62011-10-20 20:57:12430 if (host->extension_id() == extension_id)
[email protected]4814b512009-11-07 00:12:29431 return host;
432 }
rdevlin.cronin6ae04a012015-04-03 20:19:40433 return nullptr;
[email protected]481e1a42009-05-06 20:56:05434}
435
rdevlin.croninb48a98e2015-05-01 00:00:28436ExtensionHost* ProcessManager::GetExtensionHostForRenderFrameHost(
437 content::RenderFrameHost* render_frame_host) {
438 content::WebContents* web_contents =
439 content::WebContents::FromRenderFrameHost(render_frame_host);
440 for (ExtensionHost* extension_host : background_hosts_) {
441 if (extension_host->host_contents() == web_contents)
442 return extension_host;
443 }
444 return nullptr;
445}
446
kmarshall24b29b22015-04-29 01:41:47447bool ProcessManager::IsEventPageSuspended(const std::string& extension_id) {
448 return GetBackgroundHostForExtension(extension_id) == nullptr;
449}
450
451bool ProcessManager::WakeEventPage(const std::string& extension_id,
Istiaque Ahmed28edfd22018-08-30 23:40:47452 base::OnceCallback<void(bool)> callback) {
kmarshall24b29b22015-04-29 01:41:47453 if (GetBackgroundHostForExtension(extension_id)) {
Istiaque Ahmed28edfd22018-08-30 23:40:47454 // The extension is already awake.
kmarshall24b29b22015-04-29 01:41:47455 return false;
456 }
David Bertoni641e3ce02019-01-11 20:35:12457 const LazyContextId context_id(browser_context_, extension_id);
458 context_id.GetTaskQueue()->AddPendingTask(
459 context_id,
Istiaque Ahmed28edfd22018-08-30 23:40:47460 base::BindOnce(&PropagateExtensionWakeResult, std::move(callback)));
kmarshall24b29b22015-04-29 01:41:47461 return true;
462}
463
[email protected]98b6d942013-11-10 00:34:07464bool ProcessManager::IsBackgroundHostClosing(const std::string& extension_id) {
[email protected]7042b682012-04-19 22:57:51465 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
466 return (host && background_page_data_[extension_id].is_closing);
467}
468
rdevlin.cronin6ae04a012015-04-03 20:19:40469const Extension* ProcessManager::GetExtensionForRenderFrameHost(
470 content::RenderFrameHost* render_frame_host) {
471 return extension_registry_->enabled_extensions().GetByID(
472 GetExtensionID(render_frame_host));
473}
474
475const Extension* ProcessManager::GetExtensionForWebContents(
Lucas Furukawa Gadanie1c5dfda2018-11-29 17:57:41476 content::WebContents* web_contents) {
rdevlin.cronin6ae04a012015-04-03 20:19:40477 if (!web_contents->GetSiteInstance())
478 return nullptr;
Devlin Cronin7a282e32017-08-10 01:54:10479 const Extension* extension =
480 extension_registry_->enabled_extensions().GetByID(
481 GetExtensionIdForSiteInstance(web_contents->GetSiteInstance()));
482 if (extension && extension->is_hosted_app()) {
483 // For hosted apps, be sure to exclude URLs outside of the app that might
484 // be loaded in the same SiteInstance (extensions guarantee that only
485 // extension urls are loaded in that SiteInstance).
Lucas Furukawa Gadani5553a1582019-01-08 18:55:57486 content::NavigationController& controller = web_contents->GetController();
Devlin Cronin7a282e32017-08-10 01:54:10487 content::NavigationEntry* entry = controller.GetLastCommittedEntry();
488 // If there is no last committed entry, check the pending entry. This can
489 // happen in cases where we query this before any entry is fully committed,
490 // such as when attributing a WebContents for the TaskManager. If there is
491 // a committed navigation, use that instead.
492 if (!entry)
493 entry = controller.GetPendingEntry();
494 if (!entry ||
495 extension_registry_->enabled_extensions().GetExtensionOrAppByURL(
496 entry->GetURL()) != extension) {
497 return nullptr;
498 }
499 }
500
501 return extension;
rdevlin.cronin6ae04a012015-04-03 20:19:40502}
503
[email protected]98b6d942013-11-10 00:34:07504int ProcessManager::GetLazyKeepaliveCount(const Extension* extension) {
[email protected]9367eabc2013-03-01 01:29:29505 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
wez714dde12017-02-14 22:26:03506 return -1;
[email protected]720ad1312012-02-27 23:07:36507
[email protected]103f19f2012-04-02 19:30:12508 return background_page_data_[extension->id()].lazy_keepalive_count;
[email protected]720ad1312012-02-27 23:07:36509}
510
David Bertoni3e1e9fa2018-08-29 20:39:30511void ProcessManager::IncrementLazyKeepaliveCount(
512 const Extension* extension,
513 Activity::Type activity_type,
514 const std::string& extra_data) {
rdevlin.cronin6ae04a012015-04-03 20:19:40515 if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
David Bertoni3e1e9fa2018-08-29 20:39:30516 BackgroundPageData& data = background_page_data_[extension->id()];
517 if (++data.lazy_keepalive_count == 1)
rdevlin.cronin6ae04a012015-04-03 20:19:40518 OnLazyBackgroundPageActive(extension->id());
David Bertoni3e1e9fa2018-08-29 20:39:30519 data.activities.insert(std::make_pair(activity_type, extra_data));
rdevlin.cronin6ae04a012015-04-03 20:19:40520 }
[email protected]720ad1312012-02-27 23:07:36521}
522
David Bertoni3e1e9fa2018-08-29 20:39:30523void ProcessManager::DecrementLazyKeepaliveCount(
524 const Extension* extension,
525 Activity::Type activity_type,
526 const std::string& extra_data) {
rdevlin.cronin6ae04a012015-04-03 20:19:40527 if (BackgroundInfo::HasLazyBackgroundPage(extension))
David Bertoni3e1e9fa2018-08-29 20:39:30528 DecrementLazyKeepaliveCount(extension->id(), activity_type, extra_data);
529}
530
531ProcessManager::ActivitiesMultiset ProcessManager::GetLazyKeepaliveActivities(
532 const Extension* extension) {
533 ProcessManager::ActivitiesMultiset result;
534 if (BackgroundInfo::HasLazyBackgroundPage(extension))
535 result = background_page_data_[extension->id()].activities;
536 return result;
[email protected]720ad1312012-02-27 23:07:36537}
[email protected]0d475e072012-07-26 02:30:42538
rdevlin.cronin6ae04a012015-04-03 20:19:40539void ProcessManager::OnShouldSuspendAck(const std::string& extension_id,
avic9cec102015-12-23 00:39:26540 uint64_t sequence_id) {
rdevlin.cronin6ae04a012015-04-03 20:19:40541 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
542 if (host &&
543 sequence_id == background_page_data_[extension_id].close_sequence_id) {
544 host->render_process_host()->Send(new ExtensionMsg_Suspend(extension_id));
545 }
546}
547
548void ProcessManager::OnSuspendAck(const std::string& extension_id) {
549 background_page_data_[extension_id].is_closing = true;
avic9cec102015-12-23 00:39:26550 uint64_t sequence_id = background_page_data_[extension_id].close_sequence_id;
fdoraye6609ac82016-06-06 19:21:40551 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
rdevlin.cronin6ae04a012015-04-03 20:19:40552 FROM_HERE,
kylechar0686a5232019-02-19 14:10:29553 base::BindOnce(&ProcessManager::CloseLazyBackgroundPageNow,
554 weak_ptr_factory_.GetWeakPtr(), extension_id, sequence_id),
rdevlin.cronin6ae04a012015-04-03 20:19:40555 base::TimeDelta::FromMilliseconds(g_event_page_suspending_time_msec));
556}
557
558void ProcessManager::OnNetworkRequestStarted(
559 content::RenderFrameHost* render_frame_host,
avic9cec102015-12-23 00:39:26560 uint64_t request_id) {
rdevlin.cronin6ae04a012015-04-03 20:19:40561 ExtensionHost* host = GetBackgroundHostForExtension(
562 GetExtensionID(render_frame_host));
naskod13fd292016-06-07 20:33:33563 if (!host || !IsFrameInExtensionHost(host, render_frame_host))
564 return;
565
566 auto result =
567 pending_network_requests_.insert(std::make_pair(request_id, host));
rockote5703292015-09-28 23:23:09568 DCHECK(result.second) << "Duplicate network request IDs.";
naskod13fd292016-06-07 20:33:33569
David Bertoni3e1e9fa2018-08-29 20:39:30570 IncrementLazyKeepaliveCount(host->extension(), Activity::NETWORK,
571 base::NumberToString(request_id));
naskod13fd292016-06-07 20:33:33572 host->OnNetworkRequestStarted(request_id);
rdevlin.cronin6ae04a012015-04-03 20:19:40573}
574
575void ProcessManager::OnNetworkRequestDone(
576 content::RenderFrameHost* render_frame_host,
avic9cec102015-12-23 00:39:26577 uint64_t request_id) {
naskod13fd292016-06-07 20:33:33578 auto result = pending_network_requests_.find(request_id);
579 if (result == pending_network_requests_.end())
580 return;
581
582 // The cached |host| can be invalid, if it was deleted between the time it
583 // was inserted in the map and the look up. It is checked to ensure it is in
584 // the list of existing background_hosts_.
585 ExtensionHost* host = result->second;
586 pending_network_requests_.erase(result);
587
588 if (background_hosts_.find(host) == background_hosts_.end())
589 return;
590
591 DCHECK(IsFrameInExtensionHost(host, render_frame_host));
592
593 host->OnNetworkRequestDone(request_id);
David Bertoni3e1e9fa2018-08-29 20:39:30594 DecrementLazyKeepaliveCount(host->extension(), Activity::NETWORK,
595 base::NumberToString(request_id));
rdevlin.cronin6ae04a012015-04-03 20:19:40596}
597
598void ProcessManager::CancelSuspend(const Extension* extension) {
599 bool& is_closing = background_page_data_[extension->id()].is_closing;
600 ExtensionHost* host = GetBackgroundHostForExtension(extension->id());
601 if (host && is_closing) {
602 is_closing = false;
603 host->render_process_host()->Send(
604 new ExtensionMsg_CancelSuspend(extension->id()));
605 // This increment / decrement is to simulate an instantaneous event. This
606 // has the effect of invalidating close_sequence_id, preventing any in
607 // progress closes from completing and starting a new close process if
608 // necessary.
David Bertoni3e1e9fa2018-08-29 20:39:30609 IncrementLazyKeepaliveCount(extension, Activity::PROCESS_MANAGER,
610 Activity::kCancelSuspend);
611 DecrementLazyKeepaliveCount(extension, Activity::PROCESS_MANAGER,
612 Activity::kCancelSuspend);
rdevlin.cronin6ae04a012015-04-03 20:19:40613 }
614}
615
616void ProcessManager::CloseBackgroundHosts() {
avibe95fa11f2016-11-14 23:40:17617 // Delete from a copy because deletion of the ExtensionHosts will trigger
618 // callbacks to modify the |background_hosts_| set.
619 ExtensionHostSet hosts_copy = background_hosts_;
620 for (auto* host : hosts_copy) {
621 // Deleting the host will cause a NOTIFICATION_EXTENSION_HOST_DESTROYED
622 // which will cause the removal of the host from the |background_hosts_| set
623 // in the Observe() method below.
624 delete host;
625 DCHECK_EQ(0u, background_hosts_.count(host));
626 }
627
628 // At this point there should be nothing left in |background_hosts_|.
629 DCHECK(background_hosts_.empty());
rdevlin.cronin6ae04a012015-04-03 20:19:40630}
631
rdevlin.cronin6ae04a012015-04-03 20:19:40632// static
633void ProcessManager::SetEventPageIdleTimeForTesting(unsigned idle_time_msec) {
wezd6be2802017-03-27 01:49:28634 CHECK_GT(idle_time_msec, 0u);
rdevlin.cronin6ae04a012015-04-03 20:19:40635 g_event_page_idle_time_msec = idle_time_msec;
636}
637
638// static
639void ProcessManager::SetEventPageSuspendingTimeForTesting(
640 unsigned suspending_time_msec) {
641 g_event_page_suspending_time_msec = suspending_time_msec;
642}
643
644////////////////////////////////////////////////////////////////////////////////
645// Private
646
647void ProcessManager::Observe(int type,
648 const content::NotificationSource& source,
649 const content::NotificationDetails& details) {
650 TRACE_EVENT0("browser,startup", "ProcessManager::Observe");
651 switch (type) {
652 case extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED: {
653 // TODO(jamescook): Convert this to use ExtensionSystem::ready() instead
654 // of a notification.
655 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.ProcessManagerStartupHostsTime");
656 MaybeCreateStartupBackgroundHosts();
657 break;
658 }
659 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
660 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
661 if (background_hosts_.erase(host)) {
Karan Bhatiaee1e6a52017-11-09 21:32:51662 // Note: |host->extension()| may be null at this point.
663 ClearBackgroundPageData(host->extension_id());
664 background_page_data_[host->extension_id()].since_suspended.reset(
rdevlin.cronin6ae04a012015-04-03 20:19:40665 new base::ElapsedTimer());
666 }
667 break;
668 }
669 case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
670 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
671 if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
672 CloseBackgroundHost(host);
673 }
674 break;
675 }
676 default:
677 NOTREACHED();
678 }
679}
680
681void ProcessManager::OnExtensionLoaded(BrowserContext* browser_context,
682 const Extension* extension) {
683 if (ExtensionSystem::Get(browser_context)->ready().is_signaled()) {
684 // The extension system is ready, so create the background host.
685 CreateBackgroundHostForExtensionLoad(this, extension);
686 }
687}
688
limasdf0deef2042017-05-03 19:17:17689void ProcessManager::OnExtensionUnloaded(BrowserContext* browser_context,
690 const Extension* extension,
691 UnloadedExtensionReason reason) {
rdevlin.cronin6ae04a012015-04-03 20:19:40692 ExtensionHost* host = GetBackgroundHostForExtension(extension->id());
693 if (host != nullptr)
694 CloseBackgroundHost(host);
695 UnregisterExtension(extension->id());
696}
697
698void ProcessManager::CreateStartupBackgroundHosts() {
699 DCHECK(!startup_background_hosts_created_);
700 for (const scoped_refptr<const Extension>& extension :
701 extension_registry_->enabled_extensions()) {
702 CreateBackgroundHostForExtensionLoad(this, extension.get());
ericwilligersd1e28152016-10-17 22:53:14703 for (auto& observer : observer_list_)
704 observer.OnBackgroundHostStartup(extension.get());
rdevlin.cronin6ae04a012015-04-03 20:19:40705 }
706}
707
708void ProcessManager::OnBackgroundHostCreated(ExtensionHost* host) {
709 DCHECK_EQ(browser_context_, host->browser_context());
710 background_hosts_.insert(host);
711
712 if (BackgroundInfo::HasLazyBackgroundPage(host->extension())) {
lazyboyf33109d2016-08-31 00:37:08713 std::unique_ptr<base::ElapsedTimer> since_suspended = std::move(
714 background_page_data_[host->extension()->id()].since_suspended);
rdevlin.cronin6ae04a012015-04-03 20:19:40715 if (since_suspended.get()) {
716 UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime",
717 since_suspended->Elapsed());
718 }
719 }
ericwilligersd1e28152016-10-17 22:53:14720 for (auto& observer : observer_list_)
721 observer.OnBackgroundHostCreated(host);
rdevlin.cronin6ae04a012015-04-03 20:19:40722}
723
724void ProcessManager::CloseBackgroundHost(ExtensionHost* host) {
725 ExtensionId extension_id = host->extension_id();
726 CHECK(host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
727 delete host;
728 // |host| should deregister itself from our structures.
729 CHECK(background_hosts_.find(host) == background_hosts_.end());
730
ericwilligersd1e28152016-10-17 22:53:14731 for (auto& observer : observer_list_)
732 observer.OnBackgroundHostClose(extension_id);
rdevlin.cronin6ae04a012015-04-03 20:19:40733}
734
735void ProcessManager::AcquireLazyKeepaliveCountForFrame(
736 content::RenderFrameHost* render_frame_host) {
jdoerriea1e1598b2018-10-10 09:10:37737 auto it = all_extension_frames_.find(render_frame_host);
rdevlin.cronin6ae04a012015-04-03 20:19:40738 if (it == all_extension_frames_.end())
739 return;
740
741 ExtensionRenderFrameData& data = it->second;
742 if (data.CanKeepalive() && !data.has_keepalive) {
743 const Extension* extension =
744 GetExtensionForRenderFrameHost(render_frame_host);
745 if (extension) {
David Bertoni3e1e9fa2018-08-29 20:39:30746 IncrementLazyKeepaliveCount(extension, Activity::PROCESS_MANAGER,
747 Activity::kRenderFrame);
rdevlin.cronin6ae04a012015-04-03 20:19:40748 data.has_keepalive = true;
749 }
750 }
751}
752
753void ProcessManager::ReleaseLazyKeepaliveCountForFrame(
754 content::RenderFrameHost* render_frame_host) {
jdoerriea1e1598b2018-10-10 09:10:37755 auto iter = all_extension_frames_.find(render_frame_host);
rdevlin.cronin6ae04a012015-04-03 20:19:40756 if (iter == all_extension_frames_.end())
757 return;
758
759 ExtensionRenderFrameData& data = iter->second;
760 if (data.CanKeepalive() && data.has_keepalive) {
761 const Extension* extension =
762 GetExtensionForRenderFrameHost(render_frame_host);
763 if (extension) {
David Bertoni3e1e9fa2018-08-29 20:39:30764 DecrementLazyKeepaliveCount(extension, Activity::PROCESS_MANAGER,
765 Activity::kRenderFrame);
rdevlin.cronin6ae04a012015-04-03 20:19:40766 data.has_keepalive = false;
767 }
768 }
769}
770
Istiaque Ahmedb744ecf2019-02-06 00:23:32771std::string ProcessManager::IncrementServiceWorkerKeepaliveCount(
772 const WorkerId& worker_id,
773 Activity::Type activity_type,
774 const std::string& extra_data) {
775 // TODO(lazyboy): Use |activity_type| and |extra_data|.
776 int64_t service_worker_version_id = worker_id.version_id;
777 DCHECK(!worker_id.extension_id.empty());
778 const Extension* extension =
779 extension_registry_->enabled_extensions().GetByID(worker_id.extension_id);
780
781 DCHECK(extension);
782 DCHECK(BackgroundInfo::IsServiceWorkerBased(extension));
783
784 std::string request_uuid = base::GenerateGUID();
785 content::ServiceWorkerContext* service_worker_context =
786 content::BrowserContext::GetStoragePartitionForSite(browser_context_,
787 extension->url())
788 ->GetServiceWorkerContext();
789
Matt Falkenhagend55b9282019-09-10 23:53:35790 if (content::ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
791 StartServiceWorkerExternalRequest(service_worker_context,
792 service_worker_version_id, request_uuid);
793 } else {
794 content::ServiceWorkerContext::RunTask(
795 worker_task_runner_, FROM_HERE, service_worker_context,
796 base::BindOnce(&StartServiceWorkerExternalRequest,
797 service_worker_context, service_worker_version_id,
798 request_uuid));
799 }
Istiaque Ahmedb744ecf2019-02-06 00:23:32800 return request_uuid;
801}
802
rdevlin.cronin6ae04a012015-04-03 20:19:40803void ProcessManager::DecrementLazyKeepaliveCount(
David Bertoni3e1e9fa2018-08-29 20:39:30804 const std::string& extension_id,
805 Activity::Type activity_type,
806 const std::string& extra_data) {
807 BackgroundPageData& data = background_page_data_[extension_id];
808
809 DCHECK(data.lazy_keepalive_count > 0 ||
rdevlin.cronin6ae04a012015-04-03 20:19:40810 !extension_registry_->enabled_extensions().Contains(extension_id));
David Bertoni3e1e9fa2018-08-29 20:39:30811 --data.lazy_keepalive_count;
812 const auto it =
813 data.activities.find(std::make_pair(activity_type, extra_data));
814 if (it != data.activities.end()) {
815 data.activities.erase(it);
816 }
rdevlin.cronin6ae04a012015-04-03 20:19:40817
818 // If we reach a zero keepalive count when the lazy background page is about
819 // to be closed, incrementing close_sequence_id will cancel the close
820 // sequence and cause the background page to linger. So check is_closing
821 // before initiating another close sequence.
David Bertoni3e1e9fa2018-08-29 20:39:30822 if (data.lazy_keepalive_count == 0) {
823 // Clear any leftover activities.
824 data.activities.clear();
825 if (!background_page_data_[extension_id].is_closing) {
826 data.close_sequence_id = ++last_background_close_sequence_id_;
827 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
828 FROM_HERE,
kylechar0686a5232019-02-19 14:10:29829 base::BindOnce(&ProcessManager::OnLazyBackgroundPageIdle,
830 weak_ptr_factory_.GetWeakPtr(), extension_id,
831 last_background_close_sequence_id_),
David Bertoni3e1e9fa2018-08-29 20:39:30832 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec));
833 }
rdevlin.cronin6ae04a012015-04-03 20:19:40834 }
835}
836
Istiaque Ahmedb744ecf2019-02-06 00:23:32837void ProcessManager::DecrementServiceWorkerKeepaliveCount(
838 const WorkerId& worker_id,
839 const std::string& request_uuid,
840 Activity::Type activity_type,
841 const std::string& extra_data) {
842 DCHECK(!worker_id.extension_id.empty());
843 const Extension* extension =
844 extension_registry_->enabled_extensions().GetByID(worker_id.extension_id);
845 if (!extension)
846 return;
847
848 DCHECK(BackgroundInfo::IsServiceWorkerBased(extension));
849
850 int64_t service_worker_version_id = worker_id.version_id;
851 content::ServiceWorkerContext* service_worker_context =
852 content::BrowserContext::GetStoragePartitionForSite(browser_context_,
853 extension->url())
854 ->GetServiceWorkerContext();
855
Matt Falkenhagend55b9282019-09-10 23:53:35856 if (content::ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
857 FinishServiceWorkerExternalRequest(service_worker_context,
858 service_worker_version_id, request_uuid);
859 } else {
860 content::ServiceWorkerContext::RunTask(
861 worker_task_runner_, FROM_HERE, service_worker_context,
862 base::BindOnce(&FinishServiceWorkerExternalRequest,
863 service_worker_context, service_worker_version_id,
864 request_uuid));
865 }
Istiaque Ahmedb744ecf2019-02-06 00:23:32866}
867
[email protected]98b6d942013-11-10 00:34:07868void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id,
avic9cec102015-12-23 00:39:26869 uint64_t sequence_id) {
[email protected]06024c62011-10-20 20:57:12870 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
[email protected]99c49b52012-05-02 01:50:20871 if (host && !background_page_data_[extension_id].is_closing &&
872 sequence_id == background_page_data_[extension_id].close_sequence_id) {
[email protected]103f19f2012-04-02 19:30:12873 // Tell the renderer we are about to close. This is a simple ping that the
874 // renderer will respond to. The purpose is to control sequencing: if the
875 // extension remains idle until the renderer responds with an ACK, then we
[email protected]99c49b52012-05-02 01:50:20876 // know that the extension process is ready to shut down. If our
877 // close_sequence_id has already changed, then we would ignore the
[email protected]584e6572013-02-16 07:02:33878 // ShouldSuspendAck, so we don't send the ping.
rdevlin.cronin6ae04a012015-04-03 20:19:40879 host->render_process_host()->Send(new ExtensionMsg_ShouldSuspend(
[email protected]99c49b52012-05-02 01:50:20880 extension_id, sequence_id));
[email protected]103f19f2012-04-02 19:30:12881 }
[email protected]720ad1312012-02-27 23:07:36882}
883
[email protected]98b6d942013-11-10 00:34:07884void ProcessManager::OnLazyBackgroundPageActive(
[email protected]720ad1312012-02-27 23:07:36885 const std::string& extension_id) {
[email protected]77a538f2014-07-14 22:25:37886 if (!background_page_data_[extension_id].is_closing) {
[email protected]103f19f2012-04-02 19:30:12887 // Cancel the current close sequence by changing the close_sequence_id,
[email protected]584e6572013-02-16 07:02:33888 // which causes us to ignore the next ShouldSuspendAck.
[email protected]77a538f2014-07-14 22:25:37889 background_page_data_[extension_id].close_sequence_id =
890 ++last_background_close_sequence_id_;
[email protected]103f19f2012-04-02 19:30:12891 }
[email protected]720ad1312012-02-27 23:07:36892}
893
[email protected]98b6d942013-11-10 00:34:07894void ProcessManager::CloseLazyBackgroundPageNow(const std::string& extension_id,
avic9cec102015-12-23 00:39:26895 uint64_t sequence_id) {
[email protected]99c49b52012-05-02 01:50:20896 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
[email protected]0d475e072012-07-26 02:30:42897 if (host &&
898 sequence_id == background_page_data_[extension_id].close_sequence_id) {
kmarshalld3e8c082015-07-25 00:39:58899 // Handle the case where the keepalive count was increased after the
900 // OnSuspend event was sent.
901 if (background_page_data_[extension_id].lazy_keepalive_count > 0) {
902 CancelSuspend(host->extension());
903 return;
904 }
905
hashimoto5bca2272014-11-04 07:35:18906 // Close remaining views.
rdevlin.cronin6ae04a012015-04-03 20:19:40907 std::vector<content::RenderFrameHost*> frames_to_close;
908 for (const auto& key_value : all_extension_frames_) {
909 if (key_value.second.CanKeepalive() &&
910 GetExtensionID(key_value.first) == extension_id) {
911 DCHECK(!key_value.second.has_keepalive);
912 frames_to_close.push_back(key_value.first);
hashimoto5bca2272014-11-04 07:35:18913 }
914 }
rdevlin.cronin6ae04a012015-04-03 20:19:40915 for (content::RenderFrameHost* frame : frames_to_close) {
naskoc0fceff2015-04-30 15:53:52916 content::WebContents::FromRenderFrameHost(frame)->ClosePage();
917 // WebContents::ClosePage() may result in calling
Devlin Cronind2dae262017-10-16 21:04:24918 // UnregisterRenderFrameHost() asynchronously and may cause race
919 // conditions when the background page is reloaded.
hashimoto5bca2272014-11-04 07:35:18920 // To avoid this, unregister the view now.
rdevlin.cronin6ae04a012015-04-03 20:19:40921 UnregisterRenderFrameHost(frame);
hashimoto5bca2272014-11-04 07:35:18922 }
923
[email protected]0d475e072012-07-26 02:30:42924 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
925 if (host)
926 CloseBackgroundHost(host);
927 }
[email protected]06024c62011-10-20 20:57:12928}
929
dgozman47679eb12016-10-17 17:30:18930const Extension* ProcessManager::GetExtensionForAgentHost(
931 content::DevToolsAgentHost* agent_host) {
rdevlin.cronin6ae04a012015-04-03 20:19:40932 content::WebContents* web_contents = agent_host->GetWebContents();
[email protected]a23f62e2013-04-26 13:13:02933 // Ignore unrelated notifications.
rdevlin.cronin6ae04a012015-04-03 20:19:40934 if (!web_contents || web_contents->GetBrowserContext() != browser_context_)
dgozman47679eb12016-10-17 17:30:18935 return nullptr;
[email protected]b3f957e62014-08-08 10:09:02936 if (GetViewType(web_contents) != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE)
dgozman47679eb12016-10-17 17:30:18937 return nullptr;
938 return GetExtensionForWebContents(web_contents);
939}
940
941void ProcessManager::DevToolsAgentHostAttached(
942 content::DevToolsAgentHost* agent_host) {
943 if (const Extension* extension = GetExtensionForAgentHost(agent_host)) {
[email protected]a23f62e2013-04-26 13:13:02944 // Keep the lazy background page alive while it's being inspected.
945 CancelSuspend(extension);
David Bertoni3e1e9fa2018-08-29 20:39:30946 IncrementLazyKeepaliveCount(extension, Activity::DEV_TOOLS, std::string());
[email protected]a23f62e2013-04-26 13:13:02947 }
948}
949
dgozman47679eb12016-10-17 17:30:18950void ProcessManager::DevToolsAgentHostDetached(
951 content::DevToolsAgentHost* agent_host) {
952 if (const Extension* extension = GetExtensionForAgentHost(agent_host))
David Bertoni3e1e9fa2018-08-29 20:39:30953 DecrementLazyKeepaliveCount(extension, Activity::DEV_TOOLS, "");
dgozman47679eb12016-10-17 17:30:18954}
955
[email protected]98b6d942013-11-10 00:34:07956void ProcessManager::UnregisterExtension(const std::string& extension_id) {
[email protected]5b3ee852013-09-26 06:33:10957 // The lazy_keepalive_count may be greater than zero at this point because
rdevlin.cronin6ae04a012015-04-03 20:19:40958 // RenderFrameHosts are still alive. During extension reloading, they will
[email protected]5b3ee852013-09-26 06:33:10959 // decrement the lazy_keepalive_count to negative for the new extension
960 // instance when they are destroyed. Since we are erasing the background page
rdevlin.cronin6ae04a012015-04-03 20:19:40961 // data for the unloaded extension, unregister the RenderFrameHosts too.
jdoerriea1e1598b2018-10-10 09:10:37962 for (auto it = all_extension_frames_.begin();
963 it != all_extension_frames_.end();) {
rdevlin.cronin6ae04a012015-04-03 20:19:40964 content::RenderFrameHost* host = it->first;
965 if (GetExtensionID(host) == extension_id) {
966 all_extension_frames_.erase(it++);
ericwilligersd1e28152016-10-17 22:53:14967 for (auto& observer : observer_list_)
968 observer.OnExtensionFrameUnregistered(extension_id, host);
[email protected]5b3ee852013-09-26 06:33:10969 } else {
970 ++it;
971 }
972 }
973
974 background_page_data_.erase(extension_id);
Istiaque Ahmedb744ecf2019-02-06 00:23:32975
976 all_extension_workers_.RemoveAllForExtension(extension_id);
977}
978
979void ProcessManager::RegisterServiceWorker(const WorkerId& worker_id) {
980 all_extension_workers_.Add(worker_id);
Istiaque Ahmedd4b67ee2019-03-02 10:53:20981
982 // Observe the RenderProcessHost for cleaning up on process shutdown.
983 int render_process_id = worker_id.render_process_id;
984 bool inserted = worker_process_to_extension_ids_[render_process_id]
985 .insert(worker_id.extension_id)
986 .second;
987 if (inserted) {
988 content::RenderProcessHost* render_process_host =
989 content::RenderProcessHost::FromID(render_process_id);
990 DCHECK(render_process_host);
991 if (!process_observer_.IsObserving(render_process_host)) {
992 // These will be cleaned up in RenderProcessExited().
993 process_observer_.Add(render_process_host);
994 }
995 }
996}
997
998void ProcessManager::RenderProcessExited(
999 content::RenderProcessHost* host,
1000 const content::ChildProcessTerminationInfo& info) {
1001 DCHECK(process_observer_.IsObserving(host));
1002 process_observer_.Remove(host);
1003 const int render_process_id = host->GetID();
1004 // Look up and then clean up the entries that are affected by
1005 // |render_process_id| destruction.
1006 //
1007 // TODO(lazyboy): Revisit this once incognito is tested for extension SWs, as
1008 // the cleanup below only works because regular and OTR ProcessManagers are
1009 // separate. The conclusive approach would be to have a
1010 // all_extension_workers_.RemoveAllForProcess(render_process_id) method:
1011 // Pros: We won't need worker_process_to_extension_ids_ anymore.
1012 // Cons: We would require traversing all workers within
1013 // |all_extension_workers_| (slow) as things stand right now.
1014 auto iter = worker_process_to_extension_ids_.find(render_process_id);
1015 if (iter == worker_process_to_extension_ids_.end())
1016 return;
1017 for (const ExtensionId& extension_id : iter->second)
1018 all_extension_workers_.RemoveAllForExtension(extension_id);
1019 worker_process_to_extension_ids_.erase(iter);
Istiaque Ahmedb744ecf2019-02-06 00:23:321020}
1021
1022void ProcessManager::UnregisterServiceWorker(const WorkerId& worker_id) {
Istiaque Ahmedd4b67ee2019-03-02 10:53:201023 // TODO(lazyboy): DCHECK that |worker_id| exists in |all_extension_workers_|.
Istiaque Ahmedb744ecf2019-02-06 00:23:321024 all_extension_workers_.Remove(worker_id);
1025}
1026
1027bool ProcessManager::HasServiceWorker(const WorkerId& worker_id) const {
1028 return all_extension_workers_.Contains(worker_id);
1029}
1030
1031std::vector<WorkerId> ProcessManager::GetServiceWorkers(
1032 const ExtensionId& extension_id,
1033 int render_process_id) const {
1034 return all_extension_workers_.GetAllForExtension(extension_id,
1035 render_process_id);
[email protected]5b3ee852013-09-26 06:33:101036}
1037
Istiaque Ahmedd4b67ee2019-03-02 10:53:201038std::vector<WorkerId> ProcessManager::GetAllWorkersIdsForTesting() {
1039 return all_extension_workers_.GetAllForTesting();
1040}
1041
[email protected]98b6d942013-11-10 00:34:071042void ProcessManager::ClearBackgroundPageData(const std::string& extension_id) {
[email protected]caffe702012-05-03 05:30:171043 background_page_data_.erase(extension_id);
1044
Devlin Cronind2dae262017-10-16 21:04:241045 // Re-register all RenderFrames for this extension. We do this to restore
[email protected]caffe702012-05-03 05:30:171046 // the lazy_keepalive_count (if any) to properly reflect the number of open
1047 // views.
rdevlin.cronin6ae04a012015-04-03 20:19:401048 for (const auto& key_value : all_extension_frames_) {
hashimoto5bca2272014-11-04 07:35:181049 // Do not increment the count when |has_keepalive| is false
1050 // (i.e. ReleaseLazyKeepaliveCountForView() was called).
rdevlin.cronin6ae04a012015-04-03 20:19:401051 if (GetExtensionID(key_value.first) == extension_id &&
1052 key_value.second.has_keepalive) {
1053 const Extension* extension =
1054 GetExtensionForRenderFrameHost(key_value.first);
hashimoto5bca2272014-11-04 07:35:181055 if (extension)
David Bertoni3e1e9fa2018-08-29 20:39:301056 IncrementLazyKeepaliveCount(extension, Activity::PROCESS_MANAGER,
1057 Activity::kRenderFrame);
hashimoto5bca2272014-11-04 07:35:181058 }
[email protected]caffe702012-05-03 05:30:171059 }
1060}
1061
[email protected]bc535ee52010-08-31 18:40:321062//
[email protected]98b6d942013-11-10 00:34:071063// IncognitoProcessManager
[email protected]bc535ee52010-08-31 18:40:321064//
1065
[email protected]98b6d942013-11-10 00:34:071066IncognitoProcessManager::IncognitoProcessManager(
[email protected]7f474212013-11-05 04:26:161067 BrowserContext* incognito_context,
[email protected]b9f6ba32014-03-10 18:34:081068 BrowserContext* original_context,
[email protected]6b54fda2014-07-22 02:13:471069 ExtensionRegistry* extension_registry)
reillyg0ea3fa902014-10-28 15:30:231070 : ProcessManager(incognito_context, original_context, extension_registry) {
[email protected]7f474212013-11-05 04:26:161071 DCHECK(incognito_context->IsOffTheRecord());
[email protected]bc535ee52010-08-31 18:40:321072}
1073
[email protected]6ad9cdf72014-02-27 13:12:411074bool IncognitoProcessManager::CreateBackgroundHost(const Extension* extension,
1075 const GURL& url) {
[email protected]98b6d942013-11-10 00:34:071076 if (IncognitoInfo::IsSplitMode(extension)) {
[email protected]6a3d8ce42014-02-07 00:42:371077 if (ExtensionsBrowserClient::Get()->IsExtensionIncognitoEnabled(
rdevlin.cronin6ae04a012015-04-03 20:19:401078 extension->id(), browser_context()))
[email protected]98b6d942013-11-10 00:34:071079 return ProcessManager::CreateBackgroundHost(extension, url);
[email protected]bc535ee52010-08-31 18:40:321080 } else {
1081 // Do nothing. If an extension is spanning, then its original-profile
1082 // background page is shared with incognito, so we don't create another.
1083 }
[email protected]6ad9cdf72014-02-27 13:12:411084 return false;
[email protected]bc535ee52010-08-31 18:40:321085}
1086
rdevlin.cronin6ae04a012015-04-03 20:19:401087scoped_refptr<content::SiteInstance>
1088IncognitoProcessManager::GetSiteInstanceForURL(const GURL& url) {
[email protected]6b54fda2014-07-22 02:13:471089 const Extension* extension =
1090 extension_registry_->enabled_extensions().GetExtensionOrAppByURL(url);
reillyg0ea3fa902014-10-28 15:30:231091 if (extension && !IncognitoInfo::IsSplitMode(extension)) {
1092 BrowserContext* original_context =
rdevlin.cronin6ae04a012015-04-03 20:19:401093 ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context());
reillyg0ea3fa902014-10-28 15:30:231094 return ProcessManager::Get(original_context)->GetSiteInstanceForURL(url);
1095 }
[email protected]6b54fda2014-07-22 02:13:471096
[email protected]98b6d942013-11-10 00:34:071097 return ProcessManager::GetSiteInstanceForURL(url);
[email protected]bc535ee52010-08-31 18:40:321098}
1099
[email protected]98b6d942013-11-10 00:34:071100} // namespace extensions