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.
5 #include "net/base/network_config_watcher_mac.h"
10 #include "base/compiler_specific.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/thread_restrictions.h"
21 // Called back by OS. Calls OnNetworkConfigChange().
22 void DynamicStoreCallback(SCDynamicStoreRef
/* store */,
23 CFArrayRef changed_keys
,
24 void* config_delegate
) {
25 NetworkConfigWatcherMac::Delegate
* net_config_delegate
=
26 static_cast<NetworkConfigWatcherMac::Delegate
*>(config_delegate
);
27 net_config_delegate
->OnNetworkConfigChange(changed_keys
);
29 #endif // !defined(OS_IOS)
31 class NetworkConfigWatcherMacThread
: public base::Thread
{
33 NetworkConfigWatcherMacThread(NetworkConfigWatcherMac::Delegate
* delegate
);
34 virtual ~NetworkConfigWatcherMacThread();
38 virtual void Init() OVERRIDE
;
39 virtual void CleanUp() OVERRIDE
;
42 // The SystemConfiguration calls in this function can lead to contention early
43 // on, so we invoke this function later on in startup to keep it fast.
44 void InitNotifications();
46 base::ScopedCFTypeRef
<CFRunLoopSourceRef
> run_loop_source_
;
47 NetworkConfigWatcherMac::Delegate
* const delegate_
;
48 base::WeakPtrFactory
<NetworkConfigWatcherMacThread
> weak_factory_
;
50 DISALLOW_COPY_AND_ASSIGN(NetworkConfigWatcherMacThread
);
53 NetworkConfigWatcherMacThread::NetworkConfigWatcherMacThread(
54 NetworkConfigWatcherMac::Delegate
* delegate
)
55 : base::Thread("NetworkConfigWatcher"),
57 weak_factory_(this) {}
59 NetworkConfigWatcherMacThread::~NetworkConfigWatcherMacThread() {
60 // Allow IO because Stop() calls PlatformThread::Join(), which is a blocking
61 // operation. This is expected during shutdown.
62 base::ThreadRestrictions::ScopedAllowIO allow_io
;
67 void NetworkConfigWatcherMacThread::Init() {
68 // Disallow IO to make sure NetworkConfigWatcherMacThread's helper thread does
69 // not perform blocking operations.
70 base::ThreadRestrictions::SetIOAllowed(false);
74 // TODO(willchan): Look to see if there's a better signal for when it's ok to
75 // initialize this, rather than just delaying it by a fixed time.
76 const base::TimeDelta kInitializationDelay
= base::TimeDelta::FromSeconds(1);
77 message_loop()->PostDelayedTask(
79 base::Bind(&NetworkConfigWatcherMacThread::InitNotifications
,
80 weak_factory_
.GetWeakPtr()),
81 kInitializationDelay
);
84 void NetworkConfigWatcherMacThread::CleanUp() {
85 if (!run_loop_source_
.get())
88 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_
.get(),
89 kCFRunLoopCommonModes
);
90 run_loop_source_
.reset();
93 void NetworkConfigWatcherMacThread::InitNotifications() {
95 // SCDynamicStore API does not exist on iOS.
96 // Add a run loop source for a dynamic store to the current run loop.
97 SCDynamicStoreContext context
= {
99 delegate_
, // User data.
100 NULL
, // This is not reference counted. No retain function.
101 NULL
, // This is not reference counted. No release function.
102 NULL
, // No description for this.
104 base::ScopedCFTypeRef
<SCDynamicStoreRef
> store(SCDynamicStoreCreate(
105 NULL
, CFSTR("org.chromium"), DynamicStoreCallback
, &context
));
106 run_loop_source_
.reset(SCDynamicStoreCreateRunLoopSource(
107 NULL
, store
.get(), 0));
108 CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source_
.get(),
109 kCFRunLoopCommonModes
);
110 #endif // !defined(OS_IOS)
112 // Set up notifications for interface and IP address changes.
113 delegate_
->StartReachabilityNotifications();
115 delegate_
->SetDynamicStoreNotificationKeys(store
.get());
116 #endif // !defined(OS_IOS)
121 NetworkConfigWatcherMac::NetworkConfigWatcherMac(Delegate
* delegate
)
122 : notifier_thread_(new NetworkConfigWatcherMacThread(delegate
)) {
123 // We create this notifier thread because the notification implementation
124 // needs a thread with a CFRunLoop, and there's no guarantee that
125 // MessageLoop::current() meets that criterion.
126 base::Thread::Options
thread_options(base::MessageLoop::TYPE_UI
, 0);
127 notifier_thread_
->StartWithOptions(thread_options
);
130 NetworkConfigWatcherMac::~NetworkConfigWatcherMac() {}