| 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 |