1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CONTENT_BROWSER_RENDERER_HOST_RENDER_FRAME_HOST_MANAGER_H_ 6 #define CONTENT_BROWSER_RENDERER_HOST_RENDER_FRAME_HOST_MANAGER_H_ 7 8 #include <stdint.h> 9 10 #include <list> 11 #include <map> 12 #include <memory> 13 #include <set> 14 #include <unordered_map> 15 #include <unordered_set> 16 17 #include "base/containers/unique_ptr_adapters.h" 18 #include "base/macros.h" 19 #include "base/memory/weak_ptr.h" 20 #include "base/optional.h" 21 #include "content/browser/coop_coep_cross_origin_isolated_info.h" 22 #include "content/browser/renderer_host/back_forward_cache_impl.h" 23 #include "content/browser/renderer_host/render_frame_host_impl.h" 24 #include "content/browser/renderer_host/should_swap_browsing_instance.h" 25 #include "content/browser/site_instance_impl.h" 26 #include "content/common/content_export.h" 27 #include "content/public/browser/global_request_id.h" 28 #include "content/public/common/referrer.h" 29 #include "services/network/public/mojom/content_security_policy.mojom-forward.h" 30 #include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom-forward.h" 31 #include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom.h" 32 #include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-forward.h" 33 #include "ui/base/page_transition_types.h" 34 #include "url/origin.h" 35 36 namespace content { 37 class FrameTree; 38 class FrameTreeNode; 39 class NavigationControllerImpl; 40 class NavigationEntry; 41 class NavigationRequest; 42 class NavigatorTest; 43 class RenderFrameHostManagerTest; 44 class RenderFrameProxyHost; 45 class RenderViewHost; 46 class RenderViewHostImpl; 47 class RenderWidgetHostView; 48 class TestWebContents; 49 50 using PageBroadcastMethodCallback = 51 base::RepeatingCallback<void(RenderViewHostImpl*)>; 52 53 using RemoteFramesBroadcastMethodCallback = 54 base::RepeatingCallback<void(RenderFrameProxyHost*)>; 55 56 // Manages RenderFrameHosts for a FrameTreeNode. It maintains a 57 // current_frame_host() which is the content currently visible to the user. When 58 // a frame is told to navigate to a different web site (as determined by 59 // SiteInstance), it will replace its current RenderFrameHost with a new 60 // RenderFrameHost dedicated to the new SiteInstance, possibly in a new process. 61 // 62 // Cross-process navigation works like this: 63 // 64 // - RFHM::Navigate determines whether the destination is cross-site, and if so, 65 // it creates a pending_render_frame_host_. 66 // 67 // - The pending RFH is created in the "navigations suspended" state, meaning no 68 // navigation messages are sent to its renderer until the beforeunload handler 69 // has a chance to run in the current RFH. 70 // 71 // - The current RFH runs its beforeunload handler. If it returns false, we 72 // cancel all the pending logic. Otherwise we allow the pending RFH to send 73 // the navigation request to its renderer. 74 // 75 // - ResourceDispatcherHost receives a ResourceRequest on the IO thread for the 76 // main resource load from the pending RFH. It creates a 77 // CrossSiteResourceHandler to check whether a process transfer is needed when 78 // the request is ready to commit. 79 // 80 // - When RDH receives a response, the MimeTypeResourceHandler determines 81 // whether it is a navigation type that doesn't commit (e.g. download, 204 or 82 // error page). If so, it sends a message to the new renderer causing it to 83 // cancel the request, and the request (e.g. the download) proceeds. In this 84 // case, the pending RFH will never become the current RFH, but it remains 85 // until the next DidNavigate event for this WebContentsImpl. 86 // 87 // - After RDH receives a response and determines that it is safe and not a 88 // download, the CrossSiteResourceHandler checks whether a transfer for a 89 // redirect is needed. If so, it pauses the network response and starts an 90 // identical navigation in a new pending RFH. When the identical request is 91 // later received by RDH, the response is transferred and unpaused. 92 // 93 // - Otherwise, the network response commits in the pending RFH's renderer, 94 // which sends a DidCommitProvisionalLoad message back to the browser process. 95 // 96 // - RFHM::CommitPending makes visible the new RFH, and initiates the unload 97 // handler in the old RFH. The unload handler will complete in the background. 98 // 99 // - RenderFrameHostManager may keep the previous RFH alive as a 100 // RenderFrameProxyHost, to be used (for example) if the user goes back. The 101 // process only stays live if another tab is using it, but if so, the existing 102 // frame relationships will be maintained. 103 class CONTENT_EXPORT RenderFrameHostManager 104 : public SiteInstanceImpl::Observer { 105 public: 106 using RenderFrameProxyHostMap = 107 std::unordered_map<int32_t /* SiteInstance id */, 108 std::unique_ptr<RenderFrameProxyHost>>; 109 110 // Functions implemented by our owner that we need. 111 // 112 // TODO(brettw) Clean this up! These are all the functions in WebContentsImpl 113 // that are required to run this class. The design should probably be better 114 // such that these are more clear. 115 // 116 // There is additional complexity that some of the functions we need in 117 // WebContentsImpl are inherited and non-virtual. These are named with 118 // "RenderManager" so that the duplicate implementation of them will be clear. 119 class CONTENT_EXPORT Delegate { 120 public: 121 // Initializes the given renderer if necessary and creates the view ID 122 // corresponding to this view host. If this method is not called and the 123 // process is not shared, then the WebContentsImpl will act as though the 124 // renderer is not running (i.e., it will render "sad tab"). This method is 125 // automatically called from LoadURL. 126 virtual bool CreateRenderViewForRenderManager( 127 RenderViewHost* render_view_host, 128 const base::Optional<base::UnguessableToken>& opener_frame_token, 129 int proxy_routing_id) = 0; 130 virtual void CreateRenderWidgetHostViewForRenderManager( 131 RenderViewHost* render_view_host) = 0; 132 virtual void BeforeUnloadFiredFromRenderManager( 133 bool proceed, 134 const base::TimeTicks& proceed_time, 135 bool* proceed_to_fire_unload) = 0; 136 virtual void RenderProcessGoneFromRenderManager( 137 RenderViewHost* render_view_host) = 0; 138 virtual void CancelModalDialogsForRenderManager() = 0; 139 virtual void NotifySwappedFromRenderManager(RenderFrameHost* old_frame, 140 RenderFrameHost* new_frame, 141 bool is_main_frame) = 0; 142 // TODO(nasko): This should be removed once extensions no longer use 143 // NotificationService. See https://crbug.com/462682. 144 virtual void NotifyMainFrameSwappedFromRenderManager( 145 RenderFrameHost* old_frame, 146 RenderFrameHost* new_frame) = 0; 147 virtual NavigationControllerImpl& GetControllerForRenderManager() = 0; 148 149 // Returns true if the location bar should be focused by default rather than 150 // the page contents. The view calls this function when the tab is focused 151 // to see what it should do. 152 virtual bool FocusLocationBarByDefault() = 0; 153 154 // Returns true if views created for this delegate should be created in a 155 // hidden state. 156 virtual bool IsHidden() = 0; 157 158 // If the delegate is an inner WebContents, this method returns the 159 // FrameTreeNode ID of the frame in the outer WebContents which hosts 160 // the inner WebContents. Returns FrameTreeNode::kFrameTreeNodeInvalidId 161 // if the delegate does not have an outer WebContents. 162 virtual int GetOuterDelegateFrameTreeNodeId() = 0; 163 164 // If the delegate is an inner WebContents, reattach it to the outer 165 // WebContents. 166 virtual void ReattachOuterDelegateIfNeeded() = 0; 167 168 protected: 169 virtual ~Delegate() = default; 170 }; 171 172 // The delegate pointer must be non-null and is not owned by this class. It 173 // must outlive this class. 174 // 175 // You must call one of the Init*() methods before using this class. 176 RenderFrameHostManager(FrameTreeNode* frame_tree_node, Delegate* delegate); 177 ~RenderFrameHostManager(); 178 179 // Initialize this frame as the root of a new FrameTree. 180 void InitRoot(SiteInstance* site_instance, bool renderer_initiated_creation); 181 182 // Initialize this frame as the child of another frame. 183 void InitChild(SiteInstance* site_instance, 184 int32_t frame_routing_id, 185 const base::UnguessableToken& frame_token); 186 187 // Returns the currently active RenderFrameHost. 188 // 189 // This will be non-null between Init() and Shutdown(). You may want to null 190 // check it in many cases, however. Windows can send us messages during the 191 // destruction process after it has been shut down. current_frame_host()192 RenderFrameHostImpl* current_frame_host() const { 193 return render_frame_host_.get(); 194 } 195 196 // TODO(creis): Remove this when we no longer use RVH for navigation. 197 RenderViewHostImpl* current_host() const; 198 199 // Returns the view associated with the current RenderViewHost, or null if 200 // there is no current one. 201 RenderWidgetHostView* GetRenderWidgetHostView() const; 202 203 // Returns whether this manager is a main frame and belongs to a FrameTreeNode 204 // that belongs to an inner WebContents. 205 bool IsMainFrameForInnerDelegate(); 206 207 // If this is a RenderFrameHostManager for a main frame, this method returns 208 // the FrameTreeNode for the frame in the outer WebContents (if any) that 209 // contains the inner WebContents. 210 FrameTreeNode* GetOuterDelegateNode(); 211 212 // Return a proxy for this frame in the parent frame's SiteInstance. Returns 213 // nullptr if this is a main frame or if such a proxy does not exist (for 214 // example, if this frame is same-site with its parent OR if this frame will 215 // be deleted soon and we are just waiting for the frame's unload handler). 216 RenderFrameProxyHost* GetProxyToParent(); 217 218 // If this is a RenderFrameHostManager for a main frame, returns the proxy to 219 // inner WebContents in the outer WebContents's SiteInstance. Returns nullptr 220 // if this WebContents isn't part of inner/outer relationship. 221 RenderFrameProxyHost* GetProxyToOuterDelegate(); 222 223 // If this is a RenderFrameHostManager for a main frame, removes the 224 // FrameTreeNode in the outer WebContents that represents this FrameTreeNode. 225 // TODO(lazyboy): This does not belong to RenderFrameHostManager, move it to 226 // somewhere else. 227 void RemoveOuterDelegateFrame(); 228 229 // Returns the speculative RenderFrameHost, or null if there is no speculative 230 // one. speculative_frame_host()231 RenderFrameHostImpl* speculative_frame_host() const { 232 return speculative_render_frame_host_.get(); 233 } 234 235 // Instructs the various live views to stop. Called when the user directed the 236 // page to stop loading. 237 void Stop(); 238 239 // Notifies the regular and pending RenderViewHosts that a load is or is not 240 // happening. Even though the message is only for one of them, we don't know 241 // which one so we tell both. 242 void SetIsLoading(bool is_loading); 243 244 // Confirms whether we should close the page. |proceed| indicates whether the 245 // user chose to proceed. |proceed_time| is the time when the request was 246 // allowed to proceed. This is called in one of the two *distinct* scenarios 247 // below: 248 // 1- The tab/window is closed after allowing the appropriate renderer to 249 // show the beforeunload prompt. 250 // 2- The FrameTreeNode is being prepared for attaching an inner Delegate, 251 // in which case beforeunload is triggered in the current frame. This 252 // only happens for child frames. 253 void BeforeUnloadCompleted(bool proceed, const base::TimeTicks& proceed_time); 254 255 // Called when a renderer's frame navigates. 256 void DidNavigateFrame(RenderFrameHostImpl* render_frame_host, 257 bool was_caused_by_user_gesture, 258 bool is_same_document_navigation, 259 bool clear_proxies_on_commit, 260 const blink::FramePolicy& frame_policy); 261 262 // Called when this frame's opener is changed to the frame specified by 263 // |opener_frame_token| in |source_site_instance|'s process. This change 264 // could come from either the current RenderFrameHost or one of the 265 // proxies (e.g., window.open that targets a RemoteFrame by name). The 266 // updated opener will be forwarded to any other RenderFrameProxies and 267 // RenderFrames for this FrameTreeNode. 268 void DidChangeOpener( 269 const base::Optional<base::UnguessableToken>& opener_frame_token, 270 SiteInstance* source_site_instance); 271 272 // Creates and initializes a RenderFrameHost. If |for_early_commit| is true 273 // then this RenderFrameHost and its RenderFrame will be prepared knowing that 274 // it will be committed immediately. If false the it will be committed later, 275 // following the usual navigation path. 276 std::unique_ptr<RenderFrameHostImpl> CreateSpeculativeRenderFrame( 277 SiteInstance* instance, 278 bool for_early_commit); 279 280 // Helper method to create and initialize a RenderFrameProxyHost. 281 void CreateRenderFrameProxy(SiteInstance* instance); 282 283 // Creates proxies for a new child frame at FrameTreeNode |child| in all 284 // SiteInstances for which the current frame has proxies. This method is 285 // called on the parent of a new child frame before the child leaves the 286 // SiteInstance. 287 void CreateProxiesForChildFrame(FrameTreeNode* child); 288 289 // Returns the RenderFrameProxyHost for the given SiteInstance, if any. 290 RenderFrameProxyHost* GetRenderFrameProxyHost(SiteInstance* instance) const; 291 292 // If |render_frame_host| is on the pending deletion list, this deletes it. 293 // Returns whether it was deleted. 294 bool DeleteFromPendingList(RenderFrameHostImpl* render_frame_host); 295 296 // BackForwardCache: 297 // During a history navigation, unfreezes and swaps in a document from the 298 // BackForwardCache, making it active. 299 void RestoreFromBackForwardCache( 300 std::unique_ptr<BackForwardCacheImpl::Entry>); 301 302 // Deletes any proxy hosts associated with this node. Used during destruction 303 // of WebContentsImpl. 304 void ResetProxyHosts(); 305 306 void ClearRFHsPendingShutdown(); 307 void ClearWebUIInstances(); 308 309 // Returns the routing id for a RenderFrameHost or RenderFrameProxyHost 310 // that has the given SiteInstance and is associated with this 311 // RenderFrameHostManager. Returns MSG_ROUTING_NONE if none is found. 312 int GetRoutingIdForSiteInstance(SiteInstance* site_instance); 313 314 // Returns the frame token for a RenderFrameHost or RenderFrameProxyHost 315 // that has the given SiteInstance and is associated with this 316 // RenderFrameHostManager. Returns base::nullopt if none is found. 317 base::Optional<base::UnguessableToken> GetFrameTokenForSiteInstance( 318 SiteInstance* site_instance); 319 320 // Notifies the RenderFrameHostManager that a new NavigationRequest has been 321 // created and set in the FrameTreeNode so that it can speculatively create a 322 // new RenderFrameHost (and potentially a new process) if needed. 323 void DidCreateNavigationRequest(NavigationRequest* request); 324 325 // Called (possibly several times) during a navigation to select or create an 326 // appropriate RenderFrameHost for the provided URL. The returned pointer will 327 // be for the current or the speculative RenderFrameHost and the instance is 328 // owned by this manager. 329 // 330 // |reason| is an optional out-parameter that will be populated with 331 // engineer-readable information describing the reason for the method 332 // behavior. The returned |reason| should fit into 333 // base::debug::CrashKeySize::Size256. 334 RenderFrameHostImpl* GetFrameHostForNavigation(NavigationRequest* request, 335 std::string* reason = nullptr); 336 337 // Clean up any state for any ongoing navigation. 338 void CleanUpNavigation(); 339 340 // Clears the speculative members, returning the RenderFrameHost to the caller 341 // for disposal. 342 std::unique_ptr<RenderFrameHostImpl> UnsetSpeculativeRenderFrameHost(); 343 344 // Notification methods to tell this RenderFrameHostManager that the frame it 345 // is responsible for has started or stopped loading a document. 346 void OnDidStartLoading(); 347 void OnDidStopLoading(); 348 349 // OnDidUpdateName gets called when a frame changes its name - it gets the new 350 // |name| and the recalculated |unique_name| and replicates them into all 351 // frame proxies. 352 void OnDidUpdateName(const std::string& name, const std::string& unique_name); 353 354 // Sends the newly added Content Security Policy headers to all the proxies. 355 void OnDidAddContentSecurityPolicies( 356 std::vector<network::mojom::ContentSecurityPolicyHeaderPtr> headers); 357 358 // Resets Content Security Policy in all the proxies. 359 void OnDidResetContentSecurityPolicy(); 360 361 // Sends updated enforcement of insecure request policy to all frame proxies 362 // when the frame changes its setting. 363 void OnEnforceInsecureRequestPolicy( 364 blink::mojom::InsecureRequestPolicy policy); 365 366 // Sends updated enforcement of upgrade insecure navigations set to all frame 367 // proxies when the frame changes its setting. 368 void OnEnforceInsecureNavigationsSet( 369 const std::vector<uint32_t>& insecure_navigations_set); 370 371 // Called when the client changes whether the frame's owner element in the 372 // embedder document should be collapsed, that is, remove from the layout as 373 // if it did not exist. Never called for main frames. Only has an effect for 374 // <iframe> owner elements. 375 void OnDidChangeCollapsedState(bool collapsed); 376 377 // Called on a frame to notify it that its out-of-process parent frame 378 // changed a property (such as allowFullscreen) on its <iframe> element. 379 // Sends updated FrameOwnerProperties to the RenderFrame and to all proxies, 380 // skipping the parent process. 381 void OnDidUpdateFrameOwnerProperties( 382 const blink::mojom::FrameOwnerProperties& properties); 383 384 // Notify the proxies that the active sandbox flags or feature policy header 385 // on the frame have been changed during page load. Sandbox flags can change 386 // when set by a CSP header. 387 void OnDidSetFramePolicyHeaders(); 388 389 // Send updated origin to all frame proxies when the frame navigates to a new 390 // origin. 391 void OnDidUpdateOrigin(const url::Origin& origin, 392 bool is_potentially_trustworthy_unique_origin); 393 394 // Send updated ad frame type to all frame proxies at ready-to-commit time 395 // when the ad status gets updated. 396 void OnDidSetAdFrameType(blink::mojom::AdFrameType ad_frame_type); 397 398 void EnsureRenderViewInitialized(RenderViewHostImpl* render_view_host, 399 SiteInstance* instance); 400 401 // Creates RenderFrameProxies and inactive RenderViewHosts for this frame's 402 // FrameTree and for its opener chain in the given SiteInstance. This allows 403 // other tabs to send cross-process JavaScript calls to their opener(s) and 404 // to any other frames in the opener's FrameTree (e.g., supporting calls like 405 // window.opener.opener.frames[x][y]). Does not create proxies for the 406 // subtree rooted at |skip_this_node| (e.g., if a node is being navigated, it 407 // can be passed here to prevent proxies from being created for it, in 408 // case it is in the same FrameTree as another node on its opener chain). 409 void CreateOpenerProxies(SiteInstance* instance, 410 FrameTreeNode* skip_this_node); 411 412 // Ensure that this frame has proxies in all SiteInstances that can discover 413 // this frame by name (e.g., via window.open("", "frame_name")). See 414 // https://crbug.com/511474. 415 void CreateProxiesForNewNamedFrame(); 416 417 // Returns a base::UnguessableToken for the current FrameTreeNode's opener 418 // node in the given SiteInstance. May return a frame token of either a 419 // RenderFrameHost (if opener's current or pending RFH has SiteInstance 420 // |instance|) or a RenderFrameProxyHost. Returns base::nullopt if there is 421 // no opener, or if the opener node doesn't have a proxy for |instance|. 422 base::Optional<base::UnguessableToken> GetOpenerFrameToken( 423 SiteInstance* instance); 424 425 // Called on the RFHM of the inner WebContents to create a 426 // RenderFrameProxyHost in its outer WebContents's SiteInstance, 427 // |outer_contents_site_instance|. The frame in outer WebContents that is 428 // hosting the inner WebContents is |render_frame_host|, and the frame will 429 // be swapped with the proxy. Note that this method must only be called for an 430 // OOPIF-based inner WebContents. 431 RenderFrameProxyHost* CreateOuterDelegateProxy( 432 SiteInstance* outer_contents_site_instance); 433 434 // Called on an inner WebContents that's being detached from its outer 435 // WebContents. This will delete the proxy in the 436 // |outer_contents_site_instance|. 437 void DeleteOuterDelegateProxy(SiteInstance* outer_contents_site_instance); 438 439 // Tells the |render_frame_host|'s renderer that its RenderFrame is being 440 // swapped for a frame in another process, and that it should create a 441 // RenderFrameProxy to replace it using the |proxy| RenderFrameProxyHost. 442 void SwapOuterDelegateFrame(RenderFrameHostImpl* render_frame_host, 443 RenderFrameProxyHost* proxy); 444 445 // Sets the child RenderWidgetHostView for this frame, which must be part of 446 // an inner WebContents. 447 void SetRWHViewForInnerContents(RenderWidgetHostView* child_rwhv); 448 449 // Returns the number of RenderFrameProxyHosts for this frame. 450 size_t GetProxyCount(); 451 452 // Executes a PageBroadcast Mojo method to every RenderView in the FrameTree. 453 // This should only be called in the top-level RenderFrameHostManager. 454 // The |callback| is called synchronously and the |instance_to_skip| won't 455 // be referenced after this method returns. 456 void ExecutePageBroadcastMethod(PageBroadcastMethodCallback callback, 457 SiteInstance* instance_to_skip = nullptr); 458 459 // Executes a RemoteMainFrame Mojo method to every instance in |proxy_hosts|. 460 // This should only be called in the top-level RenderFrameHostManager. 461 // The |callback| is called synchronously and the |instance_to_skip| won't 462 // be referenced after this method returns. 463 void ExecuteRemoteFramesBroadcastMethod( 464 RemoteFramesBroadcastMethodCallback callback, 465 SiteInstance* instance_to_skip = nullptr); 466 467 // Returns a const reference to the map of proxy hosts. The keys are 468 // SiteInstance IDs, the values are RenderFrameProxyHosts. GetAllProxyHostsForTesting()469 const RenderFrameProxyHostMap& GetAllProxyHostsForTesting() const { 470 return proxy_hosts_; 471 } 472 473 // SiteInstanceImpl::Observer 474 void ActiveFrameCountIsZero(SiteInstanceImpl* site_instance) override; 475 void RenderProcessGone(SiteInstanceImpl* site_instance, 476 const ChildProcessTerminationInfo& info) override; 477 478 // Cancels and destroys the pending or speculative RenderFrameHost if they 479 // match the provided |render_frame_host|. 480 void CancelPendingIfNecessary(RenderFrameHostImpl* render_frame_host); 481 482 // Updates the user activation state in all proxies of this frame. For 483 // more details, see the comment on FrameTreeNode::user_activation_state_. 484 // 485 // The |notification_type| parameter is used for histograms, only for the case 486 // |update_state == kNotifyActivation|. 487 void UpdateUserActivationState( 488 blink::mojom::UserActivationUpdateType update_type, 489 blink::mojom::UserActivationNotificationType notification_type); 490 491 void OnSetHadStickyUserActivationBeforeNavigation(bool value); 492 493 // Sets up the necessary state for a new RenderViewHost. If |proxy| is not 494 // null, it creates a RenderFrameProxy in the target renderer process which is 495 // used to route IPC messages. Returns early if the RenderViewHost has 496 // already been initialized for another RenderFrameHost. 497 bool InitRenderView(RenderViewHostImpl* render_view_host, 498 RenderFrameProxyHost* proxy); 499 500 // Returns the SiteInstance that should be used to host the navigation handled 501 // by |navigation_request|. 502 // Note: the SiteInstance returned by this function may not have an 503 // initialized RenderProcessHost. It will only be initialized when 504 // GetProcess() is called on the SiteInstance. In particular, calling this 505 // function will never lead to a process being created for the navigation. 506 // 507 // |reason| is an optional out-parameter that will be populated with 508 // engineer-readable information describing the reason for the method 509 // behavior. The returned |reason| should fit into 510 // base::debug::CrashKeySize::Size256. 511 scoped_refptr<SiteInstance> GetSiteInstanceForNavigationRequest( 512 NavigationRequest* navigation_request, 513 std::string* reason = nullptr); 514 515 // Helper to initialize the main RenderFrame if it's not initialized. 516 // TODO(https://crbug.com/936696): Remove this. For now debug URLs and 517 // WebView JS execution are an exception to replacing all crashed frames for 518 // RenderDocument. This is a no-op if the frame is already initialized. 519 bool InitializeMainRenderFrameForImmediateUse(); 520 521 // Prepares the FrameTreeNode for attaching an inner WebContents. This step 522 // may involve replacing |current_frame_host()| with a new RenderFrameHost 523 // in the same SiteInstance as the parent frame. Calling this method will 524 // dispatch beforeunload event if necessary. 525 void PrepareForInnerDelegateAttach( 526 RenderFrameHost::PrepareForInnerWebContentsAttachCallback callback); 527 528 // When true the FrameTreeNode is preparing a RenderFrameHost for attaching an 529 // inner Delegate. During this phase new navigation requests are ignored. is_attaching_inner_delegate()530 bool is_attaching_inner_delegate() const { 531 return attach_to_inner_delegate_state_ != AttachToInnerDelegateState::NONE; 532 } 533 534 // Called by the delegate at the end of the attaching process. set_attach_complete()535 void set_attach_complete() { 536 attach_to_inner_delegate_state_ = AttachToInnerDelegateState::ATTACHED; 537 } 538 539 // Computes the COOP/COEP information based on the |navigation_request| 540 // and current |frame_tree_node_| & |render_frame_host_| info. 541 CoopCoepCrossOriginIsolatedInfo GetCoopCoepCrossOriginIsolationInfo( 542 NavigationRequest* navigation_request); 543 544 private: 545 friend class NavigatorTest; 546 friend class RenderFrameHostManagerTest; 547 friend class RenderFrameHostTester; 548 friend class TestWebContents; 549 550 enum class SiteInstanceRelation { 551 // A SiteInstance in a different browsing instance from the current. 552 UNRELATED, 553 // A SiteInstance in the same browsing instance as the current. 554 RELATED, 555 // A pre-existing SiteInstance that might or might not be in the same 556 // browsing instance as the current. Only used when |existing_site_instance| 557 // is specified. 558 PREEXISTING, 559 }; 560 561 enum class AttachToInnerDelegateState { 562 // There is no inner delegate attached through FrameTreeNode and no 563 // attaching is in progress. 564 NONE, 565 // A frame is being prepared for attaching. 566 PREPARE_FRAME, 567 // An inner delegate attached to the delegate of this manager. 568 ATTACHED 569 }; 570 571 // Stores information regarding a SiteInstance targeted at a specific UrlInfo 572 // to allow for comparisons without having to actually create new instances. 573 // It can point to an existing one or store the details needed to create a new 574 // one. 575 struct CONTENT_EXPORT SiteInstanceDescriptor { SiteInstanceDescriptorSiteInstanceDescriptor576 explicit SiteInstanceDescriptor(content::SiteInstance* site_instance) 577 : existing_site_instance(site_instance), 578 relation(SiteInstanceRelation::PREEXISTING), 579 cross_origin_isolated_info( 580 CoopCoepCrossOriginIsolatedInfo::CreateNonIsolated()) {} 581 582 SiteInstanceDescriptor( 583 UrlInfo dest_url_info, 584 SiteInstanceRelation relation_to_current, 585 const CoopCoepCrossOriginIsolatedInfo& cross_origin_isolated_info); 586 587 // Set with an existing SiteInstance to be reused. 588 content::SiteInstance* existing_site_instance; 589 590 // In case |existing_site_instance| is null, specify a destination URL. 591 UrlInfo dest_url_info; 592 593 // Specifies how the new site is related to the current BrowsingInstance. 594 // This is PREEXISTING iff |existing_site_instance| is defined. 595 SiteInstanceRelation relation; 596 597 // A cross-origin isolated page has its top level frame 598 // cross-origin-opener-policy set to "same-origin" and 599 // cross-origin-embedder-policy set to "require-corp". 600 // This allows the use of more powerful features such as SharedArrayBuffer. 601 // A cross-origin isolated SiteInstance hosts such pages and should only 602 // live in cross-origin isolated BrowsingInstances. 603 CoopCoepCrossOriginIsolatedInfo cross_origin_isolated_info; 604 }; 605 606 // Create a RenderFrameProxyHost owned by this object. 607 RenderFrameProxyHost* CreateRenderFrameProxyHost( 608 SiteInstance* site_instance, 609 scoped_refptr<RenderViewHostImpl> rvh); 610 611 // Delete a RenderFrameProxyHost owned by this object. 612 void DeleteRenderFrameProxyHost(SiteInstance* site_instance); 613 614 // Returns true if for the navigation from |current_effective_url| to 615 // |destination_url_info|, a new SiteInstance and BrowsingInstance should be 616 // created (even if we are in a process model that doesn't usually swap). 617 // This forces a process swap and severs script connections with existing 618 // tabs. Cases where this can happen include transitions between WebUI and 619 // regular web pages. 620 // 621 // |source_instance| is the SiteInstance of the frame that initiated the 622 // navigation. |current_instance| is the SiteInstance of the frame that is 623 // currently navigating. |destination_instance| is a predetermined 624 // SiteInstance that will be used for |destination_url| if not 625 // null - we will swap BrowsingInstances if it's in a different 626 // BrowsingInstance than the current one. 627 // 628 // If there is no current NavigationEntry, then |current_is_view_source_mode| 629 // should be the same as |dest_is_view_source_mode|. 630 // 631 // UrlInfo uses the effective URL here, since that's what is used in the 632 // SiteInstance's site and when we later call IsSameSite. If there is no 633 // current NavigationEntry, check the current SiteInstance's site, which might 634 // already be committed to a Web UI URL (such as the NTP). Note that we don't 635 // pass the effective URL for destination URL here and instead calculate the 636 // destination's effective URL within the function because some methods called 637 // in the function like IsNavigationSameSite expects a non-effective URL. 638 ShouldSwapBrowsingInstance ShouldSwapBrowsingInstancesForNavigation( 639 const GURL& current_effective_url, 640 bool current_is_view_source_mode, 641 SiteInstanceImpl* source_instance, 642 SiteInstanceImpl* current_instance, 643 SiteInstance* destination_instance, 644 const UrlInfo& destination_url_info, 645 const CoopCoepCrossOriginIsolatedInfo& cross_origin_isolated_info, 646 bool destination_is_view_source_mode, 647 ui::PageTransition transition, 648 bool is_failure, 649 bool is_reload, 650 bool is_same_document, 651 bool cross_origin_opener_policy_mismatch, 652 bool was_server_redirect, 653 bool should_replace_current_entry, 654 bool is_speculative); 655 656 ShouldSwapBrowsingInstance ShouldProactivelySwapBrowsingInstance( 657 const UrlInfo& destination_url_info, 658 const CoopCoepCrossOriginIsolatedInfo& cross_origin_isolated_info, 659 bool is_reload, 660 bool should_replace_current_entry); 661 662 // Returns the SiteInstance to use for the navigation. 663 // 664 // This is a helper function for GetSiteInstanceForNavigationRequest. 665 scoped_refptr<SiteInstance> GetSiteInstanceForNavigation( 666 const UrlInfo& dest_url_info, 667 const CoopCoepCrossOriginIsolatedInfo& cross_origin_isolated_info, 668 SiteInstanceImpl* source_instance, 669 SiteInstanceImpl* dest_instance, 670 SiteInstanceImpl* candidate_instance, 671 ui::PageTransition transition, 672 bool is_failure, 673 bool is_reload, 674 bool is_same_document, 675 bool dest_is_restore, 676 bool dest_is_view_source_mode, 677 bool was_server_redirect, 678 bool cross_origin_opener_policy_mismatch, 679 bool should_replace_current_entry, 680 bool is_speculative, 681 bool* did_same_site_proactive_browsing_instance_swap, 682 std::string* reason); 683 684 // Returns a descriptor of the appropriate SiteInstance object for the given 685 // |dest_url_info|, possibly reusing the current, source or destination 686 // SiteInstance. The actual SiteInstance can then be obtained calling 687 // ConvertToSiteInstance with the descriptor. 688 // 689 // |cross_origin_isolated_info| reflects the cross-origin isolation 690 // information we got from the response for |dest_url|, more specifically the 691 // COOP and COEP headers. 692 // 693 // |source_instance| is the SiteInstance of the frame that initiated the 694 // navigation. |current_instance| is the SiteInstance of the frame that is 695 // currently navigating. |dest_instance| is a predetermined SiteInstance that 696 // will be used if not null. 697 // For example, if you have a parent frame A, which has a child frame B, and 698 // A is trying to change the src attribute of B, this will cause a navigation 699 // where the source SiteInstance is A and B is the current SiteInstance. 700 // 701 // |is_speculative| indicates that the SiteInstance is being computed for a 702 // speculative RenderFrameHost, which may change once response is received and 703 // a final RenderFrameHost/SiteInstance is computed. It is true at request 704 // start time, but false for redirects and at OnResponseStarted time. 705 // 706 // This is a helper function for GetSiteInstanceForNavigation. 707 SiteInstanceDescriptor DetermineSiteInstanceForURL( 708 const UrlInfo& dest_url_info, 709 const CoopCoepCrossOriginIsolatedInfo& cross_origin_isolated_info, 710 SiteInstance* source_instance, 711 SiteInstance* current_instance, 712 SiteInstance* dest_instance, 713 ui::PageTransition transition, 714 bool is_failure, 715 bool dest_is_restore, 716 bool dest_is_view_source_mode, 717 bool force_browsing_instance_swap, 718 bool was_server_redirect, 719 bool is_speculative, 720 std::string* reason); 721 722 // Returns true if a navigation to |dest_url| that uses the specified 723 // PageTransition in the current frame is allowed to swap BrowsingInstances. 724 // DetermineSiteInstanceForURL() uses this helper to determine when it is 725 // allowed to swap BrowsingInstances to avoid unneeded process sharing. See 726 // https://crbug.com/803367. 727 // 728 // Note that this is different from 729 // ShouldSwapBrowsingInstancesForNavigation(), which identifies cases in 730 // which a BrowsingInstance swap is *required* (e.g., for security). This 731 // function only identifies cases where a BrowsingInstance swap *may* be 732 // performed to optimize process placement. In particular, this is true for 733 // certain browser-initiated transitions for main frame navigations. 734 // 735 // Returning true here doesn't imply that DetermineSiteInstanceForURL() will 736 // swap BrowsingInstances. For example, this swap will not be done for 737 // same-site navigations, for history navigations, or when starting from an 738 // uninitialized SiteInstance. 739 bool IsBrowsingInstanceSwapAllowedForPageTransition( 740 ui::PageTransition transition, 741 const GURL& dest_url); 742 743 // Returns true if we can use |source_instance| for |dest_url|. 744 bool CanUseSourceSiteInstance( 745 const GURL& dest_url, 746 SiteInstance* source_instance, 747 bool was_server_redirect, 748 bool is_failure, 749 const CoopCoepCrossOriginIsolatedInfo& cross_origin_isolated_info, 750 bool is_speculative); 751 752 // Converts a SiteInstanceDescriptor to the actual SiteInstance it describes. 753 // If a |candidate_instance| is provided (is not nullptr) and it matches the 754 // description, it is returned as is. 755 // |is_speculative| indicates whether we are computing a SiteInstance for a 756 // speculative RenderFrameHost or if have already received a response. 757 scoped_refptr<SiteInstance> ConvertToSiteInstance( 758 const SiteInstanceDescriptor& descriptor, 759 SiteInstanceImpl* candidate_instance, 760 bool is_speculative); 761 762 // Returns true if |candidate| is currently on the same web site as 763 // |dest_url_info|. This method is a special case for handling hosted apps in 764 // this object. Most code should call IsNavigationSameSite() on 765 // |candidate| instead of this method. 766 bool IsCandidateSameSite( 767 RenderFrameHostImpl* candidate, 768 const UrlInfo& dest_url_info, 769 const CoopCoepCrossOriginIsolatedInfo& cross_origin_isolated_info); 770 771 // Ensure that we have created all needed proxies for a new RFH with 772 // SiteInstance |new_instance|: (1) create swapped-out RVHs and proxies for 773 // the new RFH's opener chain if we are staying in the same BrowsingInstance; 774 // (2) Create proxies for the new RFH's SiteInstance in its own frame tree. 775 // |recovering_without_early_commit| is true if we are reviving a crashed 776 // render frame by creating a proxy and committing later rather than doing an 777 // immediate commit. 778 void CreateProxiesForNewRenderFrameHost(SiteInstance* old_instance, 779 SiteInstance* new_instance, 780 bool recovering_without_early_commit); 781 782 // Traverse the opener chain and populate |opener_frame_trees| with 783 // all FrameTrees accessible by following frame openers of nodes in the 784 // given node's FrameTree. |opener_frame_trees| is ordered so that openers 785 // of smaller-indexed entries point to larger-indexed entries (i.e., this 786 // node's FrameTree is at index 0, its opener's FrameTree is at index 1, 787 // etc). If the traversal encounters a node with an opener pointing to a 788 // FrameTree that has already been traversed (such as when there's a cycle), 789 // the node is added to |nodes_with_back_links|. 790 void CollectOpenerFrameTrees( 791 std::vector<FrameTree*>* opener_frame_trees, 792 std::unordered_set<FrameTreeNode*>* nodes_with_back_links); 793 794 // Create RenderFrameProxies and inactive RenderViewHosts in the given 795 // SiteInstance for the current node's FrameTree. Used as a helper function 796 // in CreateOpenerProxies for creating proxies in each FrameTree on the 797 // opener chain. Don't create proxies for the subtree rooted at 798 // |skip_this_node|. 799 void CreateOpenerProxiesForFrameTree(SiteInstance* instance, 800 FrameTreeNode* skip_this_node); 801 802 // The different types of RenderFrameHost creation that can occur. 803 // See CreateRenderFrameHost for how these influence creation. 804 enum class CreateFrameCase { 805 // Adding a child to an existing frame in the tree. 806 kInitChild, 807 // Creating the first frame in a frame tree. 808 kInitRoot, 809 // Preparing to navigate to another frame. 810 kCreateSpeculative, 811 }; 812 813 // Creates a RenderFrameHost. This uses an existing a RenderViewHost in the 814 // same SiteInstance if it exists or creates a new one (a new one will only be 815 // created if this is a root or child local root). 816 // TODO(https://crbug.com/1060082): Eliminate or rename 817 // renderer_initiated_creation. 818 std::unique_ptr<RenderFrameHostImpl> CreateRenderFrameHost( 819 CreateFrameCase create_frame_case, 820 SiteInstance* site_instance, 821 int32_t frame_routing_id, 822 const base::UnguessableToken& frame_token, 823 bool renderer_initiated_creation); 824 825 // Create and initialize a speculative RenderFrameHost for an ongoing 826 // navigation. It might be destroyed and re-created later if the navigation is 827 // redirected to a different SiteInstance. |recovering_without_early_commit| 828 // is true if we are reviving a crashed render frame by creating a proxy and 829 // committing later rather than doing an immediate commit. 830 bool CreateSpeculativeRenderFrameHost(SiteInstance* old_instance, 831 SiteInstance* new_instance, 832 bool recovering_without_early_commit); 833 834 // Initialization for RenderFrameHost uses the same sequence as InitRenderView 835 // above. 836 bool InitRenderFrame(RenderFrameHostImpl* render_frame_host); 837 838 // Find the routing ID of the frame or proxy that this frame will replace or 839 // |MSG_ROUTING_NONE| if there is none. When initializing a new RenderFrame 840 // for |render_frame_host|, it may be replacing a RenderFrameProxy or another 841 // RenderFrame in the renderer or recovering from a crash. |existing_proxy| is 842 // the proxy for |this| in the destination renderer, nullptr if there is no 843 // proxy. |render_frame_host| is used only for sanity checking. 844 int GetReplacementRoutingId(RenderFrameProxyHost* existing_proxy, 845 RenderFrameHostImpl* render_frame_host) const; 846 847 // Helper to reinitialize the RenderFrame, RenderView, and the opener chain 848 // for the provided |render_frame_host|. Used when the |render_frame_host| 849 // needs to be reused for a new navigation, but it is not live. 850 bool ReinitializeRenderFrame(RenderFrameHostImpl* render_frame_host); 851 852 // Sets the |pending_rfh| to be the active one. Called when the pending 853 // RenderFrameHost commits. 854 // 855 // This function is also called when restoring an entry from BackForwardCache. 856 // In that case, |pending_rfh| is the RenderFrameHost to be restored, and 857 // |pending_bfcache_entry| provides additional state to be restored, such as 858 // proxies. 859 // |clear_proxies_on_commit| Indicates if the proxies and opener must be 860 // removed during the commit. This can happen following some BrowsingInstance 861 // swaps, such as those for COOP. 862 void CommitPending( 863 std::unique_ptr<RenderFrameHostImpl> pending_rfh, 864 std::unique_ptr<BackForwardCacheImpl::Entry> pending_bfcache_entry, 865 bool clear_proxies_on_commit); 866 867 // Helper to call CommitPending() in all necessary cases. 868 void CommitPendingIfNecessary(RenderFrameHostImpl* render_frame_host, 869 bool was_caused_by_user_gesture, 870 bool is_same_document_navigation, 871 bool clear_proxies_on_commit); 872 873 // Commits given frame policy when the renderer's frame navigates. 874 void CommitFramePolicy(const blink::FramePolicy& frame_policy); 875 876 // Runs the unload handler in the old RenderFrameHost, after the new 877 // RenderFrameHost has committed. |old_render_frame_host| will either be 878 // deleted or put on the pending delete list during this call. 879 void UnloadOldFrame( 880 std::unique_ptr<RenderFrameHostImpl> old_render_frame_host); 881 882 // Discards a RenderFrameHost that was never made active (for active ones 883 // UnloadOldFrame is used instead). 884 void DiscardUnusedFrame( 885 std::unique_ptr<RenderFrameHostImpl> render_frame_host); 886 887 // Helper method to set the active RenderFrameHost. Returns the old 888 // RenderFrameHost and updates counts. 889 std::unique_ptr<RenderFrameHostImpl> SetRenderFrameHost( 890 std::unique_ptr<RenderFrameHostImpl> render_frame_host); 891 892 // After a renderer process crash we'd have marked the host as invisible, so 893 // we need to set the visibility of the new View to the correct value here 894 // after reload. 895 void EnsureRenderFrameHostVisibilityConsistent(); 896 897 // Similarly to visibility, we need to ensure RenderWidgetHost and 898 // RenderWidget know about page focus. 899 void EnsureRenderFrameHostPageFocusConsistent(); 900 901 // When current RenderFrameHost is not in its parent SiteInstance, this method 902 // will destroy the frame and replace it with a new RenderFrameHost in the 903 // parent frame's SiteInstance. Either way, this will eventually invoke 904 // |attach_inner_delegate_callback_| with a pointer to |render_frame_host_| 905 // which is then safe for use with WebContents::AttachToOuterWebContentsFrame. 906 void CreateNewFrameForInnerDelegateAttachIfNecessary(); 907 908 // Called when the result of preparing the FrameTreeNode for attaching an 909 // inner delegate is known. When successful, |render_frame_host_| can be used 910 // for attaching the inner Delegate. 911 void NotifyPrepareForInnerDelegateAttachComplete(bool success); 912 913 // For use in creating RenderFrameHosts. 914 FrameTreeNode* frame_tree_node_; 915 916 // Our delegate, not owned by us. Guaranteed non-null. 917 Delegate* delegate_; 918 919 // Our RenderFrameHost which is responsible for all communication with a child 920 // RenderFrame instance. 921 // For now, RenderFrameHost keeps a RenderViewHost in its SiteInstance alive. 922 // Eventually, RenderViewHost will be replaced with a page context. 923 std::unique_ptr<RenderFrameHostImpl> render_frame_host_; 924 925 // Proxy hosts, indexed by site instance ID. 926 RenderFrameProxyHostMap proxy_hosts_; 927 928 // A set of RenderFrameHosts waiting to shut down after swapping out. 929 using RFHPendingDeleteSet = 930 std::set<std::unique_ptr<RenderFrameHostImpl>, base::UniquePtrComparator>; 931 RFHPendingDeleteSet pending_delete_hosts_; 932 933 // Stores a speculative RenderFrameHost which is created early in a navigation 934 // so a renderer process can be started in parallel, if needed. 935 // This is purely a performance optimization and is not required for correct 936 // behavior. The speculative RenderFrameHost might be discarded later on if 937 // the final URL's SiteInstance isn't compatible with the one used to create 938 // it. 939 std::unique_ptr<RenderFrameHostImpl> speculative_render_frame_host_; 940 941 // After being set in RestoreFromBackForwardCache(), the bfcache entry is 942 // immediately consumed in CommitPending(). 943 std::unique_ptr<BackForwardCacheImpl::Entry> bfcache_entry_to_restore_; 944 945 // This callback is used when attaching an inner Delegate to |delegate_| 946 // through |frame_tree_node_|. 947 RenderFrameHost::PrepareForInnerWebContentsAttachCallback 948 attach_inner_delegate_callback_; 949 AttachToInnerDelegateState attach_to_inner_delegate_state_ = 950 AttachToInnerDelegateState::NONE; 951 952 base::WeakPtrFactory<RenderFrameHostManager> weak_factory_{this}; 953 954 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostManager); 955 }; 956 957 } // namespace content 958 959 #endif // CONTENT_BROWSER_RENDERER_HOST_RENDER_FRAME_HOST_MANAGER_H_ 960