[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors. All rights reserved. |
[email protected] | 481e1a4 | 2009-05-06 20:56:05 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 5 | #include "extensions/browser/process_manager.h" |
[email protected] | cb2edf2 | 2013-04-01 20:25:23 | [diff] [blame] | 6 | |
Jiaquan He | e057f67d | 2017-12-12 18:55:05 | [diff] [blame] | 7 | #include <memory> |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 8 | #include <unordered_set> |
kmarshall | 24b29b2 | 2015-04-29 01:41:47 | [diff] [blame] | 9 | #include <vector> |
| 10 | |
[email protected] | 8add541 | 2011-10-01 21:02:14 | [diff] [blame] | 11 | #include "base/bind.h" |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 12 | #include "base/guid.h" |
fdoray | e6609ac8 | 2016-06-06 19:21:40 | [diff] [blame] | 13 | #include "base/location.h" |
[email protected] | 0d475e07 | 2012-07-26 02:30:42 | [diff] [blame] | 14 | #include "base/logging.h" |
avi | c9cec10 | 2015-12-23 00:39:26 | [diff] [blame] | 15 | #include "base/macros.h" |
yoz | 1c99cbef | 2015-02-06 19:03:56 | [diff] [blame] | 16 | #include "base/metrics/histogram_macros.h" |
Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 17 | #include "base/one_shot_event.h" |
fdoray | e6609ac8 | 2016-06-06 19:21:40 | [diff] [blame] | 18 | #include "base/single_thread_task_runner.h" |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 19 | #include "base/strings/string_number_conversions.h" |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 20 | #include "base/task/post_task.h" |
fdoray | e6609ac8 | 2016-06-06 19:21:40 | [diff] [blame] | 21 | #include "base/threading/thread_task_runner_handle.h" |
[email protected] | 41a17c5 | 2013-06-28 00:27:53 | [diff] [blame] | 22 | #include "base/time/time.h" |
[email protected] | 94de8cb | 2013-11-07 06:29:21 | [diff] [blame] | 23 | #include "content/public/browser/browser_context.h" |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 24 | #include "content/public/browser/browser_task_traits.h" |
[email protected] | a23f62e | 2013-04-26 13:13:02 | [diff] [blame] | 25 | #include "content/public/browser/devtools_agent_host.h" |
Devlin Cronin | 7a282e3 | 2017-08-10 01:54:10 | [diff] [blame] | 26 | #include "content/public/browser/navigation_controller.h" |
| 27 | #include "content/public/browser/navigation_entry.h" |
[email protected] | ad50def5 | 2011-10-19 23:17:07 | [diff] [blame] | 28 | #include "content/public/browser/notification_service.h" |
[email protected] | 9dfed87 | 2013-12-30 23:08:56 | [diff] [blame] | 29 | #include "content/public/browser/render_frame_host.h" |
[email protected] | 9c1662b | 2012-03-06 15:44:33 | [diff] [blame] | 30 | #include "content/public/browser/render_view_host.h" |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 31 | #include "content/public/browser/service_worker_context.h" |
Matt Falkenhagen | 1d69a34 | 2019-09-10 23:28:57 | [diff] [blame] | 32 | #include "content/public/browser/service_worker_external_request_result.h" |
[email protected] | b658359 | 2012-01-25 19:52:33 | [diff] [blame] | 33 | #include "content/public/browser/site_instance.h" |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 34 | #include "content/public/browser/storage_partition.h" |
[email protected] | 4ca1530 | 2012-01-03 05:53:20 | [diff] [blame] | 35 | #include "content/public/browser/web_contents.h" |
[email protected] | 6703c15d | 2014-04-03 19:03:45 | [diff] [blame] | 36 | #include "content/public/common/url_constants.h" |
[email protected] | 22401dc | 2014-03-21 01:38:57 | [diff] [blame] | 37 | #include "extensions/browser/extension_host.h" |
[email protected] | 5fdfa56 | 2013-12-27 17:43:59 | [diff] [blame] | 38 | #include "extensions/browser/extension_registry.h" |
[email protected] | 59b0e60 | 2014-01-30 00:41:24 | [diff] [blame] | 39 | #include "extensions/browser/extension_system.h" |
[email protected] | 7f47421 | 2013-11-05 04:26:16 | [diff] [blame] | 40 | #include "extensions/browser/extensions_browser_client.h" |
David Bertoni | 8269a09 | 2018-12-19 15:55:42 | [diff] [blame] | 41 | #include "extensions/browser/lazy_context_id.h" |
David Bertoni | 641e3ce0 | 2019-01-11 20:35:12 | [diff] [blame] | 42 | #include "extensions/browser/lazy_context_task_queue.h" |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 43 | #include "extensions/browser/notification_types.h" |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 44 | #include "extensions/browser/process_manager_delegate.h" |
reillyg | 0ea3fa90 | 2014-10-28 15:30:23 | [diff] [blame] | 45 | #include "extensions/browser/process_manager_factory.h" |
[email protected] | 08d469b2 | 2014-03-31 00:51:24 | [diff] [blame] | 46 | #include "extensions/browser/process_manager_observer.h" |
[email protected] | cb2edf2 | 2013-04-01 20:25:23 | [diff] [blame] | 47 | #include "extensions/browser/view_type_utils.h" |
[email protected] | 6703c15d | 2014-04-03 19:03:45 | [diff] [blame] | 48 | #include "extensions/common/constants.h" |
[email protected] | e4452d3 | 2013-11-15 23:07:41 | [diff] [blame] | 49 | #include "extensions/common/extension.h" |
[email protected] | fb820c0 | 2014-03-13 15:07:08 | [diff] [blame] | 50 | #include "extensions/common/extension_messages.h" |
[email protected] | 558878cc8 | 2013-11-09 01:25:51 | [diff] [blame] | 51 | #include "extensions/common/manifest_handlers/background_info.h" |
[email protected] | 1f7de25 | 2013-11-06 22:02:00 | [diff] [blame] | 52 | #include "extensions/common/manifest_handlers/incognito_info.h" |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 53 | |
[email protected] | 7f47421 | 2013-11-05 04:26:16 | [diff] [blame] | 54 | using content::BrowserContext; |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 55 | |
| 56 | namespace extensions { |
[email protected] | 7b1aa0e | 2013-10-16 22:57:37 | [diff] [blame] | 57 | |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 58 | namespace { |
| 59 | |
yoz | a9bf560 | 2014-09-19 02:03:31 | [diff] [blame] | 60 | // The time to delay between an extension becoming idle and |
| 61 | // sending a ShouldSuspend message. |
yoz | a9bf560 | 2014-09-19 02:03:31 | [diff] [blame] | 62 | unsigned g_event_page_idle_time_msec = 10000; |
| 63 | |
| 64 | // The time to delay between sending a ShouldSuspend message and |
| 65 | // sending a Suspend message. |
| 66 | unsigned g_event_page_suspending_time_msec = 5000; |
| 67 | |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 68 | std::string GetExtensionIdForSiteInstance( |
| 69 | content::SiteInstance* site_instance) { |
[email protected] | 6703c15d | 2014-04-03 19:03:45 | [diff] [blame] | 70 | if (!site_instance) |
[email protected] | 007b3f8 | 2013-04-09 08:46:45 | [diff] [blame] | 71 | return std::string(); |
[email protected] | d1fe135 | 2012-04-26 00:47:32 | [diff] [blame] | 72 | |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 73 | // This works for both apps and extensions because the site has been |
| 74 | // normalized to the extension URL for hosted apps. |
[email protected] | 6703c15d | 2014-04-03 19:03:45 | [diff] [blame] | 75 | 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] | 6baff0b5 | 2012-03-06 01:30:18 | [diff] [blame] | 82 | } |
| 83 | |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 84 | std::string GetExtensionID(content::RenderFrameHost* render_frame_host) { |
| 85 | CHECK(render_frame_host); |
| 86 | return GetExtensionIdForSiteInstance(render_frame_host->GetSiteInstance()); |
[email protected] | 9dfed87 | 2013-12-30 23:08:56 | [diff] [blame] | 87 | } |
| 88 | |
| 89 | bool IsFrameInExtensionHost(ExtensionHost* extension_host, |
| 90 | content::RenderFrameHost* render_frame_host) { |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 91 | return content::WebContents::FromRenderFrameHost(render_frame_host) == |
[email protected] | 9dfed87 | 2013-12-30 23:08:56 | [diff] [blame] | 92 | extension_host->host_contents(); |
| 93 | } |
| 94 | |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 95 | // Incognito profiles use this process manager. It is mostly a shim that decides |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 96 | // whether to fall back on the original profile's ProcessManager based |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 97 | // on whether a given extension uses "split" or "spanning" incognito behavior. |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 98 | // 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] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 101 | class IncognitoProcessManager : public ProcessManager { |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 102 | public: |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 103 | IncognitoProcessManager(BrowserContext* incognito_context, |
[email protected] | b9f6ba3 | 2014-03-10 18:34:08 | [diff] [blame] | 104 | BrowserContext* original_context, |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 105 | ExtensionRegistry* extension_registry); |
dcheng | 9168b2f | 2014-10-21 12:38:24 | [diff] [blame] | 106 | ~IncognitoProcessManager() override {} |
| 107 | bool CreateBackgroundHost(const Extension* extension, |
| 108 | const GURL& url) override; |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 109 | scoped_refptr<content::SiteInstance> GetSiteInstanceForURL(const GURL& url) |
| 110 | override; |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 111 | |
| 112 | private: |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 113 | DISALLOW_COPY_AND_ASSIGN(IncognitoProcessManager); |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 114 | }; |
[email protected] | 481e1a4 | 2009-05-06 20:56:05 | [diff] [blame] | 115 | |
[email protected] | f72d0c6 | 2011-08-31 16:27:44 | [diff] [blame] | 116 | static void CreateBackgroundHostForExtensionLoad( |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 117 | ProcessManager* manager, const Extension* extension) { |
[email protected] | 9367eabc | 2013-03-01 01:29:29 | [diff] [blame] | 118 | if (BackgroundInfo::HasPersistentBackgroundPage(extension)) |
| 119 | manager->CreateBackgroundHost(extension, |
| 120 | BackgroundInfo::GetBackgroundURL(extension)); |
[email protected] | ae09ca6 | 2009-08-21 19:46:46 | [diff] [blame] | 121 | } |
| 122 | |
David Bertoni | 643f6a94 | 2018-12-17 16:50:07 | [diff] [blame] | 123 | void PropagateExtensionWakeResult( |
| 124 | base::OnceCallback<void(bool)> callback, |
| 125 | std::unique_ptr<LazyContextTaskQueue::ContextInfo> context_info) { |
| 126 | std::move(callback).Run(context_info != nullptr); |
kmarshall | 24b29b2 | 2015-04-29 01:41:47 | [diff] [blame] | 127 | } |
| 128 | |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 129 | void StartServiceWorkerExternalRequest(content::ServiceWorkerContext* context, |
| 130 | int64_t service_worker_version_id, |
| 131 | const std::string& request_uuid) { |
Matt Falkenhagen | d55b928 | 2019-09-10 23:53:35 | [diff] [blame] | 132 | DCHECK_CURRENTLY_ON(content::ServiceWorkerContext::GetCoreThreadId()); |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 133 | context->StartingExternalRequest(service_worker_version_id, request_uuid); |
| 134 | } |
| 135 | |
| 136 | void FinishServiceWorkerExternalRequest(content::ServiceWorkerContext* context, |
| 137 | int64_t service_worker_version_id, |
| 138 | const std::string& request_uuid) { |
Matt Falkenhagen | d55b928 | 2019-09-10 23:53:35 | [diff] [blame] | 139 | DCHECK_CURRENTLY_ON(content::ServiceWorkerContext::GetCoreThreadId()); |
Matt Falkenhagen | 1d69a34 | 2019-09-10 23:28:57 | [diff] [blame] | 140 | content::ServiceWorkerExternalRequestResult result = |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 141 | context->FinishedExternalRequest(service_worker_version_id, request_uuid); |
Matt Falkenhagen | 1d69a34 | 2019-09-10 23:28:57 | [diff] [blame] | 142 | DCHECK_EQ(result, content::ServiceWorkerExternalRequestResult::kOk); |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 143 | } |
| 144 | |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 145 | } // namespace |
| 146 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 147 | struct ProcessManager::BackgroundPageData { |
[email protected] | 103f19f | 2012-04-02 19:30:12 | [diff] [blame] | 148 | // The count of things keeping the lazy background page alive. |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 149 | // TODO(crbug.com://695711): Work on a plan to remove this and rely |
| 150 | // on activities.size() instead. |
wez | d6be280 | 2017-03-27 01:49:28 | [diff] [blame] | 151 | int lazy_keepalive_count = 0; |
[email protected] | 38877015 | 2013-12-03 01:25:32 | [diff] [blame] | 152 | |
[email protected] | 584e657 | 2013-02-16 07:02:33 | [diff] [blame] | 153 | // 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. |
wez | d6be280 | 2017-03-27 01:49:28 | [diff] [blame] | 157 | bool is_closing = false; |
[email protected] | 103f19f | 2012-04-02 19:30:12 | [diff] [blame] | 158 | |
[email protected] | 77a538f | 2014-07-14 22:25:37 | [diff] [blame] | 159 | // 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. |
wez | d6be280 | 2017-03-27 01:49:28 | [diff] [blame] | 164 | uint64_t close_sequence_id = 0ull; |
[email protected] | 77a538f | 2014-07-14 22:25:37 | [diff] [blame] | 165 | |
[email protected] | 584e657 | 2013-02-16 07:02:33 | [diff] [blame] | 166 | // Keeps track of when this page was last suspended. Used for perf metrics. |
lazyboy | f33109d | 2016-08-31 00:37:08 | [diff] [blame] | 167 | std::unique_ptr<base::ElapsedTimer> since_suspended; |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 168 | |
| 169 | ActivitiesMultiset activities; |
[email protected] | 103f19f | 2012-04-02 19:30:12 | [diff] [blame] | 170 | }; |
| 171 | |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 172 | // Data of a RenderFrameHost associated with an extension. |
| 173 | struct ProcessManager::ExtensionRenderFrameData { |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 174 | // The type of the view. |
wez | d6be280 | 2017-03-27 01:49:28 | [diff] [blame] | 175 | extensions::ViewType view_type = VIEW_TYPE_INVALID; |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 176 | |
| 177 | // Whether the view is keeping the lazy background page alive or not. |
wez | d6be280 | 2017-03-27 01:49:28 | [diff] [blame] | 178 | bool has_keepalive = false; |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 179 | |
| 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: |
dmazzoni | 5ba638d | 2016-01-07 22:58:54 | [diff] [blame] | 185 | case VIEW_TYPE_COMPONENT: |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 186 | case VIEW_TYPE_EXTENSION_DIALOG: |
rob | cdcc4b8 | 2015-12-06 12:39:45 | [diff] [blame] | 187 | case VIEW_TYPE_EXTENSION_GUEST: |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 188 | case VIEW_TYPE_EXTENSION_POPUP: |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 189 | case VIEW_TYPE_TAB_CONTENTS: |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 190 | 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] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 201 | // |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 202 | // ProcessManager |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 203 | // |
| 204 | |
| 205 | // static |
reillyg | 0ea3fa90 | 2014-10-28 15:30:23 | [diff] [blame] | 206 | ProcessManager* ProcessManager::Get(BrowserContext* context) { |
| 207 | return ProcessManagerFactory::GetForBrowserContext(context); |
| 208 | } |
| 209 | |
| 210 | // static |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 211 | ProcessManager* ProcessManager::Create(BrowserContext* context) { |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 212 | ExtensionRegistry* extension_registry = ExtensionRegistry::Get(context); |
[email protected] | d012be2b | 2014-03-03 17:02:47 | [diff] [blame] | 213 | 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] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 220 | return new ProcessManager(context, original_context, extension_registry); |
[email protected] | d012be2b | 2014-03-03 17:02:47 | [diff] [blame] | 221 | } |
| 222 | |
[email protected] | 7f47421 | 2013-11-05 04:26:16 | [diff] [blame] | 223 | if (context->IsOffTheRecord()) { |
[email protected] | d012be2b | 2014-03-03 17:02:47 | [diff] [blame] | 224 | BrowserContext* original_context = client->GetOriginalContext(context); |
[email protected] | b9f6ba3 | 2014-03-10 18:34:08 | [diff] [blame] | 225 | return new IncognitoProcessManager( |
reillyg | 0ea3fa90 | 2014-10-28 15:30:23 | [diff] [blame] | 226 | context, original_context, extension_registry); |
[email protected] | 7f47421 | 2013-11-05 04:26:16 | [diff] [blame] | 227 | } |
[email protected] | d012be2b | 2014-03-03 17:02:47 | [diff] [blame] | 228 | |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 229 | return new ProcessManager(context, context, extension_registry); |
| 230 | } |
| 231 | |
| 232 | // static |
| 233 | ProcessManager* ProcessManager::CreateForTesting( |
| 234 | BrowserContext* context, |
| 235 | ExtensionRegistry* extension_registry) { |
| 236 | DCHECK(!context->IsOffTheRecord()); |
| 237 | return new ProcessManager(context, context, extension_registry); |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 238 | } |
| 239 | |
[email protected] | b9f6ba3 | 2014-03-10 18:34:08 | [diff] [blame] | 240 | // static |
| 241 | ProcessManager* ProcessManager::CreateIncognitoForTesting( |
| 242 | BrowserContext* incognito_context, |
| 243 | BrowserContext* original_context, |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 244 | ExtensionRegistry* extension_registry) { |
[email protected] | b9f6ba3 | 2014-03-10 18:34:08 | [diff] [blame] | 245 | DCHECK(incognito_context->IsOffTheRecord()); |
| 246 | DCHECK(!original_context->IsOffTheRecord()); |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 247 | return new IncognitoProcessManager(incognito_context, |
| 248 | original_context, |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 249 | extension_registry); |
[email protected] | b9f6ba3 | 2014-03-10 18:34:08 | [diff] [blame] | 250 | } |
| 251 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 252 | ProcessManager::ProcessManager(BrowserContext* context, |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 253 | BrowserContext* original_context, |
| 254 | ExtensionRegistry* extension_registry) |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 255 | : extension_registry_(extension_registry), |
| 256 | site_instance_(content::SiteInstance::Create(context)), |
| 257 | browser_context_(context), |
Sami Kyostila | fc64668 | 2019-08-08 05:19:56 | [diff] [blame] | 258 | worker_task_runner_( |
| 259 | base::CreateSingleThreadTaskRunner({content::BrowserThread::IO})), |
[email protected] | 77a538f | 2014-07-14 22:25:37 | [diff] [blame] | 260 | startup_background_hosts_created_(false), |
Evan Stade | 922f3f1f | 2019-09-04 21:05:13 | [diff] [blame] | 261 | last_background_close_sequence_id_(0) { |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 262 | // ExtensionRegistry is shared between incognito and regular contexts. |
| 263 | DCHECK_EQ(original_context, extension_registry_->browser_context()); |
limasdf | e0f061b | 2015-02-27 00:35:06 | [diff] [blame] | 264 | extension_registry_->AddObserver(this); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 265 | |
| 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] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 270 | extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED, |
[email protected] | 7f47421 | 2013-11-05 04:26:16 | [diff] [blame] | 271 | content::Source<BrowserContext>(original_context)); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 272 | } |
[email protected] | 49e7741e | 2014-07-21 01:57:42 | [diff] [blame] | 273 | registrar_.Add(this, |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 274 | extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, |
[email protected] | 7f47421 | 2013-11-05 04:26:16 | [diff] [blame] | 275 | content::Source<BrowserContext>(context)); |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 276 | registrar_.Add(this, |
| 277 | extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, |
[email protected] | 7f47421 | 2013-11-05 04:26:16 | [diff] [blame] | 278 | content::Source<BrowserContext>(context)); |
dgozman | 47679eb1 | 2016-10-17 17:30:18 | [diff] [blame] | 279 | content::DevToolsAgentHost::AddObserver(this); |
[email protected] | 481e1a4 | 2009-05-06 20:56:05 | [diff] [blame] | 280 | } |
| 281 | |
lazyboy | f70b2eb9 | 2017-04-25 20:42:09 | [diff] [blame] | 282 | ProcessManager::~ProcessManager() { |
| 283 | content::DevToolsAgentHost::RemoveObserver(this); |
| 284 | } |
sense | 383ce0f | 2017-03-24 04:06:43 | [diff] [blame] | 285 | |
| 286 | void ProcessManager::Shutdown() { |
limasdf | e0f061b | 2015-02-27 00:35:06 | [diff] [blame] | 287 | extension_registry_->RemoveObserver(this); |
[email protected] | a95631cb | 2009-12-10 01:59:11 | [diff] [blame] | 288 | CloseBackgroundHosts(); |
[email protected] | ae5497f | 2009-11-05 00:39:46 | [diff] [blame] | 289 | DCHECK(background_hosts_.empty()); |
dgozman | 47679eb1 | 2016-10-17 17:30:18 | [diff] [blame] | 290 | content::DevToolsAgentHost::RemoveObserver(this); |
sense | 383ce0f | 2017-03-24 04:06:43 | [diff] [blame] | 291 | site_instance_ = nullptr; |
[email protected] | 481e1a4 | 2009-05-06 20:56:05 | [diff] [blame] | 292 | } |
| 293 | |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 294 | void ProcessManager::RegisterRenderFrameHost( |
| 295 | content::WebContents* web_contents, |
| 296 | content::RenderFrameHost* render_frame_host, |
| 297 | const Extension* extension) { |
Karan Bhatia | ad3b727 | 2017-12-20 21:14:36 | [diff] [blame] | 298 | DCHECK(render_frame_host->IsRenderFrameLive()); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 299 | 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 | |
ericwilligers | d1e2815 | 2016-10-17 22:53:14 | [diff] [blame] | 307 | for (auto& observer : observer_list_) |
| 308 | observer.OnExtensionFrameRegistered(extension->id(), render_frame_host); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 309 | } |
| 310 | |
| 311 | void ProcessManager::UnregisterRenderFrameHost( |
| 312 | content::RenderFrameHost* render_frame_host) { |
jdoerrie | a1e1598b | 2018-10-10 09:10:37 | [diff] [blame] | 313 | auto frame = all_extension_frames_.find(render_frame_host); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 314 | |
| 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 | |
ericwilligers | d1e2815 | 2016-10-17 22:53:14 | [diff] [blame] | 321 | for (auto& observer : observer_list_) |
| 322 | observer.OnExtensionFrameUnregistered(extension_id, render_frame_host); |
[email protected] | 6350346 | 2012-10-30 22:14:31 | [diff] [blame] | 323 | } |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 324 | } |
| 325 | |
| 326 | scoped_refptr<content::SiteInstance> ProcessManager::GetSiteInstanceForURL( |
| 327 | const GURL& url) { |
dcheng | bccd6b8 | 2016-03-30 16:24:19 | [diff] [blame] | 328 | return site_instance_->GetRelatedSiteInstance(url); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 329 | } |
| 330 | |
| 331 | const 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 | |
| 338 | ProcessManager::FrameSet ProcessManager::GetRenderFrameHostsForExtension( |
| 339 | const std::string& extension_id) { |
| 340 | FrameSet result; |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 341 | for (const auto& key_value : all_extension_frames_) { |
rob | cdcc4b8 | 2015-12-06 12:39:45 | [diff] [blame] | 342 | if (GetExtensionID(key_value.first) == extension_id) |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 343 | result.insert(key_value.first); |
| 344 | } |
[email protected] | 6350346 | 2012-10-30 22:14:31 | [diff] [blame] | 345 | return result; |
| 346 | } |
| 347 | |
rob | cdcc4b8 | 2015-12-06 12:39:45 | [diff] [blame] | 348 | bool 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] | 08d469b2 | 2014-03-31 00:51:24 | [diff] [blame] | 354 | void ProcessManager::AddObserver(ProcessManagerObserver* observer) { |
| 355 | observer_list_.AddObserver(observer); |
| 356 | } |
| 357 | |
| 358 | void ProcessManager::RemoveObserver(ProcessManagerObserver* observer) { |
| 359 | observer_list_.RemoveObserver(observer); |
| 360 | } |
| 361 | |
[email protected] | 6ad9cdf7 | 2014-02-27 13:12:41 | [diff] [blame] | 362 | bool ProcessManager::CreateBackgroundHost(const Extension* extension, |
| 363 | const GURL& url) { |
Istiaque Ahmed | ccb44402 | 2018-06-19 02:11:12 | [diff] [blame] | 364 | DCHECK(!BackgroundInfo::IsServiceWorkerBased(extension)) |
| 365 | << "CreateBackgroundHostForExtensionLoad called for service worker based" |
| 366 | "background page"; |
[email protected] | 41619a9a | 2011-04-13 20:07:32 | [diff] [blame] | 367 | // Hosted apps are taken care of from BackgroundContentsService. Ignore them |
| 368 | // here. |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 369 | if (extension->is_hosted_app()) |
[email protected] | 6ad9cdf7 | 2014-02-27 13:12:41 | [diff] [blame] | 370 | return false; |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 371 | |
| 372 | // Don't create hosts if the embedder doesn't allow it. |
| 373 | ProcessManagerDelegate* delegate = |
| 374 | ExtensionsBrowserClient::Get()->GetProcessManagerDelegate(); |
achuith | d3da4f0 | 2017-03-23 20:05:29 | [diff] [blame] | 375 | if (delegate && |
| 376 | !delegate->IsExtensionBackgroundPageAllowed(browser_context_, *extension)) |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 377 | return false; |
[email protected] | 41619a9a | 2011-04-13 20:07:32 | [diff] [blame] | 378 | |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 379 | // Don't create multiple background hosts for an extension. |
[email protected] | 6ad9cdf7 | 2014-02-27 13:12:41 | [diff] [blame] | 380 | if (GetBackgroundHostForExtension(extension->id())) |
| 381 | return true; // TODO(kalman): return false here? It might break things... |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 382 | |
achuith | d3da4f0 | 2017-03-23 20:05:29 | [diff] [blame] | 383 | DVLOG(1) << "CreateBackgroundHost " << extension->id(); |
[email protected] | ab4eaf78 | 2009-06-10 00:11:24 | [diff] [blame] | 384 | ExtensionHost* host = |
rdevlin.cronin | 3d426152 | 2015-02-10 00:48:15 | [diff] [blame] | 385 | new ExtensionHost(extension, GetSiteInstanceForURL(url).get(), url, |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 386 | VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); |
[email protected] | 952a68e | 2011-11-17 00:36:10 | [diff] [blame] | 387 | host->CreateRenderViewSoon(); |
[email protected] | 94de8cb | 2013-11-07 06:29:21 | [diff] [blame] | 388 | OnBackgroundHostCreated(host); |
[email protected] | 6ad9cdf7 | 2014-02-27 13:12:41 | [diff] [blame] | 389 | return true; |
[email protected] | 481e1a4 | 2009-05-06 20:56:05 | [diff] [blame] | 390 | } |
| 391 | |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 392 | void 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(); |
achuith | d3da4f0 | 2017-03-23 20:05:29 | [diff] [blame] | 399 | if (delegate && |
| 400 | !delegate->AreBackgroundPagesAllowedForContext(browser_context_)) |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 401 | 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] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 427 | ExtensionHost* ProcessManager::GetBackgroundHostForExtension( |
[email protected] | 06024c6 | 2011-10-20 20:57:12 | [diff] [blame] | 428 | const std::string& extension_id) { |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 429 | for (ExtensionHost* host : background_hosts_) { |
[email protected] | 06024c6 | 2011-10-20 20:57:12 | [diff] [blame] | 430 | if (host->extension_id() == extension_id) |
[email protected] | 4814b51 | 2009-11-07 00:12:29 | [diff] [blame] | 431 | return host; |
| 432 | } |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 433 | return nullptr; |
[email protected] | 481e1a4 | 2009-05-06 20:56:05 | [diff] [blame] | 434 | } |
| 435 | |
rdevlin.cronin | b48a98e | 2015-05-01 00:00:28 | [diff] [blame] | 436 | ExtensionHost* 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 | |
kmarshall | 24b29b2 | 2015-04-29 01:41:47 | [diff] [blame] | 447 | bool ProcessManager::IsEventPageSuspended(const std::string& extension_id) { |
| 448 | return GetBackgroundHostForExtension(extension_id) == nullptr; |
| 449 | } |
| 450 | |
| 451 | bool ProcessManager::WakeEventPage(const std::string& extension_id, |
Istiaque Ahmed | 28edfd2 | 2018-08-30 23:40:47 | [diff] [blame] | 452 | base::OnceCallback<void(bool)> callback) { |
kmarshall | 24b29b2 | 2015-04-29 01:41:47 | [diff] [blame] | 453 | if (GetBackgroundHostForExtension(extension_id)) { |
Istiaque Ahmed | 28edfd2 | 2018-08-30 23:40:47 | [diff] [blame] | 454 | // The extension is already awake. |
kmarshall | 24b29b2 | 2015-04-29 01:41:47 | [diff] [blame] | 455 | return false; |
| 456 | } |
David Bertoni | 641e3ce0 | 2019-01-11 20:35:12 | [diff] [blame] | 457 | const LazyContextId context_id(browser_context_, extension_id); |
| 458 | context_id.GetTaskQueue()->AddPendingTask( |
| 459 | context_id, |
Istiaque Ahmed | 28edfd2 | 2018-08-30 23:40:47 | [diff] [blame] | 460 | base::BindOnce(&PropagateExtensionWakeResult, std::move(callback))); |
kmarshall | 24b29b2 | 2015-04-29 01:41:47 | [diff] [blame] | 461 | return true; |
| 462 | } |
| 463 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 464 | bool ProcessManager::IsBackgroundHostClosing(const std::string& extension_id) { |
[email protected] | 7042b68 | 2012-04-19 22:57:51 | [diff] [blame] | 465 | ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
| 466 | return (host && background_page_data_[extension_id].is_closing); |
| 467 | } |
| 468 | |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 469 | const Extension* ProcessManager::GetExtensionForRenderFrameHost( |
| 470 | content::RenderFrameHost* render_frame_host) { |
| 471 | return extension_registry_->enabled_extensions().GetByID( |
| 472 | GetExtensionID(render_frame_host)); |
| 473 | } |
| 474 | |
| 475 | const Extension* ProcessManager::GetExtensionForWebContents( |
Lucas Furukawa Gadani | e1c5dfda | 2018-11-29 17:57:41 | [diff] [blame] | 476 | content::WebContents* web_contents) { |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 477 | if (!web_contents->GetSiteInstance()) |
| 478 | return nullptr; |
Devlin Cronin | 7a282e3 | 2017-08-10 01:54:10 | [diff] [blame] | 479 | 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 Gadani | 5553a158 | 2019-01-08 18:55:57 | [diff] [blame] | 486 | content::NavigationController& controller = web_contents->GetController(); |
Devlin Cronin | 7a282e3 | 2017-08-10 01:54:10 | [diff] [blame] | 487 | 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.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 502 | } |
| 503 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 504 | int ProcessManager::GetLazyKeepaliveCount(const Extension* extension) { |
[email protected] | 9367eabc | 2013-03-01 01:29:29 | [diff] [blame] | 505 | if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
wez | 714dde1 | 2017-02-14 22:26:03 | [diff] [blame] | 506 | return -1; |
[email protected] | 720ad131 | 2012-02-27 23:07:36 | [diff] [blame] | 507 | |
[email protected] | 103f19f | 2012-04-02 19:30:12 | [diff] [blame] | 508 | return background_page_data_[extension->id()].lazy_keepalive_count; |
[email protected] | 720ad131 | 2012-02-27 23:07:36 | [diff] [blame] | 509 | } |
| 510 | |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 511 | void ProcessManager::IncrementLazyKeepaliveCount( |
| 512 | const Extension* extension, |
| 513 | Activity::Type activity_type, |
| 514 | const std::string& extra_data) { |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 515 | if (BackgroundInfo::HasLazyBackgroundPage(extension)) { |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 516 | BackgroundPageData& data = background_page_data_[extension->id()]; |
| 517 | if (++data.lazy_keepalive_count == 1) |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 518 | OnLazyBackgroundPageActive(extension->id()); |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 519 | data.activities.insert(std::make_pair(activity_type, extra_data)); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 520 | } |
[email protected] | 720ad131 | 2012-02-27 23:07:36 | [diff] [blame] | 521 | } |
| 522 | |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 523 | void ProcessManager::DecrementLazyKeepaliveCount( |
| 524 | const Extension* extension, |
| 525 | Activity::Type activity_type, |
| 526 | const std::string& extra_data) { |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 527 | if (BackgroundInfo::HasLazyBackgroundPage(extension)) |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 528 | DecrementLazyKeepaliveCount(extension->id(), activity_type, extra_data); |
| 529 | } |
| 530 | |
| 531 | ProcessManager::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] | 720ad131 | 2012-02-27 23:07:36 | [diff] [blame] | 537 | } |
[email protected] | 0d475e07 | 2012-07-26 02:30:42 | [diff] [blame] | 538 | |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 539 | void ProcessManager::OnShouldSuspendAck(const std::string& extension_id, |
avi | c9cec10 | 2015-12-23 00:39:26 | [diff] [blame] | 540 | uint64_t sequence_id) { |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 541 | 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 | |
| 548 | void ProcessManager::OnSuspendAck(const std::string& extension_id) { |
| 549 | background_page_data_[extension_id].is_closing = true; |
avi | c9cec10 | 2015-12-23 00:39:26 | [diff] [blame] | 550 | uint64_t sequence_id = background_page_data_[extension_id].close_sequence_id; |
fdoray | e6609ac8 | 2016-06-06 19:21:40 | [diff] [blame] | 551 | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 552 | FROM_HERE, |
kylechar | 0686a523 | 2019-02-19 14:10:29 | [diff] [blame] | 553 | base::BindOnce(&ProcessManager::CloseLazyBackgroundPageNow, |
| 554 | weak_ptr_factory_.GetWeakPtr(), extension_id, sequence_id), |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 555 | base::TimeDelta::FromMilliseconds(g_event_page_suspending_time_msec)); |
| 556 | } |
| 557 | |
| 558 | void ProcessManager::OnNetworkRequestStarted( |
| 559 | content::RenderFrameHost* render_frame_host, |
avi | c9cec10 | 2015-12-23 00:39:26 | [diff] [blame] | 560 | uint64_t request_id) { |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 561 | ExtensionHost* host = GetBackgroundHostForExtension( |
| 562 | GetExtensionID(render_frame_host)); |
nasko | d13fd29 | 2016-06-07 20:33:33 | [diff] [blame] | 563 | if (!host || !IsFrameInExtensionHost(host, render_frame_host)) |
| 564 | return; |
| 565 | |
| 566 | auto result = |
| 567 | pending_network_requests_.insert(std::make_pair(request_id, host)); |
rockot | e570329 | 2015-09-28 23:23:09 | [diff] [blame] | 568 | DCHECK(result.second) << "Duplicate network request IDs."; |
nasko | d13fd29 | 2016-06-07 20:33:33 | [diff] [blame] | 569 | |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 570 | IncrementLazyKeepaliveCount(host->extension(), Activity::NETWORK, |
| 571 | base::NumberToString(request_id)); |
nasko | d13fd29 | 2016-06-07 20:33:33 | [diff] [blame] | 572 | host->OnNetworkRequestStarted(request_id); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 573 | } |
| 574 | |
| 575 | void ProcessManager::OnNetworkRequestDone( |
| 576 | content::RenderFrameHost* render_frame_host, |
avi | c9cec10 | 2015-12-23 00:39:26 | [diff] [blame] | 577 | uint64_t request_id) { |
nasko | d13fd29 | 2016-06-07 20:33:33 | [diff] [blame] | 578 | 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 Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 594 | DecrementLazyKeepaliveCount(host->extension(), Activity::NETWORK, |
| 595 | base::NumberToString(request_id)); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 596 | } |
| 597 | |
| 598 | void 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 Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 609 | IncrementLazyKeepaliveCount(extension, Activity::PROCESS_MANAGER, |
| 610 | Activity::kCancelSuspend); |
| 611 | DecrementLazyKeepaliveCount(extension, Activity::PROCESS_MANAGER, |
| 612 | Activity::kCancelSuspend); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 613 | } |
| 614 | } |
| 615 | |
| 616 | void ProcessManager::CloseBackgroundHosts() { |
avi | be95fa11f | 2016-11-14 23:40:17 | [diff] [blame] | 617 | // 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.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 630 | } |
| 631 | |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 632 | // static |
| 633 | void ProcessManager::SetEventPageIdleTimeForTesting(unsigned idle_time_msec) { |
wez | d6be280 | 2017-03-27 01:49:28 | [diff] [blame] | 634 | CHECK_GT(idle_time_msec, 0u); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 635 | g_event_page_idle_time_msec = idle_time_msec; |
| 636 | } |
| 637 | |
| 638 | // static |
| 639 | void ProcessManager::SetEventPageSuspendingTimeForTesting( |
| 640 | unsigned suspending_time_msec) { |
| 641 | g_event_page_suspending_time_msec = suspending_time_msec; |
| 642 | } |
| 643 | |
| 644 | //////////////////////////////////////////////////////////////////////////////// |
| 645 | // Private |
| 646 | |
| 647 | void 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 Bhatia | ee1e6a5 | 2017-11-09 21:32:51 | [diff] [blame] | 662 | // 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.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 665 | 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 | |
| 681 | void 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 | |
limasdf | 0deef204 | 2017-05-03 19:17:17 | [diff] [blame] | 689 | void ProcessManager::OnExtensionUnloaded(BrowserContext* browser_context, |
| 690 | const Extension* extension, |
| 691 | UnloadedExtensionReason reason) { |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 692 | ExtensionHost* host = GetBackgroundHostForExtension(extension->id()); |
| 693 | if (host != nullptr) |
| 694 | CloseBackgroundHost(host); |
| 695 | UnregisterExtension(extension->id()); |
| 696 | } |
| 697 | |
| 698 | void 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()); |
ericwilligers | d1e2815 | 2016-10-17 22:53:14 | [diff] [blame] | 703 | for (auto& observer : observer_list_) |
| 704 | observer.OnBackgroundHostStartup(extension.get()); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 705 | } |
| 706 | } |
| 707 | |
| 708 | void ProcessManager::OnBackgroundHostCreated(ExtensionHost* host) { |
| 709 | DCHECK_EQ(browser_context_, host->browser_context()); |
| 710 | background_hosts_.insert(host); |
| 711 | |
| 712 | if (BackgroundInfo::HasLazyBackgroundPage(host->extension())) { |
lazyboy | f33109d | 2016-08-31 00:37:08 | [diff] [blame] | 713 | std::unique_ptr<base::ElapsedTimer> since_suspended = std::move( |
| 714 | background_page_data_[host->extension()->id()].since_suspended); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 715 | if (since_suspended.get()) { |
| 716 | UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime", |
| 717 | since_suspended->Elapsed()); |
| 718 | } |
| 719 | } |
ericwilligers | d1e2815 | 2016-10-17 22:53:14 | [diff] [blame] | 720 | for (auto& observer : observer_list_) |
| 721 | observer.OnBackgroundHostCreated(host); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 722 | } |
| 723 | |
| 724 | void 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 | |
ericwilligers | d1e2815 | 2016-10-17 22:53:14 | [diff] [blame] | 731 | for (auto& observer : observer_list_) |
| 732 | observer.OnBackgroundHostClose(extension_id); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 733 | } |
| 734 | |
| 735 | void ProcessManager::AcquireLazyKeepaliveCountForFrame( |
| 736 | content::RenderFrameHost* render_frame_host) { |
jdoerrie | a1e1598b | 2018-10-10 09:10:37 | [diff] [blame] | 737 | auto it = all_extension_frames_.find(render_frame_host); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 738 | 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 Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 746 | IncrementLazyKeepaliveCount(extension, Activity::PROCESS_MANAGER, |
| 747 | Activity::kRenderFrame); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 748 | data.has_keepalive = true; |
| 749 | } |
| 750 | } |
| 751 | } |
| 752 | |
| 753 | void ProcessManager::ReleaseLazyKeepaliveCountForFrame( |
| 754 | content::RenderFrameHost* render_frame_host) { |
jdoerrie | a1e1598b | 2018-10-10 09:10:37 | [diff] [blame] | 755 | auto iter = all_extension_frames_.find(render_frame_host); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 756 | 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 Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 764 | DecrementLazyKeepaliveCount(extension, Activity::PROCESS_MANAGER, |
| 765 | Activity::kRenderFrame); |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 766 | data.has_keepalive = false; |
| 767 | } |
| 768 | } |
| 769 | } |
| 770 | |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 771 | std::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 Falkenhagen | d55b928 | 2019-09-10 23:53:35 | [diff] [blame] | 790 | 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 Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 800 | return request_uuid; |
| 801 | } |
| 802 | |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 803 | void ProcessManager::DecrementLazyKeepaliveCount( |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 804 | 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.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 810 | !extension_registry_->enabled_extensions().Contains(extension_id)); |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 811 | --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.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 817 | |
| 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 Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 822 | 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, |
kylechar | 0686a523 | 2019-02-19 14:10:29 | [diff] [blame] | 829 | base::BindOnce(&ProcessManager::OnLazyBackgroundPageIdle, |
| 830 | weak_ptr_factory_.GetWeakPtr(), extension_id, |
| 831 | last_background_close_sequence_id_), |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 832 | base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec)); |
| 833 | } |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 834 | } |
| 835 | } |
| 836 | |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 837 | void 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 Falkenhagen | d55b928 | 2019-09-10 23:53:35 | [diff] [blame] | 856 | 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 Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 866 | } |
| 867 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 868 | void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id, |
avi | c9cec10 | 2015-12-23 00:39:26 | [diff] [blame] | 869 | uint64_t sequence_id) { |
[email protected] | 06024c6 | 2011-10-20 20:57:12 | [diff] [blame] | 870 | ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
[email protected] | 99c49b5 | 2012-05-02 01:50:20 | [diff] [blame] | 871 | if (host && !background_page_data_[extension_id].is_closing && |
| 872 | sequence_id == background_page_data_[extension_id].close_sequence_id) { |
[email protected] | 103f19f | 2012-04-02 19:30:12 | [diff] [blame] | 873 | // 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] | 99c49b5 | 2012-05-02 01:50:20 | [diff] [blame] | 876 | // 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] | 584e657 | 2013-02-16 07:02:33 | [diff] [blame] | 878 | // ShouldSuspendAck, so we don't send the ping. |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 879 | host->render_process_host()->Send(new ExtensionMsg_ShouldSuspend( |
[email protected] | 99c49b5 | 2012-05-02 01:50:20 | [diff] [blame] | 880 | extension_id, sequence_id)); |
[email protected] | 103f19f | 2012-04-02 19:30:12 | [diff] [blame] | 881 | } |
[email protected] | 720ad131 | 2012-02-27 23:07:36 | [diff] [blame] | 882 | } |
| 883 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 884 | void ProcessManager::OnLazyBackgroundPageActive( |
[email protected] | 720ad131 | 2012-02-27 23:07:36 | [diff] [blame] | 885 | const std::string& extension_id) { |
[email protected] | 77a538f | 2014-07-14 22:25:37 | [diff] [blame] | 886 | if (!background_page_data_[extension_id].is_closing) { |
[email protected] | 103f19f | 2012-04-02 19:30:12 | [diff] [blame] | 887 | // Cancel the current close sequence by changing the close_sequence_id, |
[email protected] | 584e657 | 2013-02-16 07:02:33 | [diff] [blame] | 888 | // which causes us to ignore the next ShouldSuspendAck. |
[email protected] | 77a538f | 2014-07-14 22:25:37 | [diff] [blame] | 889 | background_page_data_[extension_id].close_sequence_id = |
| 890 | ++last_background_close_sequence_id_; |
[email protected] | 103f19f | 2012-04-02 19:30:12 | [diff] [blame] | 891 | } |
[email protected] | 720ad131 | 2012-02-27 23:07:36 | [diff] [blame] | 892 | } |
| 893 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 894 | void ProcessManager::CloseLazyBackgroundPageNow(const std::string& extension_id, |
avi | c9cec10 | 2015-12-23 00:39:26 | [diff] [blame] | 895 | uint64_t sequence_id) { |
[email protected] | 99c49b5 | 2012-05-02 01:50:20 | [diff] [blame] | 896 | ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
[email protected] | 0d475e07 | 2012-07-26 02:30:42 | [diff] [blame] | 897 | if (host && |
| 898 | sequence_id == background_page_data_[extension_id].close_sequence_id) { |
kmarshall | d3e8c08 | 2015-07-25 00:39:58 | [diff] [blame] | 899 | // 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 | |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 906 | // Close remaining views. |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 907 | 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); |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 913 | } |
| 914 | } |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 915 | for (content::RenderFrameHost* frame : frames_to_close) { |
nasko | c0fceff | 2015-04-30 15:53:52 | [diff] [blame] | 916 | content::WebContents::FromRenderFrameHost(frame)->ClosePage(); |
| 917 | // WebContents::ClosePage() may result in calling |
Devlin Cronin | d2dae26 | 2017-10-16 21:04:24 | [diff] [blame] | 918 | // UnregisterRenderFrameHost() asynchronously and may cause race |
| 919 | // conditions when the background page is reloaded. |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 920 | // To avoid this, unregister the view now. |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 921 | UnregisterRenderFrameHost(frame); |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 922 | } |
| 923 | |
[email protected] | 0d475e07 | 2012-07-26 02:30:42 | [diff] [blame] | 924 | ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
| 925 | if (host) |
| 926 | CloseBackgroundHost(host); |
| 927 | } |
[email protected] | 06024c6 | 2011-10-20 20:57:12 | [diff] [blame] | 928 | } |
| 929 | |
dgozman | 47679eb1 | 2016-10-17 17:30:18 | [diff] [blame] | 930 | const Extension* ProcessManager::GetExtensionForAgentHost( |
| 931 | content::DevToolsAgentHost* agent_host) { |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 932 | content::WebContents* web_contents = agent_host->GetWebContents(); |
[email protected] | a23f62e | 2013-04-26 13:13:02 | [diff] [blame] | 933 | // Ignore unrelated notifications. |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 934 | if (!web_contents || web_contents->GetBrowserContext() != browser_context_) |
dgozman | 47679eb1 | 2016-10-17 17:30:18 | [diff] [blame] | 935 | return nullptr; |
[email protected] | b3f957e6 | 2014-08-08 10:09:02 | [diff] [blame] | 936 | if (GetViewType(web_contents) != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) |
dgozman | 47679eb1 | 2016-10-17 17:30:18 | [diff] [blame] | 937 | return nullptr; |
| 938 | return GetExtensionForWebContents(web_contents); |
| 939 | } |
| 940 | |
| 941 | void ProcessManager::DevToolsAgentHostAttached( |
| 942 | content::DevToolsAgentHost* agent_host) { |
| 943 | if (const Extension* extension = GetExtensionForAgentHost(agent_host)) { |
[email protected] | a23f62e | 2013-04-26 13:13:02 | [diff] [blame] | 944 | // Keep the lazy background page alive while it's being inspected. |
| 945 | CancelSuspend(extension); |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 946 | IncrementLazyKeepaliveCount(extension, Activity::DEV_TOOLS, std::string()); |
[email protected] | a23f62e | 2013-04-26 13:13:02 | [diff] [blame] | 947 | } |
| 948 | } |
| 949 | |
dgozman | 47679eb1 | 2016-10-17 17:30:18 | [diff] [blame] | 950 | void ProcessManager::DevToolsAgentHostDetached( |
| 951 | content::DevToolsAgentHost* agent_host) { |
| 952 | if (const Extension* extension = GetExtensionForAgentHost(agent_host)) |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 953 | DecrementLazyKeepaliveCount(extension, Activity::DEV_TOOLS, ""); |
dgozman | 47679eb1 | 2016-10-17 17:30:18 | [diff] [blame] | 954 | } |
| 955 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 956 | void ProcessManager::UnregisterExtension(const std::string& extension_id) { |
[email protected] | 5b3ee85 | 2013-09-26 06:33:10 | [diff] [blame] | 957 | // The lazy_keepalive_count may be greater than zero at this point because |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 958 | // RenderFrameHosts are still alive. During extension reloading, they will |
[email protected] | 5b3ee85 | 2013-09-26 06:33:10 | [diff] [blame] | 959 | // 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.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 961 | // data for the unloaded extension, unregister the RenderFrameHosts too. |
jdoerrie | a1e1598b | 2018-10-10 09:10:37 | [diff] [blame] | 962 | for (auto it = all_extension_frames_.begin(); |
| 963 | it != all_extension_frames_.end();) { |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 964 | content::RenderFrameHost* host = it->first; |
| 965 | if (GetExtensionID(host) == extension_id) { |
| 966 | all_extension_frames_.erase(it++); |
ericwilligers | d1e2815 | 2016-10-17 22:53:14 | [diff] [blame] | 967 | for (auto& observer : observer_list_) |
| 968 | observer.OnExtensionFrameUnregistered(extension_id, host); |
[email protected] | 5b3ee85 | 2013-09-26 06:33:10 | [diff] [blame] | 969 | } else { |
| 970 | ++it; |
| 971 | } |
| 972 | } |
| 973 | |
| 974 | background_page_data_.erase(extension_id); |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 975 | |
| 976 | all_extension_workers_.RemoveAllForExtension(extension_id); |
| 977 | } |
| 978 | |
| 979 | void ProcessManager::RegisterServiceWorker(const WorkerId& worker_id) { |
| 980 | all_extension_workers_.Add(worker_id); |
Istiaque Ahmed | d4b67ee | 2019-03-02 10:53:20 | [diff] [blame] | 981 | |
| 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 | |
| 998 | void 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 Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 1020 | } |
| 1021 | |
| 1022 | void ProcessManager::UnregisterServiceWorker(const WorkerId& worker_id) { |
Istiaque Ahmed | d4b67ee | 2019-03-02 10:53:20 | [diff] [blame] | 1023 | // TODO(lazyboy): DCHECK that |worker_id| exists in |all_extension_workers_|. |
Istiaque Ahmed | b744ecf | 2019-02-06 00:23:32 | [diff] [blame] | 1024 | all_extension_workers_.Remove(worker_id); |
| 1025 | } |
| 1026 | |
| 1027 | bool ProcessManager::HasServiceWorker(const WorkerId& worker_id) const { |
| 1028 | return all_extension_workers_.Contains(worker_id); |
| 1029 | } |
| 1030 | |
| 1031 | std::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] | 5b3ee85 | 2013-09-26 06:33:10 | [diff] [blame] | 1036 | } |
| 1037 | |
Istiaque Ahmed | d4b67ee | 2019-03-02 10:53:20 | [diff] [blame] | 1038 | std::vector<WorkerId> ProcessManager::GetAllWorkersIdsForTesting() { |
| 1039 | return all_extension_workers_.GetAllForTesting(); |
| 1040 | } |
| 1041 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 1042 | void ProcessManager::ClearBackgroundPageData(const std::string& extension_id) { |
[email protected] | caffe70 | 2012-05-03 05:30:17 | [diff] [blame] | 1043 | background_page_data_.erase(extension_id); |
| 1044 | |
Devlin Cronin | d2dae26 | 2017-10-16 21:04:24 | [diff] [blame] | 1045 | // Re-register all RenderFrames for this extension. We do this to restore |
[email protected] | caffe70 | 2012-05-03 05:30:17 | [diff] [blame] | 1046 | // the lazy_keepalive_count (if any) to properly reflect the number of open |
| 1047 | // views. |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 1048 | for (const auto& key_value : all_extension_frames_) { |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 1049 | // Do not increment the count when |has_keepalive| is false |
| 1050 | // (i.e. ReleaseLazyKeepaliveCountForView() was called). |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 1051 | if (GetExtensionID(key_value.first) == extension_id && |
| 1052 | key_value.second.has_keepalive) { |
| 1053 | const Extension* extension = |
| 1054 | GetExtensionForRenderFrameHost(key_value.first); |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 1055 | if (extension) |
David Bertoni | 3e1e9fa | 2018-08-29 20:39:30 | [diff] [blame] | 1056 | IncrementLazyKeepaliveCount(extension, Activity::PROCESS_MANAGER, |
| 1057 | Activity::kRenderFrame); |
hashimoto | 5bca227 | 2014-11-04 07:35:18 | [diff] [blame] | 1058 | } |
[email protected] | caffe70 | 2012-05-03 05:30:17 | [diff] [blame] | 1059 | } |
| 1060 | } |
| 1061 | |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 1062 | // |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 1063 | // IncognitoProcessManager |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 1064 | // |
| 1065 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 1066 | IncognitoProcessManager::IncognitoProcessManager( |
[email protected] | 7f47421 | 2013-11-05 04:26:16 | [diff] [blame] | 1067 | BrowserContext* incognito_context, |
[email protected] | b9f6ba3 | 2014-03-10 18:34:08 | [diff] [blame] | 1068 | BrowserContext* original_context, |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 1069 | ExtensionRegistry* extension_registry) |
reillyg | 0ea3fa90 | 2014-10-28 15:30:23 | [diff] [blame] | 1070 | : ProcessManager(incognito_context, original_context, extension_registry) { |
[email protected] | 7f47421 | 2013-11-05 04:26:16 | [diff] [blame] | 1071 | DCHECK(incognito_context->IsOffTheRecord()); |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 1072 | } |
| 1073 | |
[email protected] | 6ad9cdf7 | 2014-02-27 13:12:41 | [diff] [blame] | 1074 | bool IncognitoProcessManager::CreateBackgroundHost(const Extension* extension, |
| 1075 | const GURL& url) { |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 1076 | if (IncognitoInfo::IsSplitMode(extension)) { |
[email protected] | 6a3d8ce4 | 2014-02-07 00:42:37 | [diff] [blame] | 1077 | if (ExtensionsBrowserClient::Get()->IsExtensionIncognitoEnabled( |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 1078 | extension->id(), browser_context())) |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 1079 | return ProcessManager::CreateBackgroundHost(extension, url); |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 1080 | } 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] | 6ad9cdf7 | 2014-02-27 13:12:41 | [diff] [blame] | 1084 | return false; |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 1085 | } |
| 1086 | |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 1087 | scoped_refptr<content::SiteInstance> |
| 1088 | IncognitoProcessManager::GetSiteInstanceForURL(const GURL& url) { |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 1089 | const Extension* extension = |
| 1090 | extension_registry_->enabled_extensions().GetExtensionOrAppByURL(url); |
reillyg | 0ea3fa90 | 2014-10-28 15:30:23 | [diff] [blame] | 1091 | if (extension && !IncognitoInfo::IsSplitMode(extension)) { |
| 1092 | BrowserContext* original_context = |
rdevlin.cronin | 6ae04a01 | 2015-04-03 20:19:40 | [diff] [blame] | 1093 | ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context()); |
reillyg | 0ea3fa90 | 2014-10-28 15:30:23 | [diff] [blame] | 1094 | return ProcessManager::Get(original_context)->GetSiteInstanceForURL(url); |
| 1095 | } |
[email protected] | 6b54fda | 2014-07-22 02:13:47 | [diff] [blame] | 1096 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 1097 | return ProcessManager::GetSiteInstanceForURL(url); |
[email protected] | bc535ee5 | 2010-08-31 18:40:32 | [diff] [blame] | 1098 | } |
| 1099 | |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 1100 | } // namespace extensions |