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