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 23 using content::BrowserThread; 24 using content::RenderProcessHost; 25 using content::RenderViewHost; 26 using content::WebContents; 27 28 // 29 // ExtensionRendererState::RenderViewHostObserver 30 // 31 32 class 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. 66 class 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 81 ExtensionRendererState::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 92 ExtensionRendererState::TabObserver::~TabObserver() { 93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 94 } 95 96 void 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 169 ExtensionRendererState::ExtensionRendererState() : observer_(NULL) { 170 } 171 172 ExtensionRendererState::~ExtensionRendererState() { 173 } 174 175 // static 176 ExtensionRendererState* ExtensionRendererState::GetInstance() { 177 return Singleton<ExtensionRendererState>::get(); 178 } 179 180 void ExtensionRendererState::Init() { 181 observer_ = new TabObserver; 182 } 183 184 void ExtensionRendererState::Shutdown() { 185 delete observer_; 186 } 187 188 void 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 195 void 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 202 bool 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 215 bool 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 225 void 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 233 void 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 240 bool 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