render_frame_host_manager.h revision f2477e01787aa58f445919b809d89e252beef54f
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/notification_observer.h"
16#include "content/public/browser/notification_registrar.h"
17#include "content/public/common/referrer.h"
18
19
20namespace content {
21class BrowserContext;
22class InterstitialPageImpl;
23class NavigationControllerImpl;
24class NavigationEntry;
25class NavigationEntryImpl;
26class RenderFrameHostManagerTest;
27class RenderViewHost;
28class RenderViewHostImpl;
29class RenderWidgetHostDelegate;
30class RenderWidgetHostView;
31class TestWebContents;
32class WebUIImpl;
33
34// Manages RenderFrameHosts for a FrameTreeNode.  This class acts as a state
35// machine to make cross-process navigations in a frame possible.
36class CONTENT_EXPORT RenderFrameHostManager
37    : public RenderViewHostDelegate::RendererManagement,
38      public NotificationObserver {
39 public:
40  // Functions implemented by our owner that we need.
41  //
42  // TODO(brettw) Clean this up! These are all the functions in WebContentsImpl
43  // that are required to run this class. The design should probably be better
44  // such that these are more clear.
45  //
46  // There is additional complexity that some of the functions we need in
47  // WebContentsImpl are inherited and non-virtual. These are named with
48  // "RenderManager" so that the duplicate implementation of them will be clear.
49  class CONTENT_EXPORT Delegate {
50   public:
51    // Initializes the given renderer if necessary and creates the view ID
52    // corresponding to this view host. If this method is not called and the
53    // process is not shared, then the WebContentsImpl will act as though the
54    // renderer is not running (i.e., it will render "sad tab"). This method is
55    // automatically called from LoadURL.
56    //
57    // If you are attaching to an already-existing RenderView, you should call
58    // InitWithExistingID.
59    virtual bool CreateRenderViewForRenderManager(
60        RenderViewHost* render_view_host, int opener_route_id) = 0;
61    virtual void BeforeUnloadFiredFromRenderManager(
62        bool proceed, const base::TimeTicks& proceed_time,
63        bool* proceed_to_fire_unload) = 0;
64    virtual void RenderProcessGoneFromRenderManager(
65        RenderViewHost* render_view_host) = 0;
66    virtual void UpdateRenderViewSizeForRenderManager() = 0;
67    virtual void CancelModalDialogsForRenderManager() = 0;
68    virtual void NotifySwappedFromRenderManager(
69        RenderViewHost* old_host, RenderViewHost* new_host) = 0;
70    virtual NavigationControllerImpl&
71        GetControllerForRenderManager() = 0;
72
73    // Create swapped out RenderViews in the given SiteInstance for each tab in
74    // the opener chain of this tab, if any.  This allows the current tab to
75    // make cross-process script calls to its opener(s).  Returns the route ID
76    // of the immediate opener, if one exists (otherwise MSG_ROUTING_NONE).
77    virtual int CreateOpenerRenderViewsForRenderManager(
78        SiteInstance* instance) = 0;
79
80    // Creates a WebUI object for the given URL if one applies. Ownership of the
81    // returned pointer will be passed to the caller. If no WebUI applies,
82    // returns NULL.
83    virtual WebUIImpl* CreateWebUIForRenderManager(const GURL& url) = 0;
84
85    // Returns the navigation entry of the current navigation, or NULL if there
86    // is none.
87    virtual NavigationEntry*
88        GetLastCommittedNavigationEntryForRenderManager() = 0;
89
90    // Returns true if the location bar should be focused by default rather than
91    // the page contents. The view calls this function when the tab is focused
92    // to see what it should do.
93    virtual bool FocusLocationBarByDefault() = 0;
94
95    // Focuses the location bar.
96    virtual void SetFocusToLocationBar(bool select_all) = 0;
97
98    // Creates a view and sets the size for the specified RVH.
99    virtual void CreateViewAndSetSizeForRVH(RenderViewHost* rvh) = 0;
100
101    // Returns true if views created for this delegate should be created in a
102    // hidden state.
103    virtual bool IsHidden() = 0;
104
105   protected:
106    virtual ~Delegate() {}
107  };
108
109  // All three delegate pointers must be non-NULL and are not owned by this
110  // class.  They must outlive this class. The RenderViewHostDelegate and
111  // RenderWidgetHostDelegate are what will be installed into all
112  // RenderViewHosts that are created.
113  //
114  // You must call Init() before using this class.
115  RenderFrameHostManager(
116      RenderViewHostDelegate* render_view_delegate,
117      RenderWidgetHostDelegate* render_widget_delegate,
118      Delegate* delegate);
119  virtual ~RenderFrameHostManager();
120
121  // For arguments, see WebContentsImpl constructor.
122  void Init(BrowserContext* browser_context,
123            SiteInstance* site_instance,
124            int routing_id,
125            int main_frame_routing_id);
126
127  // Returns the currently active RenderViewHost.
128  //
129  // This will be non-NULL between Init() and Shutdown(). You may want to NULL
130  // check it in many cases, however. Windows can send us messages during the
131  // destruction process after it has been shut down.
132  RenderViewHostImpl* current_host() const;
133
134  // Returns the view associated with the current RenderViewHost, or NULL if
135  // there is no current one.
136  RenderWidgetHostView* GetRenderWidgetHostView() const;
137
138  // Returns the pending render view host, or NULL if there is no pending one.
139  RenderViewHostImpl* pending_render_view_host() const;
140
141  // Returns the current committed Web UI or NULL if none applies.
142  WebUIImpl* web_ui() const { return web_ui_.get(); }
143
144  // Returns the Web UI for the pending navigation, or NULL of none applies.
145  WebUIImpl* pending_web_ui() const {
146    return pending_web_ui_.get() ? pending_web_ui_.get() :
147                                   pending_and_current_web_ui_.get();
148  }
149
150  // Sets the pending Web UI for the pending navigation, ensuring that the
151  // bindings are appropriate for the given NavigationEntry.
152  void SetPendingWebUI(const NavigationEntryImpl& entry);
153
154  // Called when we want to instruct the renderer to navigate to the given
155  // navigation entry. It may create a new RenderViewHost or re-use an existing
156  // one. The RenderViewHost to navigate will be returned. Returns NULL if one
157  // could not be created.
158  RenderViewHostImpl* Navigate(const NavigationEntryImpl& entry);
159
160  // Instructs the various live views to stop. Called when the user directed the
161  // page to stop loading.
162  void Stop();
163
164  // Notifies the regular and pending RenderViewHosts that a load is or is not
165  // happening. Even though the message is only for one of them, we don't know
166  // which one so we tell both.
167  void SetIsLoading(bool is_loading);
168
169  // Whether to close the tab or not when there is a hang during an unload
170  // handler. If we are mid-crosssite navigation, then we should proceed
171  // with the navigation instead of closing the tab.
172  bool ShouldCloseTabOnUnresponsiveRenderer();
173
174  // The RenderViewHost has been swapped out, so we should resume the pending
175  // network response and allow the pending RenderViewHost to commit.
176  void SwappedOut(RenderViewHost* render_view_host);
177
178  // Called when a renderer's main frame navigates.
179  void DidNavigateMainFrame(RenderViewHost* render_view_host);
180
181  // Called when a renderer sets its opener to null.
182  void DidDisownOpener(RenderViewHost* render_view_host);
183
184  // Helper method to create a RenderViewHost.  If |swapped_out| is true, it
185  // will be initially placed on the swapped out hosts list.  Otherwise, it
186  // will be used for a pending cross-site navigation.
187  int CreateRenderView(SiteInstance* instance,
188                       int opener_route_id,
189                       bool swapped_out,
190                       bool hidden);
191
192  // Called when a provisional load on the given renderer is aborted.
193  void RendererAbortedProvisionalLoad(RenderViewHost* render_view_host);
194
195  // Sets the passed passed interstitial as the currently showing interstitial.
196  // |interstitial_page| should be non NULL (use the remove_interstitial_page
197  // method to unset the interstitial) and no interstitial page should be set
198  // when there is already a non NULL interstitial page set.
199  void set_interstitial_page(InterstitialPageImpl* interstitial_page) {
200    DCHECK(!interstitial_page_ && interstitial_page);
201    interstitial_page_ = interstitial_page;
202  }
203
204  // Unsets the currently showing interstitial.
205  void remove_interstitial_page() {
206    DCHECK(interstitial_page_);
207    interstitial_page_ = NULL;
208  }
209
210  // Returns the currently showing interstitial, NULL if no interstitial is
211  // showing.
212  InterstitialPageImpl* interstitial_page() const { return interstitial_page_; }
213
214  // RenderViewHostDelegate::RendererManagement implementation.
215  virtual void ShouldClosePage(
216      bool for_cross_site_transition,
217      bool proceed,
218      const base::TimeTicks& proceed_time) OVERRIDE;
219  virtual void OnCrossSiteResponse(
220      RenderViewHost* pending_render_view_host,
221      const GlobalRequestID& global_request_id,
222      bool is_transfer,
223      const std::vector<GURL>& transfer_url_chain,
224      const Referrer& referrer,
225      PageTransition page_transition,
226      int64 frame_id,
227      bool should_replace_current_entry) OVERRIDE;
228
229  // NotificationObserver implementation.
230  virtual void Observe(int type,
231                       const NotificationSource& source,
232                       const NotificationDetails& details) OVERRIDE;
233
234  // Called when a RenderViewHost is about to be deleted.
235  void RenderViewDeleted(RenderViewHost* rvh);
236
237  // Returns whether the given RenderViewHost is on the list of swapped out
238  // RenderViewHosts.
239  bool IsOnSwappedOutList(RenderViewHost* rvh) const;
240
241  // Returns the swapped out RenderViewHost for the given SiteInstance, if any.
242  RenderViewHostImpl* GetSwappedOutRenderViewHost(SiteInstance* instance);
243
244  // Runs the unload handler in the current page, when we know that a pending
245  // cross-process navigation is going to commit.  We may initiate a transfer
246  // to a new process after this completes or times out.
247  void SwapOutOldPage();
248
249 private:
250  friend class RenderFrameHostManagerTest;
251  friend class TestWebContents;
252
253  // Tracks information about a navigation while a cross-process transition is
254  // in progress, in case we need to transfer it to a new RenderViewHost.
255  struct PendingNavigationParams {
256    PendingNavigationParams();
257    PendingNavigationParams(const GlobalRequestID& global_request_id,
258                            bool is_transfer,
259                            const std::vector<GURL>& transfer_url,
260                            Referrer referrer,
261                            PageTransition page_transition,
262                            int64 frame_id,
263                            bool should_replace_current_entry);
264    ~PendingNavigationParams();
265
266    // The child ID and request ID for the pending navigation.  Present whether
267    // |is_transfer| is true or false.
268    GlobalRequestID global_request_id;
269
270    // Whether this pending navigation needs to be transferred to another
271    // process than the one it was going to commit in.  If so, the
272    // |transfer_url|, |referrer|, and |frame_id| parameters will be set.
273    bool is_transfer;
274
275    // If |is_transfer|, this is the URL chain of the request.  The first entry
276    // is the original request URL, and the last entry is the destination URL to
277    // request in the new process.
278    std::vector<GURL> transfer_url_chain;
279
280    // If |is_transfer|, this is the referrer to use for the request in the new
281    // process.
282    Referrer referrer;
283
284    // If |is_transfer|, this is the transition type for the original
285    // navigation.
286    PageTransition page_transition;
287
288    // If |is_transfer|, this is the frame ID to use in RequestTransferURL.
289    int64 frame_id;
290
291    // If |is_transfer|, this is whether the navigation should replace the
292    // current history entry.
293    bool should_replace_current_entry;
294  };
295
296  // Returns whether this tab should transition to a new renderer for
297  // cross-site URLs.  Enabled unless we see the --process-per-tab command line
298  // switch.  Can be overridden in unit tests.
299  bool ShouldTransitionCrossSite();
300
301  // Returns true if for the navigation from |current_entry| to |new_entry|,
302  // a new SiteInstance and BrowsingInstance should be created (even if we are
303  // in a process model that doesn't usually swap).  This forces a process swap
304  // and severs script connections with existing tabs.  Cases where this can
305  // happen include transitions between WebUI and regular web pages.
306  // Either of the entries may be NULL.
307  bool ShouldSwapBrowsingInstancesForNavigation(
308      const NavigationEntry* current_entry,
309      const NavigationEntryImpl* new_entry) const;
310
311  // Returns true if it is safe to reuse the current WebUI when navigating from
312  // |current_entry| to |new_entry|.
313  bool ShouldReuseWebUI(
314      const NavigationEntry* current_entry,
315      const NavigationEntryImpl* new_entry) const;
316
317  // Returns an appropriate SiteInstance object for the given NavigationEntry,
318  // possibly reusing the current SiteInstance.  If --process-per-tab is used,
319  // this is only called when ShouldSwapBrowsingInstancesForNavigation returns
320  // true.
321  SiteInstance* GetSiteInstanceForEntry(
322      const NavigationEntryImpl& entry,
323      SiteInstance* current_instance,
324      bool force_browsing_instance_swap);
325
326  // Sets up the necessary state for a new RenderViewHost with the given opener.
327  bool InitRenderView(RenderViewHost* render_view_host, int opener_route_id);
328
329  // Sets the pending RenderViewHost/WebUI to be the active one. Note that this
330  // doesn't require the pending render_view_host_ pointer to be non-NULL, since
331  // there could be Web UI switching as well. Call this for every commit.
332  void CommitPending();
333
334  // Shutdown all RenderViewHosts in a SiteInstance. This is called
335  // to shutdown views when all the views in a SiteInstance are
336  // confirmed to be swapped out.
337  void ShutdownRenderViewHostsInSiteInstance(int32 site_instance_id);
338
339  // Helper method to terminate the pending RenderViewHost.
340  void CancelPending();
341
342  RenderViewHostImpl* UpdateRendererStateForNavigate(
343      const NavigationEntryImpl& entry);
344
345  // Called when a renderer process is starting to close.  We should not
346  // schedule new navigations in its swapped out RenderViewHosts after this.
347  void RendererProcessClosing(RenderProcessHost* render_process_host);
348
349  // Our delegate, not owned by us. Guaranteed non-NULL.
350  Delegate* delegate_;
351
352  // Whether a navigation requiring different RenderView's is pending. This is
353  // either cross-site request is (in the new process model), or when required
354  // for the view type (like view source versus not).
355  bool cross_navigation_pending_;
356
357  // Implemented by the owner of this class, these delegates are installed into
358  // all the RenderViewHosts that we create.
359  RenderViewHostDelegate* render_view_delegate_;
360  RenderWidgetHostDelegate* render_widget_delegate_;
361
362  // Our RenderView host and its associated Web UI (if any, will be NULL for
363  // non-DOM-UI pages). This object is responsible for all communication with
364  // a child RenderView instance.
365  RenderViewHostImpl* render_view_host_;
366  scoped_ptr<WebUIImpl> web_ui_;
367
368  // A RenderViewHost used to load a cross-site page. This remains hidden
369  // while a cross-site request is pending until it calls DidNavigate. It may
370  // have an associated Web UI, in which case the Web UI pointer will be non-
371  // NULL.
372  //
373  // The |pending_web_ui_| may be non-NULL even when the
374  // |pending_render_view_host_| is NULL. This will happen when we're
375  // transitioning between two Web UI pages: the RVH won't be swapped, so the
376  // pending pointer will be unused, but there will be a pending Web UI
377  // associated with the navigation.
378  RenderViewHostImpl* pending_render_view_host_;
379
380  // Tracks information about any current pending cross-process navigation.
381  scoped_ptr<PendingNavigationParams> pending_nav_params_;
382
383  // If either of these is non-NULL, the pending navigation is to a chrome:
384  // page. The scoped_ptr is used if pending_web_ui_ != web_ui_, the WeakPtr is
385  // used for when they reference the same object. If either is non-NULL, the
386  // other should be NULL.
387  scoped_ptr<WebUIImpl> pending_web_ui_;
388  base::WeakPtr<WebUIImpl> pending_and_current_web_ui_;
389
390  // A map of site instance ID to swapped out RenderViewHosts.  This may include
391  // pending_render_view_host_ for navigations to existing entries.
392  typedef base::hash_map<int32, RenderViewHostImpl*> RenderViewHostMap;
393  RenderViewHostMap swapped_out_hosts_;
394
395  // The intersitial page currently shown if any, not own by this class
396  // (the InterstitialPage is self-owned, it deletes itself when hidden).
397  InterstitialPageImpl* interstitial_page_;
398
399  NotificationRegistrar registrar_;
400
401  DISALLOW_COPY_AND_ASSIGN(RenderFrameHostManager);
402};
403
404}  // namespace content
405
406#endif  // CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_HOST_MANAGER_H_
407