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