• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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