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