1 // Copyright 2014 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/render_frame_proxy_host.h" 6 7 #include "base/lazy_instance.h" 8 #include "content/browser/frame_host/cross_process_frame_connector.h" 9 #include "content/browser/frame_host/frame_tree.h" 10 #include "content/browser/frame_host/frame_tree_node.h" 11 #include "content/browser/frame_host/render_frame_host_impl.h" 12 #include "content/browser/frame_host/render_widget_host_view_child_frame.h" 13 #include "content/browser/renderer_host/render_view_host_impl.h" 14 #include "content/browser/renderer_host/render_widget_host_view_base.h" 15 #include "content/browser/site_instance_impl.h" 16 #include "content/common/frame_messages.h" 17 #include "content/public/browser/browser_thread.h" 18 #include "ipc/ipc_message.h" 19 20 namespace content { 21 22 namespace { 23 24 // The (process id, routing id) pair that identifies one RenderFrameProxy. 25 typedef std::pair<int32, int32> RenderFrameProxyHostID; 26 typedef base::hash_map<RenderFrameProxyHostID, RenderFrameProxyHost*> 27 RoutingIDFrameProxyMap; 28 base::LazyInstance<RoutingIDFrameProxyMap> g_routing_id_frame_proxy_map = 29 LAZY_INSTANCE_INITIALIZER; 30 31 } 32 33 // static 34 RenderFrameProxyHost* RenderFrameProxyHost::FromID(int process_id, 35 int routing_id) { 36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 37 RoutingIDFrameProxyMap* frames = g_routing_id_frame_proxy_map.Pointer(); 38 RoutingIDFrameProxyMap::iterator it = frames->find( 39 RenderFrameProxyHostID(process_id, routing_id)); 40 return it == frames->end() ? NULL : it->second; 41 } 42 43 RenderFrameProxyHost::RenderFrameProxyHost(SiteInstance* site_instance, 44 FrameTreeNode* frame_tree_node) 45 : routing_id_(site_instance->GetProcess()->GetNextRoutingID()), 46 site_instance_(site_instance), 47 frame_tree_node_(frame_tree_node) { 48 GetProcess()->AddRoute(routing_id_, this); 49 CHECK(g_routing_id_frame_proxy_map.Get().insert( 50 std::make_pair( 51 RenderFrameProxyHostID(GetProcess()->GetID(), routing_id_), 52 this)).second); 53 54 if (!frame_tree_node_->IsMainFrame() && 55 frame_tree_node_->parent() 56 ->render_manager() 57 ->current_frame_host() 58 ->GetSiteInstance() == site_instance) { 59 // The RenderFrameHost navigating cross-process is destroyed and a proxy for 60 // it is created in the parent's process. CrossProcessFrameConnector 61 // initialization only needs to happen on an initial cross-process 62 // navigation, when the RenderFrameHost leaves the same process as its 63 // parent. The same CrossProcessFrameConnector is used for subsequent cross- 64 // process navigations, but it will be destroyed if the frame is 65 // navigated back to the same SiteInstance as its parent. 66 cross_process_frame_connector_.reset(new CrossProcessFrameConnector(this)); 67 } 68 } 69 70 RenderFrameProxyHost::~RenderFrameProxyHost() { 71 if (GetProcess()->HasConnection()) 72 Send(new FrameMsg_DeleteProxy(routing_id_)); 73 74 GetProcess()->RemoveRoute(routing_id_); 75 g_routing_id_frame_proxy_map.Get().erase( 76 RenderFrameProxyHostID(GetProcess()->GetID(), routing_id_)); 77 } 78 79 void RenderFrameProxyHost::SetChildRWHView(RenderWidgetHostView* view) { 80 cross_process_frame_connector_->set_view( 81 static_cast<RenderWidgetHostViewChildFrame*>(view)); 82 } 83 84 RenderViewHostImpl* RenderFrameProxyHost::GetRenderViewHost() { 85 return frame_tree_node_->frame_tree()->GetRenderViewHost( 86 site_instance_.get()); 87 } 88 89 scoped_ptr<RenderFrameHostImpl> RenderFrameProxyHost::PassFrameHostOwnership() { 90 render_frame_host_->set_render_frame_proxy_host(NULL); 91 return render_frame_host_.Pass(); 92 } 93 94 bool RenderFrameProxyHost::Send(IPC::Message *msg) { 95 // TODO(nasko): For now, RenderFrameHost uses this object to send IPC messages 96 // while swapped out. This can be removed once we don't have a swapped out 97 // state on RenderFrameHosts. See https://crbug.com/357747. 98 msg->set_routing_id(routing_id_); 99 return GetProcess()->Send(msg); 100 } 101 102 bool RenderFrameProxyHost::OnMessageReceived(const IPC::Message& msg) { 103 if (cross_process_frame_connector_.get() && 104 cross_process_frame_connector_->OnMessageReceived(msg)) 105 return true; 106 107 // TODO(nasko): This can be removed once we don't have a swapped out state on 108 // RenderFrameHosts. See https://crbug.com/357747. 109 if (render_frame_host_.get()) 110 return render_frame_host_->OnMessageReceived(msg); 111 112 return false; 113 } 114 115 bool RenderFrameProxyHost::InitRenderFrameProxy() { 116 // The process may (if we're sharing a process with another host that already 117 // initialized it) or may not (we have our own process or the old process 118 // crashed) have been initialized. Calling Init multiple times will be 119 // ignored, so this is safe. 120 if (!site_instance_->GetProcess()->Init()) 121 return false; 122 123 DCHECK(GetProcess()->HasConnection()); 124 125 int parent_routing_id = MSG_ROUTING_NONE; 126 if (frame_tree_node_->parent()) { 127 parent_routing_id = frame_tree_node_->parent() 128 ->render_manager() 129 ->GetRoutingIdForSiteInstance(site_instance_.get()); 130 CHECK_NE(parent_routing_id, MSG_ROUTING_NONE); 131 } 132 133 Send(new FrameMsg_NewFrameProxy(routing_id_, 134 parent_routing_id, 135 frame_tree_node_->frame_tree() 136 ->GetRenderViewHost(site_instance_.get()) 137 ->GetRoutingID())); 138 139 return true; 140 } 141 142 void RenderFrameProxyHost::DisownOpener() { 143 Send(new FrameMsg_DisownOpener(GetRoutingID())); 144 } 145 146 } // namespace content 147