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_FRAME_HOST_RENDER_FRAME_HOST_MANAGER_H_ 6 #define CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_HOST_MANAGER_H_ 7 8 #include "base/basictypes.h" 9 #include "base/logging.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/weak_ptr.h" 12 #include "content/browser/renderer_host/render_view_host_delegate.h" 13 #include "content/browser/site_instance_impl.h" 14 #include "content/common/content_export.h" 15 #include "content/public/browser/global_request_id.h" 16 #include "content/public/browser/notification_observer.h" 17 #include "content/public/browser/notification_registrar.h" 18 #include "content/public/common/referrer.h" 19 20 21 namespace content { 22 class BrowserContext; 23 class CrossProcessFrameConnector; 24 class CrossSiteTransferringRequest; 25 class InterstitialPageImpl; 26 class FrameTreeNode; 27 class NavigationControllerImpl; 28 class NavigationEntry; 29 class NavigationEntryImpl; 30 class RenderFrameHostDelegate; 31 class RenderFrameHostImpl; 32 class RenderFrameHostManagerTest; 33 class RenderFrameProxyHost; 34 class RenderViewHost; 35 class RenderViewHostImpl; 36 class RenderWidgetHostDelegate; 37 class RenderWidgetHostView; 38 class TestWebContents; 39 class WebUIImpl; 40 41 // Manages RenderFrameHosts for a FrameTreeNode. This class acts as a state 42 // machine to make cross-process navigations in a frame possible. 43 class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver { 44 public: 45 // Functions implemented by our owner that we need. 46 // 47 // TODO(brettw) Clean this up! These are all the functions in WebContentsImpl 48 // that are required to run this class. The design should probably be better 49 // such that these are more clear. 50 // 51 // There is additional complexity that some of the functions we need in 52 // WebContentsImpl are inherited and non-virtual. These are named with 53 // "RenderManager" so that the duplicate implementation of them will be clear. 54 class CONTENT_EXPORT Delegate { 55 public: 56 // Initializes the given renderer if necessary and creates the view ID 57 // corresponding to this view host. If this method is not called and the 58 // process is not shared, then the WebContentsImpl will act as though the 59 // renderer is not running (i.e., it will render "sad tab"). This method is 60 // automatically called from LoadURL. |for_main_frame| indicates whether 61 // this RenderViewHost is used to render a top-level frame, so the 62 // appropriate RenderWidgetHostView type is used. 63 virtual bool CreateRenderViewForRenderManager( 64 RenderViewHost* render_view_host, 65 int opener_route_id, 66 int proxy_routing_id, 67 bool for_main_frame) = 0; 68 virtual void BeforeUnloadFiredFromRenderManager( 69 bool proceed, const base::TimeTicks& proceed_time, 70 bool* proceed_to_fire_unload) = 0; 71 virtual void RenderProcessGoneFromRenderManager( 72 RenderViewHost* render_view_host) = 0; 73 virtual void UpdateRenderViewSizeForRenderManager() = 0; 74 virtual void CancelModalDialogsForRenderManager() = 0; 75 virtual void NotifySwappedFromRenderManager( 76 RenderViewHost* old_host, RenderViewHost* new_host) = 0; 77 virtual NavigationControllerImpl& 78 GetControllerForRenderManager() = 0; 79 80 // Create swapped out RenderViews in the given SiteInstance for each tab in 81 // the opener chain of this tab, if any. This allows the current tab to 82 // make cross-process script calls to its opener(s). Returns the route ID 83 // of the immediate opener, if one exists (otherwise MSG_ROUTING_NONE). 84 virtual int CreateOpenerRenderViewsForRenderManager( 85 SiteInstance* instance) = 0; 86 87 // Creates a WebUI object for the given URL if one applies. Ownership of the 88 // returned pointer will be passed to the caller. If no WebUI applies, 89 // returns NULL. 90 virtual WebUIImpl* CreateWebUIForRenderManager(const GURL& url) = 0; 91 92 // Returns the navigation entry of the current navigation, or NULL if there 93 // is none. 94 virtual NavigationEntry* 95 GetLastCommittedNavigationEntryForRenderManager() = 0; 96 97 // Returns true if the location bar should be focused by default rather than 98 // the page contents. The view calls this function when the tab is focused 99 // to see what it should do. 100 virtual bool FocusLocationBarByDefault() = 0; 101 102 // Focuses the location bar. 103 virtual void SetFocusToLocationBar(bool select_all) = 0; 104 105 // Creates a view and sets the size for the specified RVH. 106 virtual void CreateViewAndSetSizeForRVH(RenderViewHost* rvh) = 0; 107 108 // Returns true if views created for this delegate should be created in a 109 // hidden state. 110 virtual bool IsHidden() = 0; 111 112 protected: ~Delegate()113 virtual ~Delegate() {} 114 }; 115 116 // Used with FrameTree::ForEach to delete RenderFrameHosts pending shutdown 117 // from a FrameTreeNode's RenderFrameHostManager. Used during destruction of 118 // WebContentsImpl. 119 static bool ClearRFHsPendingShutdown(FrameTreeNode* node); 120 121 // All three delegate pointers must be non-NULL and are not owned by this 122 // class. They must outlive this class. The RenderViewHostDelegate and 123 // RenderWidgetHostDelegate are what will be installed into all 124 // RenderViewHosts that are created. 125 // 126 // You must call Init() before using this class. 127 RenderFrameHostManager( 128 FrameTreeNode* frame_tree_node, 129 RenderFrameHostDelegate* render_frame_delegate, 130 RenderViewHostDelegate* render_view_delegate, 131 RenderWidgetHostDelegate* render_widget_delegate, 132 Delegate* delegate); 133 virtual ~RenderFrameHostManager(); 134 135 // For arguments, see WebContentsImpl constructor. 136 void Init(BrowserContext* browser_context, 137 SiteInstance* site_instance, 138 int view_routing_id, 139 int frame_routing_id); 140 141 // Returns the currently active RenderFrameHost. 142 // 143 // This will be non-NULL between Init() and Shutdown(). You may want to NULL 144 // check it in many cases, however. Windows can send us messages during the 145 // destruction process after it has been shut down. current_frame_host()146 RenderFrameHostImpl* current_frame_host() const { 147 return render_frame_host_.get(); 148 } 149 150 // TODO(creis): Remove this when we no longer use RVH for navigation. 151 RenderViewHostImpl* current_host() const; 152 153 // Returns the view associated with the current RenderViewHost, or NULL if 154 // there is no current one. 155 RenderWidgetHostView* GetRenderWidgetHostView() const; 156 157 RenderFrameProxyHost* GetProxyToParent(); 158 159 // Returns the pending RenderFrameHost, or NULL if there is no pending one. pending_frame_host()160 RenderFrameHostImpl* pending_frame_host() const { 161 return pending_render_frame_host_.get(); 162 } 163 164 // TODO(creis): Remove this when we no longer use RVH for navigation. 165 RenderViewHostImpl* pending_render_view_host() const; 166 167 // Returns the current committed Web UI or NULL if none applies. web_ui()168 WebUIImpl* web_ui() const { return web_ui_.get(); } 169 170 // Returns the Web UI for the pending navigation, or NULL of none applies. pending_web_ui()171 WebUIImpl* pending_web_ui() const { 172 return pending_web_ui_.get() ? pending_web_ui_.get() : 173 pending_and_current_web_ui_.get(); 174 } 175 176 // Sets the pending Web UI for the pending navigation, ensuring that the 177 // bindings are appropriate for the given NavigationEntry. 178 void SetPendingWebUI(const NavigationEntryImpl& entry); 179 180 // Called when we want to instruct the renderer to navigate to the given 181 // navigation entry. It may create a new RenderFrameHost or re-use an existing 182 // one. The RenderFrameHost to navigate will be returned. Returns NULL if one 183 // could not be created. 184 RenderFrameHostImpl* Navigate(const NavigationEntryImpl& entry); 185 186 // Instructs the various live views to stop. Called when the user directed the 187 // page to stop loading. 188 void Stop(); 189 190 // Notifies the regular and pending RenderViewHosts that a load is or is not 191 // happening. Even though the message is only for one of them, we don't know 192 // which one so we tell both. 193 void SetIsLoading(bool is_loading); 194 195 // Whether to close the tab or not when there is a hang during an unload 196 // handler. If we are mid-crosssite navigation, then we should proceed 197 // with the navigation instead of closing the tab. 198 bool ShouldCloseTabOnUnresponsiveRenderer(); 199 200 // Confirms whether we should close the page or navigate away. This is called 201 // before a cross-site request or before a tab/window is closed (as indicated 202 // by the first parameter) to allow the appropriate renderer to approve or 203 // deny the request. |proceed| indicates whether the user chose to proceed. 204 // |proceed_time| is the time when the request was allowed to proceed. 205 void OnBeforeUnloadACK(bool for_cross_site_transition, 206 bool proceed, 207 const base::TimeTicks& proceed_time); 208 209 // The |pending_render_frame_host| is ready to commit a page. We should 210 // ensure that the old RenderFrameHost runs its unload handler first and 211 // determine whether a RenderFrameHost transfer is needed. 212 // |cross_site_transferring_request| is NULL if a request is not being 213 // transferred between renderers. 214 void OnCrossSiteResponse( 215 RenderFrameHostImpl* pending_render_frame_host, 216 const GlobalRequestID& global_request_id, 217 scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request, 218 const std::vector<GURL>& transfer_url_chain, 219 const Referrer& referrer, 220 PageTransition page_transition, 221 bool should_replace_current_entry); 222 223 // The RenderFrameHost has been swapped out, so we should resume the pending 224 // network response and allow the pending RenderFrameHost to commit. 225 void SwappedOut(RenderFrameHostImpl* render_frame_host); 226 227 // Called when a renderer's frame navigates. 228 void DidNavigateFrame(RenderFrameHostImpl* render_frame_host); 229 230 // Called when a renderer sets its opener to null. 231 void DidDisownOpener(RenderViewHost* render_view_host); 232 233 // Helper method to create and initialize a RenderFrameHost. If |swapped_out| 234 // is true, it will be initially placed on the swapped out hosts list. 235 // Otherwise, it will be used for a pending cross-site navigation. 236 // Returns the routing id of the *view* associated with the frame. 237 int CreateRenderFrame(SiteInstance* instance, 238 int opener_route_id, 239 bool swapped_out, 240 bool hidden); 241 242 // Sets the passed passed interstitial as the currently showing interstitial. 243 // |interstitial_page| should be non NULL (use the remove_interstitial_page 244 // method to unset the interstitial) and no interstitial page should be set 245 // when there is already a non NULL interstitial page set. set_interstitial_page(InterstitialPageImpl * interstitial_page)246 void set_interstitial_page(InterstitialPageImpl* interstitial_page) { 247 DCHECK(!interstitial_page_ && interstitial_page); 248 interstitial_page_ = interstitial_page; 249 } 250 251 // Unsets the currently showing interstitial. remove_interstitial_page()252 void remove_interstitial_page() { 253 DCHECK(interstitial_page_); 254 interstitial_page_ = NULL; 255 } 256 257 // Returns the currently showing interstitial, NULL if no interstitial is 258 // showing. interstitial_page()259 InterstitialPageImpl* interstitial_page() const { return interstitial_page_; } 260 261 // NotificationObserver implementation. 262 virtual void Observe(int type, 263 const NotificationSource& source, 264 const NotificationDetails& details) OVERRIDE; 265 266 // Returns whether the given RenderFrameHost (or its associated 267 // RenderViewHost) is on the list of swapped out RenderFrameHosts. 268 bool IsRVHOnSwappedOutList(RenderViewHostImpl* rvh) const; 269 bool IsOnSwappedOutList(RenderFrameHostImpl* rfh) const; 270 271 // Returns the swapped out RenderViewHost or RenderFrameHost for the given 272 // SiteInstance, if any. This method is *deprecated* and 273 // GetRenderFrameProxyHost should be used. 274 RenderViewHostImpl* GetSwappedOutRenderViewHost(SiteInstance* instance) const; 275 RenderFrameProxyHost* GetRenderFrameProxyHost( 276 SiteInstance* instance) const; 277 278 // Runs the unload handler in the current page, when we know that a pending 279 // cross-process navigation is going to commit. We may initiate a transfer 280 // to a new process after this completes or times out. 281 void SwapOutOldPage(); 282 283 // Deletes a RenderFrameHost that was pending shutdown. 284 void ClearPendingShutdownRFHForSiteInstance(int32 site_instance_id, 285 RenderFrameHostImpl* rfh); 286 287 // Deletes any proxy hosts associated with this node. Used during destruction 288 // of WebContentsImpl. 289 void ResetProxyHosts(); 290 291 private: 292 friend class RenderFrameHostManagerTest; 293 friend class TestWebContents; 294 295 // Tracks information about a navigation while a cross-process transition is 296 // in progress, in case we need to transfer it to a new RenderFrameHost. 297 // When a request is being transferred, deleting the PendingNavigationParams, 298 // and thus |cross_site_transferring_request|, will cancel the request being 299 // transferred, unless its ReleaseRequest method has been called. 300 struct PendingNavigationParams { 301 PendingNavigationParams( 302 const GlobalRequestID& global_request_id, 303 scoped_ptr<CrossSiteTransferringRequest> 304 cross_site_transferring_request, 305 const std::vector<GURL>& transfer_url, 306 Referrer referrer, 307 PageTransition page_transition, 308 int render_frame_id, 309 bool should_replace_current_entry); 310 ~PendingNavigationParams(); 311 312 // The child ID and request ID for the pending navigation. Present whether 313 // |request_transfer| is NULL or not. 314 GlobalRequestID global_request_id; 315 316 // If a pending request needs to be transferred to another process, this 317 // owns the request until it's transferred to the new process, so it will be 318 // cleaned up if the navigation is cancelled. Otherwise, this is NULL. 319 scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request; 320 321 // If |request_transfer| is non-NULL, the values below are all set. 322 323 // The first entry is the original request URL, and the last entry is the 324 // destination URL to request in the new process. 325 std::vector<GURL> transfer_url_chain; 326 327 // This is the referrer to use for the request in the new process. 328 Referrer referrer; 329 330 // This is the transition type for the original navigation. 331 PageTransition page_transition; 332 333 // This is the frame routing ID to use in RequestTransferURL. 334 int render_frame_id; 335 336 // This is whether the navigation should replace the current history entry. 337 bool should_replace_current_entry; 338 }; 339 340 // Used with FrameTree::ForEach to erase RenderFrameProxyHosts from a 341 // FrameTreeNode's RenderFrameHostManager. 342 static bool ClearProxiesInSiteInstance(int32 site_instance_id, 343 FrameTreeNode* node); 344 345 // Returns whether this tab should transition to a new renderer for 346 // cross-site URLs. Enabled unless we see the --process-per-tab command line 347 // switch. Can be overridden in unit tests. 348 bool ShouldTransitionCrossSite(); 349 350 // Returns true if for the navigation from |current_entry| to |new_entry|, 351 // a new SiteInstance and BrowsingInstance should be created (even if we are 352 // in a process model that doesn't usually swap). This forces a process swap 353 // and severs script connections with existing tabs. Cases where this can 354 // happen include transitions between WebUI and regular web pages. 355 // Either of the entries may be NULL. 356 bool ShouldSwapBrowsingInstancesForNavigation( 357 const NavigationEntry* current_entry, 358 const NavigationEntryImpl* new_entry) const; 359 360 // Returns true if it is safe to reuse the current WebUI when navigating from 361 // |current_entry| to |new_entry|. 362 bool ShouldReuseWebUI( 363 const NavigationEntry* current_entry, 364 const NavigationEntryImpl* new_entry) const; 365 366 // Returns an appropriate SiteInstance object for the given NavigationEntry, 367 // possibly reusing the current SiteInstance. If --process-per-tab is used, 368 // this is only called when ShouldSwapBrowsingInstancesForNavigation returns 369 // true. 370 SiteInstance* GetSiteInstanceForEntry( 371 const NavigationEntryImpl& entry, 372 SiteInstance* current_instance, 373 bool force_browsing_instance_swap); 374 375 // Creates a RenderFrameHost and corresponding RenderViewHost if necessary. 376 scoped_ptr<RenderFrameHostImpl> CreateRenderFrameHost(SiteInstance* instance, 377 int view_routing_id, 378 int frame_routing_id, 379 bool swapped_out, 380 bool hidden); 381 382 // Sets up the necessary state for a new RenderViewHost with the given opener, 383 // if necessary. It creates a RenderFrameProxy in the target renderer process 384 // with the given |proxy_routing_id|, which is used to route IPC messages when 385 // in swapped out state. Returns early if the RenderViewHost has already been 386 // initialized for another RenderFrameHost. 387 // TODO(creis): opener_route_id is currently for the RenderViewHost but should 388 // be for the RenderFrame, since frames can have openers. 389 bool InitRenderView(RenderViewHost* render_view_host, 390 int opener_route_id, 391 int proxy_routing_id, 392 bool for_main_frame); 393 394 // Sets the pending RenderFrameHost/WebUI to be the active one. Note that this 395 // doesn't require the pending render_frame_host_ pointer to be non-NULL, 396 // since there could be Web UI switching as well. Call this for every commit. 397 void CommitPending(); 398 399 // Shutdown all RenderFrameHosts in a SiteInstance. This is called to shutdown 400 // frames when all the frames in a SiteInstance are confirmed to be swapped 401 // out. 402 void ShutdownRenderFrameHostsInSiteInstance(int32 site_instance_id); 403 404 // Helper method to terminate the pending RenderViewHost. 405 void CancelPending(); 406 407 // Helper method to set the active RenderFrameHost. Returns the old 408 // RenderFrameHost and updates counts. 409 scoped_ptr<RenderFrameHostImpl> SetRenderFrameHost( 410 scoped_ptr<RenderFrameHostImpl> render_frame_host); 411 412 RenderFrameHostImpl* UpdateStateForNavigate( 413 const NavigationEntryImpl& entry); 414 415 // Called when a renderer process is starting to close. We should not 416 // schedule new navigations in its swapped out RenderFrameHosts after this. 417 void RendererProcessClosing(RenderProcessHost* render_process_host); 418 419 // For use in creating RenderFrameHosts. 420 FrameTreeNode* frame_tree_node_; 421 422 // Our delegate, not owned by us. Guaranteed non-NULL. 423 Delegate* delegate_; 424 425 // Whether a navigation requiring different RenderFrameHosts is pending. This 426 // is either for cross-site requests or when required for the process type 427 // (like WebUI). 428 bool cross_navigation_pending_; 429 430 // Implemented by the owner of this class. These delegates are installed into 431 // all the RenderFrameHosts that we create. 432 RenderFrameHostDelegate* render_frame_delegate_; 433 RenderViewHostDelegate* render_view_delegate_; 434 RenderWidgetHostDelegate* render_widget_delegate_; 435 436 // Our RenderFrameHost and its associated Web UI (if any, will be NULL for 437 // non-WebUI pages). This object is responsible for all communication with 438 // a child RenderFrame instance. 439 // For now, RenderFrameHost keeps a RenderViewHost in its SiteInstance alive. 440 // Eventually, RenderViewHost will be replaced with a page context. 441 scoped_ptr<RenderFrameHostImpl> render_frame_host_; 442 scoped_ptr<WebUIImpl> web_ui_; 443 444 // A RenderFrameHost used to load a cross-site page. This remains hidden 445 // while a cross-site request is pending until it calls DidNavigate. It may 446 // have an associated Web UI, in which case the Web UI pointer will be non- 447 // NULL. 448 // 449 // The |pending_web_ui_| may be non-NULL even when the 450 // |pending_render_frame_host_| is NULL. This will happen when we're 451 // transitioning between two Web UI pages: the RFH won't be swapped, so the 452 // pending pointer will be unused, but there will be a pending Web UI 453 // associated with the navigation. 454 scoped_ptr<RenderFrameHostImpl> pending_render_frame_host_; 455 456 // Tracks information about any current pending cross-process navigation. 457 scoped_ptr<PendingNavigationParams> pending_nav_params_; 458 459 // If either of these is non-NULL, the pending navigation is to a chrome: 460 // page. The scoped_ptr is used if pending_web_ui_ != web_ui_, the WeakPtr is 461 // used for when they reference the same object. If either is non-NULL, the 462 // other should be NULL. 463 scoped_ptr<WebUIImpl> pending_web_ui_; 464 base::WeakPtr<WebUIImpl> pending_and_current_web_ui_; 465 466 // A map of site instance ID to RenderFrameProxyHosts. 467 typedef base::hash_map<int32, RenderFrameProxyHost*> RenderFrameProxyHostMap; 468 RenderFrameProxyHostMap proxy_hosts_; 469 470 // A map of RenderFrameHosts pending shutdown. 471 typedef base::hash_map<int32, linked_ptr<RenderFrameHostImpl> > 472 RFHPendingDeleteMap; 473 RFHPendingDeleteMap pending_delete_hosts_; 474 475 // The intersitial page currently shown if any, not own by this class 476 // (the InterstitialPage is self-owned, it deletes itself when hidden). 477 InterstitialPageImpl* interstitial_page_; 478 479 NotificationRegistrar registrar_; 480 481 base::WeakPtrFactory<RenderFrameHostManager> weak_factory_; 482 483 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostManager); 484 }; 485 486 } // namespace content 487 488 #endif // CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_HOST_MANAGER_H_ 489