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_CURRENTLY_ON(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_CURRENTLY_ON(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_CURRENTLY_ON(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_CURRENTLY_ON(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_CURRENTLY_ON(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_CURRENTLY_ON(BrowserThread::IO);
226 return webview_partition_id_map_.find(render_process_id) !=
227 webview_partition_id_map_.end();
230 void ExtensionRendererState::AddWebView(int guest_process_id,
231 int guest_routing_id,
232 const WebViewInfo& webview_info) {
233 DCHECK_CURRENTLY_ON(BrowserThread::IO);
234 RenderId render_id(guest_process_id, guest_routing_id);
235 webview_info_map_[render_id] = webview_info;
236 WebViewPartitionIDMap::iterator iter =
237 webview_partition_id_map_.find(guest_process_id);
238 if (iter != webview_partition_id_map_.end()) {
239 ++iter->second.web_view_count;
242 WebViewPartitionInfo partition_info(1, webview_info.partition_id);
243 webview_partition_id_map_[guest_process_id] = partition_info;
246 void ExtensionRendererState::RemoveWebView(int guest_process_id,
247 int guest_routing_id) {
248 DCHECK_CURRENTLY_ON(BrowserThread::IO);
249 RenderId render_id(guest_process_id, guest_routing_id);
250 webview_info_map_.erase(render_id);
251 WebViewPartitionIDMap::iterator iter =
252 webview_partition_id_map_.find(guest_process_id);
253 if (iter != webview_partition_id_map_.end() &&
254 iter->second.web_view_count > 1) {
255 --iter->second.web_view_count;
258 webview_partition_id_map_.erase(guest_process_id);
261 bool ExtensionRendererState::GetWebViewInfo(int guest_process_id,
262 int guest_routing_id,
263 WebViewInfo* webview_info) {
264 DCHECK_CURRENTLY_ON(BrowserThread::IO);
265 RenderId render_id(guest_process_id, guest_routing_id);
266 WebViewInfoMap::iterator iter = webview_info_map_.find(render_id);
267 if (iter != webview_info_map_.end()) {
268 *webview_info = iter->second;
274 bool ExtensionRendererState::GetWebViewPartitionID(int guest_process_id,
275 std::string* partition_id) {
276 DCHECK_CURRENTLY_ON(BrowserThread::IO);
277 WebViewPartitionIDMap::iterator iter =
278 webview_partition_id_map_.find(guest_process_id);
279 if (iter != webview_partition_id_map_.end()) {
280 *partition_id = iter->second.partition_id;