1// Copyright (c) 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 "chrome/browser/extensions/extension_renderer_state.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "chrome/browser/chrome_notification_types.h" 10#include "chrome/browser/sessions/session_tab_helper.h" 11#include "chrome/browser/tab_contents/retargeting_details.h" 12#include "content/public/browser/browser_thread.h" 13#include "content/public/browser/navigation_details.h" 14#include "content/public/browser/notification_observer.h" 15#include "content/public/browser/notification_registrar.h" 16#include "content/public/browser/notification_service.h" 17#include "content/public/browser/notification_types.h" 18#include "content/public/browser/render_process_host.h" 19#include "content/public/browser/render_view_host.h" 20#include "content/public/browser/web_contents.h" 21#include "content/public/browser/web_contents_observer.h" 22 23using content::BrowserThread; 24using content::RenderProcessHost; 25using content::RenderViewHost; 26using content::WebContents; 27 28// 29// ExtensionRendererState::RenderViewHostObserver 30// 31 32class ExtensionRendererState::RenderViewHostObserver 33 : public content::WebContentsObserver { 34 public: 35 RenderViewHostObserver(RenderViewHost* host, WebContents* web_contents) 36 : content::WebContentsObserver(web_contents), 37 render_view_host_(host) { 38 } 39 40 virtual void RenderViewDeleted(content::RenderViewHost* host) OVERRIDE { 41 if (host != render_view_host_) 42 return; 43 BrowserThread::PostTask( 44 BrowserThread::IO, FROM_HERE, 45 base::Bind( 46 &ExtensionRendererState::ClearTabAndWindowId, 47 base::Unretained(ExtensionRendererState::GetInstance()), 48 host->GetProcess()->GetID(), host->GetRoutingID())); 49 50 delete this; 51 } 52 53 private: 54 RenderViewHost* render_view_host_; 55 56 DISALLOW_COPY_AND_ASSIGN(RenderViewHostObserver); 57}; 58 59// 60// ExtensionRendererState::TabObserver 61// 62 63// This class listens for notifications about changes in renderer state on the 64// UI thread, and notifies the ExtensionRendererState on the IO thread. It 65// should only ever be accessed on the UI thread. 66class ExtensionRendererState::TabObserver 67 : public content::NotificationObserver { 68 public: 69 TabObserver(); 70 virtual ~TabObserver(); 71 72 private: 73 // content::NotificationObserver interface. 74 virtual void Observe(int type, 75 const content::NotificationSource& source, 76 const content::NotificationDetails& details) OVERRIDE; 77 78 content::NotificationRegistrar registrar_; 79}; 80 81ExtensionRendererState::TabObserver::TabObserver() { 82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 83 registrar_.Add(this, 84 content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED, 85 content::NotificationService::AllBrowserContextsAndSources()); 86 registrar_.Add(this, chrome::NOTIFICATION_TAB_PARENTED, 87 content::NotificationService::AllBrowserContextsAndSources()); 88 registrar_.Add(this, chrome::NOTIFICATION_RETARGETING, 89 content::NotificationService::AllBrowserContextsAndSources()); 90} 91 92ExtensionRendererState::TabObserver::~TabObserver() { 93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 94} 95 96void ExtensionRendererState::TabObserver::Observe( 97 int type, const content::NotificationSource& source, 98 const content::NotificationDetails& details) { 99 switch (type) { 100 case content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED: { 101 WebContents* web_contents = content::Source<WebContents>(source).ptr(); 102 SessionTabHelper* session_tab_helper = 103 SessionTabHelper::FromWebContents(web_contents); 104 if (!session_tab_helper) 105 return; 106 RenderViewHost* host = content::Details<RenderViewHost>(details).ptr(); 107 // TODO(mpcomplete): How can we tell if window_id is bogus? It may not 108 // have been set yet. 109 BrowserThread::PostTask( 110 BrowserThread::IO, FROM_HERE, 111 base::Bind( 112 &ExtensionRendererState::SetTabAndWindowId, 113 base::Unretained(ExtensionRendererState::GetInstance()), 114 host->GetProcess()->GetID(), host->GetRoutingID(), 115 session_tab_helper->session_id().id(), 116 session_tab_helper->window_id().id())); 117 118 // The observer deletes itself. 119 new ExtensionRendererState::RenderViewHostObserver(host, web_contents); 120 121 break; 122 } 123 case chrome::NOTIFICATION_TAB_PARENTED: { 124 WebContents* web_contents = content::Source<WebContents>(source).ptr(); 125 SessionTabHelper* session_tab_helper = 126 SessionTabHelper::FromWebContents(web_contents); 127 if (!session_tab_helper) 128 return; 129 RenderViewHost* host = web_contents->GetRenderViewHost(); 130 BrowserThread::PostTask( 131 BrowserThread::IO, FROM_HERE, 132 base::Bind( 133 &ExtensionRendererState::SetTabAndWindowId, 134 base::Unretained(ExtensionRendererState::GetInstance()), 135 host->GetProcess()->GetID(), host->GetRoutingID(), 136 session_tab_helper->session_id().id(), 137 session_tab_helper->window_id().id())); 138 break; 139 } 140 case chrome::NOTIFICATION_RETARGETING: { 141 RetargetingDetails* retargeting_details = 142 content::Details<RetargetingDetails>(details).ptr(); 143 WebContents* web_contents = retargeting_details->target_web_contents; 144 SessionTabHelper* session_tab_helper = 145 SessionTabHelper::FromWebContents(web_contents); 146 if (!session_tab_helper) 147 return; 148 RenderViewHost* host = web_contents->GetRenderViewHost(); 149 BrowserThread::PostTask( 150 BrowserThread::IO, FROM_HERE, 151 base::Bind( 152 &ExtensionRendererState::SetTabAndWindowId, 153 base::Unretained(ExtensionRendererState::GetInstance()), 154 host->GetProcess()->GetID(), host->GetRoutingID(), 155 session_tab_helper->session_id().id(), 156 session_tab_helper->window_id().id())); 157 break; 158 } 159 default: 160 NOTREACHED(); 161 return; 162 } 163} 164 165// 166// ExtensionRendererState 167// 168 169ExtensionRendererState::ExtensionRendererState() : observer_(NULL) { 170} 171 172ExtensionRendererState::~ExtensionRendererState() { 173} 174 175// static 176ExtensionRendererState* ExtensionRendererState::GetInstance() { 177 return Singleton<ExtensionRendererState>::get(); 178} 179 180void ExtensionRendererState::Init() { 181 observer_ = new TabObserver; 182} 183 184void ExtensionRendererState::Shutdown() { 185 delete observer_; 186} 187 188void ExtensionRendererState::SetTabAndWindowId( 189 int render_process_host_id, int routing_id, int tab_id, int window_id) { 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 191 RenderId render_id(render_process_host_id, routing_id); 192 map_[render_id] = TabAndWindowId(tab_id, window_id); 193} 194 195void ExtensionRendererState::ClearTabAndWindowId( 196 int render_process_host_id, int routing_id) { 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 198 RenderId render_id(render_process_host_id, routing_id); 199 map_.erase(render_id); 200} 201 202bool ExtensionRendererState::GetTabAndWindowId( 203 int render_process_host_id, int routing_id, int* tab_id, int* window_id) { 204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 205 RenderId render_id(render_process_host_id, routing_id); 206 TabAndWindowIdMap::iterator iter = map_.find(render_id); 207 if (iter != map_.end()) { 208 *tab_id = iter->second.first; 209 *window_id = iter->second.second; 210 return true; 211 } 212 return false; 213} 214 215bool ExtensionRendererState::IsWebViewRenderer(int render_process_id) { 216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 217 for (WebViewInfoMap::iterator i = webview_info_map_.begin(); 218 i != webview_info_map_.end(); ++i) { 219 if (i->first.first == render_process_id) 220 return true; 221 } 222 return false; 223} 224 225void ExtensionRendererState::AddWebView(int guest_process_id, 226 int guest_routing_id, 227 const WebViewInfo& webview_info) { 228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 229 RenderId render_id(guest_process_id, guest_routing_id); 230 webview_info_map_[render_id] = webview_info; 231} 232 233void ExtensionRendererState::RemoveWebView(int guest_process_id, 234 int guest_routing_id) { 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 236 RenderId render_id(guest_process_id, guest_routing_id); 237 webview_info_map_.erase(render_id); 238} 239 240bool ExtensionRendererState::GetWebViewInfo(int guest_process_id, 241 int guest_routing_id, 242 WebViewInfo* webview_info) { 243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 244 RenderId render_id(guest_process_id, guest_routing_id); 245 WebViewInfoMap::iterator iter = webview_info_map_.find(render_id); 246 if (iter != webview_info_map_.end()) { 247 *webview_info = iter->second; 248 return true; 249 } 250 return false; 251} 252