Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_renderer_state.cc
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
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();
228 }
229
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;
240     return;
241   }
242   WebViewPartitionInfo partition_info(1, webview_info.partition_id);
243   webview_partition_id_map_[guest_process_id] = partition_info;
244 }
245
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;
256     return;
257   }
258   webview_partition_id_map_.erase(guest_process_id);
259 }
260
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;
269     return true;
270   }
271   return false;
272 }
273
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;
281     return true;
282   }
283   return false;
284 }