Index: chrome/common/service_process_util_mac.mm |
diff --git a/chrome/common/service_process_util_mac.mm b/chrome/common/service_process_util_mac.mm |
index 0f5746fa002c2e01d6d70600531c78f1d29a6cd1..3a9589746af64f79bb4d3e6332a1b2931285e7b2 100644 |
--- a/chrome/common/service_process_util_mac.mm |
+++ b/chrome/common/service_process_util_mac.mm |
@@ -6,14 +6,18 @@ |
#import <Foundation/Foundation.h> |
#include <launch.h> |
+#include <syslog.h> |
Mark Mentovai
2011/03/11 20:13:52
Why?
|
#include "base/command_line.h" |
#include "base/file_path.h" |
+#include "base/file_util.h" |
#include "base/mac/foundation_util.h" |
#include "base/mac/mac_util.h" |
#include "base/mac/scoped_nsautorelease_pool.h" |
#include "base/path_service.h" |
+#include "base/process_util.h" |
#include "base/scoped_nsobject.h" |
+#include "base/stringprintf.h" |
#include "base/string_util.h" |
#include "base/sys_string_conversions.h" |
#include "base/threading/thread_restrictions.h" |
@@ -26,6 +30,8 @@ |
namespace { |
+#define kServiceProcessSessionType "Background" |
+ |
NSString* GetServiceProcessLaunchDFileName() { |
NSString *bundle_id = [base::mac::MainAppBundle() bundleIdentifier]; |
NSString *label = [bundle_id stringByAppendingPathExtension:@"plist"]; |
@@ -59,7 +65,7 @@ NSString* GetServiceProcessLaunchDSocketEnvVar() { |
} |
// Creates the path that it returns. Must be called on the FILE thread. |
-NSURL* GetUserAgentPath() { |
+NSURL* GetUserAgentURL() { |
NSArray* library_paths = NSSearchPathForDirectoriesInDomains( |
NSLibraryDirectory, NSUserDomainMask, true); |
DCHECK_EQ([library_paths count], 1U); |
@@ -72,7 +78,7 @@ NSURL* GetUserAgentPath() { |
withIntermediateDirectories:YES |
attributes:nil |
error:&err]) { |
- LOG(ERROR) << "GetUserAgentPath: " << err; |
+ LOG(ERROR) << "GetUserAgentURL: " << err; |
} |
NSString* plist_file_path = |
@@ -81,7 +87,24 @@ NSURL* GetUserAgentPath() { |
return [NSURL fileURLWithPath:plist_file_path isDirectory:NO]; |
} |
-} |
+class ExecPathComponentWatcherDelegate |
+ : public base::FilePathComponentWatcher::Delegate { |
+ public: |
+ ExecPathComponentWatcherDelegate(CFDictionaryRef launchd_conf, |
+ ServiceProcessState *process_state) |
+ : launchd_conf_(launchd_conf), process_state_(process_state) { } |
+ virtual ~ExecPathComponentWatcherDelegate(); |
+ virtual void OnFilePathComponentsChanged( |
+ base::FilePathComponentWatcher* watcher, |
+ const FilePath& old_path, |
+ const FilePath& new_path) OVERRIDE; |
+ |
+private: |
+ base::mac::ScopedCFTypeRef<CFDictionaryRef> launchd_conf_; |
+ ServiceProcessState* process_state_; |
+}; |
+ |
+} // namespace |
// Gets the name of the service process IPC channel. |
IPC::ChannelHandle GetServiceProcessChannel() { |
@@ -166,6 +189,22 @@ bool ServiceProcessState::Initialize() { |
CFRelease(err); |
return false; |
} |
+ |
+ |
+ return true; |
+} |
+ |
+bool ServiceProcessState::SignalReadyPlatformSpecific() { |
sanjeevr
2011/03/11 08:26:42
It seems kind of cheating to use the SignalReady t
|
+ CFStringRef exe_path = reinterpret_cast<CFStringRef>(CFDictionaryGetValue( |
+ state_->launchd_conf_, CFSTR(LAUNCH_JOBKEY_PROGRAM))); |
+ if (!exe_path) { |
+ return false; |
+ } |
+ FilePath executable_path = FilePath(base::SysCFStringRefToUTF8(exe_path)); |
Mark Mentovai
2011/03/11 20:13:52
This is wrong. Use CFStringGetFileSystemRepresenta
|
+ if (!state_->executable_watcher_.Watch(executable_path, |
+ new ExecPathComponentWatcherDelegate(state_->launchd_conf_, this))) { |
+ return false; |
+ } |
return true; |
} |
@@ -266,7 +305,7 @@ CFDictionaryRef CreateServiceProcessLaunchdPlist(CommandLine* cmd_line, |
[[NSDictionary alloc] initWithObjectsAndKeys: |
[NSNumber numberWithBool:YES], @ LAUNCH_JOBKEY_RUNATLOAD, |
keep_alive, @ LAUNCH_JOBKEY_KEEPALIVE, |
- @"Background", @ LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE, |
+ @ kServiceProcessSessionType, @ LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE, |
nil]; |
[launchd_plist addEntriesFromDictionary:auto_launchd_plist]; |
} |
@@ -285,7 +324,7 @@ bool ServiceProcessState::AddToAutoRun() { |
scoped_nsobject<NSDictionary> plist( |
base::mac::CFToNSCast(CreateServiceProcessLaunchdPlist( |
autorun_command_line_.get(), true))); |
- NSURL* plist_url = GetUserAgentPath(); |
+ NSURL* plist_url = GetUserAgentURL(); |
return [plist writeToURL:plist_url atomically:YES]; |
} |
@@ -294,7 +333,7 @@ bool ServiceProcessState::RemoveFromAutoRun() { |
base::ThreadRestrictions::AssertIOAllowed(); |
base::mac::ScopedNSAutoreleasePool pool; |
- NSURL* plist_url = GetUserAgentPath(); |
+ NSURL* plist_url = GetUserAgentURL(); |
SInt32 error = 0; |
if (!CFURLDestroyResource(reinterpret_cast<CFURLRef>(plist_url), &error)) { |
LOG(ERROR) << "RemoveFromAutoRun: " << error; |
@@ -302,3 +341,89 @@ bool ServiceProcessState::RemoveFromAutoRun() { |
} |
return true; |
} |
+ |
+ExecPathComponentWatcherDelegate::~ExecPathComponentWatcherDelegate() { |
+} |
+ |
+void ExecPathComponentWatcherDelegate::OnFilePathComponentsChanged( |
+ base::FilePathComponentWatcher* watcher, const FilePath& old_path, |
+ const FilePath& new_path) { |
+ base::mac::ScopedNSAutoreleasePool pool; |
+ bool needs_shutdown = false; |
+ bool needs_restart = false; |
+ bool needs_plist_rewrite = false; |
+ bool needs_plist_deletion = false; |
+ if (access(new_path.value().c_str(), W_OK) != 0) { |
+ // Can we execute it? |
Mark Mentovai
2011/03/11 20:13:52
Remember, no “we.” This is better:
// Is it ex
|
+ needs_shutdown = true; |
+ needs_plist_deletion = true; |
+ } else if (file_util::IsInTrash(new_path)) { |
+ // Is it in the trash? |
+ needs_shutdown = true; |
+ needs_plist_deletion = true; |
+ } else if (!file_util::AreReferringToSameObject(old_path, new_path)) { |
+ // Did it get moved? |
+ needs_restart = true; |
+ needs_plist_rewrite = true; |
Mark Mentovai
2011/03/11 20:13:52
Judging from this logic, it seems that
needs sh
|
+ } else { |
+ // Nothing exciting happened. Let's continue to ask for events. |
Mark Mentovai
2011/03/11 20:13:52
s/Let's c/C/
|
+ if (!watcher->Watch(new_path, this)) { |
Mark Mentovai
2011/03/11 20:13:52
OK, so it *is* possible to call Watch on an existi
|
+ LOG(ERROR) << "Watch failed: " << new_path.value(); |
+ } |
+ } |
+ if (needs_plist_rewrite) { |
+ NSURL* plist_url = GetUserAgentURL(); |
+ NSMutableDictionary* plist |
+ = [NSMutableDictionary dictionaryWithContentsOfURL:plist_url]; |
Mark Mentovai
2011/03/11 20:13:52
Put the = on the preceding line, and indent this o
|
+ if (plist) { |
+ NSString* ns_new_path = base::SysUTF8ToNSString(new_path.value()); |
Mark Mentovai
2011/03/11 20:13:52
Why not just +[NSString stringWithUTF8String:]?
|
+ [plist setObject:ns_new_path forKey:@ LAUNCH_JOBKEY_PROGRAM]; |
+ scoped_nsobject<NSMutableArray> args( |
+ [[plist objectForKey:@ LAUNCH_JOBKEY_PROGRAMARGUMENTS] mutableCopy]); |
+ [args replaceObjectAtIndex:0 withObject:ns_new_path]; |
+ [plist setObject:args forKey:@ LAUNCH_JOBKEY_PROGRAMARGUMENTS]; |
+ if (![plist writeToURL:plist_url atomically:YES]) { |
+ LOG(ERROR) << "Unable to rewrite plist."; |
+ } |
+ } else { |
+ LOG(ERROR) << "Unable to read plist."; |
+ } |
+ } else if (needs_plist_deletion) { |
+ if (!process_state_->RemoveFromAutoRun()) { |
+ LOG(ERROR) << "Unable to RemoveFromAutoRun."; |
+ } |
+ } |
+ if (needs_shutdown || needs_restart) { |
+ NSURL *plist_url = GetUserAgentURL(); |
+ std::string plist_path(base::SysNSStringToUTF8([plist_url path])); |
Mark Mentovai
2011/03/11 20:13:52
No, use [plist_url fileSystemRepresentation].
|
+ std::vector<std::string> argv; |
+ |
+ if (needs_shutdown) { |
+ VLOG(1) << "Shutting down using launchctl"; |
+ argv.push_back("/bin/launchctl"); |
+ argv.push_back("unload"); |
+ argv.push_back("-S"); |
+ argv.push_back(kServiceProcessSessionType); |
+ argv.push_back(plist_path); |
+ } else if (needs_restart) { |
Mark Mentovai
2011/03/11 20:13:52
This can just be |else|, look at the enclosing con
|
+ VLOG(1) << "Restarting using launchctl"; |
Mark Mentovai
2011/03/11 20:13:52
I assume that as soon as you run launchctl unload,
|
+ argv.push_back("/bin/sh"); |
Mark Mentovai
2011/03/11 20:13:52
/bin/bash if you’re using --noprofile.
|
+ argv.push_back("--noprofile"); |
+ argv.push_back("-c"); |
+ std::string command = base::StringPrintf( |
+ "/bin/launchctl unload -S %s '%s';/bin/launchctl load -S %s '%s';", |
Mark Mentovai
2011/03/11 20:13:52
The only way I’ll let you pass arbitrary arguments
|
+ kServiceProcessSessionType, plist_path.c_str(), |
+ kServiceProcessSessionType, plist_path.c_str()); |
+ argv.push_back(command); |
+ } |
+ base::ProcessHandle handle; |
+ if (!base::LaunchAppInNewProcessGroup(argv, |
+ base::environment_vector(), |
+ base::file_handle_mapping_vector(), |
+ NO, |
+ &handle)) { |
+ LOG(ERROR) << "LaunchAppInNewProcessGroup"; |
+ } |
Mark Mentovai
2011/03/11 20:13:52
What are you expecting to happen here? Be killed?
|
+ } |
+} |
+ |
Mark Mentovai
2011/03/11 20:13:52
Blank line at EOF.
|