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 "chrome/common/service_process_util_posix.h" | 5 #include "chrome/common/service_process_util_posix.h" |
6 | 6 |
7 #import <Foundation/Foundation.h> | 7 #import <Foundation/Foundation.h> |
8 #include <launch.h> | 8 #include <launch.h> |
9 | 9 |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/files/file_path.h" | 14 #include "base/files/file_path.h" |
15 #include "base/mac/bundle_locations.h" | 15 #include "base/mac/bundle_locations.h" |
16 #include "base/mac/foundation_util.h" | 16 #include "base/mac/foundation_util.h" |
17 #include "base/mac/mac_util.h" | 17 #include "base/mac/mac_util.h" |
18 #include "base/mac/scoped_nsautorelease_pool.h" | 18 #include "base/mac/scoped_nsautorelease_pool.h" |
19 #include "base/mac/scoped_nsobject.h" | 19 #include "base/mac/scoped_nsobject.h" |
20 #include "base/metrics/histogram_macros.h" | |
20 #include "base/path_service.h" | 21 #include "base/path_service.h" |
21 #include "base/strings/string_util.h" | 22 #include "base/strings/string_util.h" |
22 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
23 #include "base/strings/sys_string_conversions.h" | 24 #include "base/strings/sys_string_conversions.h" |
24 #include "base/threading/thread_restrictions.h" | 25 #include "base/threading/thread_restrictions.h" |
25 #include "base/version.h" | 26 #include "base/version.h" |
26 #include "chrome/common/chrome_paths.h" | 27 #include "chrome/common/chrome_paths.h" |
27 #include "chrome/common/chrome_switches.h" | 28 #include "chrome/common/chrome_switches.h" |
28 #include "chrome/common/chrome_version_info.h" | 29 #include "chrome/common/chrome_version_info.h" |
29 #include "chrome/common/mac/launchd.h" | 30 #include "chrome/common/mac/launchd.h" |
31 #include "ipc/unix_domain_socket_util.h" | |
30 | 32 |
31 using ::base::FilePathWatcher; | 33 using ::base::FilePathWatcher; |
32 | 34 |
33 namespace { | 35 namespace { |
34 | 36 |
35 #define kServiceProcessSessionType "Aqua" | 37 #define kServiceProcessSessionType "Aqua" |
36 | 38 |
37 CFStringRef CopyServiceProcessLaunchDName() { | 39 CFStringRef CopyServiceProcessLaunchDName() { |
38 base::mac::ScopedNSAutoreleasePool pool; | 40 base::mac::ScopedNSAutoreleasePool pool; |
39 NSBundle* bundle = base::mac::FrameworkBundle(); | 41 NSBundle* bundle = base::mac::FrameworkBundle(); |
40 return CFStringCreateCopy(kCFAllocatorDefault, | 42 return CFStringCreateCopy(kCFAllocatorDefault, |
41 base::mac::NSToCFCast([bundle bundleIdentifier])); | 43 base::mac::NSToCFCast([bundle bundleIdentifier])); |
42 } | 44 } |
43 | 45 |
44 NSString* GetServiceProcessLaunchDLabel() { | 46 NSString* GetServiceProcessLaunchDLabel() { |
45 base::scoped_nsobject<NSString> name( | 47 base::scoped_nsobject<NSString> name( |
46 base::mac::CFToNSCast(CopyServiceProcessLaunchDName())); | 48 base::mac::CFToNSCast(CopyServiceProcessLaunchDName())); |
47 NSString *label = [name stringByAppendingString:@".service_process"]; | 49 NSString* label = [name stringByAppendingString:@".service_process"]; |
48 base::FilePath user_data_dir; | 50 base::FilePath user_data_dir; |
49 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); | 51 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); |
50 std::string user_data_dir_path = user_data_dir.value(); | 52 std::string user_data_dir_path = user_data_dir.value(); |
51 NSString *ns_path = base::SysUTF8ToNSString(user_data_dir_path); | 53 NSString* ns_path = base::SysUTF8ToNSString(user_data_dir_path); |
52 ns_path = [ns_path stringByReplacingOccurrencesOfString:@" " | 54 ns_path = [ns_path stringByReplacingOccurrencesOfString:@" " |
53 withString:@"_"]; | 55 withString:@"_"]; |
54 label = [label stringByAppendingString:ns_path]; | 56 label = [label stringByAppendingString:ns_path]; |
55 return label; | 57 return label; |
56 } | 58 } |
57 | 59 |
58 NSString* GetServiceProcessLaunchDSocketKey() { | 60 NSString* GetServiceProcessLaunchDSocketKey() { |
59 return @"ServiceProcessSocket"; | 61 return @"ServiceProcessSocket"; |
60 } | 62 } |
61 | 63 |
(...skipping 15 matching lines...) Expand all Loading... | |
77 ExecFilePathWatcherCallback() {} | 79 ExecFilePathWatcherCallback() {} |
78 ~ExecFilePathWatcherCallback() {} | 80 ~ExecFilePathWatcherCallback() {} |
79 | 81 |
80 bool Init(const base::FilePath& path); | 82 bool Init(const base::FilePath& path); |
81 void NotifyPathChanged(const base::FilePath& path, bool error); | 83 void NotifyPathChanged(const base::FilePath& path, bool error); |
82 | 84 |
83 private: | 85 private: |
84 FSRef executable_fsref_; | 86 FSRef executable_fsref_; |
85 }; | 87 }; |
86 | 88 |
89 base::FilePath GetServiceProcessSocketName() { | |
90 base::FilePath socket_name; | |
91 PathService::Get(base::DIR_TEMP, &socket_name); | |
92 std::string pipe_name = GetServiceProcessScopedName("srv"); | |
93 socket_name = socket_name.Append(pipe_name); | |
94 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceProcessSocketLength", | |
95 socket_name.value().size(), 75, 124, 50); | |
Alexei Svitkine (slow)
2015/03/12 17:35:03
Wait, does this even compile?
I think UMA_HISTOGR
Vitaly Buka (NO REVIEWS)
2015/03/12 19:44:13
Done.
| |
96 if (socket_name.value().size() < IPC::kMaxSocketNameLength) | |
97 return socket_name; | |
98 // Fallback to /tmp if $TMPDIR is too long. | |
99 // TODO(vitalybuka): Investigate how often we get there. | |
100 // See http://crbug.com/466644 | |
101 return base::FilePath("/tmp").Append(pipe_name); | |
102 } | |
103 | |
87 } // namespace | 104 } // namespace |
88 | 105 |
89 NSString* GetServiceProcessLaunchDSocketEnvVar() { | |
90 NSString *label = GetServiceProcessLaunchDLabel(); | |
91 NSString *env_var = [label stringByReplacingOccurrencesOfString:@"." | |
92 withString:@"_"]; | |
93 env_var = [env_var stringByAppendingString:@"_SOCKET"]; | |
94 env_var = [env_var uppercaseString]; | |
95 return env_var; | |
96 } | |
97 | |
98 // Gets the name of the service process IPC channel. | |
99 IPC::ChannelHandle GetServiceProcessChannel() { | 106 IPC::ChannelHandle GetServiceProcessChannel() { |
100 base::mac::ScopedNSAutoreleasePool pool; | 107 base::FilePath socket_name = GetServiceProcessSocketName(); |
101 std::string socket_path; | 108 VLOG(1) << "ServiceProcessChannel: " << socket_name.value(); |
102 base::scoped_nsobject<NSDictionary> dictionary( | 109 return IPC::ChannelHandle(socket_name.value()); |
103 base::mac::CFToNSCast(Launchd::GetInstance()->CopyExports())); | |
104 NSString *ns_socket_path = | |
105 [dictionary objectForKey:GetServiceProcessLaunchDSocketEnvVar()]; | |
106 if (ns_socket_path) { | |
107 socket_path = base::SysNSStringToUTF8(ns_socket_path); | |
108 } | |
109 return IPC::ChannelHandle(socket_path); | |
110 } | 110 } |
111 | 111 |
112 bool ForceServiceProcessShutdown(const std::string& /* version */, | 112 bool ForceServiceProcessShutdown(const std::string& /* version */, |
113 base::ProcessId /* process_id */) { | 113 base::ProcessId /* process_id */) { |
114 base::mac::ScopedNSAutoreleasePool pool; | 114 base::mac::ScopedNSAutoreleasePool pool; |
115 CFStringRef label = base::mac::NSToCFCast(GetServiceProcessLaunchDLabel()); | 115 CFStringRef label = base::mac::NSToCFCast(GetServiceProcessLaunchDLabel()); |
116 CFErrorRef err = NULL; | 116 CFErrorRef err = NULL; |
117 bool ret = Launchd::GetInstance()->RemoveJob(label, &err); | 117 bool ret = Launchd::GetInstance()->RemoveJob(label, &err); |
118 if (!ret) { | 118 if (!ret) { |
119 DLOG(ERROR) << "ForceServiceProcessShutdown: " << err << " " | 119 DLOG(ERROR) << "ForceServiceProcessShutdown: " << err << " " |
120 << base::SysCFStringRefToUTF8(label); | 120 << base::SysCFStringRefToUTF8(label); |
121 CFRelease(err); | 121 CFRelease(err); |
122 } | 122 } |
123 return ret; | 123 return ret; |
124 } | 124 } |
125 | 125 |
126 bool GetServiceProcessData(std::string* version, base::ProcessId* pid) { | 126 bool GetServiceProcessData(std::string* version, base::ProcessId* pid) { |
127 base::mac::ScopedNSAutoreleasePool pool; | 127 base::mac::ScopedNSAutoreleasePool pool; |
128 CFStringRef label = base::mac::NSToCFCast(GetServiceProcessLaunchDLabel()); | 128 CFStringRef label = base::mac::NSToCFCast(GetServiceProcessLaunchDLabel()); |
129 base::scoped_nsobject<NSDictionary> launchd_conf( | 129 base::scoped_nsobject<NSDictionary> launchd_conf( |
130 base::mac::CFToNSCast(Launchd::GetInstance()->CopyJobDictionary(label))); | 130 base::mac::CFToNSCast(Launchd::GetInstance()->CopyJobDictionary(label))); |
131 if (!launchd_conf.get()) { | 131 if (!launchd_conf.get()) { |
132 return false; | 132 return false; |
133 } | 133 } |
134 // Anything past here will return true in that there does appear | 134 // Anything past here will return true in that there does appear |
135 // to be a service process of some sort registered with launchd. | 135 // to be a service process of some sort registered with launchd. |
136 if (version) { | 136 if (version) { |
137 *version = "0"; | 137 *version = "0"; |
138 NSString *exe_path = [launchd_conf objectForKey:@ LAUNCH_JOBKEY_PROGRAM]; | 138 NSString* exe_path = [launchd_conf objectForKey:@ LAUNCH_JOBKEY_PROGRAM]; |
139 if (exe_path) { | 139 if (exe_path) { |
140 NSString *bundle_path = [[[exe_path stringByDeletingLastPathComponent] | 140 NSString* bundle_path = [[[exe_path stringByDeletingLastPathComponent] |
141 stringByDeletingLastPathComponent] | 141 stringByDeletingLastPathComponent] |
142 stringByDeletingLastPathComponent]; | 142 stringByDeletingLastPathComponent]; |
143 NSBundle *bundle = [NSBundle bundleWithPath:bundle_path]; | 143 NSBundle* bundle = [NSBundle bundleWithPath:bundle_path]; |
144 if (bundle) { | 144 if (bundle) { |
145 NSString *ns_version = | 145 NSString* ns_version = |
146 [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; | 146 [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; |
147 if (ns_version) { | 147 if (ns_version) { |
148 *version = base::SysNSStringToUTF8(ns_version); | 148 *version = base::SysNSStringToUTF8(ns_version); |
149 } else { | 149 } else { |
150 DLOG(ERROR) << "Unable to get version at: " | 150 DLOG(ERROR) << "Unable to get version at: " |
151 << reinterpret_cast<CFStringRef>(bundle_path); | 151 << reinterpret_cast<CFStringRef>(bundle_path); |
152 } | 152 } |
153 } else { | 153 } else { |
154 // The bundle has been deleted out from underneath the registered | 154 // The bundle has been deleted out from underneath the registered |
155 // job. | 155 // job. |
(...skipping 23 matching lines...) Expand all Loading... | |
179 << "CopyLaunchdDictionaryByCheckingIn: " << err; | 179 << "CopyLaunchdDictionaryByCheckingIn: " << err; |
180 CFRelease(err); | 180 CFRelease(err); |
181 return false; | 181 return false; |
182 } | 182 } |
183 state_->launchd_conf.reset(dict); | 183 state_->launchd_conf.reset(dict); |
184 return true; | 184 return true; |
185 } | 185 } |
186 | 186 |
187 IPC::ChannelHandle ServiceProcessState::GetServiceProcessChannel() { | 187 IPC::ChannelHandle ServiceProcessState::GetServiceProcessChannel() { |
188 DCHECK(state_); | 188 DCHECK(state_); |
189 NSDictionary *ns_launchd_conf = base::mac::CFToNSCast(state_->launchd_conf); | 189 NSDictionary* ns_launchd_conf = base::mac::CFToNSCast(state_->launchd_conf); |
190 NSDictionary* socket_dict = | 190 NSDictionary* socket_dict = |
191 [ns_launchd_conf objectForKey:@ LAUNCH_JOBKEY_SOCKETS]; | 191 [ns_launchd_conf objectForKey:@ LAUNCH_JOBKEY_SOCKETS]; |
192 NSArray* sockets = | 192 NSArray* sockets = |
193 [socket_dict objectForKey:GetServiceProcessLaunchDSocketKey()]; | 193 [socket_dict objectForKey:GetServiceProcessLaunchDSocketKey()]; |
194 DCHECK_EQ([sockets count], 1U); | 194 DCHECK_EQ([sockets count], 1U); |
195 int socket = [[sockets objectAtIndex:0] intValue]; | 195 int socket = [[sockets objectAtIndex:0] intValue]; |
196 base::FileDescriptor fd(socket, false); | 196 base::FileDescriptor fd(socket, false); |
197 return IPC::ChannelHandle(std::string(), fd); | 197 return IPC::ChannelHandle(std::string(), fd); |
198 } | 198 } |
199 | 199 |
(...skipping 24 matching lines...) Expand all Loading... | |
224 if (!ready) { | 224 if (!ready) { |
225 ForceServiceProcessShutdown(version, pid); | 225 ForceServiceProcessShutdown(version, pid); |
226 } | 226 } |
227 return ready; | 227 return ready; |
228 } | 228 } |
229 | 229 |
230 CFDictionaryRef CreateServiceProcessLaunchdPlist(base::CommandLine* cmd_line, | 230 CFDictionaryRef CreateServiceProcessLaunchdPlist(base::CommandLine* cmd_line, |
231 bool for_auto_launch) { | 231 bool for_auto_launch) { |
232 base::mac::ScopedNSAutoreleasePool pool; | 232 base::mac::ScopedNSAutoreleasePool pool; |
233 | 233 |
234 NSString *program = | 234 NSString* program = |
235 base::SysUTF8ToNSString(cmd_line->GetProgram().value()); | 235 base::SysUTF8ToNSString(cmd_line->GetProgram().value()); |
236 | 236 |
237 std::vector<std::string> args = cmd_line->argv(); | 237 std::vector<std::string> args = cmd_line->argv(); |
238 NSMutableArray *ns_args = [NSMutableArray arrayWithCapacity:args.size()]; | 238 NSMutableArray* ns_args = [NSMutableArray arrayWithCapacity:args.size()]; |
239 | 239 |
240 for (std::vector<std::string>::iterator iter = args.begin(); | 240 for (std::vector<std::string>::iterator iter = args.begin(); |
241 iter < args.end(); | 241 iter < args.end(); |
242 ++iter) { | 242 ++iter) { |
243 [ns_args addObject:base::SysUTF8ToNSString(*iter)]; | 243 [ns_args addObject:base::SysUTF8ToNSString(*iter)]; |
244 } | 244 } |
245 | 245 |
246 NSDictionary *socket = | 246 NSString* soket_name = |
247 [NSDictionary dictionaryWithObject:GetServiceProcessLaunchDSocketEnvVar() | 247 base::SysUTF8ToNSString(GetServiceProcessSocketName().value()); |
248 forKey:@ LAUNCH_JOBSOCKETKEY_SECUREWITHKEY]; | 248 |
249 NSDictionary *sockets = | 249 NSDictionary* socket = |
250 [NSDictionary dictionaryWithObject:soket_name | |
251 forKey:@LAUNCH_JOBSOCKETKEY_PATHNAME]; | |
252 NSDictionary* sockets = | |
250 [NSDictionary dictionaryWithObject:socket | 253 [NSDictionary dictionaryWithObject:socket |
251 forKey:GetServiceProcessLaunchDSocketKey()]; | 254 forKey:GetServiceProcessLaunchDSocketKey()]; |
252 | 255 |
253 // See the man page for launchd.plist. | 256 // See the man page for launchd.plist. |
254 NSMutableDictionary *launchd_plist = | 257 NSMutableDictionary* launchd_plist = |
255 [[NSMutableDictionary alloc] initWithObjectsAndKeys: | 258 [[NSMutableDictionary alloc] initWithObjectsAndKeys: |
256 GetServiceProcessLaunchDLabel(), @ LAUNCH_JOBKEY_LABEL, | 259 GetServiceProcessLaunchDLabel(), @LAUNCH_JOBKEY_LABEL, |
257 program, @ LAUNCH_JOBKEY_PROGRAM, | 260 program, @LAUNCH_JOBKEY_PROGRAM, |
258 ns_args, @ LAUNCH_JOBKEY_PROGRAMARGUMENTS, | 261 ns_args, @LAUNCH_JOBKEY_PROGRAMARGUMENTS, |
259 sockets, @ LAUNCH_JOBKEY_SOCKETS, | 262 sockets, @LAUNCH_JOBKEY_SOCKETS, |
260 nil]; | 263 nil]; |
261 | 264 |
262 if (for_auto_launch) { | 265 if (for_auto_launch) { |
263 // We want the service process to be able to exit if there are no services | 266 // We want the service process to be able to exit if there are no services |
264 // enabled. With a value of NO in the SuccessfulExit key, launchd will | 267 // enabled. With a value of NO in the SuccessfulExit key, launchd will |
265 // relaunch the service automatically in any other case than exiting | 268 // relaunch the service automatically in any other case than exiting |
266 // cleanly with a 0 return code. | 269 // cleanly with a 0 return code. |
267 NSDictionary *keep_alive = | 270 NSDictionary* keep_alive = |
268 [NSDictionary | 271 [NSDictionary |
269 dictionaryWithObject:[NSNumber numberWithBool:NO] | 272 dictionaryWithObject:[NSNumber numberWithBool:NO] |
270 forKey:@ LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT]; | 273 forKey:@LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT]; |
271 NSDictionary *auto_launchd_plist = | 274 NSDictionary* auto_launchd_plist = |
272 [[NSDictionary alloc] initWithObjectsAndKeys: | 275 [[NSDictionary alloc] initWithObjectsAndKeys: |
273 [NSNumber numberWithBool:YES], @ LAUNCH_JOBKEY_RUNATLOAD, | 276 [NSNumber numberWithBool:YES], @LAUNCH_JOBKEY_RUNATLOAD, |
274 keep_alive, @ LAUNCH_JOBKEY_KEEPALIVE, | 277 keep_alive, @LAUNCH_JOBKEY_KEEPALIVE, |
275 @ kServiceProcessSessionType, @ LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE, | 278 @kServiceProcessSessionType, @LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE, |
276 nil]; | 279 nil]; |
277 [launchd_plist addEntriesFromDictionary:auto_launchd_plist]; | 280 [launchd_plist addEntriesFromDictionary:auto_launchd_plist]; |
278 } | 281 } |
279 return reinterpret_cast<CFDictionaryRef>(launchd_plist); | 282 return reinterpret_cast<CFDictionaryRef>(launchd_plist); |
280 } | 283 } |
281 | 284 |
282 // Writes the launchd property list into the user's LaunchAgents directory, | 285 // Writes the launchd property list into the user's LaunchAgents directory, |
283 // creating that directory if needed. This will cause the service process to be | 286 // creating that directory if needed. This will cause the service process to be |
284 // auto launched on the next user login. | 287 // auto launched on the next user login. |
285 bool ServiceProcessState::AddToAutoRun() { | 288 bool ServiceProcessState::AddToAutoRun() { |
286 // We're creating directories and writing a file. | 289 // We're creating directories and writing a file. |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
434 CFErrorRef err = NULL; | 437 CFErrorRef err = NULL; |
435 if (!Launchd::GetInstance()->RemoveJob(label, &err)) { | 438 if (!Launchd::GetInstance()->RemoveJob(label, &err)) { |
436 base::ScopedCFTypeRef<CFErrorRef> scoped_err(err); | 439 base::ScopedCFTypeRef<CFErrorRef> scoped_err(err); |
437 DLOG(ERROR) << "RemoveJob " << err; | 440 DLOG(ERROR) << "RemoveJob " << err; |
438 // Exiting with zero, so launchd doesn't restart the process. | 441 // Exiting with zero, so launchd doesn't restart the process. |
439 exit(0); | 442 exit(0); |
440 } | 443 } |
441 } | 444 } |
442 } | 445 } |
443 } | 446 } |
OLD | NEW |