15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/notification_service_impl.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_local.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_observer.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_types.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<base::ThreadLocalPointer<NotificationServiceImpl> > 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NotificationServiceImpl* NotificationServiceImpl::current() { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return lazy_tls_ptr.Pointer()->Get(); 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NotificationService* NotificationService::current() { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NotificationServiceImpl::current(); 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NotificationService* NotificationService::Create() { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new NotificationServiceImpl; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NotificationServiceImpl::HasKey(const NotificationSourceMap& map, 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const NotificationSource& source) { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return map.find(source.map_key()) != map.end(); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NotificationServiceImpl::NotificationServiceImpl() { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(current() == NULL); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lazy_tls_ptr.Pointer()->Set(this); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NotificationServiceImpl::AddObserver(NotificationObserver* observer, 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int type, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const NotificationSource& source) { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have gotten some crashes where the observer pointer is NULL. The problem 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is that this happens when we actually execute a notification, so have no 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // way of knowing who the bad observer was. We want to know when this happens 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in release mode so we know what code to blame the crash on (since this is 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // guaranteed to crash later). 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(observer); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NotificationObserverList* observer_list; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasKey(observers_[type], source)) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observer_list = observers_[type][source.map_key()]; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observer_list = new NotificationObserverList; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observers_[type][source.map_key()] = observer_list; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observer_list->AddObserver(observer); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++observer_counts_[type]; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NotificationServiceImpl::RemoveObserver(NotificationObserver* observer, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int type, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const NotificationSource& source) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is a very serious bug. An object is most likely being deleted on 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the wrong thread, and as a result another thread's NotificationServiceImpl 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // has its deleted pointer in its map. A garbge object will be called in the 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // future. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: when this check shows crashes, use BrowserThread::DeleteOnIOThread or 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // other variants as the trait on the object. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(HasKey(observers_[type], source)); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NotificationObserverList* observer_list = 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observers_[type][source.map_key()]; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (observer_list) { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observer_list->RemoveObserver(observer); 86424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (!observer_list->might_have_observers()) { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observers_[type].erase(source.map_key()); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete observer_list; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --observer_counts_[type]; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NotificationServiceImpl::Notify(int type, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const NotificationSource& source, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const NotificationDetails& details) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GT(type, NOTIFICATION_ALL) << 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Allowed for observing, but not posting."; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There's no particular reason for the order in which the different 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // classes of observers get notified here. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Notify observers of all types and all sources 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasKey(observers_[NOTIFICATION_ALL], AllSources()) && 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source != AllSources()) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(NotificationObserver, 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *observers_[NOTIFICATION_ALL][AllSources().map_key()], 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Observe(type, source, details)); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Notify observers of all types and the given source 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasKey(observers_[NOTIFICATION_ALL], source)) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(NotificationObserver, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *observers_[NOTIFICATION_ALL][source.map_key()], 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Observe(type, source, details)); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Notify observers of the given type and all sources 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasKey(observers_[type], AllSources()) && 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source != AllSources()) { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(NotificationObserver, 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *observers_[type][AllSources().map_key()], 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Observe(type, source, details)); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Notify observers of the given type and the given source 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasKey(observers_[type], source)) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_EACH_OBSERVER(NotificationObserver, 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *observers_[type][source.map_key()], 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Observe(type, source, details)); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NotificationServiceImpl::~NotificationServiceImpl() { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lazy_tls_ptr.Pointer()->Set(NULL); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < static_cast<int>(observer_counts_.size()); i++) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (observer_counts_[i] > 0) { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This may not be completely fixable -- see 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://code.google.com/p/chromium/issues/detail?id=11010 . 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << observer_counts_[i] << " notification observer(s) leaked " 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "of notification type " << i; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < static_cast<int>(observers_.size()); i++) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NotificationSourceMap omap = observers_[i]; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (NotificationSourceMap::iterator it = omap.begin(); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != omap.end(); ++it) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete it->second; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 160