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