OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/setup/daemon_controller.h" | 5 #include <CoreFoundation/CoreFoundation.h> |
| 6 |
| 7 #include "remoting/host/setup/daemon_controller_delegate_mac.h" |
6 | 8 |
7 #include <launch.h> | 9 #include <launch.h> |
8 #include <stdio.h> | 10 #include <stdio.h> |
9 #include <sys/types.h> | 11 #include <sys/types.h> |
10 | 12 |
11 #include "base/basictypes.h" | 13 #include "base/basictypes.h" |
12 #include "base/bind.h" | 14 #include "base/bind.h" |
13 #include "base/compiler_specific.h" | 15 #include "base/compiler_specific.h" |
14 #include "base/file_util.h" | 16 #include "base/file_util.h" |
15 #include "base/files/file_path.h" | 17 #include "base/files/file_path.h" |
16 #include "base/json/json_writer.h" | 18 #include "base/json/json_writer.h" |
17 #include "base/logging.h" | 19 #include "base/logging.h" |
18 #include "base/mac/foundation_util.h" | 20 #include "base/mac/foundation_util.h" |
19 #include "base/mac/launchd.h" | 21 #include "base/mac/launchd.h" |
20 #include "base/mac/mac_logging.h" | 22 #include "base/mac/mac_logging.h" |
21 #include "base/mac/mac_util.h" | 23 #include "base/mac/mac_util.h" |
22 #include "base/mac/scoped_launch_data.h" | 24 #include "base/mac/scoped_launch_data.h" |
23 #include "base/threading/thread.h" | |
24 #include "base/time/time.h" | 25 #include "base/time/time.h" |
25 #include "base/values.h" | 26 #include "base/values.h" |
26 #include "remoting/host/constants_mac.h" | 27 #include "remoting/host/constants_mac.h" |
27 #include "remoting/host/json_host_config.h" | 28 #include "remoting/host/json_host_config.h" |
28 #include "remoting/host/usage_stats_consent.h" | 29 #include "remoting/host/usage_stats_consent.h" |
29 | 30 |
30 namespace remoting { | 31 namespace remoting { |
31 | 32 |
32 namespace { | 33 DaemonControllerDelegateMac::DaemonControllerDelegateMac() { |
33 | |
34 class DaemonControllerMac : public remoting::DaemonController { | |
35 public: | |
36 DaemonControllerMac(); | |
37 virtual ~DaemonControllerMac(); | |
38 | |
39 virtual State GetState() OVERRIDE; | |
40 virtual void GetConfig(const GetConfigCallback& callback) OVERRIDE; | |
41 virtual void SetConfigAndStart( | |
42 scoped_ptr<base::DictionaryValue> config, | |
43 bool consent, | |
44 const CompletionCallback& done) OVERRIDE; | |
45 virtual void UpdateConfig(scoped_ptr<base::DictionaryValue> config, | |
46 const CompletionCallback& done_callback) OVERRIDE; | |
47 virtual void Stop(const CompletionCallback& done_callback) OVERRIDE; | |
48 virtual void SetWindow(void* window_handle) OVERRIDE; | |
49 virtual void GetVersion(const GetVersionCallback& done_callback) OVERRIDE; | |
50 virtual void GetUsageStatsConsent( | |
51 const GetUsageStatsConsentCallback& callback) OVERRIDE; | |
52 | |
53 private: | |
54 void DoGetConfig(const GetConfigCallback& callback); | |
55 void DoGetVersion(const GetVersionCallback& callback); | |
56 void DoSetConfigAndStart(scoped_ptr<base::DictionaryValue> config, | |
57 bool consent, | |
58 const CompletionCallback& done); | |
59 void DoUpdateConfig(scoped_ptr<base::DictionaryValue> config, | |
60 const CompletionCallback& done_callback); | |
61 void DoStop(const CompletionCallback& done_callback); | |
62 void DoGetUsageStatsConsent(const GetUsageStatsConsentCallback& callback); | |
63 | |
64 void ShowPreferencePane(const std::string& config_data, | |
65 const CompletionCallback& done_callback); | |
66 void RegisterForPreferencePaneNotifications( | |
67 const CompletionCallback &done_callback); | |
68 void DeregisterForPreferencePaneNotifications(); | |
69 void PreferencePaneCallbackDelegate(CFStringRef name); | |
70 static bool DoShowPreferencePane(const std::string& config_data); | |
71 static void PreferencePaneCallback(CFNotificationCenterRef center, | |
72 void* observer, | |
73 CFStringRef name, | |
74 const void* object, | |
75 CFDictionaryRef user_info); | |
76 | |
77 base::Thread auth_thread_; | |
78 CompletionCallback current_callback_; | |
79 | |
80 DISALLOW_COPY_AND_ASSIGN(DaemonControllerMac); | |
81 }; | |
82 | |
83 DaemonControllerMac::DaemonControllerMac() | |
84 : auth_thread_("Auth thread") { | |
85 auth_thread_.Start(); | |
86 } | 34 } |
87 | 35 |
88 DaemonControllerMac::~DaemonControllerMac() { | 36 DaemonControllerDelegateMac::~DaemonControllerDelegateMac() { |
89 auth_thread_.Stop(); | |
90 DeregisterForPreferencePaneNotifications(); | 37 DeregisterForPreferencePaneNotifications(); |
91 } | 38 } |
92 | 39 |
93 void DaemonControllerMac::DeregisterForPreferencePaneNotifications() { | 40 DaemonController::State DaemonControllerDelegateMac::GetState() { |
94 CFNotificationCenterRemoveObserver( | |
95 CFNotificationCenterGetDistributedCenter(), | |
96 this, | |
97 CFSTR(UPDATE_SUCCEEDED_NOTIFICATION_NAME), | |
98 NULL); | |
99 CFNotificationCenterRemoveObserver( | |
100 CFNotificationCenterGetDistributedCenter(), | |
101 this, | |
102 CFSTR(UPDATE_FAILED_NOTIFICATION_NAME), | |
103 NULL); | |
104 } | |
105 | |
106 DaemonController::State DaemonControllerMac::GetState() { | |
107 pid_t job_pid = base::mac::PIDForJob(kServiceName); | 41 pid_t job_pid = base::mac::PIDForJob(kServiceName); |
108 if (job_pid < 0) { | 42 if (job_pid < 0) { |
109 return DaemonController::STATE_NOT_INSTALLED; | 43 return DaemonController::STATE_NOT_INSTALLED; |
110 } else if (job_pid == 0) { | 44 } else if (job_pid == 0) { |
111 // Service is stopped, or a start attempt failed. | 45 // Service is stopped, or a start attempt failed. |
112 return DaemonController::STATE_STOPPED; | 46 return DaemonController::STATE_STOPPED; |
113 } else { | 47 } else { |
114 return DaemonController::STATE_STARTED; | 48 return DaemonController::STATE_STARTED; |
115 } | 49 } |
116 } | 50 } |
117 | 51 |
118 void DaemonControllerMac::GetConfig(const GetConfigCallback& callback) { | 52 scoped_ptr<base::DictionaryValue> DaemonControllerDelegateMac::GetConfig() { |
119 // base::Unretained() is safe, since this object owns the thread and therefore | |
120 // outlives it. | |
121 auth_thread_.message_loop_proxy()->PostTask( | |
122 FROM_HERE, | |
123 base::Bind(&DaemonControllerMac::DoGetConfig, base::Unretained(this), | |
124 callback)); | |
125 } | |
126 | |
127 void DaemonControllerMac::SetConfigAndStart( | |
128 scoped_ptr<base::DictionaryValue> config, | |
129 bool consent, | |
130 const CompletionCallback& done) { | |
131 auth_thread_.message_loop_proxy()->PostTask( | |
132 FROM_HERE, base::Bind( | |
133 &DaemonControllerMac::DoSetConfigAndStart, base::Unretained(this), | |
134 base::Passed(&config), consent, done)); | |
135 } | |
136 | |
137 void DaemonControllerMac::UpdateConfig( | |
138 scoped_ptr<base::DictionaryValue> config, | |
139 const CompletionCallback& done_callback) { | |
140 auth_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | |
141 &DaemonControllerMac::DoUpdateConfig, base::Unretained(this), | |
142 base::Passed(&config), done_callback)); | |
143 } | |
144 | |
145 void DaemonControllerMac::Stop(const CompletionCallback& done_callback) { | |
146 auth_thread_.message_loop_proxy()->PostTask( | |
147 FROM_HERE, base::Bind( | |
148 &DaemonControllerMac::DoStop, base::Unretained(this), done_callback)); | |
149 } | |
150 | |
151 void DaemonControllerMac::SetWindow(void* window_handle) { | |
152 // noop | |
153 } | |
154 | |
155 void DaemonControllerMac::GetVersion(const GetVersionCallback& callback) { | |
156 auth_thread_.message_loop_proxy()->PostTask( | |
157 FROM_HERE, | |
158 base::Bind(&DaemonControllerMac::DoGetVersion, base::Unretained(this), | |
159 callback)); | |
160 } | |
161 | |
162 void DaemonControllerMac::GetUsageStatsConsent( | |
163 const GetUsageStatsConsentCallback& callback) { | |
164 auth_thread_.message_loop_proxy()->PostTask( | |
165 FROM_HERE, | |
166 base::Bind(&DaemonControllerMac::DoGetUsageStatsConsent, | |
167 base::Unretained(this), callback)); | |
168 } | |
169 | |
170 void DaemonControllerMac::DoGetConfig(const GetConfigCallback& callback) { | |
171 base::FilePath config_path(kHostConfigFilePath); | 53 base::FilePath config_path(kHostConfigFilePath); |
172 JsonHostConfig host_config(config_path); | 54 JsonHostConfig host_config(config_path); |
173 scoped_ptr<base::DictionaryValue> config; | 55 scoped_ptr<base::DictionaryValue> config; |
174 | 56 |
175 if (host_config.Read()) { | 57 if (host_config.Read()) { |
176 config.reset(new base::DictionaryValue()); | 58 config.reset(new base::DictionaryValue()); |
177 std::string value; | 59 std::string value; |
178 if (host_config.GetString(kHostIdConfigPath, &value)) | 60 if (host_config.GetString(kHostIdConfigPath, &value)) |
179 config.get()->SetString(kHostIdConfigPath, value); | 61 config.get()->SetString(kHostIdConfigPath, value); |
180 if (host_config.GetString(kXmppLoginConfigPath, &value)) | 62 if (host_config.GetString(kXmppLoginConfigPath, &value)) |
181 config.get()->SetString(kXmppLoginConfigPath, value); | 63 config.get()->SetString(kXmppLoginConfigPath, value); |
182 } | 64 } |
183 | 65 |
184 callback.Run(config.Pass()); | 66 return config.Pass(); |
185 } | 67 } |
186 | 68 |
187 void DaemonControllerMac::DoGetVersion(const GetVersionCallback& callback) { | 69 void DaemonControllerDelegateMac::SetConfigAndStart( |
| 70 scoped_ptr<base::DictionaryValue> config, |
| 71 bool consent, |
| 72 const DaemonController::CompletionCallback& done) { |
| 73 config->SetBoolean(kUsageStatsConsentConfigPath, consent); |
| 74 std::string config_data; |
| 75 base::JSONWriter::Write(config.get(), &config_data); |
| 76 ShowPreferencePane(config_data, done); |
| 77 } |
| 78 |
| 79 void DaemonControllerDelegateMac::UpdateConfig( |
| 80 scoped_ptr<base::DictionaryValue> config, |
| 81 const DaemonController::CompletionCallback& done) { |
| 82 base::FilePath config_file_path(kHostConfigFilePath); |
| 83 JsonHostConfig config_file(config_file_path); |
| 84 if (!config_file.Read()) { |
| 85 done.Run(DaemonController::RESULT_FAILED); |
| 86 return; |
| 87 } |
| 88 if (!config_file.CopyFrom(config.get())) { |
| 89 LOG(ERROR) << "Failed to update configuration."; |
| 90 done.Run(DaemonController::RESULT_FAILED); |
| 91 return; |
| 92 } |
| 93 |
| 94 std::string config_data = config_file.GetSerializedData(); |
| 95 ShowPreferencePane(config_data, done); |
| 96 } |
| 97 |
| 98 void DaemonControllerDelegateMac::Stop( |
| 99 const DaemonController::CompletionCallback& done) { |
| 100 ShowPreferencePane("", done); |
| 101 } |
| 102 |
| 103 void DaemonControllerDelegateMac::SetWindow(void* window_handle) { |
| 104 // noop |
| 105 } |
| 106 |
| 107 std::string DaemonControllerDelegateMac::GetVersion() { |
188 std::string version = ""; | 108 std::string version = ""; |
189 std::string command_line = remoting::kHostHelperScriptPath; | 109 std::string command_line = remoting::kHostHelperScriptPath; |
190 command_line += " --host-version"; | 110 command_line += " --host-version"; |
191 FILE* script_output = popen(command_line.c_str(), "r"); | 111 FILE* script_output = popen(command_line.c_str(), "r"); |
192 if (script_output) { | 112 if (script_output) { |
193 char buffer[100]; | 113 char buffer[100]; |
194 char* result = fgets(buffer, sizeof(buffer), script_output); | 114 char* result = fgets(buffer, sizeof(buffer), script_output); |
195 pclose(script_output); | 115 pclose(script_output); |
196 if (result) { | 116 if (result) { |
197 // The string is guaranteed to be null-terminated, but probably contains | 117 // The string is guaranteed to be null-terminated, but probably contains |
198 // a newline character, which we don't want. | 118 // a newline character, which we don't want. |
199 for (int i = 0; result[i]; ++i) { | 119 for (int i = 0; result[i]; ++i) { |
200 if (result[i] < ' ') { | 120 if (result[i] < ' ') { |
201 result[i] = 0; | 121 result[i] = 0; |
202 break; | 122 break; |
203 } | 123 } |
204 } | 124 } |
205 version = result; | 125 version = result; |
206 } | 126 } |
207 } | 127 } |
208 callback.Run(version); | 128 |
| 129 return version; |
209 } | 130 } |
210 | 131 |
211 void DaemonControllerMac::DoSetConfigAndStart( | 132 DaemonController::UsageStatsConsent |
212 scoped_ptr<base::DictionaryValue> config, | 133 DaemonControllerDelegateMac::GetUsageStatsConsent() { |
213 bool consent, | 134 DaemonController::UsageStatsConsent consent; |
214 const CompletionCallback& done) { | 135 consent.supported = true; |
215 config->SetBoolean(kUsageStatsConsentConfigPath, consent); | 136 consent.allowed = false; |
216 std::string config_data; | 137 // set_by_policy is not yet supported. |
217 base::JSONWriter::Write(config.get(), &config_data); | 138 consent.set_by_policy = false; |
218 ShowPreferencePane(config_data, done); | 139 |
| 140 base::FilePath config_file_path(kHostConfigFilePath); |
| 141 JsonHostConfig host_config(config_file_path); |
| 142 if (host_config.Read()) { |
| 143 host_config.GetBoolean(kUsageStatsConsentConfigPath, &consent.allowed); |
| 144 } |
| 145 |
| 146 return consent; |
219 } | 147 } |
220 | 148 |
221 void DaemonControllerMac::DoUpdateConfig( | 149 void DaemonControllerDelegateMac::ShowPreferencePane( |
222 scoped_ptr<base::DictionaryValue> config, | 150 const std::string& config_data, |
223 const CompletionCallback& done_callback) { | 151 const DaemonController::CompletionCallback& done) { |
224 base::FilePath config_file_path(kHostConfigFilePath); | 152 if (DoShowPreferencePane(config_data)) { |
225 JsonHostConfig config_file(config_file_path); | 153 RegisterForPreferencePaneNotifications(done); |
226 if (!config_file.Read()) { | 154 } else { |
227 done_callback.Run(RESULT_FAILED); | 155 done.Run(DaemonController::RESULT_FAILED); |
228 return; | |
229 } | 156 } |
230 if (!config_file.CopyFrom(config.get())) { | 157 } |
231 LOG(ERROR) << "Failed to update configuration."; | 158 |
232 done_callback.Run(RESULT_FAILED); | 159 // CFNotificationCenterAddObserver ties the thread on which distributed |
| 160 // notifications are received to the one on which it is first called. |
| 161 // This is safe because HostNPScriptObject::InvokeAsyncResultCallback |
| 162 // bounces the invocation to the correct thread, so it doesn't matter |
| 163 // which thread CompletionCallbacks are called on. |
| 164 void DaemonControllerDelegateMac::RegisterForPreferencePaneNotifications( |
| 165 const DaemonController::CompletionCallback& done) { |
| 166 // We can only have one callback registered at a time. This is enforced by the |
| 167 // UX flow of the web-app. |
| 168 DCHECK(current_callback_.is_null()); |
| 169 current_callback_ = done; |
| 170 |
| 171 CFNotificationCenterAddObserver( |
| 172 CFNotificationCenterGetDistributedCenter(), |
| 173 this, |
| 174 &DaemonControllerDelegateMac::PreferencePaneCallback, |
| 175 CFSTR(UPDATE_SUCCEEDED_NOTIFICATION_NAME), |
| 176 NULL, |
| 177 CFNotificationSuspensionBehaviorDeliverImmediately); |
| 178 CFNotificationCenterAddObserver( |
| 179 CFNotificationCenterGetDistributedCenter(), |
| 180 this, |
| 181 &DaemonControllerDelegateMac::PreferencePaneCallback, |
| 182 CFSTR(UPDATE_FAILED_NOTIFICATION_NAME), |
| 183 NULL, |
| 184 CFNotificationSuspensionBehaviorDeliverImmediately); |
| 185 } |
| 186 |
| 187 void DaemonControllerDelegateMac::DeregisterForPreferencePaneNotifications() { |
| 188 CFNotificationCenterRemoveObserver( |
| 189 CFNotificationCenterGetDistributedCenter(), |
| 190 this, |
| 191 CFSTR(UPDATE_SUCCEEDED_NOTIFICATION_NAME), |
| 192 NULL); |
| 193 CFNotificationCenterRemoveObserver( |
| 194 CFNotificationCenterGetDistributedCenter(), |
| 195 this, |
| 196 CFSTR(UPDATE_FAILED_NOTIFICATION_NAME), |
| 197 NULL); |
| 198 } |
| 199 |
| 200 void DaemonControllerDelegateMac::PreferencePaneCallbackDelegate( |
| 201 CFStringRef name) { |
| 202 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; |
| 203 if (CFStringCompare(name, CFSTR(UPDATE_SUCCEEDED_NOTIFICATION_NAME), 0) == |
| 204 kCFCompareEqualTo) { |
| 205 result = DaemonController::RESULT_OK; |
| 206 } else if (CFStringCompare(name, CFSTR(UPDATE_FAILED_NOTIFICATION_NAME), 0) == |
| 207 kCFCompareEqualTo) { |
| 208 result = DaemonController::RESULT_FAILED; |
| 209 } else { |
| 210 LOG(WARNING) << "Ignoring unexpected notification: " << name; |
233 return; | 211 return; |
234 } | 212 } |
235 | 213 |
236 std::string config_data = config_file.GetSerializedData(); | 214 DCHECK(!current_callback_.is_null()); |
237 ShowPreferencePane(config_data, done_callback); | 215 DaemonController::CompletionCallback done = current_callback_; |
| 216 current_callback_.Reset(); |
| 217 done.Run(result); |
| 218 |
| 219 DeregisterForPreferencePaneNotifications(); |
238 } | 220 } |
239 | 221 |
240 void DaemonControllerMac::DoGetUsageStatsConsent( | 222 // static |
241 const GetUsageStatsConsentCallback& callback) { | 223 bool DaemonControllerDelegateMac::DoShowPreferencePane( |
242 bool allowed = false; | 224 const std::string& config_data) { |
243 base::FilePath config_file_path(kHostConfigFilePath); | |
244 JsonHostConfig host_config(config_file_path); | |
245 if (host_config.Read()) { | |
246 host_config.GetBoolean(kUsageStatsConsentConfigPath, &allowed); | |
247 } | |
248 // set_by_policy is not yet supported. | |
249 callback.Run(true, allowed, false /* set_by_policy */); | |
250 } | |
251 | |
252 void DaemonControllerMac::ShowPreferencePane( | |
253 const std::string& config_data, const CompletionCallback& done_callback) { | |
254 if (DoShowPreferencePane(config_data)) { | |
255 RegisterForPreferencePaneNotifications(done_callback); | |
256 } else { | |
257 done_callback.Run(RESULT_FAILED); | |
258 } | |
259 } | |
260 | |
261 bool DaemonControllerMac::DoShowPreferencePane(const std::string& config_data) { | |
262 if (!config_data.empty()) { | 225 if (!config_data.empty()) { |
263 base::FilePath config_path; | 226 base::FilePath config_path; |
264 if (!file_util::GetTempDir(&config_path)) { | 227 if (!file_util::GetTempDir(&config_path)) { |
265 LOG(ERROR) << "Failed to get filename for saving configuration data."; | 228 LOG(ERROR) << "Failed to get filename for saving configuration data."; |
266 return false; | 229 return false; |
267 } | 230 } |
268 config_path = config_path.Append(kHostConfigFileName); | 231 config_path = config_path.Append(kHostConfigFileName); |
269 | 232 |
270 int written = file_util::WriteFile(config_path, config_data.data(), | 233 int written = file_util::WriteFile(config_path, config_data.data(), |
271 config_data.size()); | 234 config_data.size()); |
(...skipping 27 matching lines...) Expand all Loading... |
299 | 262 |
300 CFNotificationCenterRef center = | 263 CFNotificationCenterRef center = |
301 CFNotificationCenterGetDistributedCenter(); | 264 CFNotificationCenterGetDistributedCenter(); |
302 base::ScopedCFTypeRef<CFStringRef> service_name(CFStringCreateWithCString( | 265 base::ScopedCFTypeRef<CFStringRef> service_name(CFStringCreateWithCString( |
303 kCFAllocatorDefault, remoting::kServiceName, kCFStringEncodingUTF8)); | 266 kCFAllocatorDefault, remoting::kServiceName, kCFStringEncodingUTF8)); |
304 CFNotificationCenterPostNotification(center, service_name, NULL, NULL, | 267 CFNotificationCenterPostNotification(center, service_name, NULL, NULL, |
305 TRUE); | 268 TRUE); |
306 return true; | 269 return true; |
307 } | 270 } |
308 | 271 |
309 void DaemonControllerMac::DoStop(const CompletionCallback& done_callback) { | 272 // static |
310 ShowPreferencePane("", done_callback); | 273 void DaemonControllerDelegateMac::PreferencePaneCallback( |
| 274 CFNotificationCenterRef center, |
| 275 void* observer, |
| 276 CFStringRef name, |
| 277 const void* object, |
| 278 CFDictionaryRef user_info) { |
| 279 DaemonControllerDelegateMac* self = |
| 280 reinterpret_cast<DaemonControllerDelegateMac*>(observer); |
| 281 if (!self) { |
| 282 LOG(WARNING) << "Ignoring notification with NULL observer: " << name; |
| 283 return; |
| 284 } |
| 285 |
| 286 self->PreferencePaneCallbackDelegate(name); |
311 } | 287 } |
312 | 288 |
313 // CFNotificationCenterAddObserver ties the thread on which distributed | 289 scoped_refptr<DaemonController> DaemonController::Create() { |
314 // notifications are received to the one on which it is first called. | 290 scoped_ptr<DaemonController::Delegate> delegate( |
315 // This is safe because HostNPScriptObject::InvokeAsyncResultCallback | 291 new DaemonControllerDelegateMac()); |
316 // bounces the invocation to the correct thread, so it doesn't matter | 292 return new DaemonController(delegate.Pass()); |
317 // which thread CompletionCallbacks are called on. | |
318 void DaemonControllerMac::RegisterForPreferencePaneNotifications( | |
319 const CompletionCallback& done_callback) { | |
320 // We can only have one callback registered at a time. This is enforced by the | |
321 // UX flow of the web-app. | |
322 DCHECK(current_callback_.is_null()); | |
323 current_callback_ = done_callback; | |
324 | |
325 CFNotificationCenterAddObserver( | |
326 CFNotificationCenterGetDistributedCenter(), | |
327 this, | |
328 &DaemonControllerMac::PreferencePaneCallback, | |
329 CFSTR(UPDATE_SUCCEEDED_NOTIFICATION_NAME), | |
330 NULL, | |
331 CFNotificationSuspensionBehaviorDeliverImmediately); | |
332 CFNotificationCenterAddObserver( | |
333 CFNotificationCenterGetDistributedCenter(), | |
334 this, | |
335 &DaemonControllerMac::PreferencePaneCallback, | |
336 CFSTR(UPDATE_FAILED_NOTIFICATION_NAME), | |
337 NULL, | |
338 CFNotificationSuspensionBehaviorDeliverImmediately); | |
339 } | |
340 | |
341 void DaemonControllerMac::PreferencePaneCallbackDelegate(CFStringRef name) { | |
342 AsyncResult result = RESULT_FAILED; | |
343 if (CFStringCompare(name, CFSTR(UPDATE_SUCCEEDED_NOTIFICATION_NAME), 0) == | |
344 kCFCompareEqualTo) { | |
345 result = RESULT_OK; | |
346 } else if (CFStringCompare(name, CFSTR(UPDATE_FAILED_NOTIFICATION_NAME), 0) == | |
347 kCFCompareEqualTo) { | |
348 result = RESULT_FAILED; | |
349 } else { | |
350 LOG(WARNING) << "Ignoring unexpected notification: " << name; | |
351 return; | |
352 } | |
353 DCHECK(!current_callback_.is_null()); | |
354 current_callback_.Run(result); | |
355 current_callback_.Reset(); | |
356 DeregisterForPreferencePaneNotifications(); | |
357 } | |
358 | |
359 void DaemonControllerMac::PreferencePaneCallback(CFNotificationCenterRef center, | |
360 void* observer, | |
361 CFStringRef name, | |
362 const void* object, | |
363 CFDictionaryRef user_info) { | |
364 DaemonControllerMac* self = reinterpret_cast<DaemonControllerMac*>(observer); | |
365 if (self) { | |
366 self->PreferencePaneCallbackDelegate(name); | |
367 } else { | |
368 LOG(WARNING) << "Ignoring notification with NULL observer: " << name; | |
369 } | |
370 } | |
371 | |
372 } // namespace | |
373 | |
374 scoped_ptr<DaemonController> remoting::DaemonController::Create() { | |
375 return scoped_ptr<DaemonController>(new DaemonControllerMac()); | |
376 } | 293 } |
377 | 294 |
378 } // namespace remoting | 295 } // namespace remoting |
OLD | NEW |