OLD | NEW |
| (Empty) |
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 "net/base/network_config_watcher_mac.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/bind.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" | |
15 | |
16 namespace net { | |
17 | |
18 namespace { | |
19 | |
20 #if !defined(OS_IOS) | |
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); | |
28 } | |
29 #endif // !defined(OS_IOS) | |
30 | |
31 class NetworkConfigWatcherMacThread : public base::Thread { | |
32 public: | |
33 NetworkConfigWatcherMacThread(NetworkConfigWatcherMac::Delegate* delegate); | |
34 ~NetworkConfigWatcherMacThread() override; | |
35 | |
36 protected: | |
37 // base::Thread | |
38 void Init() override; | |
39 void CleanUp() override; | |
40 | |
41 private: | |
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(); | |
45 | |
46 base::ScopedCFTypeRef<CFRunLoopSourceRef> run_loop_source_; | |
47 NetworkConfigWatcherMac::Delegate* const delegate_; | |
48 base::WeakPtrFactory<NetworkConfigWatcherMacThread> weak_factory_; | |
49 | |
50 DISALLOW_COPY_AND_ASSIGN(NetworkConfigWatcherMacThread); | |
51 }; | |
52 | |
53 NetworkConfigWatcherMacThread::NetworkConfigWatcherMacThread( | |
54 NetworkConfigWatcherMac::Delegate* delegate) | |
55 : base::Thread("NetworkConfigWatcher"), | |
56 delegate_(delegate), | |
57 weak_factory_(this) {} | |
58 | |
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; | |
63 | |
64 Stop(); | |
65 } | |
66 | |
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); | |
71 | |
72 delegate_->Init(); | |
73 | |
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( | |
78 FROM_HERE, | |
79 base::Bind(&NetworkConfigWatcherMacThread::InitNotifications, | |
80 weak_factory_.GetWeakPtr()), | |
81 kInitializationDelay); | |
82 } | |
83 | |
84 void NetworkConfigWatcherMacThread::CleanUp() { | |
85 if (!run_loop_source_.get()) | |
86 return; | |
87 | |
88 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(), | |
89 kCFRunLoopCommonModes); | |
90 run_loop_source_.reset(); | |
91 } | |
92 | |
93 void NetworkConfigWatcherMacThread::InitNotifications() { | |
94 #if !defined(OS_IOS) | |
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 = { | |
98 0, // Version 0. | |
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. | |
103 }; | |
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) | |
111 | |
112 // Set up notifications for interface and IP address changes. | |
113 delegate_->StartReachabilityNotifications(); | |
114 #if !defined(OS_IOS) | |
115 delegate_->SetDynamicStoreNotificationKeys(store.get()); | |
116 #endif // !defined(OS_IOS) | |
117 } | |
118 | |
119 } // namespace | |
120 | |
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); | |
128 } | |
129 | |
130 NetworkConfigWatcherMac::~NetworkConfigWatcherMac() {} | |
131 | |
132 } // namespace net | |
OLD | NEW |