Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [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 | |
Sreeja Kamishetty | c227f7a | 2022-07-08 22:33:15 | [diff] [blame] | 5 | #include "content/browser/preloading/prerender/prerender_host_registry.h" |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [diff] [blame] | 6 | |
| 7 | #include "base/check.h" |
Yoshiki Tanioka | 87aab3f | 2022-09-13 06:25:37 | [diff] [blame] | 8 | #include "base/check_op.h" |
Lei Zhang | de19767 | 2021-04-29 08:11:24 | [diff] [blame] | 9 | #include "base/containers/contains.h" |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [diff] [blame] | 10 | #include "base/feature_list.h" |
Yoshiki Tanioka | 80b78fb | 2022-10-27 23:40:54 | [diff] [blame] | 11 | #include "base/functional/bind.h" |
Avi Drissman | adac2199 | 2023-01-11 23:46:39 | [diff] [blame] | 12 | #include "base/functional/callback_helpers.h" |
Hiroki Nakagawa | 34e5d67 | 2023-04-21 05:00:09 | [diff] [blame] | 13 | #include "base/memory/memory_pressure_monitor.h" |
Matt Falkenhagen | 9373d4e | 2021-08-11 16:50:22 | [diff] [blame] | 14 | #include "base/metrics/field_trial_params.h" |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 15 | #include "base/notreached.h" |
David Sanders | d4bf5eb | 2022-03-17 07:12:05 | [diff] [blame] | 16 | #include "base/observer_list.h" |
Matt Falkenhagen | f884d0f | 2021-02-18 06:31:35 | [diff] [blame] | 17 | #include "base/system/sys_info.h" |
Sean Maher | 52fa5a7 | 2022-11-14 15:53:25 | [diff] [blame] | 18 | #include "base/task/sequenced_task_runner.h" |
Sean Maher | e672a66 | 2023-01-09 21:42:28 | [diff] [blame] | 19 | #include "base/task/single_thread_task_runner.h" |
Matt Falkenhagen | 9373d4e | 2021-08-11 16:50:22 | [diff] [blame] | 20 | #include "build/build_config.h" |
Andrey Kosyakov | 6e82c3b | 2022-09-26 22:43:46 | [diff] [blame] | 21 | #include "content/browser/devtools/devtools_instrumentation.h" |
Robert Lin | 56cb9c4 | 2022-11-22 07:57:30 | [diff] [blame] | 22 | #include "content/browser/devtools/render_frame_devtools_agent_host.h" |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 23 | #include "content/browser/preloading/preloading_trigger_type_impl.h" |
keno | d930e4803 | 2023-05-18 11:38:40 | [diff] [blame] | 24 | #include "content/browser/preloading/prerender/devtools_prerender_attempt.h" |
Taiyo Mizuhashi | 9211979 | 2023-09-13 07:18:03 | [diff] [blame] | 25 | #include "content/browser/preloading/prerender/prerender_features.h" |
Yoshiki Tanioka | 49b4cfb | 2022-10-20 09:25:31 | [diff] [blame] | 26 | #include "content/browser/preloading/prerender/prerender_final_status.h" |
Sreeja Kamishetty | c227f7a | 2022-07-08 22:33:15 | [diff] [blame] | 27 | #include "content/browser/preloading/prerender/prerender_metrics.h" |
Robert Lin | 20d947ed | 2022-08-25 06:01:28 | [diff] [blame] | 28 | #include "content/browser/preloading/prerender/prerender_navigation_utils.h" |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 29 | #include "content/browser/preloading/prerender/prerender_new_tab_handle.h" |
Hiroki Nakagawa | eec217f | 2020-12-09 08:41:13 | [diff] [blame] | 30 | #include "content/browser/renderer_host/frame_tree_node.h" |
Harkiran Bolaria | ba823e4 | 2021-05-21 18:30:36 | [diff] [blame] | 31 | #include "content/browser/renderer_host/navigation_request.h" |
Hiroki Nakagawa | eec217f | 2020-12-09 08:41:13 | [diff] [blame] | 32 | #include "content/browser/renderer_host/render_frame_host_impl.h" |
Lei Zhang | 5686e52 | 2023-03-02 17:33:10 | [diff] [blame] | 33 | #include "content/browser/web_contents/web_contents_impl.h" |
| 34 | #include "content/common/frame.mojom.h" |
Domenic Denicola | bb5d843c | 2023-07-18 01:47:33 | [diff] [blame] | 35 | #include "content/public/browser/preloading.h" |
Lei Zhang | 5686e52 | 2023-03-02 17:33:10 | [diff] [blame] | 36 | #include "content/public/browser/preloading_data.h" |
Yoshiki Tanioka | 87aab3f | 2022-09-13 06:25:37 | [diff] [blame] | 37 | #include "content/public/browser/render_frame_host.h" |
Yoshiki Tanioka | b6a6d72 | 2022-10-20 07:58:50 | [diff] [blame] | 38 | #include "content/public/browser/visibility.h" |
Robert Lin | 39aaced | 2021-09-22 10:23:35 | [diff] [blame] | 39 | #include "content/public/browser/web_contents.h" |
Sreeja Kamishetty | c94a0d2 | 2022-07-06 20:43:06 | [diff] [blame] | 40 | #include "content/public/browser/web_contents_delegate.h" |
Kevin McNee | 097680d | 2023-04-05 22:14:51 | [diff] [blame] | 41 | #include "net/base/load_flags.h" |
| 42 | #include "services/network/public/cpp/simple_url_loader.h" |
Lei Zhang | 5686e52 | 2023-03-02 17:33:10 | [diff] [blame] | 43 | #include "services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h" |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 44 | #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h" |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [diff] [blame] | 45 | #include "third_party/blink/public/common/features.h" |
Lei Zhang | 5686e52 | 2023-03-02 17:33:10 | [diff] [blame] | 46 | #include "url/gurl.h" |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [diff] [blame] | 47 | |
| 48 | namespace content { |
| 49 | |
Matt Falkenhagen | 9373d4e | 2021-08-11 16:50:22 | [diff] [blame] | 50 | namespace { |
| 51 | |
Hiroki Nakagawa | 98af8c4 | 2023-03-14 05:36:38 | [diff] [blame] | 52 | bool IsBackground(Visibility visibility) { |
| 53 | // PrerenderHostRegistry treats HIDDEN and OCCLUDED as background. |
| 54 | switch (visibility) { |
| 55 | case Visibility::HIDDEN: |
| 56 | case Visibility::OCCLUDED: |
| 57 | return true; |
| 58 | case Visibility::VISIBLE: |
| 59 | return false; |
| 60 | } |
| 61 | } |
| 62 | |
Matt Falkenhagen | 9373d4e | 2021-08-11 16:50:22 | [diff] [blame] | 63 | bool DeviceHasEnoughMemoryForPrerender() { |
| 64 | // This method disallows prerendering on low-end devices if the |
| 65 | // kPrerender2MemoryControls feature is enabled. |
| 66 | if (!base::FeatureList::IsEnabled(blink::features::kPrerender2MemoryControls)) |
| 67 | return true; |
| 68 | |
Max "👨200d💻" Coplan | 0bdabf3f | 2023-09-08 13:04:53 | [diff] [blame] | 69 | // On Android, Prerender2 is only enabled for 2GB+ high memory devices. The |
| 70 | // default threshold value is set to 1700 MB to account for all 2GB devices |
| 71 | // which report lower RAM due to carveouts. |
| 72 | // Previously used the same default threshold as the back/forward cache. See |
| 73 | // comments in DeviceHasEnoughMemoryForBackForwardCache(). |
| 74 | // TODO(https://crbug.com/1470820): experiment with 1200 MB threshold like |
| 75 | // back/forward cache. |
Matt Falkenhagen | 9373d4e | 2021-08-11 16:50:22 | [diff] [blame] | 76 | static constexpr int kDefaultMemoryThresholdMb = |
Xiaohan Wang | 1e4ebde | 2022-01-15 17:29:12 | [diff] [blame] | 77 | #if BUILDFLAG(IS_ANDROID) |
Matt Falkenhagen | 9373d4e | 2021-08-11 16:50:22 | [diff] [blame] | 78 | 1700; |
| 79 | #else |
| 80 | 0; |
| 81 | #endif |
| 82 | |
| 83 | // The default is overridable by field trial param. |
| 84 | int memory_threshold_mb = base::GetFieldTrialParamByFeatureAsInt( |
| 85 | blink::features::kPrerender2MemoryControls, |
| 86 | blink::features::kPrerender2MemoryThresholdParamName, |
| 87 | kDefaultMemoryThresholdMb); |
| 88 | |
| 89 | return base::SysInfo::AmountOfPhysicalMemoryMB() > memory_threshold_mb; |
| 90 | } |
| 91 | |
Hiroki Nakagawa | 34e5d67 | 2023-04-21 05:00:09 | [diff] [blame] | 92 | base::MemoryPressureListener::MemoryPressureLevel |
| 93 | GetCurrentMemoryPressureLevel() { |
| 94 | // Ignore the memory pressure event if the memory control is disabled. |
| 95 | if (!base::FeatureList::IsEnabled( |
| 96 | blink::features::kPrerender2MemoryControls)) { |
| 97 | return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; |
| 98 | } |
| 99 | |
| 100 | auto* monitor = base::MemoryPressureMonitor::Get(); |
| 101 | if (!monitor) { |
| 102 | return base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; |
| 103 | } |
| 104 | return monitor->GetCurrentPressureLevel(); |
| 105 | } |
| 106 | |
Kevin McNee | 097680d | 2023-04-05 22:14:51 | [diff] [blame] | 107 | // Create a resource request for `back_url` that only checks whether the |
| 108 | // resource is in the HTTP cache. |
| 109 | std::unique_ptr<network::SimpleURLLoader> CreateHttpCacheQueryingResourceLoad( |
| 110 | const GURL& back_url) { |
| 111 | url::Origin origin = url::Origin::Create(back_url); |
| 112 | net::IsolationInfo isolation_info = net::IsolationInfo::Create( |
| 113 | net::IsolationInfo::RequestType::kMainFrame, origin, origin, |
| 114 | net::SiteForCookies::FromOrigin(origin)); |
| 115 | network::ResourceRequest::TrustedParams trusted_params; |
| 116 | trusted_params.isolation_info = isolation_info; |
| 117 | |
| 118 | std::unique_ptr<network::ResourceRequest> request = |
| 119 | std::make_unique<network::ResourceRequest>(); |
| 120 | request->url = back_url; |
| 121 | request->load_flags = |
| 122 | net::LOAD_ONLY_FROM_CACHE | net::LOAD_SKIP_CACHE_VALIDATION; |
| 123 | request->trusted_params = trusted_params; |
| 124 | request->site_for_cookies = trusted_params.isolation_info.site_for_cookies(); |
| 125 | request->credentials_mode = network::mojom::CredentialsMode::kOmit; |
| 126 | request->skip_service_worker = true; |
| 127 | request->do_not_prompt_for_login = true; |
| 128 | |
| 129 | CHECK(!request->SendsCookies()); |
| 130 | CHECK(!request->SavesCookies()); |
| 131 | constexpr net::NetworkTrafficAnnotationTag traffic_annotation = |
| 132 | net::DefineNetworkTrafficAnnotation("back_navigation_cache_query", |
| 133 | R"( |
| 134 | semantics { |
| 135 | sender: "Prerender" |
| 136 | description: |
| 137 | "This is not actually a network request. It is used internally " |
| 138 | "by the browser to determine if the HTTP cache would be used if " |
| 139 | "the user were to navigate back in session history. It only " |
| 140 | "checks the cache and does not hit the network." |
| 141 | trigger: |
| 142 | "When the user performs an action that would suggest that they " |
| 143 | "intend to navigate back soon. Examples include hovering the " |
| 144 | "mouse over the back button and the start of a gestural back " |
| 145 | "navigation." |
| 146 | user_data { |
| 147 | type: NONE |
| 148 | } |
| 149 | data: "None. The request doesn't hit the network." |
| 150 | destination: LOCAL |
| 151 | internal { |
| 152 | contacts { |
| 153 | email: "chrome-brapp-loading@chromium.org" |
| 154 | } |
| 155 | } |
| 156 | last_reviewed: "2023-03-24" |
| 157 | } |
| 158 | policy { |
| 159 | cookies_allowed: NO |
| 160 | setting: |
| 161 | "This is not controlled by a setting." |
| 162 | policy_exception_justification: "This is not a network request." |
| 163 | })"); |
| 164 | |
| 165 | return network::SimpleURLLoader::Create(std::move(request), |
| 166 | traffic_annotation); |
| 167 | } |
| 168 | |
| 169 | // Returns true if the given navigation is meant to be predicted by a predictor |
| 170 | // related to session history (e.g. hovering over the back button could have |
| 171 | // predicted the navigation). |
| 172 | bool IsNavigationInSessionHistoryPredictorDomain(NavigationHandle* handle) { |
| 173 | CHECK(handle->IsInPrimaryMainFrame()); |
| 174 | CHECK(!handle->IsSameDocument()); |
| 175 | |
| 176 | if (handle->IsRendererInitiated()) { |
| 177 | return false; |
| 178 | } |
| 179 | |
| 180 | // Note that currently the only predictors are for back navigations of a |
| 181 | // single step, however we still include all session history navigations in |
| 182 | // the domain. The preloading of back navigations could generalize to session |
| 183 | // history navigations of other offsets, but we haven't explored this due to |
| 184 | // the higher usage of the back button compared to the forward button or |
| 185 | // history menu. |
| 186 | if (!(handle->GetPageTransition() & ui::PAGE_TRANSITION_FORWARD_BACK)) { |
| 187 | return false; |
| 188 | } |
| 189 | |
| 190 | if (handle->IsPost()) { |
| 191 | return false; |
| 192 | } |
| 193 | |
| 194 | if (handle->IsServedFromBackForwardCache()) { |
| 195 | return false; |
| 196 | } |
| 197 | |
| 198 | if (!handle->GetURL().SchemeIsHTTPOrHTTPS()) { |
| 199 | return false; |
| 200 | } |
| 201 | |
| 202 | // Note that even though the current predictors do not handle session history |
| 203 | // navigations that are same-site or which don't use the HTTP cache, they are |
| 204 | // still included in the domain. |
| 205 | return true; |
| 206 | } |
| 207 | |
Hiroki Nakagawa | 3c25228 | 2023-04-18 10:31:35 | [diff] [blame] | 208 | bool IsDevToolsOpen(WebContents& web_contents) { |
| 209 | return DevToolsAgentHost::HasFor(&web_contents); |
| 210 | } |
| 211 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 212 | PreloadingEligibility ToEligibility(PrerenderFinalStatus status) { |
| 213 | switch (status) { |
| 214 | case PrerenderFinalStatus::kActivated: |
| 215 | case PrerenderFinalStatus::kDestroyed: |
| 216 | NOTREACHED_NORETURN(); |
| 217 | case PrerenderFinalStatus::kLowEndDevice: |
| 218 | return PreloadingEligibility::kLowMemory; |
| 219 | case PrerenderFinalStatus::kInvalidSchemeRedirect: |
Hiroki Nakagawa | fc7fd70 | 2023-08-28 15:47:56 | [diff] [blame] | 220 | NOTREACHED_NORETURN(); |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 221 | case PrerenderFinalStatus::kInvalidSchemeNavigation: |
Hiroki Nakagawa | fc7fd70 | 2023-08-28 15:47:56 | [diff] [blame] | 222 | return PreloadingEligibility::kHttpOrHttpsOnly; |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 223 | case PrerenderFinalStatus::kNavigationRequestBlockedByCsp: |
| 224 | case PrerenderFinalStatus::kMainFrameNavigation: |
| 225 | case PrerenderFinalStatus::kMojoBinderPolicy: |
| 226 | case PrerenderFinalStatus::kRendererProcessCrashed: |
| 227 | case PrerenderFinalStatus::kRendererProcessKilled: |
| 228 | case PrerenderFinalStatus::kDownload: |
| 229 | case PrerenderFinalStatus::kTriggerDestroyed: |
| 230 | case PrerenderFinalStatus::kNavigationNotCommitted: |
| 231 | case PrerenderFinalStatus::kNavigationBadHttpStatus: |
| 232 | case PrerenderFinalStatus::kClientCertRequested: |
| 233 | case PrerenderFinalStatus::kNavigationRequestNetworkError: |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 234 | case PrerenderFinalStatus::kCancelAllHostsForTesting: |
| 235 | case PrerenderFinalStatus::kDidFailLoad: |
| 236 | case PrerenderFinalStatus::kStop: |
| 237 | case PrerenderFinalStatus::kSslCertificateError: |
| 238 | case PrerenderFinalStatus::kLoginAuthRequested: |
| 239 | case PrerenderFinalStatus::kUaChangeRequiresReload: |
| 240 | case PrerenderFinalStatus::kBlockedByClient: |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 241 | case PrerenderFinalStatus::kMixedContent: |
| 242 | NOTREACHED_NORETURN(); |
| 243 | case PrerenderFinalStatus::kTriggerBackgrounded: |
| 244 | return PreloadingEligibility::kHidden; |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 245 | case PrerenderFinalStatus::kMemoryLimitExceeded: |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 246 | NOTREACHED_NORETURN(); |
| 247 | case PrerenderFinalStatus::kDataSaverEnabled: |
| 248 | return PreloadingEligibility::kDataSaverEnabled; |
Hiroki Nakagawa | d77864c | 2023-09-20 22:34:03 | [diff] [blame] | 249 | case PrerenderFinalStatus::kTriggerUrlHasEffectiveUrl: |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 250 | return PreloadingEligibility::kHasEffectiveUrl; |
| 251 | case PrerenderFinalStatus::kActivatedBeforeStarted: |
| 252 | case PrerenderFinalStatus::kInactivePageRestriction: |
| 253 | case PrerenderFinalStatus::kStartFailed: |
| 254 | case PrerenderFinalStatus::kTimeoutBackgrounded: |
| 255 | case PrerenderFinalStatus::kCrossSiteRedirectInInitialNavigation: |
| 256 | NOTREACHED_NORETURN(); |
| 257 | case PrerenderFinalStatus::kCrossSiteNavigationInInitialNavigation: |
| 258 | return PreloadingEligibility::kCrossOrigin; |
| 259 | case PrerenderFinalStatus:: |
| 260 | kSameSiteCrossOriginRedirectNotOptInInInitialNavigation: |
| 261 | case PrerenderFinalStatus:: |
| 262 | kSameSiteCrossOriginNavigationNotOptInInInitialNavigation: |
| 263 | case PrerenderFinalStatus::kActivationNavigationParameterMismatch: |
| 264 | case PrerenderFinalStatus::kActivatedInBackground: |
| 265 | case PrerenderFinalStatus::kEmbedderHostDisallowed: |
| 266 | case PrerenderFinalStatus::kActivationNavigationDestroyedBeforeSuccess: |
| 267 | case PrerenderFinalStatus::kTabClosedByUserGesture: |
| 268 | case PrerenderFinalStatus::kTabClosedWithoutUserGesture: |
| 269 | case PrerenderFinalStatus::kPrimaryMainFrameRendererProcessCrashed: |
| 270 | case PrerenderFinalStatus::kPrimaryMainFrameRendererProcessKilled: |
| 271 | case PrerenderFinalStatus::kActivationFramePolicyNotCompatible: |
| 272 | NOTREACHED_NORETURN(); |
| 273 | case PrerenderFinalStatus::kPreloadingDisabled: |
| 274 | return PreloadingEligibility::kPreloadingDisabled; |
| 275 | case PrerenderFinalStatus::kBatterySaverEnabled: |
| 276 | return PreloadingEligibility::kBatterySaverEnabled; |
| 277 | case PrerenderFinalStatus::kActivatedDuringMainFrameNavigation: |
| 278 | NOTREACHED_NORETURN(); |
| 279 | case PrerenderFinalStatus::kPreloadingUnsupportedByWebContents: |
| 280 | return PreloadingEligibility::kPreloadingUnsupportedByWebContents; |
| 281 | case PrerenderFinalStatus::kCrossSiteRedirectInMainFrameNavigation: |
| 282 | case PrerenderFinalStatus::kCrossSiteNavigationInMainFrameNavigation: |
| 283 | case PrerenderFinalStatus:: |
| 284 | kSameSiteCrossOriginRedirectNotOptInInMainFrameNavigation: |
| 285 | case PrerenderFinalStatus:: |
| 286 | kSameSiteCrossOriginNavigationNotOptInInMainFrameNavigation: |
| 287 | NOTREACHED_NORETURN(); |
| 288 | case PrerenderFinalStatus::kMemoryPressureOnTrigger: |
| 289 | return PreloadingEligibility::kMemoryPressure; |
| 290 | case PrerenderFinalStatus::kMemoryPressureAfterTriggered: |
| 291 | NOTREACHED_NORETURN(); |
keno | 8480d579f | 2023-05-25 11:34:17 | [diff] [blame] | 292 | case PrerenderFinalStatus::kPrerenderingDisabledByDevTools: |
| 293 | return PreloadingEligibility::kPreloadingDisabledByDevTools; |
Hiroki Nakagawa | 5f7d2db | 2023-07-12 22:54:06 | [diff] [blame] | 294 | case PrerenderFinalStatus::kSpeculationRuleRemoved: |
Hiroki Nakagawa | 2f42734 | 2023-07-19 23:27:04 | [diff] [blame] | 295 | case PrerenderFinalStatus::kActivatedWithAuxiliaryBrowsingContexts: |
Taiyo Mizuhashi | 459a6b2 | 2023-09-13 07:56:48 | [diff] [blame] | 296 | case PrerenderFinalStatus::kMaxNumOfRunningEagerPrerendersExceeded: |
| 297 | case PrerenderFinalStatus::kMaxNumOfRunningNonEagerPrerendersExceeded: |
| 298 | case PrerenderFinalStatus::kMaxNumOfRunningEmbedderPrerendersExceeded: |
Hiroki Nakagawa | 5f7d2db | 2023-07-12 22:54:06 | [diff] [blame] | 299 | NOTREACHED_NORETURN(); |
Hiroki Nakagawa | d77864c | 2023-09-20 22:34:03 | [diff] [blame] | 300 | case PrerenderFinalStatus::kPrerenderingUrlHasEffectiveUrl: |
| 301 | case PrerenderFinalStatus::kRedirectedPrerenderingUrlHasEffectiveUrl: |
| 302 | case PrerenderFinalStatus::kActivationUrlHasEffectiveUrl: |
| 303 | return PreloadingEligibility::kHasEffectiveUrl; |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 304 | } |
| 305 | |
| 306 | NOTREACHED_NORETURN(); |
| 307 | } |
| 308 | |
| 309 | // Represents a contract and ensures that the given prerender attempt is started |
| 310 | // as a PrerenderHost or rejected with a reason. It is allowed to use it only in |
| 311 | // PrerenderHostRegistry::CreateAndStartHost. |
| 312 | // |
| 313 | // TODO(kenoss): Add emits of Preload.prerenderStatusUpdated. |
| 314 | class PrerenderHostBuilder { |
| 315 | public: |
| 316 | explicit PrerenderHostBuilder(PreloadingAttempt* attempt); |
| 317 | ~PrerenderHostBuilder(); |
| 318 | |
| 319 | PrerenderHostBuilder(const PrerenderHostBuilder&) = delete; |
| 320 | PrerenderHostBuilder& operator=(const PrerenderHostBuilder&) = delete; |
| 321 | PrerenderHostBuilder(PrerenderHostBuilder&&) = delete; |
| 322 | PrerenderHostBuilder& operator=(PrerenderHostBuilder&&) = delete; |
| 323 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 324 | // The following methods consumes this class. |
| 325 | std::unique_ptr<PrerenderHost> Build(const PrerenderAttributes& attributes, |
| 326 | WebContentsImpl& prerender_web_contents); |
| 327 | void RejectAsNotEligible(const PrerenderAttributes& attributes, |
| 328 | PrerenderFinalStatus status); |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 329 | void RejectAsDuplicate(); |
| 330 | void RejectAsFailure(const PrerenderAttributes& attributes, |
| 331 | PrerenderFinalStatus status); |
Simon Pelchat | efc0619 | 2023-06-28 02:04:44 | [diff] [blame] | 332 | void RejectDueToHoldback(); |
| 333 | |
Domenic Denicola | bb5d843c | 2023-07-18 01:47:33 | [diff] [blame] | 334 | void SetHoldbackOverride(PreloadingHoldbackStatus status); |
Simon Pelchat | efc0619 | 2023-06-28 02:04:44 | [diff] [blame] | 335 | bool CheckIfShouldHoldback(); |
| 336 | |
keno | c9782d9 | 2023-05-19 06:28:28 | [diff] [blame] | 337 | // Public only for exceptional case. |
| 338 | // TODO(https://crbug.com/1435376): Make this private again. |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 339 | void Drop(); |
keno | a8f9571 | 2023-05-19 08:09:22 | [diff] [blame] | 340 | bool IsDropped(); |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 341 | |
keno | c9782d9 | 2023-05-19 06:28:28 | [diff] [blame] | 342 | private: |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 343 | // Use raw pointer as PrerenderHostBuilder is alive only during |
| 344 | // PrerenderHostRegistry::CreateAndStartHost(), and PreloadingAttempt should |
| 345 | // outlive the function. |
| 346 | raw_ptr<PreloadingAttempt> attempt_; |
keno | d930e4803 | 2023-05-18 11:38:40 | [diff] [blame] | 347 | std::unique_ptr<DevToolsPrerenderAttempt> devtools_attempt_; |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 348 | }; |
| 349 | |
| 350 | PrerenderHostBuilder::PrerenderHostBuilder(PreloadingAttempt* attempt) |
keno | d930e4803 | 2023-05-18 11:38:40 | [diff] [blame] | 351 | : attempt_(attempt), |
| 352 | devtools_attempt_(std::make_unique<DevToolsPrerenderAttempt>()) {} |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 353 | |
| 354 | PrerenderHostBuilder::~PrerenderHostBuilder() { |
keno | a8f9571 | 2023-05-19 08:09:22 | [diff] [blame] | 355 | CHECK(IsDropped()); |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 356 | } |
| 357 | |
| 358 | void PrerenderHostBuilder::Drop() { |
| 359 | attempt_ = nullptr; |
keno | d930e4803 | 2023-05-18 11:38:40 | [diff] [blame] | 360 | devtools_attempt_.reset(); |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 361 | } |
| 362 | |
keno | a8f9571 | 2023-05-19 08:09:22 | [diff] [blame] | 363 | bool PrerenderHostBuilder::IsDropped() { |
| 364 | return devtools_attempt_ == nullptr; |
| 365 | } |
| 366 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 367 | std::unique_ptr<PrerenderHost> PrerenderHostBuilder::Build( |
| 368 | const PrerenderAttributes& attributes, |
| 369 | WebContentsImpl& prerender_web_contents) { |
keno | a8f9571 | 2023-05-19 08:09:22 | [diff] [blame] | 370 | CHECK(!IsDropped()); |
| 371 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 372 | auto prerender_host = std::make_unique<PrerenderHost>( |
| 373 | attributes, prerender_web_contents, |
keno | d930e4803 | 2023-05-18 11:38:40 | [diff] [blame] | 374 | attempt_ ? attempt_->GetWeakPtr() : nullptr, |
| 375 | std::move(devtools_attempt_)); |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 376 | |
| 377 | Drop(); |
| 378 | |
| 379 | return prerender_host; |
| 380 | } |
| 381 | |
| 382 | void PrerenderHostBuilder::RejectAsNotEligible( |
| 383 | const PrerenderAttributes& attributes, |
| 384 | PrerenderFinalStatus status) { |
keno | a8f9571 | 2023-05-19 08:09:22 | [diff] [blame] | 385 | CHECK(!IsDropped()); |
| 386 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 387 | if (attempt_) { |
| 388 | attempt_->SetEligibility(ToEligibility(status)); |
| 389 | } |
| 390 | |
keno | d930e4803 | 2023-05-18 11:38:40 | [diff] [blame] | 391 | devtools_attempt_->SetFailureReason(attributes, status); |
| 392 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 393 | RecordFailedPrerenderFinalStatus(PrerenderCancellationReason(status), |
| 394 | attributes); |
| 395 | |
| 396 | Drop(); |
| 397 | } |
| 398 | |
Simon Pelchat | efc0619 | 2023-06-28 02:04:44 | [diff] [blame] | 399 | bool PrerenderHostBuilder::CheckIfShouldHoldback() { |
| 400 | CHECK(!IsDropped()); |
| 401 | |
| 402 | // Assigns the holdback status in the attempt it was not overridden earlier. |
| 403 | return attempt_ && attempt_->ShouldHoldback(); |
| 404 | } |
| 405 | |
| 406 | void PrerenderHostBuilder::RejectDueToHoldback() { |
| 407 | CHECK(!IsDropped()); |
| 408 | |
| 409 | // If DevTools is opened, holdbacks are force-disabled. So, we don't need to |
| 410 | // report this case to DevTools. |
| 411 | |
| 412 | Drop(); |
| 413 | } |
| 414 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 415 | void PrerenderHostBuilder::RejectAsDuplicate() { |
keno | a8f9571 | 2023-05-19 08:09:22 | [diff] [blame] | 416 | CHECK(!IsDropped()); |
| 417 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 418 | if (attempt_) { |
| 419 | attempt_->SetTriggeringOutcome(PreloadingTriggeringOutcome::kDuplicate); |
| 420 | } |
| 421 | |
keno | d930e4803 | 2023-05-18 11:38:40 | [diff] [blame] | 422 | // No need to report DevTools nor UMA; just removing duplicates. |
| 423 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 424 | Drop(); |
| 425 | } |
| 426 | |
Domenic Denicola | bb5d843c | 2023-07-18 01:47:33 | [diff] [blame] | 427 | void PrerenderHostBuilder::SetHoldbackOverride( |
| 428 | PreloadingHoldbackStatus status) { |
Simon Pelchat | efc0619 | 2023-06-28 02:04:44 | [diff] [blame] | 429 | if (!attempt_) { |
| 430 | return; |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 431 | } |
Domenic Denicola | bb5d843c | 2023-07-18 01:47:33 | [diff] [blame] | 432 | attempt_->SetHoldbackStatus(status); |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 433 | } |
| 434 | |
| 435 | void PrerenderHostBuilder::RejectAsFailure( |
| 436 | const PrerenderAttributes& attributes, |
| 437 | PrerenderFinalStatus status) { |
keno | a8f9571 | 2023-05-19 08:09:22 | [diff] [blame] | 438 | CHECK(!IsDropped()); |
| 439 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 440 | if (attempt_) { |
| 441 | attempt_->SetFailureReason(ToPreloadingFailureReason(status)); |
| 442 | } |
| 443 | |
keno | d930e4803 | 2023-05-18 11:38:40 | [diff] [blame] | 444 | devtools_attempt_->SetFailureReason(attributes, status); |
| 445 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 446 | RecordFailedPrerenderFinalStatus(PrerenderCancellationReason(status), |
| 447 | attributes); |
| 448 | |
| 449 | Drop(); |
| 450 | } |
| 451 | |
Matt Falkenhagen | 9373d4e | 2021-08-11 16:50:22 | [diff] [blame] | 452 | } // namespace |
| 453 | |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 454 | const char kMaxNumOfRunningSpeculationRulesEagerPrerenders[] = |
| 455 | "max_num_of_running_speculation_rules_eager_prerenders"; |
| 456 | const char kMaxNumOfRunningSpeculationRulesNonEagerPrerenders[] = |
| 457 | "max_num_of_running_speculation_rules_non_eager_prerenders"; |
| 458 | const char kMaxNumOfRunningEmbedderPrerenders[] = |
| 459 | "max_num_of_running_embedder_prerenders"; |
Taiyo Mizuhashi | 7bf7924 | 2023-07-25 06:30:59 | [diff] [blame] | 460 | |
Hiroki Nakagawa | 34e5d67 | 2023-04-21 05:00:09 | [diff] [blame] | 461 | PrerenderHostRegistry::PrerenderHostRegistry(WebContents& web_contents) |
| 462 | : memory_pressure_listener_( |
| 463 | FROM_HERE, |
| 464 | base::BindRepeating(&PrerenderHostRegistry::OnMemoryPressure, |
| 465 | base::Unretained(this))) { |
Yoshiki Tanioka | b6a6d72 | 2022-10-20 07:58:50 | [diff] [blame] | 466 | Observe(&web_contents); |
Lingqi Chi | 22f3c2d | 2023-04-27 15:55:50 | [diff] [blame] | 467 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [diff] [blame] | 468 | } |
| 469 | |
Matt Falkenhagen | f884d0f | 2021-02-18 06:31:35 | [diff] [blame] | 470 | PrerenderHostRegistry::~PrerenderHostRegistry() { |
lingqi | 42ab9f45 | 2022-12-30 16:56:49 | [diff] [blame] | 471 | // This function is called by WebContentsImpl's dtor, so web_contents() should |
| 472 | // not be a null ptr at this moment. |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 473 | CHECK(web_contents()); |
Lingqi Chi | 22f3c2d | 2023-04-27 15:55:50 | [diff] [blame] | 474 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
lingqi | 42ab9f45 | 2022-12-30 16:56:49 | [diff] [blame] | 475 | |
| 476 | PrerenderFinalStatus final_status = |
| 477 | web_contents()->GetClosedByUserGesture() |
| 478 | ? PrerenderFinalStatus::kTabClosedByUserGesture |
| 479 | : PrerenderFinalStatus::kTabClosedWithoutUserGesture; |
| 480 | |
| 481 | // Here we have to delete the prerender hosts synchronously, to ensure the |
| 482 | // FrameTrees would not access the WebContents. |
| 483 | CancelAllHosts(final_status); |
Yoshiki Tanioka | b6a6d72 | 2022-10-20 07:58:50 | [diff] [blame] | 484 | Observe(nullptr); |
Matt Falkenhagen | f884d0f | 2021-02-18 06:31:35 | [diff] [blame] | 485 | for (Observer& obs : observers_) |
| 486 | obs.OnRegistryDestroyed(); |
| 487 | } |
| 488 | |
| 489 | void PrerenderHostRegistry::AddObserver(Observer* observer) { |
| 490 | observers_.AddObserver(observer); |
| 491 | } |
| 492 | |
| 493 | void PrerenderHostRegistry::RemoveObserver(Observer* observer) { |
| 494 | observers_.RemoveObserver(observer); |
| 495 | } |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [diff] [blame] | 496 | |
Lingqi Chi | 4e06ae7 | 2021-01-28 13:48:35 | [diff] [blame] | 497 | int PrerenderHostRegistry::CreateAndStartHost( |
Lingqi Chi | ca31e24 | 2021-09-24 03:54:16 | [diff] [blame] | 498 | const PrerenderAttributes& attributes, |
Sreeja Kamishetty | ac12140e | 2022-07-14 22:16:51 | [diff] [blame] | 499 | PreloadingAttempt* attempt) { |
Lingqi Chi | 22f3c2d | 2023-04-27 15:55:50 | [diff] [blame] | 500 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
Robert Lin | c37fb58 | 2021-11-11 03:18:47 | [diff] [blame] | 501 | std::string recorded_url = |
| 502 | attributes.initiator_origin.has_value() |
| 503 | ? attributes.initiator_origin.value().GetURL().spec() |
| 504 | : "(empty_url)"; |
| 505 | |
Robert Lin | d75062bf | 2021-10-28 12:50:55 | [diff] [blame] | 506 | TRACE_EVENT2("navigation", "PrerenderHostRegistry::CreateAndStartHost", |
Robert Lin | c37fb58 | 2021-11-11 03:18:47 | [diff] [blame] | 507 | "attributes", attributes, "initiator_origin", recorded_url); |
Hiroki Nakagawa | 8f6a95d8 | 2020-12-04 02:56:38 | [diff] [blame] | 508 | |
Hiroki Nakagawa | b930733e | 2023-01-04 16:40:52 | [diff] [blame] | 509 | // The initiator WebContents can be different from the WebContents that will |
| 510 | // host a prerendered page only when the prerender-in-new-tab runs. |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 511 | CHECK(attributes.initiator_web_contents); |
Hiroki Nakagawa | b930733e | 2023-01-04 16:40:52 | [diff] [blame] | 512 | auto& initiator_web_contents = |
| 513 | static_cast<WebContentsImpl&>(*attributes.initiator_web_contents); |
| 514 | auto& prerender_web_contents = static_cast<WebContentsImpl&>(*web_contents()); |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 515 | CHECK(&initiator_web_contents == &prerender_web_contents || |
| 516 | base::FeatureList::IsEnabled(blink::features::kPrerender2InNewTab)); |
Hiroki Nakagawa | b930733e | 2023-01-04 16:40:52 | [diff] [blame] | 517 | |
David Bokan | 5e9db7b | 2021-11-02 12:29:04 | [diff] [blame] | 518 | int frame_tree_node_id = RenderFrameHost::kNoFrameTreeNodeId; |
Matt Falkenhagen | f884d0f | 2021-02-18 06:31:35 | [diff] [blame] | 519 | |
David Bokan | 5e9db7b | 2021-11-02 12:29:04 | [diff] [blame] | 520 | { |
keno | 8480d579f | 2023-05-25 11:34:17 | [diff] [blame] | 521 | RenderFrameHostImpl* initiator_rfh = |
| 522 | attributes.IsBrowserInitiated() |
| 523 | ? nullptr |
| 524 | : RenderFrameHostImpl::FromFrameToken( |
| 525 | attributes.initiator_process_id, |
| 526 | attributes.initiator_frame_token.value()); |
| 527 | |
David Bokan | 5e9db7b | 2021-11-02 12:29:04 | [diff] [blame] | 528 | // Ensure observers are notified that a trigger occurred. |
| 529 | base::ScopedClosureRunner notify_trigger( |
| 530 | base::BindOnce(&PrerenderHostRegistry::NotifyTrigger, |
| 531 | base::Unretained(this), attributes.prerendering_url)); |
| 532 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 533 | auto builder = PrerenderHostBuilder(attempt); |
| 534 | |
keno | c9782d9 | 2023-05-19 06:28:28 | [diff] [blame] | 535 | // We don't know the root cause, but there is a case this is null. |
| 536 | // |
| 537 | // TODO(https://crbug.com/1435376): Continue investigation and fix the root |
| 538 | // cause. |
| 539 | if (initiator_web_contents.GetDelegate() == nullptr) { |
| 540 | // Note that return without consuming `builder` is exceptional. |
| 541 | builder.Drop(); |
| 542 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 543 | } |
| 544 | |
Johann | a0b3e9b | 2023-01-19 23:23:35 | [diff] [blame] | 545 | // Check whether preloading is enabled. If it is not enabled, report the |
| 546 | // reason. |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 547 | switch (initiator_web_contents.GetDelegate()->IsPrerender2Supported( |
| 548 | initiator_web_contents)) { |
| 549 | case PreloadingEligibility::kEligible: |
| 550 | // nop |
| 551 | break; |
| 552 | case PreloadingEligibility::kPreloadingDisabled: |
| 553 | builder.RejectAsNotEligible(attributes, |
| 554 | PrerenderFinalStatus::kPreloadingDisabled); |
| 555 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 556 | case PreloadingEligibility::kDataSaverEnabled: |
| 557 | builder.RejectAsNotEligible(attributes, |
| 558 | PrerenderFinalStatus::kDataSaverEnabled); |
| 559 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 560 | case PreloadingEligibility::kBatterySaverEnabled: |
| 561 | builder.RejectAsNotEligible(attributes, |
| 562 | PrerenderFinalStatus::kBatterySaverEnabled); |
| 563 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 564 | case PreloadingEligibility::kPreloadingUnsupportedByWebContents: |
| 565 | builder.RejectAsNotEligible( |
| 566 | attributes, |
| 567 | PrerenderFinalStatus::kPreloadingUnsupportedByWebContents); |
| 568 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 569 | default: |
| 570 | NOTREACHED_NORETURN(); |
Sreeja Kamishetty | c94a0d2 | 2022-07-06 20:43:06 | [diff] [blame] | 571 | } |
| 572 | |
Taiyo Mizuhashi | d82e433 | 2023-05-09 11:25:16 | [diff] [blame] | 573 | // Don't prerender when the initiator is in the background and its type is |
| 574 | // `kEmbedder`, as current implementation doesn't use `pending_prerenders_` |
| 575 | // when kEmbedder. |
| 576 | // If the trigger type is speculation rules, nothing should be done here and |
| 577 | // then prerender host will be created and its id will be enqueued to |
| 578 | // `pending_prerenders_`. The visibility of the initiator will be considered |
| 579 | // when trying to pop from `pending_prerenders_` on `StartPrerendering()`. |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 580 | if (attributes.trigger_type == PreloadingTriggerType::kEmbedder && |
Taiyo Mizuhashi | d82e433 | 2023-05-09 11:25:16 | [diff] [blame] | 581 | initiator_web_contents.GetVisibility() == Visibility::HIDDEN) { |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 582 | builder.RejectAsNotEligible(attributes, |
| 583 | PrerenderFinalStatus::kTriggerBackgrounded); |
David Bokan | 5e9db7b | 2021-11-02 12:29:04 | [diff] [blame] | 584 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 585 | } |
| 586 | |
| 587 | // Don't prerender on low-end devices. |
David Bokan | 5e9db7b | 2021-11-02 12:29:04 | [diff] [blame] | 588 | if (!DeviceHasEnoughMemoryForPrerender()) { |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 589 | builder.RejectAsNotEligible(attributes, |
| 590 | PrerenderFinalStatus::kLowEndDevice); |
David Bokan | 5e9db7b | 2021-11-02 12:29:04 | [diff] [blame] | 591 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 592 | } |
| 593 | |
Hiroki Nakagawa | 34e5d67 | 2023-04-21 05:00:09 | [diff] [blame] | 594 | // Don't prerender under critical memory pressure. |
| 595 | switch (GetCurrentMemoryPressureLevel()) { |
| 596 | case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE: |
| 597 | case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: |
| 598 | break; |
| 599 | case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 600 | builder.RejectAsNotEligible( |
| 601 | attributes, PrerenderFinalStatus::kMemoryPressureOnTrigger); |
Hiroki Nakagawa | 34e5d67 | 2023-04-21 05:00:09 | [diff] [blame] | 602 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 603 | } |
| 604 | |
Hiroki Nakagawa | 1500e7a | 2023-01-31 07:44:55 | [diff] [blame] | 605 | // Allow prerendering only for same-site. The initiator origin is nullopt |
| 606 | // when prerendering is initiated by the browser (not by a renderer using |
| 607 | // Speculation Rules API). In that case, skip this same-site check. |
Robert Lin | 20d947ed | 2022-08-25 06:01:28 | [diff] [blame] | 608 | // TODO(crbug.com/1176054): Support cross-site prerendering. |
Hiroki Nakagawa | 1500e7a | 2023-01-31 07:44:55 | [diff] [blame] | 609 | if (!attributes.IsBrowserInitiated() && |
| 610 | !prerender_navigation_utils::IsSameSite( |
| 611 | attributes.prerendering_url, attributes.initiator_origin.value())) { |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 612 | builder.RejectAsNotEligible( |
| 613 | attributes, |
| 614 | PrerenderFinalStatus::kCrossSiteNavigationInInitialNavigation); |
Hiroki Nakagawa | 1500e7a | 2023-01-31 07:44:55 | [diff] [blame] | 615 | return RenderFrameHost::kNoFrameTreeNodeId; |
David Bokan | 5e9db7b | 2021-11-02 12:29:04 | [diff] [blame] | 616 | } |
| 617 | |
Hiroki Nakagawa | ef90206c | 2023-08-25 05:03:27 | [diff] [blame] | 618 | // Allow prerendering only HTTP(S) scheme URLs. For redirection, this will |
| 619 | // be checked in PrerenderNavigationThrottle::WillStartOrRedirectRequest(). |
| 620 | if (!attributes.prerendering_url.SchemeIsHTTPOrHTTPS()) { |
| 621 | builder.RejectAsNotEligible( |
| 622 | attributes, PrerenderFinalStatus::kInvalidSchemeNavigation); |
| 623 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 624 | } |
| 625 | |
Hiroki Nakagawa | b930733e | 2023-01-04 16:40:52 | [diff] [blame] | 626 | // Disallow all pages that have an effective URL like hosted apps and NTP. |
Hiroki Nakagawa | d77864c | 2023-09-20 22:34:03 | [diff] [blame] | 627 | auto* browser_context = prerender_web_contents.GetBrowserContext(); |
| 628 | if (SiteInstanceImpl::HasEffectiveURL(browser_context, |
| 629 | initiator_web_contents.GetURL())) { |
| 630 | builder.RejectAsNotEligible( |
| 631 | attributes, PrerenderFinalStatus::kTriggerUrlHasEffectiveUrl); |
| 632 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 633 | } |
| 634 | if (SiteInstanceImpl::HasEffectiveURL(browser_context, |
| 635 | attributes.prerendering_url)) { |
| 636 | builder.RejectAsNotEligible( |
| 637 | attributes, PrerenderFinalStatus::kPrerenderingUrlHasEffectiveUrl); |
Miyoung Shin | 551df1cb | 2022-08-25 14:14:58 | [diff] [blame] | 638 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 639 | } |
| 640 | |
keno | 8480d579f | 2023-05-25 11:34:17 | [diff] [blame] | 641 | if (initiator_rfh && initiator_rfh->frame_tree() && |
| 642 | !devtools_instrumentation::IsPrerenderAllowed( |
| 643 | *initiator_rfh->frame_tree())) { |
| 644 | builder.RejectAsNotEligible( |
| 645 | attributes, PrerenderFinalStatus::kPrerenderingDisabledByDevTools); |
| 646 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 647 | } |
| 648 | |
Sreeja Kamishetty | ac12140e | 2022-07-14 22:16:51 | [diff] [blame] | 649 | // Once all eligibility checks are completed, set the status to kEligible. |
| 650 | if (attempt) |
| 651 | attempt->SetEligibility(PreloadingEligibility::kEligible); |
| 652 | |
Domenic Denicola | bb5d843c | 2023-07-18 01:47:33 | [diff] [blame] | 653 | // Normally CheckIfShouldHoldback() computes the holdback status based on |
| 654 | // PreloadingConfig. In special cases, we call SetHoldbackOverride() to |
| 655 | // override that processing. |
| 656 | bool has_devtools_open = |
Robert Lin | 56cb9c4 | 2022-11-22 07:57:30 | [diff] [blame] | 657 | initiator_rfh && |
| 658 | RenderFrameDevToolsAgentHost::GetFor(initiator_rfh) != nullptr; |
Domenic Denicola | bb5d843c | 2023-07-18 01:47:33 | [diff] [blame] | 659 | |
| 660 | if (has_devtools_open) { |
| 661 | // Never holdback when DevTools is opened, to avoid web developer |
| 662 | // frustration. |
| 663 | builder.SetHoldbackOverride(PreloadingHoldbackStatus::kAllowed); |
Domenic Denicola | bb5d843c | 2023-07-18 01:47:33 | [diff] [blame] | 664 | } else if (attributes.holdback_status_override != |
| 665 | PreloadingHoldbackStatus::kUnspecified) { |
| 666 | // The caller (e.g. from chrome/) is allowed to specify a holdback that |
| 667 | // overrides the default logic. |
| 668 | builder.SetHoldbackOverride(attributes.holdback_status_override); |
Simon Pelchat | efc0619 | 2023-06-28 02:04:44 | [diff] [blame] | 669 | } |
Domenic Denicola | bb5d843c | 2023-07-18 01:47:33 | [diff] [blame] | 670 | |
Simon Pelchat | efc0619 | 2023-06-28 02:04:44 | [diff] [blame] | 671 | // Check if the attempt is held back either due to the check above or via |
| 672 | // PreloadingConfig. |
| 673 | if (builder.CheckIfShouldHoldback()) { |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 674 | builder.RejectDueToHoldback(); |
Sreeja Kamishetty | ac12140e | 2022-07-14 22:16:51 | [diff] [blame] | 675 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 676 | } |
Sreeja Kamishetty | ac12140e | 2022-07-14 22:16:51 | [diff] [blame] | 677 | |
David Bokan | 5e9db7b | 2021-11-02 12:29:04 | [diff] [blame] | 678 | // Ignore prerendering requests for the same URL. |
| 679 | for (auto& iter : prerender_host_by_frame_tree_node_id_) { |
Sreeja Kamishetty | ac12140e | 2022-07-14 22:16:51 | [diff] [blame] | 680 | if (iter.second->GetInitialUrl() == attributes.prerendering_url) { |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 681 | builder.RejectAsDuplicate(); |
Hiroki Nakagawa | d9f772d | 2021-11-11 07:50:26 | [diff] [blame] | 682 | return RenderFrameHost::kNoFrameTreeNodeId; |
Sreeja Kamishetty | ac12140e | 2022-07-14 22:16:51 | [diff] [blame] | 683 | } |
David Bokan | 5e9db7b | 2021-11-02 12:29:04 | [diff] [blame] | 684 | } |
| 685 | |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 686 | // Under kPrerender2InNewTab, CreateAndStartHost will be called in |
| 687 | // the newly created WebContents’s PrerenderHostRegistry for new tab |
| 688 | // triggers, rather than in initiator WebContents’s registry, while |
| 689 | // it is called in initiator ones for normal triggers. In either |
| 690 | // case, we want to control the limit based on the initiator |
| 691 | // WebContents. |
| 692 | // |
Yoshiki Tanioka | 58b8fefa | 2022-09-16 02:05:10 | [diff] [blame] | 693 | // TODO(crbug.com/1355151): Enqueue the request exceeding the number limit |
| 694 | // until the forerunners are cancelled, and suspend starting a new prerender |
| 695 | // when the number reaches the limit. |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 696 | if (!initiator_web_contents.GetPrerenderHostRegistry() |
| 697 | ->IsAllowedToStartPrerenderingForTrigger(attributes.trigger_type, |
| 698 | attributes.eagerness)) { |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 699 | // The reason we don't consider limit exceeded as an ineligibility |
| 700 | // reason is because we can't replicate the behavior in our other |
| 701 | // experiment groups for analysis. To prevent this we set |
| 702 | // TriggeringOutcome to kFailure and look into the failure reason to |
| 703 | // learn more. |
Taiyo Mizuhashi | 459a6b2 | 2023-09-13 07:56:48 | [diff] [blame] | 704 | PrerenderFinalStatus final_status; |
| 705 | switch (GetPrerenderLimitGroup(attributes.trigger_type, |
| 706 | attributes.eagerness)) { |
| 707 | case PrerenderLimitGroup::kSpeculationRulesEager: |
| 708 | final_status = |
| 709 | PrerenderFinalStatus::kMaxNumOfRunningEagerPrerendersExceeded; |
| 710 | break; |
| 711 | case PrerenderLimitGroup::kSpeculationRulesNonEager: |
| 712 | final_status = |
| 713 | PrerenderFinalStatus::kMaxNumOfRunningNonEagerPrerendersExceeded; |
| 714 | break; |
| 715 | case PrerenderLimitGroup::kEmbedder: |
| 716 | final_status = |
| 717 | PrerenderFinalStatus::kMaxNumOfRunningEmbedderPrerendersExceeded; |
| 718 | break; |
| 719 | } |
| 720 | builder.RejectAsFailure(attributes, final_status); |
David Bokan | 5e9db7b | 2021-11-02 12:29:04 | [diff] [blame] | 721 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 722 | } |
| 723 | |
keno | 85004bc | 2023-05-18 09:45:41 | [diff] [blame] | 724 | auto prerender_host = builder.Build(attributes, prerender_web_contents); |
David Bokan | 5e9db7b | 2021-11-02 12:29:04 | [diff] [blame] | 725 | frame_tree_node_id = prerender_host->frame_tree_node_id(); |
| 726 | |
| 727 | CHECK(!base::Contains(prerender_host_by_frame_tree_node_id_, |
| 728 | frame_tree_node_id)); |
Yoshiki Tanioka | 07915d8 | 2022-09-15 06:07:51 | [diff] [blame] | 729 | prerender_host_by_frame_tree_node_id_[frame_tree_node_id] = |
| 730 | std::move(prerender_host); |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 731 | |
Taiyo Mizuhashi | 9211979 | 2023-09-13 07:18:03 | [diff] [blame] | 732 | if (base::FeatureList::IsEnabled( |
| 733 | features::kPrerender2NewLimitAndScheduler)) { |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 734 | if (GetPrerenderLimitGroup(attributes.trigger_type, |
| 735 | attributes.eagerness) == |
| 736 | PrerenderLimitGroup::kSpeculationRulesNonEager) { |
| 737 | non_eager_prerender_host_id_by_arrival_order_.push_back( |
| 738 | frame_tree_node_id); |
| 739 | } |
| 740 | } |
Yoshiki Tanioka | c72b7b72 | 2022-09-06 05:38:38 | [diff] [blame] | 741 | } |
| 742 | |
Taiyo Mizuhashi | 31bcb199 | 2023-04-27 05:03:03 | [diff] [blame] | 743 | switch (attributes.trigger_type) { |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 744 | case PreloadingTriggerType::kSpeculationRule: |
| 745 | case PreloadingTriggerType::kSpeculationRuleFromIsolatedWorld: |
Taiyo Mizuhashi | 31bcb199 | 2023-04-27 05:03:03 | [diff] [blame] | 746 | pending_prerenders_.push_back(frame_tree_node_id); |
| 747 | // Start the initial prerendering navigation of the pending request in |
Taiyo Mizuhashi | d82e433 | 2023-05-09 11:25:16 | [diff] [blame] | 748 | // the head of the queue if there's no running prerender and the initiator |
| 749 | // is in the foreground. |
Taiyo Mizuhashi | 31bcb199 | 2023-04-27 05:03:03 | [diff] [blame] | 750 | if (running_prerender_host_id_ == RenderFrameHost::kNoFrameTreeNodeId) { |
Taiyo Mizuhashi | d82e433 | 2023-05-09 11:25:16 | [diff] [blame] | 751 | // No running prerender means that either no other prerenders are in the |
| 752 | // pending queue or the initiator continues to be in the background. |
| 753 | // Skip starting prerendering in the latter case. |
| 754 | if (IsBackground(initiator_web_contents.GetVisibility())) { |
| 755 | break; |
| 756 | } |
Taiyo Mizuhashi | 31bcb199 | 2023-04-27 05:03:03 | [diff] [blame] | 757 | CHECK_EQ(pending_prerenders_.size(), 1u); |
| 758 | int started_frame_tree_node_id = |
| 759 | StartPrerendering(RenderFrameHost::kNoFrameTreeNodeId); |
| 760 | CHECK(started_frame_tree_node_id == frame_tree_node_id || |
| 761 | started_frame_tree_node_id == |
| 762 | RenderFrameHost::kNoFrameTreeNodeId); |
| 763 | frame_tree_node_id = started_frame_tree_node_id; |
| 764 | } |
| 765 | break; |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 766 | case PreloadingTriggerType::kEmbedder: |
Taiyo Mizuhashi | 31bcb199 | 2023-04-27 05:03:03 | [diff] [blame] | 767 | // The prerendering request from embedder should have high-priority |
| 768 | // because embedder prediction is more likely for the user to visit. |
| 769 | // Hold the return value of `StartPrerendering` because the requested |
| 770 | // prerender might be cancelled due to some restrictions and |
| 771 | // `kNoFrameTreeNodeId` should be returned in that case. |
| 772 | frame_tree_node_id = StartPrerendering(frame_tree_node_id); |
| 773 | break; |
Yoshiki Tanioka | 87aab3f | 2022-09-13 06:25:37 | [diff] [blame] | 774 | } |
| 775 | |
| 776 | return frame_tree_node_id; |
| 777 | } |
| 778 | |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 779 | int PrerenderHostRegistry::CreateAndStartHostForNewTab( |
Hiroki Nakagawa | 4c4e62b | 2023-09-12 08:54:29 | [diff] [blame] | 780 | const PrerenderAttributes& attributes, |
| 781 | PreloadingPredictor preloading_predictor) { |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 782 | CHECK(base::FeatureList::IsEnabled(blink::features::kPrerender2InNewTab)); |
Takashi Toyoshima | 43dcf431 | 2023-04-21 09:33:05 | [diff] [blame] | 783 | CHECK(IsSpeculationRuleType(attributes.trigger_type)); |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 784 | std::string recorded_url = |
| 785 | attributes.initiator_origin.has_value() |
| 786 | ? attributes.initiator_origin.value().GetURL().spec() |
| 787 | : "(empty_url)"; |
| 788 | TRACE_EVENT2("navigation", |
| 789 | "PrerenderHostRegistry::CreateAndStartHostForNewTab", |
| 790 | "attributes", attributes, "initiator_origin", recorded_url); |
| 791 | |
| 792 | auto handle = std::make_unique<PrerenderNewTabHandle>( |
Hiroki Nakagawa | a000bb8 | 2022-11-29 06:01:02 | [diff] [blame] | 793 | attributes, *web_contents()->GetBrowserContext()); |
Hiroki Nakagawa | 4c4e62b | 2023-09-12 08:54:29 | [diff] [blame] | 794 | int prerender_host_id = handle->StartPrerendering(preloading_predictor); |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 795 | if (prerender_host_id == RenderFrameHost::kNoFrameTreeNodeId) |
| 796 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 797 | prerender_new_tab_handle_by_frame_tree_node_id_[prerender_host_id] = |
| 798 | std::move(handle); |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 799 | |
| 800 | if (base::FeatureList::IsEnabled(features::kPrerender2NewLimitAndScheduler)) { |
| 801 | if (GetPrerenderLimitGroup(attributes.trigger_type, attributes.eagerness) == |
| 802 | PrerenderLimitGroup::kSpeculationRulesNonEager) { |
| 803 | non_eager_prerender_host_id_by_arrival_order_.push_back( |
| 804 | prerender_host_id); |
| 805 | } |
| 806 | } |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 807 | return prerender_host_id; |
| 808 | } |
| 809 | |
Yoshiki Tanioka | 87aab3f | 2022-09-13 06:25:37 | [diff] [blame] | 810 | int PrerenderHostRegistry::StartPrerendering(int frame_tree_node_id) { |
Hiroki Nakagawa | 34e5d67 | 2023-04-21 05:00:09 | [diff] [blame] | 811 | // TODO(https://crbug.com/1424425): Don't start prerendering if the current |
| 812 | // memory pressure level is critical, and then retry prerendering when the |
| 813 | // memory pressure level goes down. |
| 814 | |
Yoshiki Tanioka | 87aab3f | 2022-09-13 06:25:37 | [diff] [blame] | 815 | if (frame_tree_node_id == RenderFrameHost::kNoFrameTreeNodeId) { |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 816 | CHECK_EQ(running_prerender_host_id_, RenderFrameHost::kNoFrameTreeNodeId); |
Yoshiki Tanioka | 07915d8 | 2022-09-15 06:07:51 | [diff] [blame] | 817 | |
Taiyo Mizuhashi | 8fe56d06 | 2023-08-28 15:13:43 | [diff] [blame] | 818 | while (!pending_prerenders_.empty()) { |
| 819 | int host_id = pending_prerenders_.front(); |
Yoshiki Tanioka | b6a6d72 | 2022-10-20 07:58:50 | [diff] [blame] | 820 | |
Hiroki Nakagawa | b930733e | 2023-01-04 16:40:52 | [diff] [blame] | 821 | // Skip a cancelled request. |
| 822 | auto found = prerender_host_by_frame_tree_node_id_.find(host_id); |
| 823 | if (found == prerender_host_by_frame_tree_node_id_.end()) { |
| 824 | // Remove the cancelled request from the pending queue. |
Taiyo Mizuhashi | 8fe56d06 | 2023-08-28 15:13:43 | [diff] [blame] | 825 | pending_prerenders_.pop_front(); |
Hiroki Nakagawa | b930733e | 2023-01-04 16:40:52 | [diff] [blame] | 826 | continue; |
Yoshiki Tanioka | 07915d8 | 2022-09-15 06:07:51 | [diff] [blame] | 827 | } |
Hiroki Nakagawa | b930733e | 2023-01-04 16:40:52 | [diff] [blame] | 828 | PrerenderHost* prerender_host = found->second.get(); |
| 829 | |
| 830 | // The initiator WebContents should be alive as it cancels all the |
| 831 | // prerendering requests during destruction. |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 832 | CHECK(prerender_host->initiator_web_contents()); |
Hiroki Nakagawa | b930733e | 2023-01-04 16:40:52 | [diff] [blame] | 833 | |
| 834 | // Don't start the pending prerender triggered by the background tab. |
Hiroki Nakagawa | 98af8c4 | 2023-03-14 05:36:38 | [diff] [blame] | 835 | if (IsBackground( |
| 836 | prerender_host->initiator_web_contents()->GetVisibility())) { |
Hiroki Nakagawa | b930733e | 2023-01-04 16:40:52 | [diff] [blame] | 837 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 838 | } |
| 839 | |
| 840 | // Found the request to run. |
Taiyo Mizuhashi | 8fe56d06 | 2023-08-28 15:13:43 | [diff] [blame] | 841 | pending_prerenders_.pop_front(); |
Hiroki Nakagawa | b930733e | 2023-01-04 16:40:52 | [diff] [blame] | 842 | frame_tree_node_id = host_id; |
| 843 | break; |
Yoshiki Tanioka | 87aab3f | 2022-09-13 06:25:37 | [diff] [blame] | 844 | } |
| 845 | |
Yoshiki Tanioka | 07915d8 | 2022-09-15 06:07:51 | [diff] [blame] | 846 | if (frame_tree_node_id == RenderFrameHost::kNoFrameTreeNodeId) { |
| 847 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 848 | } |
Yoshiki Tanioka | 87aab3f | 2022-09-13 06:25:37 | [diff] [blame] | 849 | } |
| 850 | |
Andrey Kosyakov | 6e82c3b | 2022-09-26 22:43:46 | [diff] [blame] | 851 | auto prerender_host_it = |
| 852 | prerender_host_by_frame_tree_node_id_.find(frame_tree_node_id); |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 853 | CHECK(prerender_host_it != prerender_host_by_frame_tree_node_id_.end()); |
Andrey Kosyakov | 6e82c3b | 2022-09-26 22:43:46 | [diff] [blame] | 854 | PrerenderHost& prerender_host = *prerender_host_it->second; |
| 855 | devtools_instrumentation::WillInitiatePrerender( |
| 856 | prerender_host.GetPrerenderFrameTree()); |
| 857 | if (!prerender_host.StartPrerendering()) { |
Yoshiki Tanioka | 49b4cfb | 2022-10-20 09:25:31 | [diff] [blame] | 858 | CancelHost(frame_tree_node_id, PrerenderFinalStatus::kStartFailed); |
Joel Hockey | e7e03ca7 | 2022-09-08 07:35:24 | [diff] [blame] | 859 | return RenderFrameHost::kNoFrameTreeNodeId; |
Harkiran Bolaria | ba823e4 | 2021-05-21 18:30:36 | [diff] [blame] | 860 | } |
Lingqi Chi | 0a5636f | 2021-01-26 07:47:25 | [diff] [blame] | 861 | |
Yoshiki Tanioka | 87aab3f | 2022-09-13 06:25:37 | [diff] [blame] | 862 | switch (prerender_host_by_frame_tree_node_id_[frame_tree_node_id] |
| 863 | ->trigger_type()) { |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 864 | case PreloadingTriggerType::kSpeculationRule: |
| 865 | case PreloadingTriggerType::kSpeculationRuleFromIsolatedWorld: |
Taiyo Mizuhashi | 31bcb199 | 2023-04-27 05:03:03 | [diff] [blame] | 866 | // Check the current memory usage and destroy a prerendering if the entire |
| 867 | // browser uses excessive memory. This occurs asynchronously. |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 868 | DestroyWhenUsingExcessiveMemory(frame_tree_node_id); |
Taiyo Mizuhashi | 31bcb199 | 2023-04-27 05:03:03 | [diff] [blame] | 869 | |
| 870 | // Update the `running_prerender_host_id` to the starting prerender's id. |
| 871 | running_prerender_host_id_ = frame_tree_node_id; |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 872 | break; |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 873 | case PreloadingTriggerType::kEmbedder: |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 874 | // We don't check the memory usage for embedder triggered prerenderings |
| 875 | // for now. |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 876 | |
Taiyo Mizuhashi | 31bcb199 | 2023-04-27 05:03:03 | [diff] [blame] | 877 | // `running_prerender_host_id` only tracks the id for speculation rules |
| 878 | // trigger, so we also don't update it in the case of embedder. |
| 879 | break; |
Yoshiki Tanioka | ac78c70f | 2022-09-20 01:28:29 | [diff] [blame] | 880 | } |
| 881 | |
Yoshiki Tanioka | 87aab3f | 2022-09-13 06:25:37 | [diff] [blame] | 882 | RecordPrerenderTriggered( |
| 883 | prerender_host_by_frame_tree_node_id_[frame_tree_node_id] |
| 884 | ->initiator_ukm_id()); |
Joel Hockey | e7e03ca7 | 2022-09-08 07:35:24 | [diff] [blame] | 885 | return frame_tree_node_id; |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [diff] [blame] | 886 | } |
| 887 | |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 888 | std::set<int> PrerenderHostRegistry::CancelHosts( |
Yoshiki Tanioka | 12e6006 | 2022-10-05 08:13:55 | [diff] [blame] | 889 | const std::vector<int>& frame_tree_node_ids, |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 890 | const PrerenderCancellationReason& reason) { |
Yoshiki Tanioka | 12e6006 | 2022-10-05 08:13:55 | [diff] [blame] | 891 | TRACE_EVENT1("navigation", "PrerenderHostRegistry::CancelHosts", |
| 892 | "frame_tree_node_ids", frame_tree_node_ids); |
| 893 | |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 894 | // Cancel must not be requested during activation. |
| 895 | CHECK(!reserved_prerender_host_); |
Yoshiki Tanioka | 12e6006 | 2022-10-05 08:13:55 | [diff] [blame] | 896 | |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 897 | std::set<int> cancelled_ids; |
| 898 | |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 899 | for (int host_id : frame_tree_node_ids) { |
Yoshiki Tanioka | 12e6006 | 2022-10-05 08:13:55 | [diff] [blame] | 900 | // Look up the id in the non-reserved host map. |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 901 | if (auto iter = prerender_host_by_frame_tree_node_id_.find(host_id); |
| 902 | iter != prerender_host_by_frame_tree_node_id_.end()) { |
| 903 | if (running_prerender_host_id_ == host_id) |
| 904 | running_prerender_host_id_ = RenderFrameHost::kNoFrameTreeNodeId; |
Yoshiki Tanioka | 12e6006 | 2022-10-05 08:13:55 | [diff] [blame] | 905 | |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 906 | // Remove the prerender host from the host map so that it's not used for |
| 907 | // activation during asynchronous deletion. |
| 908 | std::unique_ptr<PrerenderHost> prerender_host = std::move(iter->second); |
| 909 | prerender_host_by_frame_tree_node_id_.erase(iter); |
Yoshiki Tanioka | 12e6006 | 2022-10-05 08:13:55 | [diff] [blame] | 910 | |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 911 | reason.ReportMetrics(prerender_host->trigger_type(), |
| 912 | prerender_host->embedder_histogram_suffix()); |
| 913 | |
Taiyo Mizuhashi | 5694b82 | 2023-09-26 16:10:30 | [diff] [blame] | 914 | NotifyCancel(prerender_host->frame_tree_node_id(), reason); |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 915 | |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 916 | // Asynchronously delete the prerender host. |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 917 | ScheduleToDeleteAbandonedHost(std::move(prerender_host), reason); |
| 918 | cancelled_ids.insert(host_id); |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 919 | } |
Yoshiki Tanioka | 12e6006 | 2022-10-05 08:13:55 | [diff] [blame] | 920 | |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 921 | if (base::FeatureList::IsEnabled(blink::features::kPrerender2InNewTab)) { |
| 922 | // Look up the id in the prerender-in-new-tab handle map. |
| 923 | if (auto iter = |
| 924 | prerender_new_tab_handle_by_frame_tree_node_id_.find(host_id); |
| 925 | iter != prerender_new_tab_handle_by_frame_tree_node_id_.end()) { |
| 926 | // The host should be driven by PrerenderHostRegistry associated with |
| 927 | // the new tab. |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 928 | CHECK_NE(running_prerender_host_id_, host_id); |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 929 | |
| 930 | std::unique_ptr<PrerenderNewTabHandle> handle = std::move(iter->second); |
| 931 | prerender_new_tab_handle_by_frame_tree_node_id_.erase(iter); |
Taiyo Mizuhashi | 1ef962b1 | 2023-10-31 08:10:10 | [diff] [blame] | 932 | NotifyCancel(host_id, reason); |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 933 | handle->CancelPrerendering(reason); |
| 934 | cancelled_ids.insert(host_id); |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 935 | } |
| 936 | } else { |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 937 | CHECK(prerender_new_tab_handle_by_frame_tree_node_id_.empty()); |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 938 | } |
Yoshiki Tanioka | 12e6006 | 2022-10-05 08:13:55 | [diff] [blame] | 939 | } |
| 940 | |
| 941 | // Start another prerender if the running prerender is cancelled. |
Taiyo Mizuhashi | 31bcb199 | 2023-04-27 05:03:03 | [diff] [blame] | 942 | if (running_prerender_host_id_ == RenderFrameHost::kNoFrameTreeNodeId) { |
Yoshiki Tanioka | 12e6006 | 2022-10-05 08:13:55 | [diff] [blame] | 943 | StartPrerendering(RenderFrameHost::kNoFrameTreeNodeId); |
| 944 | } |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 945 | |
| 946 | return cancelled_ids; |
Yoshiki Tanioka | 12e6006 | 2022-10-05 08:13:55 | [diff] [blame] | 947 | } |
| 948 | |
Yoshiki Tanioka | 49b4cfb | 2022-10-20 09:25:31 | [diff] [blame] | 949 | bool PrerenderHostRegistry::CancelHost(int frame_tree_node_id, |
| 950 | PrerenderFinalStatus final_status) { |
Lingqi Chi | 8e192ba | 2022-11-22 04:34:25 | [diff] [blame] | 951 | return CancelHost(frame_tree_node_id, |
| 952 | PrerenderCancellationReason(final_status)); |
| 953 | } |
| 954 | |
| 955 | bool PrerenderHostRegistry::CancelHost( |
| 956 | int frame_tree_node_id, |
| 957 | const PrerenderCancellationReason& reason) { |
Hiroki Nakagawa | ec54daf | 2021-06-08 06:12:31 | [diff] [blame] | 958 | TRACE_EVENT1("navigation", "PrerenderHostRegistry::CancelHost", |
Hiroki Nakagawa | 9ba6669 | 2021-03-09 07:26:55 | [diff] [blame] | 959 | "frame_tree_node_id", frame_tree_node_id); |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 960 | std::set<int> cancelled_ids = CancelHosts({frame_tree_node_id}, reason); |
| 961 | return !cancelled_ids.empty(); |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 962 | } |
Hiroki Nakagawa | a177830 | 2021-06-29 08:44:37 | [diff] [blame] | 963 | |
Takashi Toyoshima | 43dcf431 | 2023-04-21 09:33:05 | [diff] [blame] | 964 | void PrerenderHostRegistry::CancelHostsForTriggers( |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 965 | std::vector<PreloadingTriggerType> trigger_types, |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 966 | const PrerenderCancellationReason& reason) { |
Asami Doi | 714d434 | 2022-12-07 08:28:05 | [diff] [blame] | 967 | TRACE_EVENT1("navigation", "PrerenderHostRegistry::CancelHostsForTrigger", |
Takashi Toyoshima | 43dcf431 | 2023-04-21 09:33:05 | [diff] [blame] | 968 | "trigger_type", trigger_types[0]); |
Asami Doi | 714d434 | 2022-12-07 08:28:05 | [diff] [blame] | 969 | |
| 970 | std::vector<int> ids_to_be_deleted; |
| 971 | |
| 972 | for (auto& iter : prerender_host_by_frame_tree_node_id_) { |
Takashi Toyoshima | 43dcf431 | 2023-04-21 09:33:05 | [diff] [blame] | 973 | if (base::Contains(trigger_types, iter.second->trigger_type())) { |
Asami Doi | 714d434 | 2022-12-07 08:28:05 | [diff] [blame] | 974 | ids_to_be_deleted.push_back(iter.first); |
| 975 | } |
| 976 | } |
Asami Doi | 714d434 | 2022-12-07 08:28:05 | [diff] [blame] | 977 | if (base::FeatureList::IsEnabled(blink::features::kPrerender2InNewTab)) { |
Takashi Toyoshima | 43dcf431 | 2023-04-21 09:33:05 | [diff] [blame] | 978 | for (auto& iter : prerender_new_tab_handle_by_frame_tree_node_id_) { |
| 979 | if (base::Contains(trigger_types, iter.second->trigger_type())) { |
| 980 | // Prerendering into a new tab can be triggered by speculation rules |
| 981 | // only. |
| 982 | CHECK(IsSpeculationRuleType(iter.second->trigger_type())); |
| 983 | ids_to_be_deleted.push_back(iter.first); |
| 984 | } |
Asami Doi | 714d434 | 2022-12-07 08:28:05 | [diff] [blame] | 985 | } |
| 986 | } else { |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 987 | CHECK(prerender_new_tab_handle_by_frame_tree_node_id_.empty()); |
Asami Doi | 714d434 | 2022-12-07 08:28:05 | [diff] [blame] | 988 | } |
| 989 | |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 990 | CancelHosts(ids_to_be_deleted, reason); |
Asami Doi | 714d434 | 2022-12-07 08:28:05 | [diff] [blame] | 991 | } |
| 992 | |
Yoshiki Tanioka | 49b4cfb | 2022-10-20 09:25:31 | [diff] [blame] | 993 | void PrerenderHostRegistry::CancelAllHosts(PrerenderFinalStatus final_status) { |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 994 | // Cancel must not be requested during activation. |
| 995 | CHECK(!reserved_prerender_host_); |
Takashi Toyoshima | dc3f747 | 2021-07-21 08:02:32 | [diff] [blame] | 996 | |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 997 | PrerenderCancellationReason reason(final_status); |
| 998 | |
Takashi Toyoshima | dc3f747 | 2021-07-21 08:02:32 | [diff] [blame] | 999 | auto prerender_host_map = std::move(prerender_host_by_frame_tree_node_id_); |
| 1000 | for (auto& iter : prerender_host_map) { |
| 1001 | std::unique_ptr<PrerenderHost> prerender_host = std::move(iter.second); |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 1002 | ScheduleToDeleteAbandonedHost(std::move(prerender_host), reason); |
Takashi Toyoshima | dc3f747 | 2021-07-21 08:02:32 | [diff] [blame] | 1003 | } |
Yoshiki Tanioka | 87aab3f | 2022-09-13 06:25:37 | [diff] [blame] | 1004 | |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 1005 | if (base::FeatureList::IsEnabled(blink::features::kPrerender2InNewTab)) { |
| 1006 | auto prerender_new_tab_handle_map = |
| 1007 | std::move(prerender_new_tab_handle_by_frame_tree_node_id_); |
| 1008 | for (auto& iter : prerender_new_tab_handle_map) |
| 1009 | iter.second->CancelPrerendering(reason); |
| 1010 | } else { |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 1011 | CHECK(prerender_new_tab_handle_by_frame_tree_node_id_.empty()); |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 1012 | } |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 1013 | |
Yoshiki Tanioka | 07915d8 | 2022-09-15 06:07:51 | [diff] [blame] | 1014 | pending_prerenders_.clear(); |
Takashi Toyoshima | dc3f747 | 2021-07-21 08:02:32 | [diff] [blame] | 1015 | } |
| 1016 | |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1017 | int PrerenderHostRegistry::FindPotentialHostToActivate( |
| 1018 | NavigationRequest& navigation_request) { |
| 1019 | TRACE_EVENT2( |
| 1020 | "navigation", "PrerenderHostRegistry::FindPotentialHostToActivate", |
| 1021 | "navigation_url", navigation_request.GetURL().spec(), "render_frame_host", |
| 1022 | navigation_request.frame_tree_node()->current_frame_host()); |
| 1023 | return FindHostToActivateInternal(navigation_request); |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [diff] [blame] | 1024 | } |
| 1025 | |
Hiroki Nakagawa | 0064a9b | 2021-02-15 11:42:09 | [diff] [blame] | 1026 | int PrerenderHostRegistry::ReserveHostToActivate( |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1027 | NavigationRequest& navigation_request, |
| 1028 | int expected_host_id) { |
Harkiran Bolaria | ba823e4 | 2021-05-21 18:30:36 | [diff] [blame] | 1029 | RenderFrameHostImpl* render_frame_host = |
| 1030 | navigation_request.frame_tree_node()->current_frame_host(); |
Hiroki Nakagawa | 0064a9b | 2021-02-15 11:42:09 | [diff] [blame] | 1031 | TRACE_EVENT2("navigation", "PrerenderHostRegistry::ReserveHostToActivate", |
Harkiran Bolaria | ba823e4 | 2021-05-21 18:30:36 | [diff] [blame] | 1032 | "navigation_url", navigation_request.GetURL().spec(), |
| 1033 | "render_frame_host", render_frame_host); |
Lingqi Chi | 22f3c2d | 2023-04-27 15:55:50 | [diff] [blame] | 1034 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
Hiroki Nakagawa | eec217f | 2020-12-09 08:41:13 | [diff] [blame] | 1035 | |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1036 | // Find an available host for the navigation request. |
| 1037 | int host_id = FindHostToActivateInternal(navigation_request); |
| 1038 | if (host_id == RenderFrameHost::kNoFrameTreeNodeId) |
Hiroki Nakagawa | 0064a9b | 2021-02-15 11:42:09 | [diff] [blame] | 1039 | return RenderFrameHost::kNoFrameTreeNodeId; |
Hiroki Nakagawa | 040a214 | 2021-01-13 16:43:51 | [diff] [blame] | 1040 | |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1041 | // Check if the host is what the NavigationRequest expects. The host can be |
| 1042 | // different when a trigger page removes the existing prerender and then |
| 1043 | // re-adds a new prerender for the same URL. |
| 1044 | // |
| 1045 | // NavigationRequest makes sure that the prerender is ready for activation by |
| 1046 | // waiting for PrerenderCommitDeferringCondition before this point. Without |
| 1047 | // this check, if the prerender is changed during the period, |
| 1048 | // NavigationRequest may attempt to activate the new prerender that is not |
| 1049 | // ready. |
| 1050 | if (host_id != expected_host_id) |
Hiroki Nakagawa | 0064a9b | 2021-02-15 11:42:09 | [diff] [blame] | 1051 | return RenderFrameHost::kNoFrameTreeNodeId; |
Hiroki Nakagawa | eec217f | 2020-12-09 08:41:13 | [diff] [blame] | 1052 | |
Asami Doi | 3965173 | 2023-01-31 05:25:26 | [diff] [blame] | 1053 | // Disallow activation when ongoing navigations exist. It can happen when the |
| 1054 | // main frame navigation starts after PrerenderCommitDeferringCondition posts |
| 1055 | // a task to resume activation and before the activation is completed. |
| 1056 | auto& prerender_frame_tree = prerender_host_by_frame_tree_node_id_[host_id] |
| 1057 | .get() |
| 1058 | ->GetPrerenderFrameTree(); |
| 1059 | if (prerender_frame_tree.root()->HasNavigation()) { |
| 1060 | CancelHost(host_id, |
| 1061 | PrerenderFinalStatus::kActivatedDuringMainFrameNavigation); |
| 1062 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 1063 | } |
| 1064 | |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1065 | // Remove the host from the map of non-reserved hosts. |
| 1066 | std::unique_ptr<PrerenderHost> host = |
| 1067 | std::move(prerender_host_by_frame_tree_node_id_[host_id]); |
| 1068 | prerender_host_by_frame_tree_node_id_.erase(host_id); |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 1069 | CHECK_EQ(host_id, host->frame_tree_node_id()); |
Harkiran Bolaria | ba823e4 | 2021-05-21 18:30:36 | [diff] [blame] | 1070 | |
Hiroki Nakagawa | 0064a9b | 2021-02-15 11:42:09 | [diff] [blame] | 1071 | // Reserve the host for activation. |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 1072 | CHECK(!reserved_prerender_host_); |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 1073 | reserved_prerender_host_ = std::move(host); |
Hiroki Nakagawa | 0064a9b | 2021-02-15 11:42:09 | [diff] [blame] | 1074 | |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1075 | return host_id; |
Hiroki Nakagawa | 0064a9b | 2021-02-15 11:42:09 | [diff] [blame] | 1076 | } |
| 1077 | |
Harkiran Bolaria | 59290d6 | 2021-03-17 01:53:01 | [diff] [blame] | 1078 | RenderFrameHostImpl* PrerenderHostRegistry::GetRenderFrameHostForReservedHost( |
| 1079 | int frame_tree_node_id) { |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 1080 | if (!reserved_prerender_host_) |
Harkiran Bolaria | 59290d6 | 2021-03-17 01:53:01 | [diff] [blame] | 1081 | return nullptr; |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 1082 | |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 1083 | CHECK_EQ(frame_tree_node_id, reserved_prerender_host_->frame_tree_node_id()); |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 1084 | |
| 1085 | return reserved_prerender_host_->GetPrerenderedMainFrameHost(); |
Harkiran Bolaria | 59290d6 | 2021-03-17 01:53:01 | [diff] [blame] | 1086 | } |
| 1087 | |
Yuzu Saijo | 68390b99 | 2021-07-27 06:17:20 | [diff] [blame] | 1088 | std::unique_ptr<StoredPage> PrerenderHostRegistry::ActivateReservedHost( |
Harkiran Bolaria | 59290d6 | 2021-03-17 01:53:01 | [diff] [blame] | 1089 | int frame_tree_node_id, |
Harkiran Bolaria | 59290d6 | 2021-03-17 01:53:01 | [diff] [blame] | 1090 | NavigationRequest& navigation_request) { |
Lingqi Chi | 22f3c2d | 2023-04-27 15:55:50 | [diff] [blame] | 1091 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 1092 | CHECK(reserved_prerender_host_); |
| 1093 | CHECK_EQ(frame_tree_node_id, reserved_prerender_host_->frame_tree_node_id()); |
| 1094 | |
| 1095 | std::unique_ptr<PrerenderHost> prerender_host = |
| 1096 | std::move(reserved_prerender_host_); |
Hiroki Nakagawa | df55bac | 2021-04-26 06:56:57 | [diff] [blame] | 1097 | return prerender_host->Activate(navigation_request); |
Hiroki Nakagawa | 0064a9b | 2021-02-15 11:42:09 | [diff] [blame] | 1098 | } |
| 1099 | |
Hiroki Nakagawa | ec54daf | 2021-06-08 06:12:31 | [diff] [blame] | 1100 | void PrerenderHostRegistry::OnActivationFinished(int frame_tree_node_id) { |
| 1101 | // OnActivationFinished() should not be called for non-reserved hosts. |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 1102 | CHECK(!base::Contains(prerender_host_by_frame_tree_node_id_, |
| 1103 | frame_tree_node_id)); |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 1104 | |
lingqi | 8a71823 | 2022-12-21 03:58:51 | [diff] [blame] | 1105 | if (!reserved_prerender_host_) { |
| 1106 | // The activation finished successfully and has already activated the |
| 1107 | // reserved host. |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 1108 | return; |
lingqi | 8a71823 | 2022-12-21 03:58:51 | [diff] [blame] | 1109 | } |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 1110 | |
lingqi | 8a71823 | 2022-12-21 03:58:51 | [diff] [blame] | 1111 | // The activation navigation is cancelled before activating the prerendered |
| 1112 | // page, which means the activation failed. |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 1113 | CHECK_EQ(frame_tree_node_id, reserved_prerender_host_->frame_tree_node_id()); |
lingqi | 8a71823 | 2022-12-21 03:58:51 | [diff] [blame] | 1114 | |
| 1115 | // TODO(https://crbug.com/1378151): Monitor the final status metric and see |
| 1116 | // whether it could be possible. |
| 1117 | ScheduleToDeleteAbandonedHost( |
| 1118 | std::move(reserved_prerender_host_), |
| 1119 | PrerenderCancellationReason( |
| 1120 | PrerenderFinalStatus::kActivationNavigationDestroyedBeforeSuccess)); |
Hiroki Nakagawa | 5034e196 | 2020-11-12 09:11:30 | [diff] [blame] | 1121 | } |
| 1122 | |
Matt Falkenhagen | 21ee4f8 | 2021-04-13 08:14:28 | [diff] [blame] | 1123 | PrerenderHost* PrerenderHostRegistry::FindNonReservedHostById( |
| 1124 | int frame_tree_node_id) { |
Hiroki Nakagawa | 9ba6669 | 2021-03-09 07:26:55 | [diff] [blame] | 1125 | auto id_iter = prerender_host_by_frame_tree_node_id_.find(frame_tree_node_id); |
| 1126 | if (id_iter == prerender_host_by_frame_tree_node_id_.end()) |
| 1127 | return nullptr; |
| 1128 | return id_iter->second.get(); |
| 1129 | } |
| 1130 | |
Hiroki Nakagawa | da88a82 | 2023-11-13 02:39:24 | [diff] [blame^] | 1131 | bool PrerenderHostRegistry::HasReservedHost() const { |
| 1132 | return !!reserved_prerender_host_; |
Matt Falkenhagen | 21ee4f8 | 2021-04-13 08:14:28 | [diff] [blame] | 1133 | } |
| 1134 | |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 1135 | std::unique_ptr<WebContentsImpl> |
| 1136 | PrerenderHostRegistry::TakePreCreatedWebContentsForNewTabIfExists( |
| 1137 | const mojom::CreateNewWindowParams& create_new_window_params, |
| 1138 | const WebContents::CreateParams& web_contents_create_params) { |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 1139 | CHECK(base::FeatureList::IsEnabled(blink::features::kPrerender2InNewTab)); |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 1140 | |
| 1141 | // Don't serve a prerendered page if the window needs the opener or is created |
| 1142 | // for non-regular navigations. |
| 1143 | if (!create_new_window_params.opener_suppressed || |
| 1144 | create_new_window_params.is_form_submission || |
| 1145 | create_new_window_params.pip_options) { |
| 1146 | return nullptr; |
| 1147 | } |
| 1148 | |
| 1149 | for (auto& iter : prerender_new_tab_handle_by_frame_tree_node_id_) { |
| 1150 | std::unique_ptr<WebContentsImpl> web_contents = |
| 1151 | iter.second->TakeWebContentsIfAvailable(create_new_window_params, |
| 1152 | web_contents_create_params); |
| 1153 | if (web_contents) { |
| 1154 | prerender_new_tab_handle_by_frame_tree_node_id_.erase(iter); |
| 1155 | return web_contents; |
| 1156 | } |
| 1157 | } |
| 1158 | return nullptr; |
| 1159 | } |
| 1160 | |
Kevin McNee | 53f0b2d | 2021-11-02 18:00:45 | [diff] [blame] | 1161 | std::vector<FrameTree*> PrerenderHostRegistry::GetPrerenderFrameTrees() { |
| 1162 | std::vector<FrameTree*> result; |
Kevin McNee | c9d0fda | 2021-05-19 15:55:17 | [diff] [blame] | 1163 | for (auto& i : prerender_host_by_frame_tree_node_id_) { |
Kevin McNee | 53f0b2d | 2021-11-02 18:00:45 | [diff] [blame] | 1164 | result.push_back(&i.second->GetPrerenderFrameTree()); |
Kevin McNee | c9d0fda | 2021-05-19 15:55:17 | [diff] [blame] | 1165 | } |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 1166 | if (reserved_prerender_host_) |
| 1167 | result.push_back(&reserved_prerender_host_->GetPrerenderFrameTree()); |
| 1168 | |
Kevin McNee | c9d0fda | 2021-05-19 15:55:17 | [diff] [blame] | 1169 | return result; |
| 1170 | } |
| 1171 | |
Hiroki Nakagawa | 5034e196 | 2020-11-12 09:11:30 | [diff] [blame] | 1172 | PrerenderHost* PrerenderHostRegistry::FindHostByUrlForTesting( |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [diff] [blame] | 1173 | const GURL& prerendering_url) { |
Hiroki Nakagawa | eb39fce | 2021-05-20 05:38:23 | [diff] [blame] | 1174 | for (auto& iter : prerender_host_by_frame_tree_node_id_) { |
Hiroki Nakagawa | ae141ca | 2023-10-19 06:01:24 | [diff] [blame] | 1175 | if (iter.second->IsUrlMatch(prerendering_url)) { |
Hiroki Nakagawa | eb39fce | 2021-05-20 05:38:23 | [diff] [blame] | 1176 | return iter.second.get(); |
Hiroki Nakagawa | ae141ca | 2023-10-19 06:01:24 | [diff] [blame] | 1177 | } |
Hiroki Nakagawa | eb39fce | 2021-05-20 05:38:23 | [diff] [blame] | 1178 | } |
Hiroki Nakagawa | eb39fce | 2021-05-20 05:38:23 | [diff] [blame] | 1179 | return nullptr; |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [diff] [blame] | 1180 | } |
| 1181 | |
Dominique Fauteux-Chapleau | 3e8d345 | 2021-07-14 17:20:02 | [diff] [blame] | 1182 | void PrerenderHostRegistry::CancelAllHostsForTesting() { |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 1183 | CHECK(!reserved_prerender_host_) |
Yoshiki Tanioka | 75decd9 | 2022-10-26 12:23:06 | [diff] [blame] | 1184 | << "It is not possible to cancel a reserved host, so they must not exist " |
Dominique Fauteux-Chapleau | 3e8d345 | 2021-07-14 17:20:02 | [diff] [blame] | 1185 | "when trying to cancel all hosts"; |
| 1186 | |
| 1187 | for (auto& iter : prerender_host_by_frame_tree_node_id_) { |
| 1188 | // Asynchronously delete the prerender host. |
| 1189 | ScheduleToDeleteAbandonedHost( |
| 1190 | std::move(iter.second), |
Lingqi Chi | 20b3fd84 | 2022-11-24 05:29:11 | [diff] [blame] | 1191 | PrerenderCancellationReason( |
| 1192 | PrerenderFinalStatus::kCancelAllHostsForTesting)); |
Dominique Fauteux-Chapleau | 3e8d345 | 2021-07-14 17:20:02 | [diff] [blame] | 1193 | } |
Yoshiki Tanioka | 87aab3f | 2022-09-13 06:25:37 | [diff] [blame] | 1194 | |
Yoshiki Tanioka | 07915d8 | 2022-09-15 06:07:51 | [diff] [blame] | 1195 | // After we're done scheduling deletion, clear the map and the pending queue. |
| 1196 | prerender_host_by_frame_tree_node_id_.clear(); |
| 1197 | pending_prerenders_.clear(); |
Dominique Fauteux-Chapleau | 3e8d345 | 2021-07-14 17:20:02 | [diff] [blame] | 1198 | } |
| 1199 | |
Kevin McNee | 097680d | 2023-04-05 22:14:51 | [diff] [blame] | 1200 | void PrerenderHostRegistry::BackNavigationLikely( |
| 1201 | PreloadingPredictor predictor) { |
| 1202 | if (http_cache_query_loader_) { |
| 1203 | return; |
| 1204 | } |
| 1205 | |
| 1206 | PreloadingData* preloading_data = |
| 1207 | PreloadingData::GetOrCreateForWebContents(web_contents()); |
| 1208 | preloading_data->SetIsNavigationInDomainCallback( |
| 1209 | predictor, |
| 1210 | base::BindRepeating(IsNavigationInSessionHistoryPredictorDomain)); |
| 1211 | |
| 1212 | WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents()); |
| 1213 | NavigationControllerImpl& controller = contents->GetController(); |
| 1214 | const absl::optional<int> target_index = controller.GetIndexForGoBack(); |
| 1215 | |
| 1216 | if (!target_index.has_value()) { |
| 1217 | RecordPrerenderBackNavigationEligibility( |
| 1218 | predictor, PrerenderBackNavigationEligibility::kNoBackEntry, nullptr); |
| 1219 | return; |
| 1220 | } |
| 1221 | |
| 1222 | NavigationEntryImpl* back_entry = controller.GetEntryAtIndex(*target_index); |
| 1223 | CHECK(back_entry); |
| 1224 | const GURL& back_url = back_entry->GetURL(); |
| 1225 | |
Mingyu Lei | 7584b6b | 2023-04-13 03:02:56 | [diff] [blame] | 1226 | if (controller.GetBackForwardCache() |
| 1227 | .GetOrEvictEntry(back_entry->GetUniqueID()) |
| 1228 | .has_value()) { |
Kevin McNee | 097680d | 2023-04-05 22:14:51 | [diff] [blame] | 1229 | RecordPrerenderBackNavigationEligibility( |
| 1230 | predictor, PrerenderBackNavigationEligibility::kBfcacheEntryExists, |
| 1231 | nullptr); |
| 1232 | return; |
| 1233 | } |
| 1234 | |
| 1235 | PreloadingURLMatchCallback same_url_matcher = |
| 1236 | PreloadingData::GetSameURLMatcher(back_url); |
| 1237 | preloading_data->AddPreloadingPrediction(predictor, /*confidence=*/100, |
| 1238 | same_url_matcher); |
| 1239 | PreloadingAttempt* attempt = preloading_data->AddPreloadingAttempt( |
Hiroki Nakagawa | f93776b | 2023-09-12 22:04:27 | [diff] [blame] | 1240 | predictor, PreloadingType::kPrerender, same_url_matcher, |
| 1241 | web_contents()->GetPrimaryMainFrame()->GetPageUkmSourceId()); |
Kevin McNee | 097680d | 2023-04-05 22:14:51 | [diff] [blame] | 1242 | |
| 1243 | if (back_entry->GetMainFrameDocumentSequenceNumber() == |
| 1244 | controller.GetLastCommittedEntry() |
| 1245 | ->GetMainFrameDocumentSequenceNumber()) { |
| 1246 | RecordPrerenderBackNavigationEligibility( |
| 1247 | predictor, PrerenderBackNavigationEligibility::kTargetIsSameDocument, |
| 1248 | attempt); |
| 1249 | return; |
| 1250 | } |
| 1251 | |
| 1252 | if (back_entry->root_node()->frame_entry->method() != "GET") { |
| 1253 | RecordPrerenderBackNavigationEligibility( |
| 1254 | predictor, PrerenderBackNavigationEligibility::kMethodNotGet, attempt); |
| 1255 | return; |
| 1256 | } |
| 1257 | |
| 1258 | if (prerender_navigation_utils::IsDisallowedHttpResponseCode( |
| 1259 | back_entry->GetHttpStatusCode())) { |
| 1260 | RecordPrerenderBackNavigationEligibility( |
| 1261 | predictor, |
| 1262 | PrerenderBackNavigationEligibility::kTargetIsFailedNavigation, attempt); |
| 1263 | return; |
| 1264 | } |
| 1265 | |
| 1266 | if (!back_url.SchemeIsHTTPOrHTTPS()) { |
| 1267 | RecordPrerenderBackNavigationEligibility( |
| 1268 | predictor, PrerenderBackNavigationEligibility::kTargetIsNonHttp, |
| 1269 | attempt); |
| 1270 | return; |
| 1271 | } |
| 1272 | |
| 1273 | // While same site back navigations could potentially be prerendered, doing so |
| 1274 | // would involve more significant compat risk. For now, we consider them |
| 1275 | // ineligible. See https://crbug.com/1422266 . |
| 1276 | if (prerender_navigation_utils::IsSameSite( |
| 1277 | back_url, |
| 1278 | contents->GetPrimaryMainFrame()->GetLastCommittedOrigin())) { |
| 1279 | RecordPrerenderBackNavigationEligibility( |
| 1280 | predictor, PrerenderBackNavigationEligibility::kTargetIsSameSite, |
| 1281 | attempt); |
| 1282 | return; |
| 1283 | } |
| 1284 | |
Kevin McNee | 8bad63f | 2023-08-23 21:19:37 | [diff] [blame] | 1285 | // Session history prerendering will reuse the back navigation entry's |
| 1286 | // existing SiteInstance. We can't have a prerendered document share a |
| 1287 | // SiteInstance with related active content (i.e. an active document with the |
| 1288 | // same BrowsingInstance) as that would risk having scripting connections to |
| 1289 | // prerendered documents. So this case is not eligible for prerendering. |
| 1290 | SiteInstanceImpl* entry_site_instance = back_entry->site_instance(); |
| 1291 | // `entry_site_instance` could be null in cases such as session restore. |
| 1292 | if (entry_site_instance) { |
| 1293 | const bool current_and_target_related = |
| 1294 | contents->GetSiteInstance()->IsRelatedSiteInstance(entry_site_instance); |
| 1295 | const size_t allowable_related_count = current_and_target_related ? 1u : 0u; |
| 1296 | if (entry_site_instance->GetRelatedActiveContentsCount() > |
| 1297 | allowable_related_count) { |
| 1298 | RecordPrerenderBackNavigationEligibility( |
| 1299 | predictor, PrerenderBackNavigationEligibility::kRelatedActiveContents, |
| 1300 | attempt); |
| 1301 | return; |
| 1302 | } |
| 1303 | } |
| 1304 | |
Kevin McNee | 097680d | 2023-04-05 22:14:51 | [diff] [blame] | 1305 | // To determine whether the resource for the target entry is in the HTTP |
| 1306 | // cache, we send a "fake" ResourceRequest which only loads from the cache. |
| 1307 | scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory = |
| 1308 | contents->GetPrimaryMainFrame() |
| 1309 | ->GetStoragePartition() |
| 1310 | ->GetURLLoaderFactoryForBrowserProcess(); |
| 1311 | http_cache_query_loader_ = CreateHttpCacheQueryingResourceLoad(back_url); |
| 1312 | http_cache_query_loader_->DownloadHeadersOnly( |
| 1313 | url_loader_factory.get(), |
| 1314 | base::BindOnce(&PrerenderHostRegistry::OnBackResourceCacheResult, |
| 1315 | base::Unretained(this), predictor, attempt->GetWeakPtr(), |
| 1316 | back_url)); |
| 1317 | } |
| 1318 | |
| 1319 | void PrerenderHostRegistry::OnBackResourceCacheResult( |
| 1320 | PreloadingPredictor predictor, |
| 1321 | base::WeakPtr<PreloadingAttempt> attempt, |
| 1322 | GURL back_url, |
| 1323 | scoped_refptr<net::HttpResponseHeaders> headers) { |
| 1324 | // It's safe to delete the SimpleURLLoader while running the callback that was |
| 1325 | // passed to it. We do so once we're done with it in this method. |
| 1326 | std::unique_ptr<network::SimpleURLLoader> http_cache_query_loader = |
| 1327 | std::move(http_cache_query_loader_); |
| 1328 | |
| 1329 | if (!http_cache_query_loader->LoadedFromCache()) { |
| 1330 | // If not in the cache, then this cache-only request must have failed. |
| 1331 | CHECK_NE(http_cache_query_loader->NetError(), net::OK); |
| 1332 | |
| 1333 | RecordPrerenderBackNavigationEligibility( |
| 1334 | predictor, PrerenderBackNavigationEligibility::kNoHttpCacheEntry, |
| 1335 | attempt.get()); |
| 1336 | return; |
| 1337 | } |
| 1338 | |
| 1339 | RecordPrerenderBackNavigationEligibility( |
| 1340 | predictor, PrerenderBackNavigationEligibility::kEligible, attempt.get()); |
| 1341 | |
| 1342 | if (attempt) { |
| 1343 | attempt->SetHoldbackStatus(PreloadingHoldbackStatus::kAllowed); |
| 1344 | // At this point, we are only collecting metrics and not actually |
| 1345 | // prerendering anything. |
| 1346 | attempt->SetTriggeringOutcome(PreloadingTriggeringOutcome::kNoOp); |
| 1347 | } |
| 1348 | } |
| 1349 | |
Lingqi Chi | 35549e9 | 2021-06-22 02:36:13 | [diff] [blame] | 1350 | base::WeakPtr<PrerenderHostRegistry> PrerenderHostRegistry::GetWeakPtr() { |
| 1351 | return weak_factory_.GetWeakPtr(); |
| 1352 | } |
| 1353 | |
Asami Doi | 3965173 | 2023-01-31 05:25:26 | [diff] [blame] | 1354 | void PrerenderHostRegistry::DidStartNavigation( |
| 1355 | NavigationHandle* navigation_handle) { |
| 1356 | if (!base::FeatureList::IsEnabled( |
| 1357 | blink::features::kPrerender2MainFrameNavigation)) { |
| 1358 | return; |
| 1359 | } |
| 1360 | |
| 1361 | // DidStartNavigation is used for monitoring the main frame navigation in a |
| 1362 | // prerendered page so do nothing for other navigations. |
| 1363 | auto* navigation_request = NavigationRequest::From(navigation_handle); |
| 1364 | if (!navigation_request->IsInPrerenderedMainFrame() || |
| 1365 | navigation_request->IsSameDocument()) { |
| 1366 | return; |
| 1367 | } |
| 1368 | |
Hiroki Nakagawa | 5e85b9f | 2023-04-10 07:43:44 | [diff] [blame] | 1369 | // This navigation is running on the main frame in the prerendered page, so |
| 1370 | // its FrameTree::Delegate should be PrerenderHost. |
| 1371 | auto* prerender_host = static_cast<PrerenderHost*>( |
| 1372 | navigation_request->frame_tree_node()->frame_tree().delegate()); |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 1373 | CHECK(prerender_host); |
Asami Doi | 3965173 | 2023-01-31 05:25:26 | [diff] [blame] | 1374 | |
| 1375 | prerender_host->DidStartNavigation(navigation_handle); |
| 1376 | } |
| 1377 | |
Yoshiki Tanioka | b6a6d72 | 2022-10-20 07:58:50 | [diff] [blame] | 1378 | void PrerenderHostRegistry::DidFinishNavigation( |
| 1379 | NavigationHandle* navigation_handle) { |
| 1380 | auto* navigation_request = NavigationRequest::From(navigation_handle); |
| 1381 | |
| 1382 | if (navigation_request->IsSameDocument()) |
| 1383 | return; |
| 1384 | |
| 1385 | int main_frame_host_id = navigation_request->frame_tree_node() |
| 1386 | ->frame_tree() |
Arthur Sonzogni | f6785ec | 2022-12-05 10:11:50 | [diff] [blame] | 1387 | .root() |
Yoshiki Tanioka | b6a6d72 | 2022-10-20 07:58:50 | [diff] [blame] | 1388 | ->frame_tree_node_id(); |
| 1389 | PrerenderHost* prerender_host = FindNonReservedHostById(main_frame_host_id); |
| 1390 | if (!prerender_host) |
| 1391 | return; |
| 1392 | |
| 1393 | prerender_host->DidFinishNavigation(navigation_handle); |
| 1394 | |
Taiyo Mizuhashi | 31bcb199 | 2023-04-27 05:03:03 | [diff] [blame] | 1395 | if (running_prerender_host_id_ == main_frame_host_id) { |
Yoshiki Tanioka | b6a6d72 | 2022-10-20 07:58:50 | [diff] [blame] | 1396 | running_prerender_host_id_ = RenderFrameHost::kNoFrameTreeNodeId; |
| 1397 | StartPrerendering(RenderFrameHost::kNoFrameTreeNodeId); |
| 1398 | } |
| 1399 | } |
| 1400 | |
| 1401 | void PrerenderHostRegistry::OnVisibilityChanged(Visibility visibility) { |
Hiroki Nakagawa | 937bf4f | 2023-02-28 03:26:39 | [diff] [blame] | 1402 | // Update the timer for prerendering timeout in the background. |
Hiroki Nakagawa | 98af8c4 | 2023-03-14 05:36:38 | [diff] [blame] | 1403 | if (IsBackground(visibility)) { |
| 1404 | if (timeout_timer_for_embedder_.IsRunning() || |
| 1405 | timeout_timer_for_speculation_rules_.IsRunning()) { |
| 1406 | // Keep the timers which started on a previous visibility change. |
| 1407 | return; |
| 1408 | } |
| 1409 | // Keep a prerendered page alive in the background when its visibility |
| 1410 | // state changes to HIDDEN or OCCLUDED. |
| 1411 | timeout_timer_for_embedder_.SetTaskRunner(GetTimerTaskRunner()); |
| 1412 | timeout_timer_for_speculation_rules_.SetTaskRunner(GetTimerTaskRunner()); |
Yoshiki Tanioka | 80b78fb | 2022-10-27 23:40:54 | [diff] [blame] | 1413 | |
Hiroki Nakagawa | 98af8c4 | 2023-03-14 05:36:38 | [diff] [blame] | 1414 | // Cancel PrerenderHost in the background when it exceeds a certain |
| 1415 | // amount of time. The timeout differs depending on the trigger type. |
| 1416 | timeout_timer_for_embedder_.Start( |
| 1417 | FROM_HERE, kTimeToLiveInBackgroundForEmbedder, |
Takashi Toyoshima | 43dcf431 | 2023-04-21 09:33:05 | [diff] [blame] | 1418 | base::BindOnce(&PrerenderHostRegistry::CancelHostsForTriggers, |
| 1419 | base::Unretained(this), |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 1420 | std::vector({PreloadingTriggerType::kEmbedder}), |
Hiroki Nakagawa | 98af8c4 | 2023-03-14 05:36:38 | [diff] [blame] | 1421 | PrerenderCancellationReason( |
| 1422 | PrerenderFinalStatus::kTimeoutBackgrounded))); |
| 1423 | timeout_timer_for_speculation_rules_.Start( |
| 1424 | FROM_HERE, kTimeToLiveInBackgroundForSpeculationRules, |
Takashi Toyoshima | 43dcf431 | 2023-04-21 09:33:05 | [diff] [blame] | 1425 | base::BindOnce( |
| 1426 | &PrerenderHostRegistry::CancelHostsForTriggers, |
| 1427 | base::Unretained(this), |
| 1428 | std::vector( |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 1429 | {PreloadingTriggerType::kSpeculationRule, |
| 1430 | PreloadingTriggerType::kSpeculationRuleFromIsolatedWorld}), |
Takashi Toyoshima | 43dcf431 | 2023-04-21 09:33:05 | [diff] [blame] | 1431 | PrerenderCancellationReason( |
| 1432 | PrerenderFinalStatus::kTimeoutBackgrounded))); |
Hiroki Nakagawa | 98af8c4 | 2023-03-14 05:36:38 | [diff] [blame] | 1433 | } else { |
| 1434 | // Stop the timer when a prerendered page gets visible to users. |
| 1435 | timeout_timer_for_embedder_.Stop(); |
| 1436 | timeout_timer_for_speculation_rules_.Stop(); |
Asami Doi | 714d434 | 2022-12-07 08:28:05 | [diff] [blame] | 1437 | |
Taiyo Mizuhashi | 31bcb199 | 2023-04-27 05:03:03 | [diff] [blame] | 1438 | // Start the next prerender if needed. |
| 1439 | if (running_prerender_host_id_ == RenderFrameHost::kNoFrameTreeNodeId) { |
| 1440 | StartPrerendering(RenderFrameHost::kNoFrameTreeNodeId); |
Yoshiki Tanioka | b6a6d72 | 2022-10-20 07:58:50 | [diff] [blame] | 1441 | } |
Yoshiki Tanioka | b6a6d72 | 2022-10-20 07:58:50 | [diff] [blame] | 1442 | } |
| 1443 | } |
| 1444 | |
Asami Doi | 7aaf750 | 2022-12-08 09:02:38 | [diff] [blame] | 1445 | void PrerenderHostRegistry::PrimaryMainFrameRenderProcessGone( |
| 1446 | base::TerminationStatus status) { |
Asami Doi | dac3f11 | 2023-01-18 06:31:02 | [diff] [blame] | 1447 | CancelAllHosts( |
| 1448 | status == base::TERMINATION_STATUS_PROCESS_CRASHED |
| 1449 | ? PrerenderFinalStatus::kPrimaryMainFrameRendererProcessCrashed |
| 1450 | : PrerenderFinalStatus::kPrimaryMainFrameRendererProcessKilled); |
Asami Doi | 7aaf750 | 2022-12-08 09:02:38 | [diff] [blame] | 1451 | } |
| 1452 | |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1453 | int PrerenderHostRegistry::FindHostToActivateInternal( |
| 1454 | NavigationRequest& navigation_request) { |
| 1455 | RenderFrameHostImpl* render_frame_host = |
| 1456 | navigation_request.frame_tree_node()->current_frame_host(); |
| 1457 | TRACE_EVENT2("navigation", |
| 1458 | "PrerenderHostRegistry::FindHostToActivateInternal", |
| 1459 | "navigation_url", navigation_request.GetURL().spec(), |
| 1460 | "render_frame_host", render_frame_host); |
| 1461 | |
| 1462 | // Disallow activation when the navigation is for a nested browsing context |
Tsuyoshi Horo | 22e0513 | 2021-12-01 10:57:27 | [diff] [blame] | 1463 | // (e.g., iframes, fenced frames). This is because nested browsing contexts |
| 1464 | // such as iframes are supposed to be created in the parent's browsing context |
| 1465 | // group and can script with the parent, but prerendered pages are created in |
| 1466 | // new browsing context groups. And also, we disallow activation when the |
| 1467 | // navigation is for a fenced frame to prevent the communication path from the |
| 1468 | // embedding page to the fenced frame. |
| 1469 | if (!navigation_request.IsInPrimaryMainFrame()) |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1470 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 1471 | |
| 1472 | // Disallow activation when the navigation happens in the prerendering frame |
| 1473 | // tree. |
| 1474 | if (navigation_request.IsInPrerenderedMainFrame()) |
| 1475 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 1476 | |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1477 | // Find an available host for the navigation URL. |
| 1478 | PrerenderHost* host = nullptr; |
Yoshiki Tanioka | 7e13cbcc | 2022-10-19 03:34:37 | [diff] [blame] | 1479 | for (const auto& [host_id, it_prerender_host] : |
Lingqi Chi | 21d9feb | 2022-02-02 09:42:18 | [diff] [blame] | 1480 | prerender_host_by_frame_tree_node_id_) { |
| 1481 | if (it_prerender_host->IsUrlMatch(navigation_request.GetURL())) { |
| 1482 | host = it_prerender_host.get(); |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1483 | break; |
| 1484 | } |
| 1485 | } |
| 1486 | if (!host) |
| 1487 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 1488 | |
Hiroki Nakagawa | d77864c | 2023-09-20 22:34:03 | [diff] [blame] | 1489 | // Disallow activation when the navigation URL has an effective URL like |
| 1490 | // hosted apps and NTP. |
| 1491 | if (SiteInstanceImpl::HasEffectiveURL(web_contents()->GetBrowserContext(), |
| 1492 | navigation_request.GetURL())) { |
| 1493 | CancelHost(host->frame_tree_node_id(), |
| 1494 | PrerenderFinalStatus::kActivationUrlHasEffectiveUrl); |
| 1495 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 1496 | } |
| 1497 | |
Hiroki Nakagawa | 2f42734 | 2023-07-19 23:27:04 | [diff] [blame] | 1498 | // Disallow activation when other auxiliary browsing contexts (e.g., pop-up |
| 1499 | // windows) exist in the same browsing context group. This is because these |
| 1500 | // browsing contexts should be able to script each other, but prerendered |
| 1501 | // pages are created in new browsing context groups. |
| 1502 | SiteInstance* site_instance = render_frame_host->GetSiteInstance(); |
| 1503 | if (site_instance->GetRelatedActiveContentsCount() != 1u) { |
| 1504 | CancelHost(host->frame_tree_node_id(), |
| 1505 | PrerenderFinalStatus::kActivatedWithAuxiliaryBrowsingContexts); |
| 1506 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 1507 | } |
| 1508 | |
Asami Doi | 7e33f2f | 2022-12-12 16:15:09 | [diff] [blame] | 1509 | // TODO(crbug.com/1399709): Remove the restriction after further investigation |
| 1510 | // and discussion. |
Hiroki Nakagawa | 98af8c4 | 2023-03-14 05:36:38 | [diff] [blame] | 1511 | // Disallow activation when the navigation happens in the hidden tab. |
Asami Doi | 7e33f2f | 2022-12-12 16:15:09 | [diff] [blame] | 1512 | if (web_contents()->GetVisibility() == Visibility::HIDDEN) { |
| 1513 | CancelHost(host->frame_tree_node_id(), |
| 1514 | PrerenderFinalStatus::kActivatedInBackground); |
| 1515 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 1516 | } |
| 1517 | |
Yoshiki Tanioka | 07915d8 | 2022-09-15 06:07:51 | [diff] [blame] | 1518 | if (!host->GetInitialNavigationId().has_value()) { |
Yoshiki Tanioka | 07915d8 | 2022-09-15 06:07:51 | [diff] [blame] | 1519 | CancelHost(host->frame_tree_node_id(), |
Yoshiki Tanioka | 49b4cfb | 2022-10-20 09:25:31 | [diff] [blame] | 1520 | PrerenderFinalStatus::kActivatedBeforeStarted); |
Yoshiki Tanioka | 044f6b5 | 2022-10-20 12:18:53 | [diff] [blame] | 1521 | return RenderFrameHost::kNoFrameTreeNodeId; |
Yoshiki Tanioka | 07915d8 | 2022-09-15 06:07:51 | [diff] [blame] | 1522 | } |
| 1523 | |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1524 | // Compare navigation params from activation with the navigation params |
| 1525 | // from the initial prerender navigation. If they don't match, the navigation |
| 1526 | // should not activate the prerendered page. |
Miina Koyama | 89b81504 | 2023-10-31 08:20:12 | [diff] [blame] | 1527 | if (std::unique_ptr<PrerenderMismatchedHeaders> mismatched_headers = |
| 1528 | host->CheckInitialPrerenderNavigationParamsCompatibleWithNavigation( |
| 1529 | navigation_request)) { |
Lingqi Chi | aeec5df1 | 2022-10-26 03:41:42 | [diff] [blame] | 1530 | // TODO(https://crbug.com/1328365): Report a detailed reason to devtools. |
| 1531 | // Currently users have to check |
| 1532 | // Prerender.Experimental.ActivationNavigationParamsMatch. |
| 1533 | // TODO(lingqi): We'd better cancel all hosts. |
Miina Koyama | 89b81504 | 2023-10-31 08:20:12 | [diff] [blame] | 1534 | |
| 1535 | PrerenderCancellationReason reason = PrerenderCancellationReason:: |
| 1536 | BuildForActivationNavigationParameterMismatch( |
| 1537 | std::move(mismatched_headers)); |
| 1538 | |
| 1539 | CancelHost(host->frame_tree_node_id(), reason); |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1540 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 1541 | } |
| 1542 | |
Harkiran Bolaria | 2336053 | 2021-08-12 10:27:25 | [diff] [blame] | 1543 | if (!host->IsFramePolicyCompatibleWithPrimaryFrameTree()) { |
lingqi | 6d03e42 | 2023-01-19 02:37:06 | [diff] [blame] | 1544 | CancelHost(host->frame_tree_node_id(), |
| 1545 | PrerenderFinalStatus::kActivationFramePolicyNotCompatible); |
Harkiran Bolaria | 2336053 | 2021-08-12 10:27:25 | [diff] [blame] | 1546 | return RenderFrameHost::kNoFrameTreeNodeId; |
| 1547 | } |
| 1548 | |
Yoshiki Tanioka | 7e13cbcc | 2022-10-19 03:34:37 | [diff] [blame] | 1549 | // Cancel all the other prerender hosts because we no longer need the other |
| 1550 | // hosts after we determine the host to be activated. |
| 1551 | std::vector<int> cancelled_prerenders; |
| 1552 | for (const auto& [host_id, _] : prerender_host_by_frame_tree_node_id_) { |
| 1553 | if (host_id != host->frame_tree_node_id()) { |
| 1554 | cancelled_prerenders.push_back(host_id); |
| 1555 | } |
| 1556 | } |
Hiroki Nakagawa | 640dd71 | 2022-12-08 04:05:08 | [diff] [blame] | 1557 | if (base::FeatureList::IsEnabled(blink::features::kPrerender2InNewTab)) { |
| 1558 | for (const auto& [host_id, _] : |
| 1559 | prerender_new_tab_handle_by_frame_tree_node_id_) { |
| 1560 | cancelled_prerenders.push_back(host_id); |
| 1561 | } |
| 1562 | } else { |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 1563 | CHECK(prerender_new_tab_handle_by_frame_tree_node_id_.empty()); |
Hiroki Nakagawa | 3e252704 | 2022-11-24 06:46:42 | [diff] [blame] | 1564 | } |
Samar Chehade-Lepleux | ce1baf2 | 2023-05-16 09:50:09 | [diff] [blame] | 1565 | CancelHosts( |
| 1566 | cancelled_prerenders, |
| 1567 | PrerenderCancellationReason(PrerenderFinalStatus::kTriggerDestroyed)); |
Yoshiki Tanioka | 7e13cbcc | 2022-10-19 03:34:37 | [diff] [blame] | 1568 | pending_prerenders_.clear(); |
| 1569 | |
Hiroki Nakagawa | 6c5f39bd | 2021-07-13 00:22:36 | [diff] [blame] | 1570 | return host->frame_tree_node_id(); |
| 1571 | } |
| 1572 | |
Hiroki Nakagawa | ec54daf | 2021-06-08 06:12:31 | [diff] [blame] | 1573 | void PrerenderHostRegistry::ScheduleToDeleteAbandonedHost( |
| 1574 | std::unique_ptr<PrerenderHost> prerender_host, |
Lingqi Chi | 20b3fd84 | 2022-11-24 05:29:11 | [diff] [blame] | 1575 | const PrerenderCancellationReason& cancellation_reason) { |
Lingqi Chi | 22f3c2d | 2023-04-27 15:55:50 | [diff] [blame] | 1576 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 1577 | CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) |
| 1578 | << "Post tasks to destroy PrerenderHosts on non-ui threads " |
| 1579 | "with reason of " |
| 1580 | << static_cast<int>(cancellation_reason.final_status()); |
Lingqi Chi | 20b3fd84 | 2022-11-24 05:29:11 | [diff] [blame] | 1581 | prerender_host->RecordFailedFinalStatus(PassKey(), cancellation_reason); |
Hiroki Nakagawa | ec54daf | 2021-06-08 06:12:31 | [diff] [blame] | 1582 | |
| 1583 | // Asynchronously delete the prerender host. |
| 1584 | to_be_deleted_hosts_.push_back(std::move(prerender_host)); |
Sean Maher | 52fa5a7 | 2022-11-14 15:53:25 | [diff] [blame] | 1585 | base::SequencedTaskRunner::GetCurrentDefault()->PostTask( |
Hiroki Nakagawa | ec54daf | 2021-06-08 06:12:31 | [diff] [blame] | 1586 | FROM_HERE, base::BindOnce(&PrerenderHostRegistry::DeleteAbandonedHosts, |
| 1587 | weak_factory_.GetWeakPtr())); |
| 1588 | } |
| 1589 | |
Takashi Toyoshima | 9304e84 | 2021-05-19 11:24:55 | [diff] [blame] | 1590 | void PrerenderHostRegistry::DeleteAbandonedHosts() { |
Lingqi Chi | 22f3c2d | 2023-04-27 15:55:50 | [diff] [blame] | 1591 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
Hiroki Nakagawa | e2d0e49 | 2023-05-17 05:37:28 | [diff] [blame] | 1592 | // Swap the vector and let it scope out instead of directly destructing the |
| 1593 | // hosts in the vector, for example, by `to_be_deleted_hosts_.clear()`. This |
| 1594 | // avoids potential cases where a host being deleted indirectly modifies |
| 1595 | // `to_be_deleted_hosts_` while the vector is being cleared up. See |
| 1596 | // https://crbug.com/1431744 for contexts. |
| 1597 | std::vector<std::unique_ptr<PrerenderHost>> hosts; |
| 1598 | to_be_deleted_hosts_.swap(hosts); |
Takashi Toyoshima | 9304e84 | 2021-05-19 11:24:55 | [diff] [blame] | 1599 | } |
| 1600 | |
Matt Falkenhagen | f884d0f | 2021-02-18 06:31:35 | [diff] [blame] | 1601 | void PrerenderHostRegistry::NotifyTrigger(const GURL& url) { |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 1602 | for (Observer& obs : observers_) { |
Matt Falkenhagen | f884d0f | 2021-02-18 06:31:35 | [diff] [blame] | 1603 | obs.OnTrigger(url); |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 1604 | } |
| 1605 | } |
| 1606 | |
| 1607 | void PrerenderHostRegistry::NotifyCancel( |
Taiyo Mizuhashi | 5694b82 | 2023-09-26 16:10:30 | [diff] [blame] | 1608 | int host_frame_tree_node_id, |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 1609 | const PrerenderCancellationReason& reason) { |
| 1610 | for (Observer& obs : observers_) { |
Taiyo Mizuhashi | 5694b82 | 2023-09-26 16:10:30 | [diff] [blame] | 1611 | obs.OnCancel(host_frame_tree_node_id, reason); |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 1612 | } |
Carlos Caballero | d364451 | 2021-02-11 15:59:53 | [diff] [blame] | 1613 | } |
| 1614 | |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 1615 | PreloadingTriggerType PrerenderHostRegistry::GetPrerenderTriggerType( |
Asami Doi | 0240627 | 2021-11-12 05:01:44 | [diff] [blame] | 1616 | int frame_tree_node_id) { |
Hiroki Nakagawa | da88a82 | 2023-11-13 02:39:24 | [diff] [blame^] | 1617 | CHECK(reserved_prerender_host_); |
| 1618 | CHECK_EQ(reserved_prerender_host_->frame_tree_node_id(), frame_tree_node_id); |
| 1619 | return reserved_prerender_host_->trigger_type(); |
Asami Doi | 0240627 | 2021-11-12 05:01:44 | [diff] [blame] | 1620 | } |
| 1621 | |
| 1622 | const std::string& PrerenderHostRegistry::GetPrerenderEmbedderHistogramSuffix( |
| 1623 | int frame_tree_node_id) { |
Hiroki Nakagawa | da88a82 | 2023-11-13 02:39:24 | [diff] [blame^] | 1624 | CHECK(reserved_prerender_host_); |
| 1625 | CHECK_EQ(reserved_prerender_host_->frame_tree_node_id(), frame_tree_node_id); |
| 1626 | return reserved_prerender_host_->embedder_histogram_suffix(); |
Asami Doi | 0240627 | 2021-11-12 05:01:44 | [diff] [blame] | 1627 | } |
| 1628 | |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1629 | PrerenderHostRegistry::PrerenderLimitGroup |
| 1630 | PrerenderHostRegistry::GetPrerenderLimitGroup( |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 1631 | PreloadingTriggerType trigger_type, |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1632 | absl::optional<blink::mojom::SpeculationEagerness> eagerness) { |
Robert Lin | 0e31d56 | 2022-01-26 12:12:30 | [diff] [blame] | 1633 | switch (trigger_type) { |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 1634 | case PreloadingTriggerType::kSpeculationRule: |
| 1635 | case PreloadingTriggerType::kSpeculationRuleFromIsolatedWorld: |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1636 | CHECK(eagerness.has_value()); |
| 1637 | switch (eagerness.value()) { |
| 1638 | // Separate the limits of speculation rules into two categories: eager, |
| 1639 | // which are triggered immediately after adding the rule, and |
| 1640 | // non-eager(moderate, conservative), which wait for a specific user |
| 1641 | // action to trigger, aiming to apply the appropriate corresponding |
| 1642 | // limits for these attributes. |
| 1643 | case blink::mojom::SpeculationEagerness::kEager: |
| 1644 | return PrerenderLimitGroup::kSpeculationRulesEager; |
| 1645 | case blink::mojom::SpeculationEagerness::kModerate: |
| 1646 | case blink::mojom::SpeculationEagerness::kConservative: |
| 1647 | return PrerenderLimitGroup::kSpeculationRulesNonEager; |
| 1648 | } |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 1649 | case PreloadingTriggerType::kEmbedder: |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1650 | return PrerenderLimitGroup::kEmbedder; |
| 1651 | } |
| 1652 | } |
| 1653 | |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1654 | int PrerenderHostRegistry::GetHostCountByTriggerType( |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 1655 | PreloadingTriggerType trigger_type) { |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1656 | int host_count = 0; |
| 1657 | for (const auto& [_, host] : prerender_host_by_frame_tree_node_id_) { |
| 1658 | if (host->trigger_type() == trigger_type) { |
| 1659 | ++host_count; |
| 1660 | } |
| 1661 | } |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 1662 | |
| 1663 | if (base::FeatureList::IsEnabled(blink::features::kPrerender2InNewTab)) { |
| 1664 | for (const auto& [_, handle] : |
| 1665 | prerender_new_tab_handle_by_frame_tree_node_id_) { |
| 1666 | if (handle->trigger_type() == trigger_type) { |
| 1667 | ++host_count; |
| 1668 | } |
| 1669 | } |
| 1670 | } |
| 1671 | |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1672 | return host_count; |
| 1673 | } |
| 1674 | |
| 1675 | int PrerenderHostRegistry::GetHostCountByLimitGroup( |
| 1676 | PrerenderLimitGroup limit_group) { |
Taiyo Mizuhashi | 9211979 | 2023-09-13 07:18:03 | [diff] [blame] | 1677 | CHECK( |
| 1678 | base::FeatureList::IsEnabled(features::kPrerender2NewLimitAndScheduler)); |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1679 | int host_count = 0; |
| 1680 | for (const auto& [_, host] : prerender_host_by_frame_tree_node_id_) { |
| 1681 | if (GetPrerenderLimitGroup(host->trigger_type(), host->eagerness()) == |
| 1682 | limit_group) { |
| 1683 | ++host_count; |
| 1684 | } |
| 1685 | } |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 1686 | |
| 1687 | if (base::FeatureList::IsEnabled(blink::features::kPrerender2InNewTab)) { |
| 1688 | for (const auto& [_, handle] : |
| 1689 | prerender_new_tab_handle_by_frame_tree_node_id_) { |
| 1690 | if (GetPrerenderLimitGroup(handle->trigger_type(), handle->eagerness()) == |
| 1691 | limit_group) { |
| 1692 | ++host_count; |
| 1693 | } |
| 1694 | } |
| 1695 | } |
| 1696 | |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1697 | return host_count; |
| 1698 | } |
| 1699 | |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1700 | bool PrerenderHostRegistry::IsAllowedToStartPrerenderingForTrigger( |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 1701 | PreloadingTriggerType trigger_type, |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1702 | absl::optional<blink::mojom::SpeculationEagerness> eagerness) { |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1703 | PrerenderLimitGroup limit_group; |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1704 | int host_count; |
Taiyo Mizuhashi | 9211979 | 2023-09-13 07:18:03 | [diff] [blame] | 1705 | if (base::FeatureList::IsEnabled(features::kPrerender2NewLimitAndScheduler)) { |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1706 | limit_group = GetPrerenderLimitGroup(trigger_type, eagerness); |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1707 | host_count = GetHostCountByLimitGroup(limit_group); |
| 1708 | } else { |
| 1709 | host_count = GetHostCountByTriggerType(trigger_type); |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1710 | } |
| 1711 | |
Taiyo Mizuhashi | 9211979 | 2023-09-13 07:18:03 | [diff] [blame] | 1712 | if (base::FeatureList::IsEnabled(features::kPrerender2NewLimitAndScheduler)) { |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1713 | // Apply the limit of maximum number of running prerenders per |
| 1714 | // PrerenderLimitGroup. |
| 1715 | switch (limit_group) { |
| 1716 | case PrerenderLimitGroup::kSpeculationRulesEager: |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1717 | return host_count < base::GetFieldTrialParamByFeatureAsInt( |
Taiyo Mizuhashi | 9211979 | 2023-09-13 07:18:03 | [diff] [blame] | 1718 | features::kPrerender2NewLimitAndScheduler, |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1719 | kMaxNumOfRunningSpeculationRulesEagerPrerenders, |
| 1720 | 10); |
| 1721 | case PrerenderLimitGroup::kSpeculationRulesNonEager: { |
| 1722 | int limit_non_eager = base::GetFieldTrialParamByFeatureAsInt( |
Taiyo Mizuhashi | 9211979 | 2023-09-13 07:18:03 | [diff] [blame] | 1723 | features::kPrerender2NewLimitAndScheduler, |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1724 | kMaxNumOfRunningSpeculationRulesNonEagerPrerenders, 2); |
| 1725 | |
| 1726 | // When the limit on non-eager speculation rules is reached, cancel the |
| 1727 | // oldest host to allow a newly incoming trigger to start. |
| 1728 | if (host_count >= limit_non_eager) { |
| 1729 | int oldest_prerender_host_id; |
| 1730 | |
| 1731 | // Find the oldest non-eager prerender that has not been canceled yet. |
| 1732 | do { |
| 1733 | oldest_prerender_host_id = |
| 1734 | non_eager_prerender_host_id_by_arrival_order_.front(); |
| 1735 | non_eager_prerender_host_id_by_arrival_order_.pop_front(); |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 1736 | } while ( |
| 1737 | base::FeatureList::IsEnabled(blink::features::kPrerender2InNewTab) |
| 1738 | ? !prerender_host_by_frame_tree_node_id_.contains( |
| 1739 | oldest_prerender_host_id) && |
| 1740 | !prerender_new_tab_handle_by_frame_tree_node_id_ |
| 1741 | .contains(oldest_prerender_host_id) |
| 1742 | : !prerender_host_by_frame_tree_node_id_.contains( |
| 1743 | oldest_prerender_host_id)); |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1744 | |
Taiyo Mizuhashi | 459a6b2 | 2023-09-13 07:56:48 | [diff] [blame] | 1745 | CHECK(CancelHost(oldest_prerender_host_id, |
| 1746 | PrerenderFinalStatus:: |
| 1747 | kMaxNumOfRunningNonEagerPrerendersExceeded)); |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1748 | |
| 1749 | CHECK_LT(GetHostCountByLimitGroup(limit_group), limit_non_eager); |
| 1750 | } |
| 1751 | |
| 1752 | return true; |
| 1753 | } |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1754 | case PrerenderLimitGroup::kEmbedder: |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1755 | return host_count < base::GetFieldTrialParamByFeatureAsInt( |
Taiyo Mizuhashi | 9211979 | 2023-09-13 07:18:03 | [diff] [blame] | 1756 | features::kPrerender2NewLimitAndScheduler, |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1757 | kMaxNumOfRunningEmbedderPrerenders, 2); |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1758 | } |
| 1759 | } |
| 1760 | switch (trigger_type) { |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 1761 | case PreloadingTriggerType::kSpeculationRule: |
| 1762 | case PreloadingTriggerType::kSpeculationRuleFromIsolatedWorld: |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1763 | // The number of prerenders triggered by speculation rules is limited to |
| 1764 | // a Finch config param. |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1765 | return host_count < |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 1766 | base::GetFieldTrialParamByFeatureAsInt( |
| 1767 | blink::features::kPrerender2, |
| 1768 | blink::features::kPrerender2MaxNumOfRunningSpeculationRules, |
Asami Doi | c032d618 | 2022-09-16 15:42:29 | [diff] [blame] | 1769 | 10); |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 1770 | case PreloadingTriggerType::kEmbedder: |
Taiyo Mizuhashi | 748071f | 2023-08-01 03:46:01 | [diff] [blame] | 1771 | // Currently the number of prerenders triggered by an embedder is |
| 1772 | // limited to two. |
Taiyo Mizuhashi | cf7fd30 | 2023-08-29 04:38:09 | [diff] [blame] | 1773 | return host_count < 2; |
Robert Lin | 0e31d56 | 2022-01-26 12:12:30 | [diff] [blame] | 1774 | } |
| 1775 | } |
| 1776 | |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 1777 | void PrerenderHostRegistry::DestroyWhenUsingExcessiveMemory( |
| 1778 | int frame_tree_node_id) { |
Hiroki Nakagawa | 8b160fa | 2023-06-09 01:47:32 | [diff] [blame] | 1779 | if (!base::FeatureList::IsEnabled( |
| 1780 | blink::features::kPrerender2MemoryControls)) { |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 1781 | return; |
Hiroki Nakagawa | 8b160fa | 2023-06-09 01:47:32 | [diff] [blame] | 1782 | } |
| 1783 | |
Taiyo Mizuhashi | 0ea5102b | 2023-09-13 07:38:40 | [diff] [blame] | 1784 | if (base::FeatureList::IsEnabled( |
| 1785 | features::kPrerender2BypassMemoryLimitCheck)) { |
Hiroki Nakagawa | 8b160fa | 2023-06-09 01:47:32 | [diff] [blame] | 1786 | return; |
| 1787 | } |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 1788 | |
Hiroki Nakagawa | 3c25228 | 2023-04-18 10:31:35 | [diff] [blame] | 1789 | // Override the memory restriction when the DevTools is open. |
| 1790 | if (IsDevToolsOpen(*web_contents())) { |
| 1791 | return; |
| 1792 | } |
| 1793 | |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 1794 | memory_instrumentation::MemoryInstrumentation::GetInstance() |
| 1795 | ->RequestPrivateMemoryFootprint( |
| 1796 | base::kNullProcessId, |
| 1797 | base::BindOnce(&PrerenderHostRegistry::DidReceiveMemoryDump, |
| 1798 | weak_factory_.GetWeakPtr(), frame_tree_node_id)); |
| 1799 | } |
| 1800 | |
| 1801 | void PrerenderHostRegistry::DidReceiveMemoryDump( |
| 1802 | int frame_tree_node_id, |
| 1803 | bool success, |
| 1804 | std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump) { |
Ho Cheung | 13d432c2 | 2023-03-28 08:39:42 | [diff] [blame] | 1805 | CHECK( |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 1806 | base::FeatureList::IsEnabled(blink::features::kPrerender2MemoryControls)); |
Hiroki Nakagawa | 3c25228 | 2023-04-18 10:31:35 | [diff] [blame] | 1807 | |
| 1808 | // Override the memory restriction when the DevTools is open. |
| 1809 | if (IsDevToolsOpen(*web_contents())) { |
| 1810 | return; |
| 1811 | } |
| 1812 | |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 1813 | if (!success) { |
Hiroki Nakagawa | 35fda74 | 2023-09-07 03:51:47 | [diff] [blame] | 1814 | // Give up checking the memory consumption and continue prerendering. This |
| 1815 | // case commonly happens due to lifecycle changes of renderer processes |
| 1816 | // during the query. Skipping the check should be safe for other safety |
| 1817 | // measures: the limit on the number of ongoing prerendering requests and |
| 1818 | // memory pressure events should prevent excessive memory usage. |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 1819 | return; |
| 1820 | } |
| 1821 | |
| 1822 | int64_t private_footprint_total_kb = 0; |
| 1823 | for (const auto& pmd : dump->process_dumps()) { |
| 1824 | private_footprint_total_kb += pmd.os_dump().private_footprint_kb; |
| 1825 | } |
| 1826 | |
Hiroki Nakagawa | 04838d54 | 2023-05-25 04:15:21 | [diff] [blame] | 1827 | // The default acceptable percent is 60% of the system memory. |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 1828 | int acceptable_percent_of_system_memory = |
| 1829 | base::GetFieldTrialParamByFeatureAsInt( |
| 1830 | blink::features::kPrerender2MemoryControls, |
| 1831 | blink::features:: |
| 1832 | kPrerender2MemoryAcceptablePercentOfSystemMemoryParamName, |
Hiroki Nakagawa | 04838d54 | 2023-05-25 04:15:21 | [diff] [blame] | 1833 | 60); |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 1834 | |
| 1835 | // When the current memory usage is higher than |
| 1836 | // `acceptable_percent_of_system_memory` % of the system memory, cancel a |
| 1837 | // prerendering with `frame_tree_node_id`. |
| 1838 | if (private_footprint_total_kb * 1024 >= |
| 1839 | acceptable_percent_of_system_memory * 0.01 * |
| 1840 | base::SysInfo::AmountOfPhysicalMemory()) { |
Yoshiki Tanioka | 49b4cfb | 2022-10-20 09:25:31 | [diff] [blame] | 1841 | CancelHost(frame_tree_node_id, PrerenderFinalStatus::kMemoryLimitExceeded); |
Asami Doi | 3b684021 | 2022-07-28 02:39:19 | [diff] [blame] | 1842 | } |
| 1843 | } |
| 1844 | |
Hiroki Nakagawa | 34e5d67 | 2023-04-21 05:00:09 | [diff] [blame] | 1845 | void PrerenderHostRegistry::OnMemoryPressure( |
| 1846 | base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { |
| 1847 | // Ignore the memory pressure event if the memory control is disabled. |
| 1848 | if (!base::FeatureList::IsEnabled( |
| 1849 | blink::features::kPrerender2MemoryControls)) { |
| 1850 | return; |
| 1851 | } |
| 1852 | |
| 1853 | switch (memory_pressure_level) { |
| 1854 | case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE: |
| 1855 | case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: |
| 1856 | break; |
| 1857 | case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: |
| 1858 | CancelAllHosts(PrerenderFinalStatus::kMemoryPressureAfterTriggered); |
| 1859 | break; |
| 1860 | } |
| 1861 | } |
| 1862 | |
Yoshiki Tanioka | 80b78fb | 2022-10-27 23:40:54 | [diff] [blame] | 1863 | scoped_refptr<base::SingleThreadTaskRunner> |
| 1864 | PrerenderHostRegistry::GetTimerTaskRunner() { |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 1865 | return timer_task_runner_for_testing_ |
| 1866 | ? timer_task_runner_for_testing_ |
| 1867 | : base::SingleThreadTaskRunner::GetCurrentDefault(); |
Yoshiki Tanioka | 80b78fb | 2022-10-27 23:40:54 | [diff] [blame] | 1868 | } |
| 1869 | |
| 1870 | void PrerenderHostRegistry::SetTaskRunnerForTesting( |
| 1871 | scoped_refptr<base::SingleThreadTaskRunner> task_runner) { |
| 1872 | timer_task_runner_for_testing_ = std::move(task_runner); |
| 1873 | } |
| 1874 | |
Hiroki Nakagawa | 968139e2 | 2020-10-22 15:03:56 | [diff] [blame] | 1875 | } // namespace content |