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:
RenderViewHostObserver(RenderViewHost * host,WebContents * web_contents)35 RenderViewHostObserver(RenderViewHost* host, WebContents* web_contents)
36 : content::WebContentsObserver(web_contents),
37 render_view_host_(host) {
38 }
39
RenderViewDeleted(content::RenderViewHost * host)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
TabObserver()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
~TabObserver()92 ExtensionRendererState::TabObserver::~TabObserver() {
93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
94 }
95
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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
ExtensionRendererState()169 ExtensionRendererState::ExtensionRendererState() : observer_(NULL) {
170 }
171
~ExtensionRendererState()172 ExtensionRendererState::~ExtensionRendererState() {
173 }
174
175 // static
GetInstance()176 ExtensionRendererState* ExtensionRendererState::GetInstance() {
177 return Singleton<ExtensionRendererState>::get();
178 }
179
Init()180 void ExtensionRendererState::Init() {
181 observer_ = new TabObserver;
182 }
183
Shutdown()184 void ExtensionRendererState::Shutdown() {
185 delete observer_;
186 }
187
SetTabAndWindowId(int render_process_host_id,int routing_id,int tab_id,int window_id)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
ClearTabAndWindowId(int render_process_host_id,int routing_id)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
GetTabAndWindowId(int render_process_host_id,int routing_id,int * tab_id,int * window_id)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
IsWebViewRenderer(int render_process_id)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
AddWebView(int guest_process_id,int guest_routing_id,const WebViewInfo & webview_info)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
RemoveWebView(int guest_process_id,int guest_routing_id)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
GetWebViewInfo(int guest_process_id,int guest_routing_id,WebViewInfo * webview_info)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