Home | History | Annotate | Download | only in browser
      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
      3 // found in the LICENSE file.
      4 
      5 #include "content/public/browser/notification_registrar.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/logging.h"
     10 #include "content/browser/notification_service_impl.h"
     11 
     12 namespace content {
     13 
     14 struct NotificationRegistrar::Record {
     15   bool operator==(const Record& other) const;
     16 
     17   NotificationObserver* observer;
     18   int type;
     19   NotificationSource source;
     20 };
     21 
     22 bool NotificationRegistrar::Record::operator==(const Record& other) const {
     23   return observer == other.observer &&
     24          type == other.type &&
     25          source == other.source;
     26 }
     27 
     28 NotificationRegistrar::NotificationRegistrar() {
     29   // Force the NotificationService to be constructed (if it isn't already).
     30   // This ensures the NotificationService will be registered on the
     31   // AtExitManager before any objects which access it via NotificationRegistrar.
     32   // This in turn means it will be destroyed after these objects, so they will
     33   // never try to access the NotificationService after it's been destroyed.
     34   NotificationServiceImpl::current();
     35   // It is OK to create a NotificationRegistrar instance on one thread and then
     36   // use it (exclusively) on another, so we detach from the initial thread.
     37   DetachFromThread();
     38 }
     39 
     40 NotificationRegistrar::~NotificationRegistrar() {
     41   RemoveAll();
     42 }
     43 
     44 void NotificationRegistrar::Add(NotificationObserver* observer,
     45                                 int type,
     46                                 const NotificationSource& source) {
     47   DCHECK(CalledOnValidThread());
     48   DCHECK(!IsRegistered(observer, type, source)) << "Duplicate registration.";
     49 
     50   Record record = { observer, type, source };
     51   registered_.push_back(record);
     52 
     53   NotificationServiceImpl::current()->AddObserver(observer, type, source);
     54 }
     55 
     56 void NotificationRegistrar::Remove(NotificationObserver* observer,
     57                                    int type,
     58                                    const NotificationSource& source) {
     59   DCHECK(CalledOnValidThread());
     60 
     61   Record record = { observer, type, source };
     62   RecordVector::iterator found = std::find(
     63       registered_.begin(), registered_.end(), record);
     64   DCHECK(found != registered_.end());
     65 
     66   registered_.erase(found);
     67 
     68   // This can be NULL if our owner outlives the NotificationService, e.g. if our
     69   // owner is a Singleton.
     70   NotificationServiceImpl* service = NotificationServiceImpl::current();
     71   if (service)
     72     service->RemoveObserver(observer, type, source);
     73 }
     74 
     75 void NotificationRegistrar::RemoveAll() {
     76   CHECK(CalledOnValidThread());
     77   // Early-exit if no registrations, to avoid calling
     78   // NotificationService::current.  If we've constructed an object with a
     79   // NotificationRegistrar member, but haven't actually used the notification
     80   // service, and we reach prgram exit, then calling current() below could try
     81   // to initialize the service's lazy TLS pointer during exit, which throws
     82   // wrenches at things.
     83   if (registered_.empty())
     84     return;
     85 
     86   // This can be NULL if our owner outlives the NotificationService, e.g. if our
     87   // owner is a Singleton.
     88   NotificationServiceImpl* service = NotificationServiceImpl::current();
     89   if (service) {
     90     for (size_t i = 0; i < registered_.size(); i++) {
     91       service->RemoveObserver(registered_[i].observer,
     92                               registered_[i].type,
     93                               registered_[i].source);
     94     }
     95   }
     96   registered_.clear();
     97 }
     98 
     99 bool NotificationRegistrar::IsEmpty() const {
    100   DCHECK(CalledOnValidThread());
    101   return registered_.empty();
    102 }
    103 
    104 bool NotificationRegistrar::IsRegistered(NotificationObserver* observer,
    105                                          int type,
    106                                          const NotificationSource& source) {
    107   DCHECK(CalledOnValidThread());
    108   Record record = { observer, type, source };
    109   return std::find(registered_.begin(), registered_.end(), record) !=
    110       registered_.end();
    111 }
    112 
    113 }  // namespace content
    114