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/render_view_host_observer.h"
     21 #include "content/public/browser/web_contents.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::RenderViewHostObserver {
     34  public:
     35   explicit RenderViewHostObserver(content::RenderViewHost* host)
     36       : content::RenderViewHostObserver(host) {
     37   }
     38 
     39   virtual void RenderViewHostDestroyed(content::RenderViewHost* host) OVERRIDE {
     40     BrowserThread::PostTask(
     41         BrowserThread::IO, FROM_HERE,
     42         base::Bind(
     43             &ExtensionRendererState::ClearTabAndWindowId,
     44             base::Unretained(ExtensionRendererState::GetInstance()),
     45             host->GetProcess()->GetID(), host->GetRoutingID()));
     46 
     47     delete this;
     48   }
     49 
     50  private:
     51   DISALLOW_COPY_AND_ASSIGN(RenderViewHostObserver);
     52 };
     53 
     54 //
     55 // ExtensionRendererState::TabObserver
     56 //
     57 
     58 // This class listens for notifications about changes in renderer state on the
     59 // UI thread, and notifies the ExtensionRendererState on the IO thread. It
     60 // should only ever be accessed on the UI thread.
     61 class ExtensionRendererState::TabObserver
     62     : public content::NotificationObserver {
     63  public:
     64   TabObserver();
     65   virtual ~TabObserver();
     66 
     67  private:
     68   // content::NotificationObserver interface.
     69   virtual void Observe(int type,
     70                        const content::NotificationSource& source,
     71                        const content::NotificationDetails& details) OVERRIDE;
     72 
     73   content::NotificationRegistrar registrar_;
     74 };
     75 
     76 ExtensionRendererState::TabObserver::TabObserver() {
     77   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     78   registrar_.Add(this,
     79                  content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
     80                  content::NotificationService::AllBrowserContextsAndSources());
     81   registrar_.Add(this, chrome::NOTIFICATION_TAB_PARENTED,
     82                  content::NotificationService::AllBrowserContextsAndSources());
     83   registrar_.Add(this, chrome::NOTIFICATION_RETARGETING,
     84                  content::NotificationService::AllBrowserContextsAndSources());
     85 }
     86 
     87 ExtensionRendererState::TabObserver::~TabObserver() {
     88   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     89 }
     90 
     91 void ExtensionRendererState::TabObserver::Observe(
     92     int type, const content::NotificationSource& source,
     93     const content::NotificationDetails& details) {
     94   switch (type) {
     95     case content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED: {
     96       WebContents* web_contents = content::Source<WebContents>(source).ptr();
     97       SessionTabHelper* session_tab_helper =
     98           SessionTabHelper::FromWebContents(web_contents);
     99       if (!session_tab_helper)
    100         return;
    101       RenderViewHost* host = content::Details<RenderViewHost>(details).ptr();
    102       // TODO(mpcomplete): How can we tell if window_id is bogus? It may not
    103       // have been set yet.
    104       BrowserThread::PostTask(
    105           BrowserThread::IO, FROM_HERE,
    106           base::Bind(
    107               &ExtensionRendererState::SetTabAndWindowId,
    108               base::Unretained(ExtensionRendererState::GetInstance()),
    109               host->GetProcess()->GetID(), host->GetRoutingID(),
    110               session_tab_helper->session_id().id(),
    111               session_tab_helper->window_id().id()));
    112 
    113       // The observer deletes itself.
    114       new ExtensionRendererState::RenderViewHostObserver(host);
    115 
    116       break;
    117     }
    118     case chrome::NOTIFICATION_TAB_PARENTED: {
    119       WebContents* web_contents = content::Source<WebContents>(source).ptr();
    120       SessionTabHelper* session_tab_helper =
    121           SessionTabHelper::FromWebContents(web_contents);
    122       if (!session_tab_helper)
    123         return;
    124       RenderViewHost* host = web_contents->GetRenderViewHost();
    125       BrowserThread::PostTask(
    126           BrowserThread::IO, FROM_HERE,
    127           base::Bind(
    128               &ExtensionRendererState::SetTabAndWindowId,
    129               base::Unretained(ExtensionRendererState::GetInstance()),
    130               host->GetProcess()->GetID(), host->GetRoutingID(),
    131               session_tab_helper->session_id().id(),
    132               session_tab_helper->window_id().id()));
    133       break;
    134     }
    135     case chrome::NOTIFICATION_RETARGETING: {
    136       RetargetingDetails* retargeting_details =
    137           content::Details<RetargetingDetails>(details).ptr();
    138       WebContents* web_contents = retargeting_details->target_web_contents;
    139       SessionTabHelper* session_tab_helper =
    140           SessionTabHelper::FromWebContents(web_contents);
    141       if (!session_tab_helper)
    142         return;
    143       RenderViewHost* host = web_contents->GetRenderViewHost();
    144       BrowserThread::PostTask(
    145           BrowserThread::IO, FROM_HERE,
    146           base::Bind(
    147               &ExtensionRendererState::SetTabAndWindowId,
    148               base::Unretained(ExtensionRendererState::GetInstance()),
    149               host->GetProcess()->GetID(), host->GetRoutingID(),
    150               session_tab_helper->session_id().id(),
    151               session_tab_helper->window_id().id()));
    152       break;
    153     }
    154     default:
    155       NOTREACHED();
    156       return;
    157   }
    158 }
    159 
    160 //
    161 // ExtensionRendererState
    162 //
    163 
    164 ExtensionRendererState::ExtensionRendererState() : observer_(NULL) {
    165 }
    166 
    167 ExtensionRendererState::~ExtensionRendererState() {
    168 }
    169 
    170 // static
    171 ExtensionRendererState* ExtensionRendererState::GetInstance() {
    172   return Singleton<ExtensionRendererState>::get();
    173 }
    174 
    175 void ExtensionRendererState::Init() {
    176   observer_ = new TabObserver;
    177 }
    178 
    179 void ExtensionRendererState::Shutdown() {
    180   delete observer_;
    181 }
    182 
    183 void ExtensionRendererState::SetTabAndWindowId(
    184     int render_process_host_id, int routing_id, int tab_id, int window_id) {
    185   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    186   RenderId render_id(render_process_host_id, routing_id);
    187   map_[render_id] = TabAndWindowId(tab_id, window_id);
    188 }
    189 
    190 void ExtensionRendererState::ClearTabAndWindowId(
    191     int render_process_host_id, int routing_id) {
    192   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    193   RenderId render_id(render_process_host_id, routing_id);
    194   map_.erase(render_id);
    195 }
    196 
    197 bool ExtensionRendererState::GetTabAndWindowId(
    198     int render_process_host_id, int routing_id, int* tab_id, int* window_id) {
    199   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    200   RenderId render_id(render_process_host_id, routing_id);
    201   TabAndWindowIdMap::iterator iter = map_.find(render_id);
    202   if (iter != map_.end()) {
    203     *tab_id = iter->second.first;
    204     *window_id = iter->second.second;
    205     return true;
    206   }
    207   return false;
    208 }
    209 
    210 void ExtensionRendererState::AddWebView(int guest_process_id,
    211                                         int guest_routing_id,
    212                                         const WebViewInfo& webview_info) {
    213   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    214   RenderId render_id(guest_process_id, guest_routing_id);
    215   webview_info_map_[render_id] = webview_info;
    216 }
    217 
    218 void ExtensionRendererState::RemoveWebView(int guest_process_id,
    219                                            int guest_routing_id) {
    220   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    221   RenderId render_id(guest_process_id, guest_routing_id);
    222   webview_info_map_.erase(render_id);
    223 }
    224 
    225 bool ExtensionRendererState::GetWebViewInfo(int guest_process_id,
    226                                             int guest_routing_id,
    227                                             WebViewInfo* webview_info) {
    228   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    229   RenderId render_id(guest_process_id, guest_routing_id);
    230   WebViewInfoMap::iterator iter = webview_info_map_.find(render_id);
    231   if (iter != webview_info_map_.end()) {
    232     *webview_info = iter->second;
    233     return true;
    234   }
    235   return false;
    236 }
    237