• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "content/browser/frame_host/frame_tree.h"
6 
7 #include <queue>
8 
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "content/browser/frame_host/frame_tree_node.h"
12 #include "content/browser/frame_host/navigator.h"
13 #include "content/browser/frame_host/render_frame_host_factory.h"
14 #include "content/browser/frame_host/render_frame_host_impl.h"
15 #include "content/browser/renderer_host/render_view_host_factory.h"
16 #include "content/browser/renderer_host/render_view_host_impl.h"
17 
18 namespace content {
19 
20 namespace {
21 // Used with FrameTree::ForEach() to search for the FrameTreeNode
22 // corresponding to |frame_tree_node_id|.
FrameTreeNodeForId(int64 frame_tree_node_id,FrameTreeNode ** out_node,FrameTreeNode * node)23 bool FrameTreeNodeForId(int64 frame_tree_node_id,
24                         FrameTreeNode** out_node,
25                         FrameTreeNode* node) {
26   if (node->frame_tree_node_id() == frame_tree_node_id) {
27     *out_node = node;
28     // Terminate iteration once the node has been found.
29     return false;
30   }
31   return true;
32 }
33 
FrameTreeNodeForRoutingId(int routing_id,int process_id,FrameTreeNode ** out_node,FrameTreeNode * node)34 bool FrameTreeNodeForRoutingId(int routing_id,
35                                int process_id,
36                                FrameTreeNode** out_node,
37                                FrameTreeNode* node) {
38   // TODO(creis): Look through the swapped out RFHs as well.
39   if (node->current_frame_host()->GetProcess()->GetID() == process_id &&
40       node->current_frame_host()->GetRoutingID() == routing_id) {
41     *out_node = node;
42     // Terminate iteration once the node has been found.
43     return false;
44   }
45   return true;
46 }
47 
48 // Iterate over the FrameTree to reset any node affected by the loss of the
49 // given RenderViewHost's process.
ResetNodesForNewProcess(RenderViewHost * render_view_host,FrameTreeNode * node)50 bool ResetNodesForNewProcess(RenderViewHost* render_view_host,
51                              FrameTreeNode* node) {
52   if (render_view_host == node->current_frame_host()->render_view_host())
53     node->ResetForNewProcess();
54   return true;
55 }
56 
57 }  // namespace
58 
FrameTree(Navigator * navigator,RenderFrameHostDelegate * render_frame_delegate,RenderViewHostDelegate * render_view_delegate,RenderWidgetHostDelegate * render_widget_delegate,RenderFrameHostManager::Delegate * manager_delegate)59 FrameTree::FrameTree(Navigator* navigator,
60                      RenderFrameHostDelegate* render_frame_delegate,
61                      RenderViewHostDelegate* render_view_delegate,
62                      RenderWidgetHostDelegate* render_widget_delegate,
63                      RenderFrameHostManager::Delegate* manager_delegate)
64     : render_frame_delegate_(render_frame_delegate),
65       render_view_delegate_(render_view_delegate),
66       render_widget_delegate_(render_widget_delegate),
67       manager_delegate_(manager_delegate),
68       root_(new FrameTreeNode(this,
69                               navigator,
70                               render_frame_delegate,
71                               render_view_delegate,
72                               render_widget_delegate,
73                               manager_delegate,
74                               std::string())),
75       focused_frame_tree_node_id_(-1) {
76 }
77 
~FrameTree()78 FrameTree::~FrameTree() {
79 }
80 
FindByID(int64 frame_tree_node_id)81 FrameTreeNode* FrameTree::FindByID(int64 frame_tree_node_id) {
82   FrameTreeNode* node = NULL;
83   ForEach(base::Bind(&FrameTreeNodeForId, frame_tree_node_id, &node));
84   return node;
85 }
86 
FindByRoutingID(int routing_id,int process_id)87 FrameTreeNode* FrameTree::FindByRoutingID(int routing_id, int process_id) {
88   FrameTreeNode* node = NULL;
89   ForEach(
90       base::Bind(&FrameTreeNodeForRoutingId, routing_id, process_id, &node));
91   return node;
92 }
93 
ForEach(const base::Callback<bool (FrameTreeNode *)> & on_node) const94 void FrameTree::ForEach(
95     const base::Callback<bool(FrameTreeNode*)>& on_node) const {
96   std::queue<FrameTreeNode*> queue;
97   queue.push(root_.get());
98 
99   while (!queue.empty()) {
100     FrameTreeNode* node = queue.front();
101     queue.pop();
102     if (!on_node.Run(node))
103       break;
104 
105     for (size_t i = 0; i < node->child_count(); ++i)
106       queue.push(node->child_at(i));
107   }
108 }
109 
AddFrame(FrameTreeNode * parent,int new_routing_id,const std::string & frame_name)110 RenderFrameHostImpl* FrameTree::AddFrame(FrameTreeNode* parent,
111                                          int new_routing_id,
112                                          const std::string& frame_name) {
113   scoped_ptr<FrameTreeNode> node(new FrameTreeNode(
114       this, parent->navigator(), render_frame_delegate_, render_view_delegate_,
115       render_widget_delegate_, manager_delegate_, frame_name));
116   FrameTreeNode* node_ptr = node.get();
117   // AddChild is what creates the RenderFrameHost.
118   parent->AddChild(node.Pass(), new_routing_id);
119   return node_ptr->current_frame_host();
120 }
121 
RemoveFrame(FrameTreeNode * child)122 void FrameTree::RemoveFrame(FrameTreeNode* child) {
123   FrameTreeNode* parent = child->parent();
124   if (!parent) {
125     NOTREACHED() << "Unexpected RemoveFrame call for main frame.";
126     return;
127   }
128 
129   // Notify observers of the frame removal.
130   RenderFrameHostImpl* render_frame_host = child->current_frame_host();
131   if (!on_frame_removed_.is_null()) {
132     on_frame_removed_.Run(
133         render_frame_host->render_view_host(),
134         render_frame_host->GetRoutingID());
135   }
136 
137   parent->RemoveChild(child);
138 }
139 
ResetForMainFrameSwap()140 void FrameTree::ResetForMainFrameSwap() {
141   root_->ResetForNewProcess();
142   focused_frame_tree_node_id_ = -1;
143 }
144 
RenderProcessGone(RenderViewHost * render_view_host)145 void FrameTree::RenderProcessGone(RenderViewHost* render_view_host) {
146   // Walk the full tree looking for nodes that may be affected.  Once a frame
147   // crashes, all of its child FrameTreeNodes go away.
148   // Note that the helper function may call ResetForNewProcess on a node, which
149   // clears its children before we iterate over them.  That's ok, because
150   // ForEach does not add a node's children to the queue until after visiting
151   // the node itself.
152   ForEach(base::Bind(&ResetNodesForNewProcess, render_view_host));
153 }
154 
GetMainFrame() const155 RenderFrameHostImpl* FrameTree::GetMainFrame() const {
156   return root_->current_frame_host();
157 }
158 
GetFocusedFrame()159 FrameTreeNode* FrameTree::GetFocusedFrame() {
160   return FindByID(focused_frame_tree_node_id_);
161 }
162 
SetFocusedFrame(FrameTreeNode * node)163 void FrameTree::SetFocusedFrame(FrameTreeNode* node) {
164   focused_frame_tree_node_id_ = node->frame_tree_node_id();
165 }
166 
SetFrameRemoveListener(const base::Callback<void (RenderViewHostImpl *,int)> & on_frame_removed)167 void FrameTree::SetFrameRemoveListener(
168     const base::Callback<void(RenderViewHostImpl*, int)>& on_frame_removed) {
169   on_frame_removed_ = on_frame_removed;
170 }
171 
CreateRenderViewHostForMainFrame(SiteInstance * site_instance,int routing_id,int main_frame_routing_id,bool swapped_out,bool hidden)172 RenderViewHostImpl* FrameTree::CreateRenderViewHostForMainFrame(
173     SiteInstance* site_instance,
174     int routing_id,
175     int main_frame_routing_id,
176     bool swapped_out,
177     bool hidden) {
178   DCHECK(main_frame_routing_id != MSG_ROUTING_NONE);
179   RenderViewHostMap::iterator iter =
180       render_view_host_map_.find(site_instance->GetId());
181   if (iter != render_view_host_map_.end()) {
182     // If a RenderViewHost is pending shutdown for this |site_instance|, put it
183     // in the map of RenderViewHosts pending shutdown. Otherwise there should
184     // not be a RenderViewHost for the SiteInstance.
185     CHECK_EQ(RenderViewHostImpl::STATE_PENDING_SHUTDOWN,
186              iter->second->rvh_state());
187     render_view_host_pending_shutdown_map_.insert(
188         std::pair<int, RenderViewHostImpl*>(site_instance->GetId(),
189                                             iter->second));
190     render_view_host_map_.erase(iter);
191   }
192   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
193       RenderViewHostFactory::Create(site_instance,
194                                     render_view_delegate_,
195                                     render_widget_delegate_,
196                                     routing_id,
197                                     main_frame_routing_id,
198                                     swapped_out,
199                                     hidden));
200 
201   render_view_host_map_[site_instance->GetId()] = rvh;
202   return rvh;
203 }
204 
GetRenderViewHostForSubFrame(SiteInstance * site_instance)205 RenderViewHostImpl* FrameTree::GetRenderViewHostForSubFrame(
206     SiteInstance* site_instance) {
207   RenderViewHostMap::iterator iter =
208       render_view_host_map_.find(site_instance->GetId());
209   // TODO(creis): Mirror the frame tree so this check can't fail.
210   if (iter == render_view_host_map_.end())
211     return NULL;
212   return iter->second;
213 }
214 
RegisterRenderFrameHost(RenderFrameHostImpl * render_frame_host)215 void FrameTree::RegisterRenderFrameHost(
216     RenderFrameHostImpl* render_frame_host) {
217   SiteInstance* site_instance =
218       render_frame_host->render_view_host()->GetSiteInstance();
219   RenderViewHostMap::iterator iter =
220       render_view_host_map_.find(site_instance->GetId());
221   CHECK(iter != render_view_host_map_.end());
222 
223   iter->second->increment_ref_count();
224 }
225 
UnregisterRenderFrameHost(RenderFrameHostImpl * render_frame_host)226 void FrameTree::UnregisterRenderFrameHost(
227     RenderFrameHostImpl* render_frame_host) {
228   SiteInstance* site_instance =
229       render_frame_host->render_view_host()->GetSiteInstance();
230   int32 site_instance_id = site_instance->GetId();
231   RenderViewHostMap::iterator iter =
232       render_view_host_map_.find(site_instance_id);
233   if (iter != render_view_host_map_.end() &&
234       iter->second == render_frame_host->render_view_host()) {
235     // Decrement the refcount and shutdown the RenderViewHost if no one else is
236     // using it.
237     CHECK_GT(iter->second->ref_count(), 0);
238     iter->second->decrement_ref_count();
239     if (iter->second->ref_count() == 0) {
240       iter->second->Shutdown();
241       render_view_host_map_.erase(iter);
242     }
243   } else {
244     // The RenderViewHost should be in the list of RenderViewHosts pending
245     // shutdown.
246     bool render_view_host_found = false;
247     std::pair<RenderViewHostMultiMap::iterator,
248               RenderViewHostMultiMap::iterator> result =
249         render_view_host_pending_shutdown_map_.equal_range(site_instance_id);
250     for (RenderViewHostMultiMap::iterator multi_iter = result.first;
251          multi_iter != result.second;
252          ++multi_iter) {
253       if (multi_iter->second != render_frame_host->render_view_host())
254         continue;
255       render_view_host_found = true;
256       RenderViewHostImpl* rvh = multi_iter->second;
257       // Decrement the refcount and shutdown the RenderViewHost if no one else
258       // is using it.
259       CHECK_GT(rvh->ref_count(), 0);
260       rvh->decrement_ref_count();
261       if (rvh->ref_count() == 0) {
262         rvh->Shutdown();
263         render_view_host_pending_shutdown_map_.erase(multi_iter);
264       }
265       break;
266     }
267     CHECK(render_view_host_found);
268   }
269 }
270 
271 }  // namespace content
272