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