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. 16DISABLE_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. 25class 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 39ExtensionTabIdMap::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 49ExtensionTabIdMap::TabObserver::~TabObserver() { 50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 51} 52 53void 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 106ExtensionTabIdMap::ExtensionTabIdMap() : observer_(NULL) { 107} 108 109ExtensionTabIdMap::~ExtensionTabIdMap() { 110} 111 112// static 113ExtensionTabIdMap* ExtensionTabIdMap::GetInstance() { 114 return Singleton<ExtensionTabIdMap>::get(); 115} 116 117void ExtensionTabIdMap::Init() { 118 observer_ = new TabObserver; 119} 120 121void ExtensionTabIdMap::Shutdown() { 122 delete observer_; 123} 124 125void 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 132void 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 139bool 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