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.
5 #include "chrome/browser/extensions/extension_renderer_state.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"
25 using content::BrowserThread
;
26 using content::RenderProcessHost
;
27 using content::RenderViewHost
;
28 using content::WebContents
;
31 // ExtensionRendererState::RenderViewHostObserver
34 class ExtensionRendererState::RenderViewHostObserver
35 : public content::WebContentsObserver
{
37 RenderViewHostObserver(RenderViewHost
* host
, WebContents
* web_contents
)
38 : content::WebContentsObserver(web_contents
),
39 render_view_host_(host
) {
42 virtual void RenderViewDeleted(content::RenderViewHost
* host
) OVERRIDE
{
43 if (host
!= render_view_host_
)
45 BrowserThread::PostTask(
46 BrowserThread::IO
, FROM_HERE
,
48 &ExtensionRendererState::ClearTabAndWindowId
,
49 base::Unretained(ExtensionRendererState::GetInstance()),
50 host
->GetProcess()->GetID(), host
->GetRoutingID()));
56 RenderViewHost
* render_view_host_
;
58 DISALLOW_COPY_AND_ASSIGN(RenderViewHostObserver
);
62 // ExtensionRendererState::TabObserver
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
{
72 virtual ~TabObserver();
75 // content::NotificationObserver interface.
76 virtual void Observe(int type
,
77 const content::NotificationSource
& source
,
78 const content::NotificationDetails
& details
) OVERRIDE
;
80 content::NotificationRegistrar registrar_
;
83 ExtensionRendererState::TabObserver::TabObserver() {
84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
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());
94 ExtensionRendererState::TabObserver::~TabObserver() {
95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
98 void ExtensionRendererState::TabObserver::Observe(
99 int type
, const content::NotificationSource
& source
,
100 const content::NotificationDetails
& details
) {
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
)
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
,
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()));
120 // The observer deletes itself.
121 new ExtensionRendererState::RenderViewHostObserver(host
, web_contents
);
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
)
131 RenderViewHost
* host
= web_contents
->GetRenderViewHost();
132 BrowserThread::PostTask(
133 BrowserThread::IO
, FROM_HERE
,
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()));
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
)
150 RenderViewHost
* host
= web_contents
->GetRenderViewHost();
151 BrowserThread::PostTask(
152 BrowserThread::IO
, FROM_HERE
,
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()));
168 // ExtensionRendererState
171 ExtensionRendererState::ExtensionRendererState() : observer_(NULL
) {
174 ExtensionRendererState::~ExtensionRendererState() {
178 ExtensionRendererState
* ExtensionRendererState::GetInstance() {
179 return Singleton
<ExtensionRendererState
>::get();
182 void ExtensionRendererState::Init() {
183 observer_
= new TabObserver
;
186 void ExtensionRendererState::Shutdown() {
190 void ExtensionRendererState::SetTabAndWindowId(
191 int render_process_host_id
, int routing_id
, int tab_id
, int window_id
) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
193 RenderId
render_id(render_process_host_id
, routing_id
);
194 map_
[render_id
] = TabAndWindowId(tab_id
, window_id
);
197 void ExtensionRendererState::ClearTabAndWindowId(
198 int render_process_host_id
, int routing_id
) {
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
200 RenderId
render_id(render_process_host_id
, routing_id
);
201 map_
.erase(render_id
);
204 bool ExtensionRendererState::GetTabAndWindowId(
205 const content::ResourceRequestInfo
* info
, int* tab_id
, int* window_id
) {
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
207 int render_process_id
;
208 if (info
->GetProcessType() == content::PROCESS_TYPE_PLUGIN
) {
209 render_process_id
= info
->GetOriginPID();
211 render_process_id
= info
->GetChildID();
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
;
224 bool ExtensionRendererState::IsWebViewRenderer(int render_process_id
) {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
226 for (WebViewInfoMap::iterator i
= webview_info_map_
.begin();
227 i
!= webview_info_map_
.end(); ++i
) {
228 if (i
->first
.first
== render_process_id
)
234 void ExtensionRendererState::AddWebView(int guest_process_id
,
235 int guest_routing_id
,
236 const WebViewInfo
& webview_info
) {
237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
238 RenderId
render_id(guest_process_id
, guest_routing_id
);
239 webview_info_map_
[render_id
] = webview_info
;
242 void ExtensionRendererState::RemoveWebView(int guest_process_id
,
243 int guest_routing_id
) {
244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
245 RenderId
render_id(guest_process_id
, guest_routing_id
);
246 webview_info_map_
.erase(render_id
);
249 bool ExtensionRendererState::GetWebViewInfo(int guest_process_id
,
250 int guest_routing_id
,
251 WebViewInfo
* webview_info
) {
252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
253 RenderId
render_id(guest_process_id
, guest_routing_id
);
254 WebViewInfoMap::iterator iter
= webview_info_map_
.find(render_id
);
255 if (iter
!= webview_info_map_
.end()) {
256 *webview_info
= iter
->second
;