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

Side by Side Diff: remoting/host/setup/daemon_controller_delegate_mac.mm

Issue 23606019: Refactor the daemon controller so that the callbacks are called on the caller thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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 <CoreFoundation/CoreFoundation.h>
6
7 #include "remoting/host/setup/daemon_controller_delegate_mac.h"
8
9 #include <launch.h>
10 #include <stdio.h>
11 #include <sys/types.h>
12
13 #include "base/basictypes.h"
14 #include "base/bind.h"
15 #include "base/compiler_specific.h"
16 #include "base/file_util.h"
17 #include "base/files/file_path.h"
18 #include "base/json/json_writer.h"
19 #include "base/logging.h"
20 #include "base/mac/foundation_util.h"
21 #include "base/mac/launchd.h"
22 #include "base/mac/mac_logging.h"
23 #include "base/mac/mac_util.h"
24 #include "base/mac/scoped_launch_data.h"
25 #include "base/time/time.h"
26 #include "base/values.h"
27 #include "remoting/host/constants_mac.h"
28 #include "remoting/host/json_host_config.h"
29 #include "remoting/host/usage_stats_consent.h"
30
31 namespace remoting {
32
33 DaemonControllerDelegateMac::DaemonControllerDelegateMac() {
34 }
35
36 DaemonControllerDelegateMac::~DaemonControllerDelegateMac() {
37 DeregisterForPreferencePaneNotifications();
38 }
39
40 DaemonController::State DaemonControllerDelegateMac::GetState() {
41 pid_t job_pid = base::mac::PIDForJob(kServiceName);
42 if (job_pid < 0) {
43 return DaemonController::STATE_NOT_INSTALLED;
44 } else if (job_pid == 0) {
45 // Service is stopped, or a start attempt failed.
46 return DaemonController::STATE_STOPPED;
47 } else {
48 return DaemonController::STATE_STARTED;
49 }
50 }
51
52 scoped_ptr<base::DictionaryValue> DaemonControllerDelegateMac::GetConfig() {
53 base::FilePath config_path(kHostConfigFilePath);
54 JsonHostConfig host_config(config_path);
55 scoped_ptr<base::DictionaryValue> config;
56
57 if (host_config.Read()) {
58 config.reset(new base::DictionaryValue());
59 std::string value;
60 if (host_config.GetString(kHostIdConfigPath, &value))
61 config.get()->SetString(kHostIdConfigPath, value);
62 if (host_config.GetString(kXmppLoginConfigPath, &value))
63 config.get()->SetString(kXmppLoginConfigPath, value);
64 }
65
66 return config.Pass();
67 }
68
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() {
108 std::string version = "";
109 std::string command_line = remoting::kHostHelperScriptPath;
110 command_line += " --host-version";
111 FILE* script_output = popen(command_line.c_str(), "r");
112 if (script_output) {
113 char buffer[100];
114 char* result = fgets(buffer, sizeof(buffer), script_output);
115 pclose(script_output);
116 if (result) {
117 // The string is guaranteed to be null-terminated, but probably contains
118 // a newline character, which we don't want.
119 for (int i = 0; result[i]; ++i) {
120 if (result[i] < ' ') {
121 result[i] = 0;
122 break;
123 }
124 }
125 version = result;
126 }
127 }
128
129 return version;
130 }
131
132 DaemonController::UsageStatsConsent
133 DaemonControllerDelegateMac::GetUsageStatsConsent() {
134 DaemonController::UsageStatsConsent consent;
135 consent.supported = true;
136 consent.allowed = false;
137 // set_by_policy is not yet supported.
138 consent.set_by_policy = false;
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;
147 }
148
149 void DaemonControllerDelegateMac::ShowPreferencePane(
150 const std::string& config_data,
151 const DaemonController::CompletionCallback& done) {
152 if (DoShowPreferencePane(config_data)) {
153 RegisterForPreferencePaneNotifications(done);
154 } else {
155 done.Run(DaemonController::RESULT_FAILED);
156 }
157 }
158
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;
211 return;
212 }
213
214 DCHECK(!current_callback_.is_null());
215 DaemonController::CompletionCallback done = current_callback_;
216 current_callback_.Reset();
217 done.Run(result);
218
219 DeregisterForPreferencePaneNotifications();
220 }
221
222 // static
223 bool DaemonControllerDelegateMac::DoShowPreferencePane(
224 const std::string& config_data) {
225 if (!config_data.empty()) {
226 base::FilePath config_path;
227 if (!file_util::GetTempDir(&config_path)) {
228 LOG(ERROR) << "Failed to get filename for saving configuration data.";
229 return false;
230 }
231 config_path = config_path.Append(kHostConfigFileName);
232
233 int written = file_util::WriteFile(config_path, config_data.data(),
234 config_data.size());
235 if (written != static_cast<int>(config_data.size())) {
236 LOG(ERROR) << "Failed to save configuration data to: "
237 << config_path.value();
238 return false;
239 }
240 }
241
242 base::FilePath pane_path;
243 // TODO(lambroslambrou): Use NSPreferencePanesDirectory once we start
244 // building against SDK 10.6.
245 if (!base::mac::GetLocalDirectory(NSLibraryDirectory, &pane_path)) {
246 LOG(ERROR) << "Failed to get directory for local preference panes.";
247 return false;
248 }
249 pane_path = pane_path.Append("PreferencePanes").Append(kPrefPaneFileName);
250
251 FSRef pane_path_ref;
252 if (!base::mac::FSRefFromPath(pane_path.value(), &pane_path_ref)) {
253 LOG(ERROR) << "Failed to create FSRef";
254 return false;
255 }
256 OSStatus status = LSOpenFSRef(&pane_path_ref, NULL);
257 if (status != noErr) {
258 OSSTATUS_LOG(ERROR, status) << "LSOpenFSRef failed for path: "
259 << pane_path.value();
260 return false;
261 }
262
263 CFNotificationCenterRef center =
264 CFNotificationCenterGetDistributedCenter();
265 base::ScopedCFTypeRef<CFStringRef> service_name(CFStringCreateWithCString(
266 kCFAllocatorDefault, remoting::kServiceName, kCFStringEncodingUTF8));
267 CFNotificationCenterPostNotification(center, service_name, NULL, NULL,
268 TRUE);
269 return true;
270 }
271
272 // static
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);
287 }
288
289 scoped_refptr<DaemonController> DaemonController::Create() {
290 scoped_ptr<DaemonController::Delegate> delegate(
291 new DaemonControllerDelegateMac());
292 return new DaemonController(delegate.Pass());
293 }
294
295 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698