Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(409)

Unified Diff: net/base/network_change_notifier_mac.cc

Issue 2802015: Massively simplify the NetworkChangeNotifier infrastructure:... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/base/network_change_notifier_mac.cc
===================================================================
--- net/base/network_change_notifier_mac.cc (revision 50775)
+++ net/base/network_change_notifier_mac.cc (working copy)
@@ -2,168 +2,116 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// There are three classes involved here. There's NetworkChangeNotifierMac,
-// which is the Mac specific implementation of NetworkChangeNotifier. It is the
-// class with which clients can register themselves as network change
-// observers. There's NetworkChangeNotifierThread, which is a base::Thread
-// subclass of MessageLoop::TYPE_UI (since it needs a CFRunLoop) that contains
-// the NetworkChangeNotifierImpl. NetworkChangeNotifierImpl is the object
-// that receives the actual OS X notifications and posts them to the
-// NetworkChangeNotifierMac's message loop, so that NetworkChangeNotifierMac
-// can notify all its observers.
-//
-// When NetworkChangeNotifierMac is being deleted, it will delete the
-// NetworkChangeNotifierThread, which will Stop() it and also delete the
-// NetworkChangeNotifierImpl. Therefore, NetworkChangeNotifierImpl and
-// NetworkChangeNotifierThread's lifetimes generally begin after and end before
-// NetworkChangeNotifierMac. There is an edge case where a notification task
-// gets posted to the IO thread, thereby maintaining a reference to
-// NetworkChangeNotifierImpl beyond the lifetime of NetworkChangeNotifierThread.
-// In this case, the notification is cancelled, and NetworkChangeNotifierImpl
-// will be deleted once all notification tasks that reference it have been run.
-
#include "net/base/network_change_notifier_mac.h"
-#include <SystemConfiguration/SCDynamicStore.h>
+
#include <SystemConfiguration/SCDynamicStoreKey.h>
#include <SystemConfiguration/SCSchemaDefinitions.h>
#include <algorithm>
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/scoped_cftyperef.h"
+
#include "base/thread.h"
+// We only post tasks to a child thread we own, so we don't need refcounting.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(net::NetworkChangeNotifierMac);
+
namespace net {
-namespace {
+NetworkChangeNotifierMac::NetworkChangeNotifierMac()
+ : notifier_thread_(new base::Thread("NetworkChangeNotifier")) {
+ // We create this notifier thread because the notification implementation
+ // needs a thread with a CFRunLoop, and there's no guarantee that
+ // MessageLoop::current() meets that criterion.
+ base::Thread::Options thread_options(MessageLoop::TYPE_UI, 0);
+ notifier_thread_->StartWithOptions(thread_options);
+ // TODO(willchan): Look to see if there's a better signal for when it's ok to
+ // initialize this, rather than just delaying it by a fixed time.
+ const int kNotifierThreadInitializationDelayMS = 1000;
+ notifier_thread_->message_loop()->PostDelayedTask(FROM_HERE,
+ NewRunnableMethod(this, &NetworkChangeNotifierMac::Init),
+ kNotifierThreadInitializationDelayMS);
+}
-// NetworkChangeNotifierImpl should be created on a thread with a CFRunLoop,
-// since it requires one to pump notifications. However, it also runs some
-// methods on |notifier_loop_|, because it cannot post calls to |notifier_|
-// since NetworkChangeNotifier is not ref counted in a thread safe manner.
-class NetworkChangeNotifierImpl
- : public base::RefCountedThreadSafe<NetworkChangeNotifierImpl> {
- public:
- NetworkChangeNotifierImpl(MessageLoop* notifier_loop,
- NetworkChangeNotifierMac* notifier);
+NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {
+ // We don't need to explicitly Stop(), but doing so allows us to sanity-
+ // check that the notifier thread shut down properly.
+ notifier_thread_->Stop();
+ DCHECK(run_loop_source_ == NULL);
+}
- void Shutdown();
+// static
+void NetworkChangeNotifierMac::DynamicStoreCallback(
+ SCDynamicStoreRef /* store */,
+ CFArrayRef changed_keys,
+ void* config) {
+ NetworkChangeNotifierMac* net_config =
+ static_cast<NetworkChangeNotifierMac*>(config);
+ net_config->OnNetworkConfigChange(changed_keys);
+}
- private:
- friend class base::RefCountedThreadSafe<NetworkChangeNotifierImpl>;
- ~NetworkChangeNotifierImpl();
+void NetworkChangeNotifierMac::WillDestroyCurrentMessageLoop() {
+ DCHECK(notifier_thread_ != NULL);
+ // We can't check the notifier_thread_'s message_loop(), as it's now 0.
+ // DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current());
- static void DynamicStoreCallback(SCDynamicStoreRef /* store */,
- CFArrayRef changed_keys,
- void* config);
+ DCHECK(run_loop_source_ != NULL);
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
+ kCFRunLoopCommonModes);
+ run_loop_source_.reset();
+}
- void OnNetworkConfigChange(CFArrayRef changed_keys);
+void NetworkChangeNotifierMac::Init() {
+ DCHECK(notifier_thread_ != NULL);
+ DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current());
- // Runs on |notifier_loop_|.
- void OnIPAddressChanged();
-
- // Raw pointers. Note that |notifier_| _must_ outlive the
- // NetworkChangeNotifierImpl. For lifecycle management details, read the
- // comment at the top of the file.
- MessageLoop* const notifier_loop_;
- NetworkChangeNotifierMac* notifier_;
-
- scoped_cftyperef<CFRunLoopSourceRef> source_;
-
- DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierImpl);
-};
-
-NetworkChangeNotifierImpl::NetworkChangeNotifierImpl(
- MessageLoop* notifier_loop, NetworkChangeNotifierMac* notifier)
- : notifier_loop_(notifier_loop),
- notifier_(notifier) {
- DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
+ // Add a run loop source for a dynamic store to the current run loop.
SCDynamicStoreContext context = {
- 0, // Version 0.
- this, // User data.
- NULL, // This is not reference counted. No retain function.
- NULL, // This is not reference counted. No release function.
- NULL, // No description for this.
+ 0, // Version 0.
+ this, // User data.
+ NULL, // This is not reference counted. No retain function.
+ NULL, // This is not reference counted. No release function.
+ NULL, // No description for this.
};
-
- // Get a reference to the dynamic store.
- scoped_cftyperef<SCDynamicStoreRef> store(
- SCDynamicStoreCreate(NULL /* use default allocator */,
- CFSTR("org.chromium"),
- DynamicStoreCallback, &context));
-
- // Create a run loop source for the dynamic store.
- source_.reset(SCDynamicStoreCreateRunLoopSource(
- NULL /* use default allocator */,
- store.get(),
- 0 /* 0 sounds like a fine source order to me! */));
-
- // Add the run loop source to the current run loop.
- CFRunLoopAddSource(CFRunLoopGetCurrent(),
- source_.get(),
+ scoped_cftyperef<SCDynamicStoreRef> store(SCDynamicStoreCreate(
+ NULL, CFSTR("org.chromium"), DynamicStoreCallback, &context));
+ run_loop_source_.reset(SCDynamicStoreCreateRunLoopSource(
+ NULL, store.get(), 0));
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
kCFRunLoopCommonModes);
- // Set up the notification keys.
+ // Set up notifications for interface and IP address changes.
scoped_cftyperef<CFMutableArrayRef> notification_keys(
CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
-
- // Monitor interface changes.
- scoped_cftyperef<CFStringRef> key(
- SCDynamicStoreKeyCreateNetworkGlobalEntity(
- NULL /* default allocator */, kSCDynamicStoreDomainState,
- kSCEntNetInterface));
+ scoped_cftyperef<CFStringRef> key(SCDynamicStoreKeyCreateNetworkGlobalEntity(
+ NULL, kSCDynamicStoreDomainState, kSCEntNetInterface));
CFArrayAppendValue(notification_keys.get(), key.get());
-
- // Monitor IP address changes.
-
key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity(
- NULL /* default allocator */, kSCDynamicStoreDomainState,
- kSCEntNetIPv4));
+ NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4));
CFArrayAppendValue(notification_keys.get(), key.get());
-
key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity(
- NULL /* default allocator */, kSCDynamicStoreDomainState,
- kSCEntNetIPv6));
+ NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6));
CFArrayAppendValue(notification_keys.get(), key.get());
- // Ok, let's ask for notifications!
+ // Set the notification keys. This starts us receiving notifications.
+ bool ret = SCDynamicStoreSetNotificationKeys(
+ store.get(), notification_keys.get(), NULL);
// TODO(willchan): Figure out a proper way to handle this rather than crash.
- CHECK(SCDynamicStoreSetNotificationKeys(
- store.get(), notification_keys.get(), NULL));
-}
+ CHECK(ret);
-NetworkChangeNotifierImpl::~NetworkChangeNotifierImpl() {
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
- source_.get(),
- kCFRunLoopCommonModes);
+ MessageLoop::current()->AddDestructionObserver(this);
}
-void NetworkChangeNotifierImpl::Shutdown() {
- CHECK(notifier_);
- notifier_ = NULL;
-}
+void NetworkChangeNotifierMac::OnNetworkConfigChange(CFArrayRef changed_keys) {
+ DCHECK(notifier_thread_ != NULL);
+ DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current());
-// static
-void NetworkChangeNotifierImpl::DynamicStoreCallback(
- SCDynamicStoreRef /* store */,
- CFArrayRef changed_keys,
- void* config) {
- NetworkChangeNotifierImpl* net_config =
- static_cast<NetworkChangeNotifierImpl*>(config);
- net_config->OnNetworkConfigChange(changed_keys);
-}
-
-void NetworkChangeNotifierImpl::OnNetworkConfigChange(CFArrayRef changed_keys) {
for (CFIndex i = 0; i < CFArrayGetCount(changed_keys); ++i) {
CFStringRef key = static_cast<CFStringRef>(
CFArrayGetValueAtIndex(changed_keys, i));
if (CFStringHasSuffix(key, kSCEntNetIPv4) ||
CFStringHasSuffix(key, kSCEntNetIPv6)) {
- notifier_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(
- this,
- &NetworkChangeNotifierImpl::OnIPAddressChanged));
- } else if (CFStringHasSuffix(key, kSCEntNetInterface)) {
+ NotifyObserversOfIPAddressChange();
+ return;
+ }
+ if (CFStringHasSuffix(key, kSCEntNetInterface)) {
// TODO(willchan): Does not appear to be working. Look into this.
// Perhaps this isn't needed anyway.
} else {
@@ -172,91 +120,4 @@
}
}
-void NetworkChangeNotifierImpl::OnIPAddressChanged() {
- // If |notifier_| doesn't exist, then that means we're shutting down, so
- // notifications are all cancelled.
- if (notifier_)
- notifier_->OnIPAddressChanged();
-}
-
-class NetworkChangeNotifierThread : public base::Thread {
- public:
- NetworkChangeNotifierThread(MessageLoop* notifier_loop,
- NetworkChangeNotifierMac* notifier);
- ~NetworkChangeNotifierThread();
-
- protected:
- virtual void Init();
-
- private:
- MessageLoop* const notifier_loop_;
- NetworkChangeNotifierMac* const notifier_;
- scoped_refptr<NetworkChangeNotifierImpl> notifier_impl_;
-
- DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierThread);
-};
-
-NetworkChangeNotifierThread::NetworkChangeNotifierThread(
- MessageLoop* notifier_loop, NetworkChangeNotifierMac* notifier)
- : base::Thread("NetworkChangeNotifier"),
- notifier_loop_(notifier_loop),
- notifier_(notifier) {}
-
-NetworkChangeNotifierThread::~NetworkChangeNotifierThread() {
- notifier_impl_->Shutdown();
- Stop();
-}
-
-// Note that |notifier_impl_| is initialized on the network change
-// notifier thread, not whatever thread constructs the
-// NetworkChangeNotifierThread object. This is important, because this thread
-// is the one that has a CFRunLoop.
-void NetworkChangeNotifierThread::Init() {
- notifier_impl_ =
- new NetworkChangeNotifierImpl(notifier_loop_, notifier_);
-}
-
-} // namespace
-
-NetworkChangeNotifierMac::NetworkChangeNotifierMac()
- : notifier_thread_(NULL),
- method_factory_(this) {
- // TODO(willchan): Look to see if there's a better signal for when it's ok to
- // initialize this, rather than just delaying it by a fixed time.
- const int kNotifierThreadInitializationDelayMS = 1000;
- MessageLoop* loop = MessageLoop::current();
- loop->PostDelayedTask(
- FROM_HERE,
- method_factory_.NewRunnableMethod(
- &NetworkChangeNotifierMac::InitializeNotifierThread, loop),
- kNotifierThreadInitializationDelayMS);
-}
-
-void NetworkChangeNotifierMac::OnIPAddressChanged() {
- DCHECK(CalledOnValidThread());
- FOR_EACH_OBSERVER(Observer, observers_, OnIPAddressChanged());
-}
-
-void NetworkChangeNotifierMac::AddObserver(Observer* observer) {
- DCHECK(CalledOnValidThread());
- observers_.AddObserver(observer);
-}
-
-void NetworkChangeNotifierMac::RemoveObserver(Observer* observer) {
- DCHECK(CalledOnValidThread());
- observers_.RemoveObserver(observer);
-}
-
-NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {
- DCHECK(CalledOnValidThread());
-}
-
-void NetworkChangeNotifierMac::InitializeNotifierThread(MessageLoop* loop) {
- DCHECK(CalledOnValidThread());
- notifier_thread_.reset(new NetworkChangeNotifierThread(loop, this));
- base::Thread::Options thread_options;
- thread_options.message_loop_type = MessageLoop::TYPE_UI;
- notifier_thread_->StartWithOptions(thread_options);
-}
-
} // namespace net

Powered by Google App Engine
This is Rietveld 408576698