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