| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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> |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 return IPC::ChannelHandle(socket_path); | 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 LOG(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 scoped_nsobject<NSDictionary> launchd_conf(base::mac::CFToNSCast( | 129 scoped_nsobject<NSDictionary> launchd_conf(base::mac::CFToNSCast( |
| 130 Launchd::GetInstance()->CopyJobDictionary(label))); | 130 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 LOG(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. |
| 156 LOG(ERROR) << "Unable to get bundle at: " | 156 DLOG(ERROR) << "Unable to get bundle at: " |
| 157 << reinterpret_cast<CFStringRef>(bundle_path); | 157 << reinterpret_cast<CFStringRef>(bundle_path); |
| 158 } | 158 } |
| 159 } else { | 159 } else { |
| 160 LOG(ERROR) << "Unable to get executable path for service process"; | 160 DLOG(ERROR) << "Unable to get executable path for service process"; |
| 161 } | 161 } |
| 162 } | 162 } |
| 163 if (pid) { | 163 if (pid) { |
| 164 *pid = -1; | 164 *pid = -1; |
| 165 NSNumber* ns_pid = [launchd_conf objectForKey:@ LAUNCH_JOBKEY_PID]; | 165 NSNumber* ns_pid = [launchd_conf objectForKey:@ LAUNCH_JOBKEY_PID]; |
| 166 if (ns_pid) { | 166 if (ns_pid) { |
| 167 *pid = [ns_pid intValue]; | 167 *pid = [ns_pid intValue]; |
| 168 } | 168 } |
| 169 } | 169 } |
| 170 return true; | 170 return true; |
| 171 } | 171 } |
| 172 | 172 |
| 173 bool ServiceProcessState::Initialize() { | 173 bool ServiceProcessState::Initialize() { |
| 174 CFErrorRef err = NULL; | 174 CFErrorRef err = NULL; |
| 175 CFDictionaryRef dict = | 175 CFDictionaryRef dict = |
| 176 Launchd::GetInstance()->CopyDictionaryByCheckingIn(&err); | 176 Launchd::GetInstance()->CopyDictionaryByCheckingIn(&err); |
| 177 if (!dict) { | 177 if (!dict) { |
| 178 LOG(ERROR) << "ServiceProcess must be launched by launchd. " | 178 DLOG(ERROR) << "ServiceProcess must be launched by launchd. " |
| 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 CHECK(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 CHECK_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 |
| 200 bool CheckServiceProcessReady() { | 200 bool CheckServiceProcessReady() { |
| 201 std::string version; | 201 std::string version; |
| 202 pid_t pid; | 202 pid_t pid; |
| 203 if (!GetServiceProcessData(&version, &pid)) { | 203 if (!GetServiceProcessData(&version, &pid)) { |
| 204 return false; | 204 return false; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 | 306 |
| 307 bool ServiceProcessState::RemoveFromAutoRun() { | 307 bool ServiceProcessState::RemoveFromAutoRun() { |
| 308 return RemoveFromLaunchd(); | 308 return RemoveFromLaunchd(); |
| 309 } | 309 } |
| 310 | 310 |
| 311 bool ServiceProcessState::StateData::WatchExecutable() { | 311 bool ServiceProcessState::StateData::WatchExecutable() { |
| 312 base::mac::ScopedNSAutoreleasePool pool; | 312 base::mac::ScopedNSAutoreleasePool pool; |
| 313 NSDictionary* ns_launchd_conf = base::mac::CFToNSCast(launchd_conf_); | 313 NSDictionary* ns_launchd_conf = base::mac::CFToNSCast(launchd_conf_); |
| 314 NSString* exe_path = [ns_launchd_conf objectForKey:@ LAUNCH_JOBKEY_PROGRAM]; | 314 NSString* exe_path = [ns_launchd_conf objectForKey:@ LAUNCH_JOBKEY_PROGRAM]; |
| 315 if (!exe_path) { | 315 if (!exe_path) { |
| 316 LOG(ERROR) << "No " LAUNCH_JOBKEY_PROGRAM; | 316 DLOG(ERROR) << "No " LAUNCH_JOBKEY_PROGRAM; |
| 317 return false; | 317 return false; |
| 318 } | 318 } |
| 319 | 319 |
| 320 FilePath executable_path = FilePath([exe_path fileSystemRepresentation]); | 320 FilePath executable_path = FilePath([exe_path fileSystemRepresentation]); |
| 321 scoped_ptr<ExecFilePathWatcherDelegate> delegate( | 321 scoped_ptr<ExecFilePathWatcherDelegate> delegate( |
| 322 new ExecFilePathWatcherDelegate); | 322 new ExecFilePathWatcherDelegate); |
| 323 if (!delegate->Init(executable_path)) { | 323 if (!delegate->Init(executable_path)) { |
| 324 LOG(ERROR) << "executable_watcher_.Init " << executable_path.value(); | 324 DLOG(ERROR) << "executable_watcher_.Init " << executable_path.value(); |
| 325 return false; | 325 return false; |
| 326 } | 326 } |
| 327 if (!executable_watcher_.Watch(executable_path, delegate.release())) { | 327 if (!executable_watcher_.Watch(executable_path, delegate.release())) { |
| 328 LOG(ERROR) << "executable_watcher_.watch " << executable_path.value(); | 328 DLOG(ERROR) << "executable_watcher_.watch " << executable_path.value(); |
| 329 return false; | 329 return false; |
| 330 } | 330 } |
| 331 return true; | 331 return true; |
| 332 } | 332 } |
| 333 | 333 |
| 334 bool ExecFilePathWatcherDelegate::Init(const FilePath& path) { | 334 bool ExecFilePathWatcherDelegate::Init(const FilePath& path) { |
| 335 return base::mac::FSRefFromPath(path.value(), &executable_fsref_); | 335 return base::mac::FSRefFromPath(path.value(), &executable_fsref_); |
| 336 } | 336 } |
| 337 | 337 |
| 338 void ExecFilePathWatcherDelegate::OnFilePathChanged(const FilePath& path) { | 338 void ExecFilePathWatcherDelegate::OnFilePathChanged(const FilePath& path) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 [ns_plist setObject:ns_new_path forKey:@ LAUNCH_JOBKEY_PROGRAM]; | 397 [ns_plist setObject:ns_new_path forKey:@ LAUNCH_JOBKEY_PROGRAM]; |
| 398 scoped_nsobject<NSMutableArray> args( | 398 scoped_nsobject<NSMutableArray> args( |
| 399 [[ns_plist objectForKey:@ LAUNCH_JOBKEY_PROGRAMARGUMENTS] | 399 [[ns_plist objectForKey:@ LAUNCH_JOBKEY_PROGRAMARGUMENTS] |
| 400 mutableCopy]); | 400 mutableCopy]); |
| 401 [args replaceObjectAtIndex:0 withObject:ns_new_path]; | 401 [args replaceObjectAtIndex:0 withObject:ns_new_path]; |
| 402 [ns_plist setObject:args forKey:@ LAUNCH_JOBKEY_PROGRAMARGUMENTS]; | 402 [ns_plist setObject:args forKey:@ LAUNCH_JOBKEY_PROGRAMARGUMENTS]; |
| 403 if (!Launchd::GetInstance()->WritePlistToFile(Launchd::User, | 403 if (!Launchd::GetInstance()->WritePlistToFile(Launchd::User, |
| 404 Launchd::Agent, | 404 Launchd::Agent, |
| 405 name, | 405 name, |
| 406 plist)) { | 406 plist)) { |
| 407 LOG(ERROR) << "Unable to rewrite plist."; | 407 DLOG(ERROR) << "Unable to rewrite plist."; |
| 408 needs_shutdown = true; | 408 needs_shutdown = true; |
| 409 } | 409 } |
| 410 } else { | 410 } else { |
| 411 LOG(ERROR) << "Unable to read plist."; | 411 DLOG(ERROR) << "Unable to read plist."; |
| 412 needs_shutdown = true; | 412 needs_shutdown = true; |
| 413 } | 413 } |
| 414 } | 414 } |
| 415 if (needs_shutdown) { | 415 if (needs_shutdown) { |
| 416 if (!RemoveFromLaunchd()) { | 416 if (!RemoveFromLaunchd()) { |
| 417 LOG(ERROR) << "Unable to RemoveFromLaunchd."; | 417 DLOG(ERROR) << "Unable to RemoveFromLaunchd."; |
| 418 } | 418 } |
| 419 } | 419 } |
| 420 | 420 |
| 421 // Then deal with the process. | 421 // Then deal with the process. |
| 422 CFStringRef session_type = CFSTR(kServiceProcessSessionType); | 422 CFStringRef session_type = CFSTR(kServiceProcessSessionType); |
| 423 if (needs_restart) { | 423 if (needs_restart) { |
| 424 if (!Launchd::GetInstance()->RestartJob(Launchd::User, | 424 if (!Launchd::GetInstance()->RestartJob(Launchd::User, |
| 425 Launchd::Agent, | 425 Launchd::Agent, |
| 426 name, | 426 name, |
| 427 session_type)) { | 427 session_type)) { |
| 428 LOG(ERROR) << "RestartLaunchdJob"; | 428 DLOG(ERROR) << "RestartLaunchdJob"; |
| 429 needs_shutdown = true; | 429 needs_shutdown = true; |
| 430 } | 430 } |
| 431 } | 431 } |
| 432 if (needs_shutdown) { | 432 if (needs_shutdown) { |
| 433 CFStringRef label = | 433 CFStringRef label = |
| 434 base::mac::NSToCFCast(GetServiceProcessLaunchDLabel()); | 434 base::mac::NSToCFCast(GetServiceProcessLaunchDLabel()); |
| 435 CFErrorRef err = NULL; | 435 CFErrorRef err = NULL; |
| 436 if (!Launchd::GetInstance()->RemoveJob(label, &err)) { | 436 if (!Launchd::GetInstance()->RemoveJob(label, &err)) { |
| 437 base::mac::ScopedCFTypeRef<CFErrorRef> scoped_err(err); | 437 base::mac::ScopedCFTypeRef<CFErrorRef> scoped_err(err); |
| 438 LOG(ERROR) << "RemoveJob " << err; | 438 DLOG(ERROR) << "RemoveJob " << err; |
| 439 // Exiting with zero, so launchd doesn't restart the process. | 439 // Exiting with zero, so launchd doesn't restart the process. |
| 440 exit(0); | 440 exit(0); |
| 441 } | 441 } |
| 442 } | 442 } |
| 443 } | 443 } |
| 444 } | 444 } |
| OLD | NEW |