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/path_service.h" | 20 #include "base/path_service.h" |
21 #include "base/strings/string_util.h" | 21 #include "base/strings/string_util.h" |
22 #include "base/strings/stringprintf.h" | 22 #include "base/strings/stringprintf.h" |
23 #include "base/strings/sys_string_conversions.h" | 23 #include "base/strings/sys_string_conversions.h" |
24 #include "base/threading/thread_restrictions.h" | 24 #include "base/threading/thread_restrictions.h" |
25 #include "base/version.h" | 25 #include "base/version.h" |
26 #include "chrome/common/chrome_paths.h" | 26 #include "chrome/common/chrome_paths.h" |
27 #include "chrome/common/chrome_switches.h" | 27 #include "chrome/common/chrome_switches.h" |
28 #include "chrome/common/chrome_version_info.h" | 28 #include "chrome/common/chrome_version_info.h" |
29 #include "chrome/common/mac/launchd.h" | 29 #include "chrome/common/mac/launchd.h" |
30 #include "ipc/unix_domain_socket_util.h" | |
30 | 31 |
31 using ::base::FilePathWatcher; | 32 using ::base::FilePathWatcher; |
32 | 33 |
33 namespace { | 34 namespace { |
34 | 35 |
35 #define kServiceProcessSessionType "Aqua" | 36 #define kServiceProcessSessionType "Aqua" |
36 | 37 |
37 CFStringRef CopyServiceProcessLaunchDName() { | 38 CFStringRef CopyServiceProcessLaunchDName() { |
38 base::mac::ScopedNSAutoreleasePool pool; | 39 base::mac::ScopedNSAutoreleasePool pool; |
39 NSBundle* bundle = base::mac::FrameworkBundle(); | 40 NSBundle* bundle = base::mac::FrameworkBundle(); |
40 return CFStringCreateCopy(kCFAllocatorDefault, | 41 return CFStringCreateCopy(kCFAllocatorDefault, |
41 base::mac::NSToCFCast([bundle bundleIdentifier])); | 42 base::mac::NSToCFCast([bundle bundleIdentifier])); |
42 } | 43 } |
43 | 44 |
44 NSString* GetServiceProcessLaunchDLabel() { | 45 NSString* GetServiceProcessLaunchDLabel() { |
45 base::scoped_nsobject<NSString> name( | 46 base::scoped_nsobject<NSString> name( |
46 base::mac::CFToNSCast(CopyServiceProcessLaunchDName())); | 47 base::mac::CFToNSCast(CopyServiceProcessLaunchDName())); |
47 NSString *label = [name stringByAppendingString:@".service_process"]; | 48 NSString *label = [name stringByAppendingString:@".service_process"]; |
48 base::FilePath user_data_dir; | 49 base::FilePath user_data_dir; |
49 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); | 50 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); |
50 std::string user_data_dir_path = user_data_dir.value(); | 51 std::string user_data_dir_path = user_data_dir.value(); |
51 NSString *ns_path = base::SysUTF8ToNSString(user_data_dir_path); | 52 NSString *ns_path = base::SysUTF8ToNSString(user_data_dir_path); |
52 ns_path = [ns_path stringByReplacingOccurrencesOfString:@" " | 53 ns_path = [ns_path stringByReplacingOccurrencesOfString:@" " |
53 withString:@"_"]; | 54 withString:@"_"]; |
54 label = [label stringByAppendingString:ns_path]; | 55 label = [label stringByAppendingString:ns_path]; |
55 return label; | 56 return label; |
56 } | 57 } |
57 | 58 |
58 NSString* GetServiceProcessLaunchDSocketKey() { | |
59 return @"ServiceProcessSocket"; | |
60 } | |
61 | |
62 bool GetParentFSRef(const FSRef& child, FSRef* parent) { | 59 bool GetParentFSRef(const FSRef& child, FSRef* parent) { |
63 return FSGetCatalogInfo(&child, 0, NULL, NULL, NULL, parent) == noErr; | 60 return FSGetCatalogInfo(&child, 0, NULL, NULL, NULL, parent) == noErr; |
64 } | 61 } |
65 | 62 |
66 bool RemoveFromLaunchd() { | 63 bool RemoveFromLaunchd() { |
67 // We're killing a file. | 64 // We're killing a file. |
68 base::ThreadRestrictions::AssertIOAllowed(); | 65 base::ThreadRestrictions::AssertIOAllowed(); |
69 base::ScopedCFTypeRef<CFStringRef> name(CopyServiceProcessLaunchDName()); | 66 base::ScopedCFTypeRef<CFStringRef> name(CopyServiceProcessLaunchDName()); |
70 return Launchd::GetInstance()->DeletePlist(Launchd::User, | 67 return Launchd::GetInstance()->DeletePlist(Launchd::User, |
71 Launchd::Agent, | 68 Launchd::Agent, |
72 name); | 69 name); |
73 } | 70 } |
74 | 71 |
75 class ExecFilePathWatcherCallback { | 72 class ExecFilePathWatcherCallback { |
76 public: | 73 public: |
77 ExecFilePathWatcherCallback() {} | 74 ExecFilePathWatcherCallback() {} |
78 ~ExecFilePathWatcherCallback() {} | 75 ~ExecFilePathWatcherCallback() {} |
79 | 76 |
80 bool Init(const base::FilePath& path); | 77 bool Init(const base::FilePath& path); |
81 void NotifyPathChanged(const base::FilePath& path, bool error); | 78 void NotifyPathChanged(const base::FilePath& path, bool error); |
82 | 79 |
83 private: | 80 private: |
84 FSRef executable_fsref_; | 81 FSRef executable_fsref_; |
85 }; | 82 }; |
86 | 83 |
84 base::FilePath GetServiceProcessSocketName() { | |
85 base::FilePath socket_name; | |
86 PathService::Get(base::DIR_TEMP, &socket_name); | |
87 std::string pipe_name = GetServiceProcessScopedName("srv"); | |
88 socket_name = socket_name.Append(pipe_name); | |
89 if (socket_name.value().size() < IPC::kMaxSocketNameLength) | |
90 return socket_name; | |
91 // Fallback to /tmp if $TMPDIR is too long. | |
92 return base::FilePath("/tmp").Append(pipe_name); | |
93 } | |
94 | |
87 } // namespace | 95 } // namespace |
88 | 96 |
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() { | 97 IPC::ChannelHandle GetServiceProcessChannel() { |
100 base::mac::ScopedNSAutoreleasePool pool; | 98 base::FilePath socket_name = GetServiceProcessSocketName(); |
101 std::string socket_path; | 99 VLOG(1) << "ServiceProcessChannel: " << socket_name.value(); |
102 base::scoped_nsobject<NSDictionary> dictionary( | 100 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 } | 101 } |
111 | 102 |
112 bool ForceServiceProcessShutdown(const std::string& /* version */, | 103 bool ForceServiceProcessShutdown(const std::string& /* version */, |
113 base::ProcessId /* process_id */) { | 104 base::ProcessId /* process_id */) { |
114 base::mac::ScopedNSAutoreleasePool pool; | 105 base::mac::ScopedNSAutoreleasePool pool; |
115 CFStringRef label = base::mac::NSToCFCast(GetServiceProcessLaunchDLabel()); | 106 CFStringRef label = base::mac::NSToCFCast(GetServiceProcessLaunchDLabel()); |
116 CFErrorRef err = NULL; | 107 CFErrorRef err = NULL; |
117 bool ret = Launchd::GetInstance()->RemoveJob(label, &err); | 108 bool ret = Launchd::GetInstance()->RemoveJob(label, &err); |
118 if (!ret) { | 109 if (!ret) { |
119 DLOG(ERROR) << "ForceServiceProcessShutdown: " << err << " " | 110 DLOG(ERROR) << "ForceServiceProcessShutdown: " << err << " " |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 DLOG(ERROR) << "ServiceProcess must be launched by launchd. " | 169 DLOG(ERROR) << "ServiceProcess must be launched by launchd. " |
179 << "CopyLaunchdDictionaryByCheckingIn: " << err; | 170 << "CopyLaunchdDictionaryByCheckingIn: " << err; |
180 CFRelease(err); | 171 CFRelease(err); |
181 return false; | 172 return false; |
182 } | 173 } |
183 state_->launchd_conf.reset(dict); | 174 state_->launchd_conf.reset(dict); |
184 return true; | 175 return true; |
185 } | 176 } |
186 | 177 |
187 IPC::ChannelHandle ServiceProcessState::GetServiceProcessChannel() { | 178 IPC::ChannelHandle ServiceProcessState::GetServiceProcessChannel() { |
188 DCHECK(state_); | 179 return ::GetServiceProcessChannel(); |
189 NSDictionary *ns_launchd_conf = base::mac::CFToNSCast(state_->launchd_conf); | |
190 NSDictionary* socket_dict = | |
191 [ns_launchd_conf objectForKey:@ LAUNCH_JOBKEY_SOCKETS]; | |
192 NSArray* sockets = | |
193 [socket_dict objectForKey:GetServiceProcessLaunchDSocketKey()]; | |
194 DCHECK_EQ([sockets count], 1U); | |
195 int socket = [[sockets objectAtIndex:0] intValue]; | |
196 base::FileDescriptor fd(socket, false); | |
197 return IPC::ChannelHandle(std::string(), fd); | |
198 } | 180 } |
199 | 181 |
200 bool CheckServiceProcessReady() { | 182 bool CheckServiceProcessReady() { |
201 std::string version; | 183 std::string version; |
202 pid_t pid; | 184 pid_t pid; |
203 if (!GetServiceProcessData(&version, &pid)) { | 185 if (!GetServiceProcessData(&version, &pid) || pid == -1) { |
Vitaly Buka (NO REVIEWS)
2015/03/06 01:51:08
this check was the reason why on demand didn't wor
| |
204 return false; | 186 return false; |
205 } | 187 } |
206 Version service_version(version); | 188 Version service_version(version); |
207 bool ready = true; | 189 bool ready = true; |
208 if (!service_version.IsValid()) { | 190 if (!service_version.IsValid()) { |
209 ready = false; | 191 ready = false; |
210 } else { | 192 } else { |
211 chrome::VersionInfo version_info; | 193 chrome::VersionInfo version_info; |
212 Version running_version(version_info.Version()); | 194 Version running_version(version_info.Version()); |
213 if (!running_version.IsValid()) { | 195 if (!running_version.IsValid()) { |
(...skipping 22 matching lines...) Expand all Loading... | |
236 | 218 |
237 std::vector<std::string> args = cmd_line->argv(); | 219 std::vector<std::string> args = cmd_line->argv(); |
238 NSMutableArray *ns_args = [NSMutableArray arrayWithCapacity:args.size()]; | 220 NSMutableArray *ns_args = [NSMutableArray arrayWithCapacity:args.size()]; |
239 | 221 |
240 for (std::vector<std::string>::iterator iter = args.begin(); | 222 for (std::vector<std::string>::iterator iter = args.begin(); |
241 iter < args.end(); | 223 iter < args.end(); |
242 ++iter) { | 224 ++iter) { |
243 [ns_args addObject:base::SysUTF8ToNSString(*iter)]; | 225 [ns_args addObject:base::SysUTF8ToNSString(*iter)]; |
244 } | 226 } |
245 | 227 |
246 NSDictionary *socket = | |
247 [NSDictionary dictionaryWithObject:GetServiceProcessLaunchDSocketEnvVar() | |
248 forKey:@ LAUNCH_JOBSOCKETKEY_SECUREWITHKEY]; | |
249 NSDictionary *sockets = | |
250 [NSDictionary dictionaryWithObject:socket | |
251 forKey:GetServiceProcessLaunchDSocketKey()]; | |
252 | |
253 // See the man page for launchd.plist. | 228 // See the man page for launchd.plist. |
254 NSMutableDictionary *launchd_plist = | 229 NSMutableDictionary* launchd_plist = [[NSMutableDictionary alloc] |
255 [[NSMutableDictionary alloc] initWithObjectsAndKeys: | 230 initWithObjectsAndKeys:GetServiceProcessLaunchDLabel(), |
256 GetServiceProcessLaunchDLabel(), @ LAUNCH_JOBKEY_LABEL, | 231 @LAUNCH_JOBKEY_LABEL, program, |
257 program, @ LAUNCH_JOBKEY_PROGRAM, | 232 @LAUNCH_JOBKEY_PROGRAM, ns_args, |
258 ns_args, @ LAUNCH_JOBKEY_PROGRAMARGUMENTS, | 233 @LAUNCH_JOBKEY_PROGRAMARGUMENTS, @YES, |
259 sockets, @ LAUNCH_JOBKEY_SOCKETS, | 234 @LAUNCH_JOBKEY_RUNATLOAD, nil]; |
260 nil]; | |
261 | 235 |
262 if (for_auto_launch) { | 236 if (for_auto_launch) { |
263 // We want the service process to be able to exit if there are no services | 237 // 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 | 238 // enabled. With a value of NO in the SuccessfulExit key, launchd will |
265 // relaunch the service automatically in any other case than exiting | 239 // relaunch the service automatically in any other case than exiting |
266 // cleanly with a 0 return code. | 240 // cleanly with a 0 return code. |
267 NSDictionary *keep_alive = | 241 NSDictionary* keep_alive = [NSDictionary |
268 [NSDictionary | |
269 dictionaryWithObject:[NSNumber numberWithBool:NO] | 242 dictionaryWithObject:[NSNumber numberWithBool:NO] |
270 forKey:@ LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT]; | 243 forKey:@LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT]; |
271 NSDictionary *auto_launchd_plist = | 244 NSDictionary* auto_launchd_plist = [[NSDictionary alloc] |
272 [[NSDictionary alloc] initWithObjectsAndKeys: | 245 initWithObjectsAndKeys:keep_alive, @LAUNCH_JOBKEY_KEEPALIVE, |
273 [NSNumber numberWithBool:YES], @ LAUNCH_JOBKEY_RUNATLOAD, | 246 @kServiceProcessSessionType, |
274 keep_alive, @ LAUNCH_JOBKEY_KEEPALIVE, | 247 @LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE, nil]; |
275 @ kServiceProcessSessionType, @ LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE, | |
276 nil]; | |
277 [launchd_plist addEntriesFromDictionary:auto_launchd_plist]; | 248 [launchd_plist addEntriesFromDictionary:auto_launchd_plist]; |
278 } | 249 } |
279 return reinterpret_cast<CFDictionaryRef>(launchd_plist); | 250 return reinterpret_cast<CFDictionaryRef>(launchd_plist); |
280 } | 251 } |
281 | 252 |
282 // Writes the launchd property list into the user's LaunchAgents directory, | 253 // 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 | 254 // creating that directory if needed. This will cause the service process to be |
284 // auto launched on the next user login. | 255 // auto launched on the next user login. |
285 bool ServiceProcessState::AddToAutoRun() { | 256 bool ServiceProcessState::AddToAutoRun() { |
286 // We're creating directories and writing a file. | 257 // 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; | 405 CFErrorRef err = NULL; |
435 if (!Launchd::GetInstance()->RemoveJob(label, &err)) { | 406 if (!Launchd::GetInstance()->RemoveJob(label, &err)) { |
436 base::ScopedCFTypeRef<CFErrorRef> scoped_err(err); | 407 base::ScopedCFTypeRef<CFErrorRef> scoped_err(err); |
437 DLOG(ERROR) << "RemoveJob " << err; | 408 DLOG(ERROR) << "RemoveJob " << err; |
438 // Exiting with zero, so launchd doesn't restart the process. | 409 // Exiting with zero, so launchd doesn't restart the process. |
439 exit(0); | 410 exit(0); |
440 } | 411 } |
441 } | 412 } |
442 } | 413 } |
443 } | 414 } |
OLD | NEW |