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
TabObserver()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
~TabObserver()49 ExtensionTabIdMap::TabObserver::~TabObserver() {
50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
51 }
52
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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
ExtensionTabIdMap()106 ExtensionTabIdMap::ExtensionTabIdMap() : observer_(NULL) {
107 }
108
~ExtensionTabIdMap()109 ExtensionTabIdMap::~ExtensionTabIdMap() {
110 }
111
112 // static
GetInstance()113 ExtensionTabIdMap* ExtensionTabIdMap::GetInstance() {
114 return Singleton<ExtensionTabIdMap>::get();
115 }
116
Init()117 void ExtensionTabIdMap::Init() {
118 observer_ = new TabObserver;
119 }
120
Shutdown()121 void ExtensionTabIdMap::Shutdown() {
122 delete observer_;
123 }
124
SetTabAndWindowId(int render_process_host_id,int routing_id,int tab_id,int window_id)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
ClearTabAndWindowId(int render_process_host_id,int routing_id)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
GetTabAndWindowId(int render_process_host_id,int routing_id,int * tab_id,int * window_id)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