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.
5 #include "content/browser/frame_host/frame_tree.h"
10 #include "base/callback.h"
11 #include "base/containers/hash_tables.h"
12 #include "base/lazy_instance.h"
13 #include "content/browser/frame_host/frame_tree_node.h"
14 #include "content/browser/frame_host/navigator.h"
15 #include "content/browser/frame_host/render_frame_host_factory.h"
16 #include "content/browser/frame_host/render_frame_host_impl.h"
17 #include "content/browser/frame_host/render_frame_proxy_host.h"
18 #include "content/browser/renderer_host/render_view_host_factory.h"
19 #include "content/browser/renderer_host/render_view_host_impl.h"
20 #include "content/public/browser/browser_thread.h"
26 // This is a global map between frame_tree_node_ids and pointer to
28 typedef base::hash_map
<int64
, FrameTreeNode
*> FrameTreeNodeIDMap
;
30 base::LazyInstance
<FrameTreeNodeIDMap
> g_frame_tree_node_id_map
=
31 LAZY_INSTANCE_INITIALIZER
;
33 // Used with FrameTree::ForEach() to search for the FrameTreeNode
34 // corresponding to |frame_tree_node_id| whithin a specific FrameTree.
35 bool FrameTreeNodeForId(int64 frame_tree_node_id
,
36 FrameTreeNode
** out_node
,
37 FrameTreeNode
* node
) {
38 if (node
->frame_tree_node_id() == frame_tree_node_id
) {
40 // Terminate iteration once the node has been found.
46 // Iterate over the FrameTree to reset any node affected by the loss of the
47 // given RenderViewHost's process.
48 bool ResetNodesForNewProcess(RenderViewHost
* render_view_host
,
49 FrameTreeNode
* node
) {
50 if (render_view_host
== node
->current_frame_host()->render_view_host()) {
51 // Ensure that if the frame host is reused for a new RenderFrame, it will
52 // set up the Mojo connection with that frame.
53 node
->current_frame_host()->InvalidateMojoConnection();
54 node
->ResetForNewProcess();
59 bool CreateProxyForSiteInstance(const scoped_refptr
<SiteInstance
>& instance
,
60 FrameTreeNode
* node
) {
61 // If a new frame is created in the current SiteInstance, other frames in
62 // that SiteInstance don't need a proxy for the new frame.
63 SiteInstance
* current_instance
=
64 node
->render_manager()->current_frame_host()->GetSiteInstance();
65 if (current_instance
!= instance
.get())
66 node
->render_manager()->CreateRenderFrameProxy(instance
.get());
72 FrameTree::FrameTree(Navigator
* navigator
,
73 RenderFrameHostDelegate
* render_frame_delegate
,
74 RenderViewHostDelegate
* render_view_delegate
,
75 RenderWidgetHostDelegate
* render_widget_delegate
,
76 RenderFrameHostManager::Delegate
* manager_delegate
)
77 : render_frame_delegate_(render_frame_delegate
),
78 render_view_delegate_(render_view_delegate
),
79 render_widget_delegate_(render_widget_delegate
),
80 manager_delegate_(manager_delegate
),
81 root_(new FrameTreeNode(this,
83 render_frame_delegate
,
85 render_widget_delegate
,
88 focused_frame_tree_node_id_(-1) {
89 std::pair
<FrameTreeNodeIDMap::iterator
, bool> result
=
90 g_frame_tree_node_id_map
.Get().insert(
91 std::make_pair(root_
->frame_tree_node_id(), root_
.get()));
95 FrameTree::~FrameTree() {
96 g_frame_tree_node_id_map
.Get().erase(root_
->frame_tree_node_id());
100 FrameTreeNode
* FrameTree::GloballyFindByID(int64 frame_tree_node_id
) {
101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
102 FrameTreeNodeIDMap
* nodes
= g_frame_tree_node_id_map
.Pointer();
103 FrameTreeNodeIDMap::iterator it
= nodes
->find(frame_tree_node_id
);
104 return it
== nodes
->end() ? NULL
: it
->second
;
107 FrameTreeNode
* FrameTree::FindByID(int64 frame_tree_node_id
) {
108 FrameTreeNode
* node
= NULL
;
109 ForEach(base::Bind(&FrameTreeNodeForId
, frame_tree_node_id
, &node
));
113 FrameTreeNode
* FrameTree::FindByRoutingID(int routing_id
, int process_id
) {
114 RenderFrameHostImpl
* render_frame_host
=
115 RenderFrameHostImpl::FromID(process_id
, routing_id
);
116 if (render_frame_host
) {
117 FrameTreeNode
* result
= render_frame_host
->frame_tree_node();
118 if (this == result
->frame_tree())
122 RenderFrameProxyHost
* render_frame_proxy_host
=
123 RenderFrameProxyHost::FromID(process_id
, routing_id
);
124 if (render_frame_proxy_host
) {
125 FrameTreeNode
* result
= render_frame_proxy_host
->frame_tree_node();
126 if (this == result
->frame_tree())
133 void FrameTree::ForEach(
134 const base::Callback
<bool(FrameTreeNode
*)>& on_node
) const {
135 ForEach(on_node
, NULL
);
138 void FrameTree::ForEach(
139 const base::Callback
<bool(FrameTreeNode
*)>& on_node
,
140 FrameTreeNode
* skip_this_subtree
) const {
141 std::queue
<FrameTreeNode
*> queue
;
142 queue
.push(root_
.get());
144 while (!queue
.empty()) {
145 FrameTreeNode
* node
= queue
.front();
147 if (skip_this_subtree
== node
)
150 if (!on_node
.Run(node
))
153 for (size_t i
= 0; i
< node
->child_count(); ++i
)
154 queue
.push(node
->child_at(i
));
158 RenderFrameHostImpl
* FrameTree::AddFrame(FrameTreeNode
* parent
,
161 const std::string
& frame_name
) {
162 // A child frame always starts with an initial empty document, which means
163 // it is in the same SiteInstance as the parent frame. Ensure that the process
164 // which requested a child frame to be added is the same as the process of the
166 if (parent
->current_frame_host()->GetProcess()->GetID() != process_id
)
169 scoped_ptr
<FrameTreeNode
> node(new FrameTreeNode(
170 this, parent
->navigator(), render_frame_delegate_
, render_view_delegate_
,
171 render_widget_delegate_
, manager_delegate_
, frame_name
));
172 std::pair
<FrameTreeNodeIDMap::iterator
, bool> result
=
173 g_frame_tree_node_id_map
.Get().insert(
174 std::make_pair(node
->frame_tree_node_id(), node
.get()));
175 CHECK(result
.second
);
176 FrameTreeNode
* node_ptr
= node
.get();
177 // AddChild is what creates the RenderFrameHost.
178 parent
->AddChild(node
.Pass(), process_id
, new_routing_id
);
179 return node_ptr
->current_frame_host();
182 void FrameTree::RemoveFrame(FrameTreeNode
* child
) {
183 FrameTreeNode
* parent
= child
->parent();
185 NOTREACHED() << "Unexpected RemoveFrame call for main frame.";
189 // Notify observers of the frame removal.
190 RenderFrameHostImpl
* render_frame_host
= child
->current_frame_host();
191 if (!on_frame_removed_
.is_null()) {
192 on_frame_removed_
.Run(render_frame_host
);
194 g_frame_tree_node_id_map
.Get().erase(child
->frame_tree_node_id());
195 parent
->RemoveChild(child
);
198 void FrameTree::CreateProxiesForSiteInstance(
199 FrameTreeNode
* source
,
200 SiteInstance
* site_instance
) {
201 // Create the swapped out RVH for the new SiteInstance. This will create
202 // a top-level swapped out RFH as well, which will then be wrapped by a
203 // RenderFrameProxyHost.
204 if (!source
->IsMainFrame()) {
205 RenderViewHostImpl
* render_view_host
=
206 source
->frame_tree()->GetRenderViewHost(site_instance
);
207 if (!render_view_host
) {
208 root()->render_manager()->CreateRenderFrame(site_instance
,
216 scoped_refptr
<SiteInstance
> instance(site_instance
);
218 // Proxies are created in the FrameTree in response to a node navigating to a
219 // new SiteInstance. Since |source|'s navigation will replace the currently
220 // loaded document, the entire subtree under |source| will be removed.
221 ForEach(base::Bind(&CreateProxyForSiteInstance
, instance
), source
);
224 void FrameTree::ResetForMainFrameSwap() {
225 root_
->ResetForNewProcess();
226 focused_frame_tree_node_id_
= -1;
229 void FrameTree::RenderProcessGone(RenderViewHost
* render_view_host
) {
230 // Walk the full tree looking for nodes that may be affected. Once a frame
231 // crashes, all of its child FrameTreeNodes go away.
232 // Note that the helper function may call ResetForNewProcess on a node, which
233 // clears its children before we iterate over them. That's ok, because
234 // ForEach does not add a node's children to the queue until after visiting
236 ForEach(base::Bind(&ResetNodesForNewProcess
, render_view_host
));
239 RenderFrameHostImpl
* FrameTree::GetMainFrame() const {
240 return root_
->current_frame_host();
243 FrameTreeNode
* FrameTree::GetFocusedFrame() {
244 return FindByID(focused_frame_tree_node_id_
);
247 void FrameTree::SetFocusedFrame(FrameTreeNode
* node
) {
248 focused_frame_tree_node_id_
= node
->frame_tree_node_id();
251 void FrameTree::SetFrameRemoveListener(
252 const base::Callback
<void(RenderFrameHost
*)>& on_frame_removed
) {
253 on_frame_removed_
= on_frame_removed
;
256 RenderViewHostImpl
* FrameTree::CreateRenderViewHost(SiteInstance
* site_instance
,
258 int main_frame_routing_id
,
261 DCHECK(main_frame_routing_id
!= MSG_ROUTING_NONE
);
262 RenderViewHostMap::iterator iter
=
263 render_view_host_map_
.find(site_instance
->GetId());
264 if (iter
!= render_view_host_map_
.end()) {
265 // If a RenderViewHost's main frame is pending deletion for this
266 // |site_instance|, put it in the map of RenderViewHosts pending shutdown.
267 // Otherwise return the existing RenderViewHost for the SiteInstance.
268 RenderFrameHostImpl
* main_frame
= static_cast<RenderFrameHostImpl
*>(
269 iter
->second
->GetMainFrame());
270 if (main_frame
->frame_tree_node()->render_manager()->IsPendingDeletion(
272 render_view_host_pending_shutdown_map_
.insert(
273 std::pair
<int, RenderViewHostImpl
*>(site_instance
->GetId(),
275 render_view_host_map_
.erase(iter
);
280 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
281 RenderViewHostFactory::Create(site_instance
,
282 render_view_delegate_
,
283 render_widget_delegate_
,
285 main_frame_routing_id
,
289 render_view_host_map_
[site_instance
->GetId()] = rvh
;
293 RenderViewHostImpl
* FrameTree::GetRenderViewHost(SiteInstance
* site_instance
) {
294 RenderViewHostMap::iterator iter
=
295 render_view_host_map_
.find(site_instance
->GetId());
296 // TODO(creis): Mirror the frame tree so this check can't fail.
297 if (iter
== render_view_host_map_
.end())
302 void FrameTree::RegisterRenderFrameHost(
303 RenderFrameHostImpl
* render_frame_host
) {
304 SiteInstance
* site_instance
=
305 render_frame_host
->render_view_host()->GetSiteInstance();
306 RenderViewHostMap::iterator iter
=
307 render_view_host_map_
.find(site_instance
->GetId());
308 CHECK(iter
!= render_view_host_map_
.end());
310 iter
->second
->increment_ref_count();
313 void FrameTree::UnregisterRenderFrameHost(
314 RenderFrameHostImpl
* render_frame_host
) {
315 SiteInstance
* site_instance
=
316 render_frame_host
->render_view_host()->GetSiteInstance();
317 int32 site_instance_id
= site_instance
->GetId();
318 RenderViewHostMap::iterator iter
=
319 render_view_host_map_
.find(site_instance_id
);
320 if (iter
!= render_view_host_map_
.end() &&
321 iter
->second
== render_frame_host
->render_view_host()) {
322 // Decrement the refcount and shutdown the RenderViewHost if no one else is
324 CHECK_GT(iter
->second
->ref_count(), 0);
325 iter
->second
->decrement_ref_count();
326 if (iter
->second
->ref_count() == 0) {
327 iter
->second
->Shutdown();
328 render_view_host_map_
.erase(iter
);
331 // The RenderViewHost should be in the list of RenderViewHosts pending
333 bool render_view_host_found
= false;
334 std::pair
<RenderViewHostMultiMap::iterator
,
335 RenderViewHostMultiMap::iterator
> result
=
336 render_view_host_pending_shutdown_map_
.equal_range(site_instance_id
);
337 for (RenderViewHostMultiMap::iterator multi_iter
= result
.first
;
338 multi_iter
!= result
.second
;
340 if (multi_iter
->second
!= render_frame_host
->render_view_host())
342 render_view_host_found
= true;
343 RenderViewHostImpl
* rvh
= multi_iter
->second
;
344 // Decrement the refcount and shutdown the RenderViewHost if no one else
346 CHECK_GT(rvh
->ref_count(), 0);
347 rvh
->decrement_ref_count();
348 if (rvh
->ref_count() == 0) {
350 render_view_host_pending_shutdown_map_
.erase(multi_iter
);
354 CHECK(render_view_host_found
);
358 } // namespace content