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