Home | History | Annotate | Download | only in extensions
      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:
     35   RenderViewHostObserver(RenderViewHost* host, WebContents* web_contents)
     36       : content::WebContentsObserver(web_contents),
     37         render_view_host_(host) {
     38   }
     39 
     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 
     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 
     92 ExtensionRendererState::TabObserver::~TabObserver() {
     93   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     94 }
     95 
     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 
    169 ExtensionRendererState::ExtensionRendererState() : observer_(NULL) {
    170 }
    171 
    172 ExtensionRendererState::~ExtensionRendererState() {
    173 }
    174 
    175 // static
    176 ExtensionRendererState* ExtensionRendererState::GetInstance() {
    177   return Singleton<ExtensionRendererState>::get();
    178 }
    179 
    180 void ExtensionRendererState::Init() {
    181   observer_ = new TabObserver;
    182 }
    183 
    184 void ExtensionRendererState::Shutdown() {
    185   delete observer_;
    186 }
    187 
    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 
    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 
    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 
    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 
    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 
    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 
    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