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

Unified Diff: chrome/common/service_process_util_mac.mm

Issue 6660001: Getting service process on Mac to handle having things moved/changed underneath it. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed up phajdan's comments, got things working properly Created 9 years, 9 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 side-by-side diff with in-line comments
Download patch
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.

Powered by Google App Engine
This is Rietveld 408576698