OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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 "content/common/notification_service.h" | |
6 | |
7 #include "base/lazy_instance.h" | |
8 #include "base/threading/thread_local.h" | |
9 #include "content/public/browser/notification_observer.h" | |
10 #include "content/public/browser/notification_types.h" | |
11 | |
12 static base::LazyInstance<base::ThreadLocalPointer<NotificationService> > | |
13 lazy_tls_ptr(base::LINKER_INITIALIZED); | |
14 | |
15 // static | |
16 NotificationService* NotificationService::current() { | |
17 return lazy_tls_ptr.Pointer()->Get(); | |
18 } | |
19 | |
20 // static | |
21 bool NotificationService::HasKey(const NotificationSourceMap& map, | |
22 const content::NotificationSource& source) { | |
23 return map.find(source.map_key()) != map.end(); | |
24 } | |
25 | |
26 NotificationService::NotificationService() { | |
27 DCHECK(current() == NULL); | |
28 lazy_tls_ptr.Pointer()->Set(this); | |
29 } | |
30 | |
31 void NotificationService::AddObserver( | |
32 content::NotificationObserver* observer, | |
33 int type, | |
34 const content::NotificationSource& source) { | |
35 // We have gotten some crashes where the observer pointer is NULL. The problem | |
36 // is that this happens when we actually execute a notification, so have no | |
37 // way of knowing who the bad observer was. We want to know when this happens | |
38 // in release mode so we know what code to blame the crash on (since this is | |
39 // guaranteed to crash later). | |
40 CHECK(observer); | |
41 | |
42 NotificationObserverList* observer_list; | |
43 if (HasKey(observers_[type], source)) { | |
44 observer_list = observers_[type][source.map_key()]; | |
45 } else { | |
46 observer_list = new NotificationObserverList; | |
47 observers_[type][source.map_key()] = observer_list; | |
48 } | |
49 | |
50 observer_list->AddObserver(observer); | |
51 #ifndef NDEBUG | |
52 ++observer_counts_[type]; | |
53 #endif | |
54 } | |
55 | |
56 void NotificationService::RemoveObserver( | |
57 content::NotificationObserver* observer, | |
58 int type, | |
59 const content::NotificationSource& source) { | |
60 // This is a very serious bug. An object is most likely being deleted on | |
61 // the wrong thread, and as a result another thread's NotificationService | |
62 // has its deleted pointer in its map. A garbge object will be called in the | |
63 // future. | |
64 // NOTE: when this check shows crashes, use BrowserThread::DeleteOnIOThread or | |
65 // other variants as the trait on the object. | |
66 CHECK(HasKey(observers_[type], source)); | |
67 | |
68 NotificationObserverList* observer_list = | |
69 observers_[type][source.map_key()]; | |
70 if (observer_list) { | |
71 observer_list->RemoveObserver(observer); | |
72 #ifndef NDEBUG | |
73 --observer_counts_[type]; | |
74 #endif | |
75 } | |
76 | |
77 // TODO(jhughes): Remove observer list from map if empty? | |
78 } | |
79 | |
80 void NotificationService::Notify(int type, | |
81 const content::NotificationSource& source, | |
82 const content::NotificationDetails& details) { | |
83 DCHECK(type > content::NOTIFICATION_ALL) << | |
84 "Allowed for observing, but not posting."; | |
85 | |
86 // There's no particular reason for the order in which the different | |
87 // classes of observers get notified here. | |
88 | |
89 // Notify observers of all types and all sources | |
90 if (HasKey(observers_[content::NOTIFICATION_ALL], AllSources()) && | |
91 source != AllSources()) { | |
92 FOR_EACH_OBSERVER(content::NotificationObserver, | |
93 *observers_[content::NOTIFICATION_ALL][AllSources().map_key()], | |
94 Observe(type, source, details)); | |
95 } | |
96 | |
97 // Notify observers of all types and the given source | |
98 if (HasKey(observers_[content::NOTIFICATION_ALL], source)) { | |
99 FOR_EACH_OBSERVER(content::NotificationObserver, | |
100 *observers_[content::NOTIFICATION_ALL][source.map_key()], | |
101 Observe(type, source, details)); | |
102 } | |
103 | |
104 // Notify observers of the given type and all sources | |
105 if (HasKey(observers_[type], AllSources()) && | |
106 source != AllSources()) { | |
107 FOR_EACH_OBSERVER(content::NotificationObserver, | |
108 *observers_[type][AllSources().map_key()], | |
109 Observe(type, source, details)); | |
110 } | |
111 | |
112 // Notify observers of the given type and the given source | |
113 if (HasKey(observers_[type], source)) { | |
114 FOR_EACH_OBSERVER(content::NotificationObserver, | |
115 *observers_[type][source.map_key()], | |
116 Observe(type, source, details)); | |
117 } | |
118 } | |
119 | |
120 | |
121 NotificationService::~NotificationService() { | |
122 lazy_tls_ptr.Pointer()->Set(NULL); | |
123 | |
124 #ifndef NDEBUG | |
125 for (int i = 0; i < static_cast<int>(observer_counts_.size()); i++) { | |
126 if (observer_counts_[i] > 0) { | |
127 // This may not be completely fixable -- see | |
128 // http://code.google.com/p/chromium/issues/detail?id=11010 . | |
129 VLOG(1) << observer_counts_[i] << " notification observer(s) leaked " | |
130 "of notification type " << i; | |
131 } | |
132 } | |
133 #endif | |
134 | |
135 for (int i = 0; i < static_cast<int>(observers_.size()); i++) { | |
136 NotificationSourceMap omap = observers_[i]; | |
137 for (NotificationSourceMap::iterator it = omap.begin(); | |
138 it != omap.end(); ++it) | |
139 delete it->second; | |
140 } | |
141 } | |
OLD | NEW |