Implement SSLKEYLOGFILE for OpenSSL.
[chromium-blink-merge.git] / content / browser / frame_host / frame_tree.cc
blobd5a183ff8cbdb3d1ddd04bbc11c38b092f834a50
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"
7 #include <queue>
9 #include "base/bind.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"
22 namespace content {
24 namespace {
26 // This is a global map between frame_tree_node_ids and pointer to
27 // FrameTreeNodes.
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) {
39 *out_node = node;
40 // Terminate iteration once the node has been found.
41 return false;
43 return true;
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 node->ResetForNewProcess();
52 return true;
55 bool CreateProxyForSiteInstance(const scoped_refptr<SiteInstance>& instance,
56 FrameTreeNode* node) {
57 node->render_manager()->CreateRenderFrameProxy(instance.get());
58 return true;
61 } // namespace
63 FrameTree::FrameTree(Navigator* navigator,
64 RenderFrameHostDelegate* render_frame_delegate,
65 RenderViewHostDelegate* render_view_delegate,
66 RenderWidgetHostDelegate* render_widget_delegate,
67 RenderFrameHostManager::Delegate* manager_delegate)
68 : render_frame_delegate_(render_frame_delegate),
69 render_view_delegate_(render_view_delegate),
70 render_widget_delegate_(render_widget_delegate),
71 manager_delegate_(manager_delegate),
72 root_(new FrameTreeNode(this,
73 navigator,
74 render_frame_delegate,
75 render_view_delegate,
76 render_widget_delegate,
77 manager_delegate,
78 std::string())),
79 focused_frame_tree_node_id_(-1) {
80 std::pair<FrameTreeNodeIDMap::iterator, bool> result =
81 g_frame_tree_node_id_map.Get().insert(
82 std::make_pair(root_->frame_tree_node_id(), root_.get()));
83 CHECK(result.second);
86 FrameTree::~FrameTree() {
87 g_frame_tree_node_id_map.Get().erase(root_->frame_tree_node_id());
90 // static
91 FrameTreeNode* FrameTree::GloballyFindByID(int64 frame_tree_node_id) {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
93 FrameTreeNodeIDMap* nodes = g_frame_tree_node_id_map.Pointer();
94 FrameTreeNodeIDMap::iterator it = nodes->find(frame_tree_node_id);
95 return it == nodes->end() ? NULL : it->second;
98 FrameTreeNode* FrameTree::FindByID(int64 frame_tree_node_id) {
99 FrameTreeNode* node = NULL;
100 ForEach(base::Bind(&FrameTreeNodeForId, frame_tree_node_id, &node));
101 return node;
104 FrameTreeNode* FrameTree::FindByRoutingID(int routing_id, int process_id) {
105 RenderFrameHostImpl* render_frame_host =
106 RenderFrameHostImpl::FromID(process_id, routing_id);
107 if (render_frame_host) {
108 FrameTreeNode* result = render_frame_host->frame_tree_node();
109 if (this == result->frame_tree())
110 return result;
113 RenderFrameProxyHost* render_frame_proxy_host =
114 RenderFrameProxyHost::FromID(process_id, routing_id);
115 if (render_frame_proxy_host) {
116 FrameTreeNode* result = render_frame_proxy_host->frame_tree_node();
117 if (this == result->frame_tree())
118 return result;
121 return NULL;
124 void FrameTree::ForEach(
125 const base::Callback<bool(FrameTreeNode*)>& on_node) const {
126 ForEach(on_node, NULL);
129 void FrameTree::ForEach(
130 const base::Callback<bool(FrameTreeNode*)>& on_node,
131 FrameTreeNode* skip_this_subtree) const {
132 std::queue<FrameTreeNode*> queue;
133 queue.push(root_.get());
135 while (!queue.empty()) {
136 FrameTreeNode* node = queue.front();
137 queue.pop();
138 if (skip_this_subtree == node)
139 continue;
141 if (!on_node.Run(node))
142 break;
144 for (size_t i = 0; i < node->child_count(); ++i)
145 queue.push(node->child_at(i));
149 RenderFrameHostImpl* FrameTree::AddFrame(FrameTreeNode* parent,
150 int new_routing_id,
151 const std::string& frame_name) {
152 scoped_ptr<FrameTreeNode> node(new FrameTreeNode(
153 this, parent->navigator(), render_frame_delegate_, render_view_delegate_,
154 render_widget_delegate_, manager_delegate_, frame_name));
155 std::pair<FrameTreeNodeIDMap::iterator, bool> result =
156 g_frame_tree_node_id_map.Get().insert(
157 std::make_pair(node->frame_tree_node_id(), node.get()));
158 CHECK(result.second);
159 FrameTreeNode* node_ptr = node.get();
160 // AddChild is what creates the RenderFrameHost.
161 parent->AddChild(node.Pass(), new_routing_id);
162 return node_ptr->current_frame_host();
165 void FrameTree::RemoveFrame(FrameTreeNode* child) {
166 FrameTreeNode* parent = child->parent();
167 if (!parent) {
168 NOTREACHED() << "Unexpected RemoveFrame call for main frame.";
169 return;
172 // Notify observers of the frame removal.
173 RenderFrameHostImpl* render_frame_host = child->current_frame_host();
174 if (!on_frame_removed_.is_null()) {
175 on_frame_removed_.Run(render_frame_host);
177 g_frame_tree_node_id_map.Get().erase(child->frame_tree_node_id());
178 parent->RemoveChild(child);
181 void FrameTree::CreateProxiesForSiteInstance(
182 FrameTreeNode* source,
183 SiteInstance* site_instance) {
184 // Create the swapped out RVH for the new SiteInstance. This will create
185 // a top-level swapped out RFH as well, which will then be wrapped by a
186 // RenderFrameProxyHost.
187 if (!source->IsMainFrame()) {
188 RenderViewHostImpl* render_view_host =
189 source->frame_tree()->GetRenderViewHost(site_instance);
190 if (!render_view_host) {
191 root()->render_manager()->CreateRenderFrame(site_instance,
192 MSG_ROUTING_NONE,
193 true,
194 false,
195 true);
199 scoped_refptr<SiteInstance> instance(site_instance);
201 // Proxies are created in the FrameTree in response to a node navigating to a
202 // new SiteInstance. Since |source|'s navigation will replace the currently
203 // loaded document, the entire subtree under |source| will be removed.
204 ForEach(base::Bind(&CreateProxyForSiteInstance, instance), source);
207 void FrameTree::ResetForMainFrameSwap() {
208 root_->ResetForNewProcess();
209 focused_frame_tree_node_id_ = -1;
212 void FrameTree::RenderProcessGone(RenderViewHost* render_view_host) {
213 // Walk the full tree looking for nodes that may be affected. Once a frame
214 // crashes, all of its child FrameTreeNodes go away.
215 // Note that the helper function may call ResetForNewProcess on a node, which
216 // clears its children before we iterate over them. That's ok, because
217 // ForEach does not add a node's children to the queue until after visiting
218 // the node itself.
219 ForEach(base::Bind(&ResetNodesForNewProcess, render_view_host));
222 RenderFrameHostImpl* FrameTree::GetMainFrame() const {
223 return root_->current_frame_host();
226 FrameTreeNode* FrameTree::GetFocusedFrame() {
227 return FindByID(focused_frame_tree_node_id_);
230 void FrameTree::SetFocusedFrame(FrameTreeNode* node) {
231 focused_frame_tree_node_id_ = node->frame_tree_node_id();
234 void FrameTree::SetFrameRemoveListener(
235 const base::Callback<void(RenderFrameHost*)>& on_frame_removed) {
236 on_frame_removed_ = on_frame_removed;
239 RenderViewHostImpl* FrameTree::CreateRenderViewHost(SiteInstance* site_instance,
240 int routing_id,
241 int main_frame_routing_id,
242 bool swapped_out,
243 bool hidden) {
244 DCHECK(main_frame_routing_id != MSG_ROUTING_NONE);
245 RenderViewHostMap::iterator iter =
246 render_view_host_map_.find(site_instance->GetId());
247 if (iter != render_view_host_map_.end()) {
248 // If a RenderViewHost is pending shutdown for this |site_instance|, put it
249 // in the map of RenderViewHosts pending shutdown. Otherwise return the
250 // existing RenderViewHost for the SiteInstance.
251 if (iter->second->rvh_state() ==
252 RenderViewHostImpl::STATE_PENDING_SHUTDOWN) {
253 render_view_host_pending_shutdown_map_.insert(
254 std::pair<int, RenderViewHostImpl*>(site_instance->GetId(),
255 iter->second));
256 render_view_host_map_.erase(iter);
257 } else {
258 return iter->second;
261 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
262 RenderViewHostFactory::Create(site_instance,
263 render_view_delegate_,
264 render_widget_delegate_,
265 routing_id,
266 main_frame_routing_id,
267 swapped_out,
268 hidden));
270 render_view_host_map_[site_instance->GetId()] = rvh;
271 return rvh;
274 RenderViewHostImpl* FrameTree::GetRenderViewHost(SiteInstance* site_instance) {
275 RenderViewHostMap::iterator iter =
276 render_view_host_map_.find(site_instance->GetId());
277 // TODO(creis): Mirror the frame tree so this check can't fail.
278 if (iter == render_view_host_map_.end())
279 return NULL;
280 return iter->second;
283 void FrameTree::RegisterRenderFrameHost(
284 RenderFrameHostImpl* render_frame_host) {
285 SiteInstance* site_instance =
286 render_frame_host->render_view_host()->GetSiteInstance();
287 RenderViewHostMap::iterator iter =
288 render_view_host_map_.find(site_instance->GetId());
289 CHECK(iter != render_view_host_map_.end());
291 iter->second->increment_ref_count();
294 void FrameTree::UnregisterRenderFrameHost(
295 RenderFrameHostImpl* render_frame_host) {
296 SiteInstance* site_instance =
297 render_frame_host->render_view_host()->GetSiteInstance();
298 int32 site_instance_id = site_instance->GetId();
299 RenderViewHostMap::iterator iter =
300 render_view_host_map_.find(site_instance_id);
301 if (iter != render_view_host_map_.end() &&
302 iter->second == render_frame_host->render_view_host()) {
303 // Decrement the refcount and shutdown the RenderViewHost if no one else is
304 // using it.
305 CHECK_GT(iter->second->ref_count(), 0);
306 iter->second->decrement_ref_count();
307 if (iter->second->ref_count() == 0) {
308 iter->second->Shutdown();
309 render_view_host_map_.erase(iter);
311 } else {
312 // The RenderViewHost should be in the list of RenderViewHosts pending
313 // shutdown.
314 bool render_view_host_found = false;
315 std::pair<RenderViewHostMultiMap::iterator,
316 RenderViewHostMultiMap::iterator> result =
317 render_view_host_pending_shutdown_map_.equal_range(site_instance_id);
318 for (RenderViewHostMultiMap::iterator multi_iter = result.first;
319 multi_iter != result.second;
320 ++multi_iter) {
321 if (multi_iter->second != render_frame_host->render_view_host())
322 continue;
323 render_view_host_found = true;
324 RenderViewHostImpl* rvh = multi_iter->second;
325 // Decrement the refcount and shutdown the RenderViewHost if no one else
326 // is using it.
327 CHECK_GT(rvh->ref_count(), 0);
328 rvh->decrement_ref_count();
329 if (rvh->ref_count() == 0) {
330 rvh->Shutdown();
331 render_view_host_pending_shutdown_map_.erase(multi_iter);
333 break;
335 CHECK(render_view_host_found);
339 } // namespace content