Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2011 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_tab_id_map.h"
      6 
      7 #include "content/browser/browser_thread.h"
      8 #include "content/browser/tab_contents/tab_contents.h"
      9 #include "content/browser/renderer_host/render_view_host.h"
     10 #include "content/browser/renderer_host/render_process_host.h"
     11 #include "content/common/notification_registrar.h"
     12 #include "content/common/notification_observer.h"
     13 #include "content/common/notification_service.h"
     14 
     15 // ExtensionTabIdMap is a Singleton, so it doesn't need refcounting.
     16 DISABLE_RUNNABLE_METHOD_REFCOUNT(ExtensionTabIdMap);
     17 
     18 //
     19 // ExtensionTabIdMap::TabObserver
     20 //
     21 
     22 // This class listens for notifications about new and closed tabs on the UI
     23 // thread, and notifies the ExtensionTabIdMap on the IO thread. It should only
     24 // ever be accessed on the UI thread.
     25 class ExtensionTabIdMap::TabObserver : public NotificationObserver {
     26  public:
     27   TabObserver();
     28   ~TabObserver();
     29 
     30  private:
     31   // NotificationObserver interface.
     32   virtual void Observe(NotificationType type,
     33                        const NotificationSource& source,
     34                        const NotificationDetails& details);
     35 
     36   NotificationRegistrar registrar_;
     37 };
     38 
     39 ExtensionTabIdMap::TabObserver::TabObserver() {
     40   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     41   registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB,
     42                  NotificationService::AllSources());
     43   registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED,
     44                  NotificationService::AllSources());
     45   registrar_.Add(this, NotificationType::TAB_PARENTED,
     46                  NotificationService::AllSources());
     47 }
     48 
     49 ExtensionTabIdMap::TabObserver::~TabObserver() {
     50   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     51 }
     52 
     53 void ExtensionTabIdMap::TabObserver::Observe(
     54     NotificationType type, const NotificationSource& source,
     55     const NotificationDetails& details) {
     56   switch (type.value) {
     57     case NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB: {
     58       TabContents* contents = Source<TabContents>(source).ptr();
     59       RenderViewHost* host = Details<RenderViewHost>(details).ptr();
     60       // TODO(mpcmoplete): How can we tell if window_id is bogus? It may not
     61       // have been set yet.
     62       BrowserThread::PostTask(
     63           BrowserThread::IO, FROM_HERE,
     64           NewRunnableMethod(
     65               ExtensionTabIdMap::GetInstance(),
     66               &ExtensionTabIdMap::SetTabAndWindowId,
     67               host->process()->id(), host->routing_id(),
     68               contents->controller().session_id().id(),
     69               contents->controller().window_id().id()));
     70       break;
     71     }
     72     case NotificationType::TAB_PARENTED: {
     73       NavigationController* controller =
     74           Source<NavigationController>(source).ptr();
     75       RenderViewHost* host = controller->tab_contents()->render_view_host();
     76       BrowserThread::PostTask(
     77           BrowserThread::IO, FROM_HERE,
     78           NewRunnableMethod(
     79               ExtensionTabIdMap::GetInstance(),
     80               &ExtensionTabIdMap::SetTabAndWindowId,
     81               host->process()->id(), host->routing_id(),
     82               controller->session_id().id(),
     83               controller->window_id().id()));
     84       break;
     85     }
     86     case NotificationType::RENDER_VIEW_HOST_DELETED: {
     87       RenderViewHost* host = Source<RenderViewHost>(source).ptr();
     88       BrowserThread::PostTask(
     89           BrowserThread::IO, FROM_HERE,
     90           NewRunnableMethod(
     91               ExtensionTabIdMap::GetInstance(),
     92               &ExtensionTabIdMap::ClearTabAndWindowId,
     93               host->process()->id(), host->routing_id()));
     94       break;
     95     }
     96     default:
     97       NOTREACHED();
     98       return;
     99   }
    100 }
    101 
    102 //
    103 // ExtensionTabIdMap
    104 //
    105 
    106 ExtensionTabIdMap::ExtensionTabIdMap() : observer_(NULL) {
    107 }
    108 
    109 ExtensionTabIdMap::~ExtensionTabIdMap() {
    110 }
    111 
    112 // static
    113 ExtensionTabIdMap* ExtensionTabIdMap::GetInstance() {
    114   return Singleton<ExtensionTabIdMap>::get();
    115 }
    116 
    117 void ExtensionTabIdMap::Init() {
    118   observer_ = new TabObserver;
    119 }
    120 
    121 void ExtensionTabIdMap::Shutdown() {
    122   delete observer_;
    123 }
    124 
    125 void ExtensionTabIdMap::SetTabAndWindowId(
    126     int render_process_host_id, int routing_id, int tab_id, int window_id) {
    127   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    128   RenderId render_id(render_process_host_id, routing_id);
    129   map_[render_id] = TabAndWindowId(tab_id, window_id);
    130 }
    131 
    132 void ExtensionTabIdMap::ClearTabAndWindowId(
    133     int render_process_host_id, int routing_id) {
    134   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    135   RenderId render_id(render_process_host_id, routing_id);
    136   map_.erase(render_id);
    137 }
    138 
    139 bool ExtensionTabIdMap::GetTabAndWindowId(
    140     int render_process_host_id, int routing_id, int* tab_id, int* window_id) {
    141   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    142   RenderId render_id(render_process_host_id, routing_id);
    143   TabAndWindowIdMap::iterator iter = map_.find(render_id);
    144   if (iter != map_.end()) {
    145     *tab_id = iter->second.first;
    146     *window_id = iter->second.second;
    147     return true;
    148   }
    149   return false;
    150 }
    151