[go: nahoru, domu]

Get service process running standalone on the mac by hooking it into launchd.

BUG=NONE
TEST=BUILD

Review URL: http://codereview.chromium.org/6482016

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75893 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/DEPS b/DEPS
index 2439936c..967fadb0 100644
--- a/DEPS
+++ b/DEPS
@@ -250,7 +250,7 @@
       "/trunk/deps/reference_builds/chrome_mac@71120",
 
     "src/third_party/GTM":
-      (Var("googlecode_url") % "google-toolbox-for-mac") + "/trunk@427",
+      (Var("googlecode_url") % "google-toolbox-for-mac") + "/trunk@434",
     "src/third_party/pdfsqueeze":
       (Var("googlecode_url") % "pdfsqueeze") + "/trunk@4",
     "src/third_party/lighttpd":
diff --git a/base/process_util.h b/base/process_util.h
index a7f8496..29b08ca0 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -162,9 +162,6 @@
 ProcessId GetProcId(ProcessHandle process);
 
 #if defined(OS_LINUX)
-// Returns the ID for the parent of the given process.
-ProcessId GetParentProcessId(ProcessHandle process);
-
 // Returns the path to the executable of the given process.
 FilePath GetProcessExecutablePath(ProcessHandle process);
 
@@ -182,6 +179,9 @@
 #endif
 
 #if defined(OS_POSIX)
+// Returns the ID for the parent of the given process.
+ProcessId GetParentProcessId(ProcessHandle process);
+
 // Close all file descriptors, except those which are a destination in the
 // given multimap. Only call this function in a child process where you know
 // that there aren't any other threads.
@@ -359,7 +359,7 @@
 // will no longer be available).
 TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code);
 
-// Waits for process to exit. In POSIX systems, if the process hasn't been
+// Waits for process to exit. On POSIX systems, if the process hasn't been
 // signaled then puts the exit code in |exit_code|; otherwise it's considered
 // a failure. On Windows |exit_code| is always filled. Returns true on success,
 // and closes |handle| in any case.
@@ -382,9 +382,9 @@
                             const ProcessFilter* filter);
 
 // Wait for a single process to exit. Return true if it exited cleanly within
-// the given time limit.
-bool WaitForSingleProcess(ProcessHandle handle,
-                          int64 wait_milliseconds);
+// the given time limit. On Linux |handle| must be a child process, however
+// on Mac and Windows it can be any process.
+bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds);
 
 // Returns true when |wait_milliseconds| have elapsed and the process
 // is still running.
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index aa0f14d..6d05581 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -880,4 +880,17 @@
                            reinterpret_cast<IMP>(oom_killer_allocWithZone));
 }
 
+ProcessId GetParentProcessId(ProcessHandle process) {
+  struct kinfo_proc info;
+  size_t length = sizeof(struct kinfo_proc);
+  int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process };
+  if (sysctl(mib, 4, &info, &length, NULL, 0) < 0) {
+    PLOG(ERROR) << "sysctl";
+    return -1;
+  }
+  if (length == 0)
+    return -1;
+  return info.kp_eproc.e_ppid;
+}
+
 }  // namespace base
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index 9d0ba58..9a5f5a7 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -32,6 +32,7 @@
 
 #if defined(OS_MACOSX)
 #include <crt_externs.h>
+#include <sys/event.h>
 #define environ (*_NSGetEnviron())
 #else
 extern char** environ;
@@ -496,17 +497,20 @@
   scoped_array<char*> new_environ(AlterEnvironment(env_changes, environ));
 
   pid = fork();
-  if (pid < 0)
+  if (pid < 0) {
+    PLOG(ERROR) << "fork";
     return false;
-
+  }
   if (pid == 0) {
     // Child process
 
     if (start_new_process_group) {
       // Instead of inheriting the process group ID of the parent, the child
       // starts off a new process group with pgid equal to its process ID.
-      if (setpgid(0, 0) < 0)
+      if (setpgid(0, 0) < 0) {
+        PLOG(ERROR) << "setpgid";
         return false;
+      }
     }
 #if defined(OS_MACOSX)
     RestoreDefaultExceptionHandler();
@@ -713,7 +717,79 @@
   return true;
 }
 
+#if defined(OS_MACOSX)
+// Using kqueue on Mac so that we can wait on non-child processes.
+// We can't use kqueues on child processes because we need to reap
+// our own children using wait.
+static bool WaitForSingleNonChildProcess(ProcessHandle handle,
+                                         int64 wait_milliseconds) {
+  int kq = kqueue();
+  if (kq == -1) {
+    PLOG(ERROR) << "kqueue";
+    return false;
+  }
+
+  struct kevent change = { 0 };
+  EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
+
+  struct timespec spec;
+  struct timespec *spec_ptr;
+  if (wait_milliseconds != base::kNoTimeout) {
+    time_t sec = static_cast<time_t>(wait_milliseconds / 1000);
+    wait_milliseconds = wait_milliseconds - (sec * 1000);
+    spec.tv_sec = sec;
+    spec.tv_nsec = wait_milliseconds * 1000000L;
+    spec_ptr = &spec;
+  } else {
+    spec_ptr = NULL;
+  }
+
+  while(true) {
+    struct kevent event = { 0 };
+    int event_count = HANDLE_EINTR(kevent(kq, &change, 1, &event, 1, spec_ptr));
+    if (close(kq) != 0) {
+      PLOG(ERROR) << "close";
+    }
+    if (event_count < 0) {
+      PLOG(ERROR) << "kevent";
+      return false;
+    } else if (event_count == 0) {
+      if (wait_milliseconds != base::kNoTimeout) {
+        // Timed out.
+        return false;
+      }
+    } else if ((event_count == 1) &&
+               (handle == static_cast<pid_t>(event.ident)) &&
+               (event.filter == EVFILT_PROC)) {
+      if (event.fflags == NOTE_EXIT) {
+        return true;
+      } else if (event.flags == EV_ERROR) {
+        LOG(ERROR) << "kevent error " << event.data;
+        return false;
+      } else {
+        NOTREACHED();
+        return false;
+      }
+    } else {
+      NOTREACHED();
+      return false;
+    }
+  }
+}
+#endif  // OS_MACOSX
+
 bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) {
+  ProcessHandle parent_pid = GetParentProcessId(handle);
+  ProcessHandle our_pid = Process::Current().handle();
+  if (parent_pid != our_pid) {
+#if defined(OS_MACOSX)
+    // On Mac we can wait on non child processes.
+    return WaitForSingleNonChildProcess(handle, wait_milliseconds);
+#else
+    // Currently on Linux we can't handle non child processes.
+    NOTIMPLEMENTED();
+#endif  // OS_MACOSX
+  }
   bool waitpid_success;
   int status;
   if (wait_milliseconds == base::kNoTimeout)
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index 1b7368a..31e1dec 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_unittest.cc
@@ -658,12 +658,12 @@
   }
 }
 
-#if defined(OS_LINUX)
 TEST_F(ProcessUtilTest, GetParentProcessId) {
   base::ProcessId ppid = base::GetParentProcessId(base::GetCurrentProcId());
   EXPECT_EQ(ppid, getppid());
 }
 
+#if defined(OS_LINUX)
 TEST_F(ProcessUtilTest, ParseProcStatCPU) {
   // /proc/self/stat for a process running "top".
   const char kTopStat[] = "960 (top) S 16230 960 16230 34818 960 "
@@ -683,7 +683,7 @@
 
   EXPECT_EQ(0, base::ParseProcStatCPU(kSelfStat));
 }
-#endif
+#endif  // defined(OS_LINUX)
 
 #endif  // defined(OS_POSIX)
 
diff --git a/chrome/browser/service/service_process_control.cc b/chrome/browser/service/service_process_control.cc
index 09bc1ad..eb7a983 100644
--- a/chrome/browser/service/service_process_control.cc
+++ b/chrome/browser/service/service_process_control.cc
@@ -21,79 +21,6 @@
 #include "chrome/common/service_process_util.h"
 #include "ui/base/ui_base_switches.h"
 
-// ServiceProcessControl::Launcher implementation.
-// This class is responsible for launching the service process on the
-// PROCESS_LAUNCHER thread.
-class ServiceProcessControl::Launcher
-    : public base::RefCountedThreadSafe<ServiceProcessControl::Launcher> {
- public:
-  Launcher(ServiceProcessControl* process, CommandLine* cmd_line)
-      : process_(process),
-        cmd_line_(cmd_line),
-        launched_(false),
-        retry_count_(0) {
-  }
-
-  // Execute the command line to start the process asynchronously.
-  // After the comamnd is executed |task| is called with the process handle on
-  // the UI thread.
-  void Run(Task* task) {
-    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-    notify_task_.reset(task);
-    BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
-                           NewRunnableMethod(this, &Launcher::DoRun));
-  }
-
-  bool launched() const { return launched_; }
-
- private:
-  void DoRun() {
-    DCHECK(notify_task_.get());
-    base::LaunchApp(*cmd_line_.get(), false, true, NULL);
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        NewRunnableMethod(this, &Launcher::DoDetectLaunched));
-  }
-
-  void DoDetectLaunched() {
-    DCHECK(notify_task_.get());
-    const uint32 kMaxLaunchDetectRetries = 10;
-
-    {
-      // We should not be doing blocking disk IO from this thread!
-      // Temporarily allowed until we fix
-      //   http://code.google.com/p/chromium/issues/detail?id=60207
-      base::ThreadRestrictions::ScopedAllowIO allow_io;
-      launched_ = CheckServiceProcessReady();
-    }
-
-    if (launched_ || (retry_count_ >= kMaxLaunchDetectRetries)) {
-      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-          NewRunnableMethod(this, &Launcher::Notify));
-      return;
-    }
-    retry_count_++;
-    // If the service process is not launched yet then check again in 2 seconds.
-    const int kDetectLaunchRetry = 2000;
-    MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        NewRunnableMethod(this, &Launcher::DoDetectLaunched),
-        kDetectLaunchRetry);
-  }
-
-  void Notify() {
-    DCHECK(notify_task_.get());
-    notify_task_->Run();
-    notify_task_.reset();
-  }
-
-  ServiceProcessControl* process_;
-  scoped_ptr<CommandLine> cmd_line_;
-  scoped_ptr<Task> notify_task_;
-  bool launched_;
-  uint32 retry_count_;
-};
 
 // ServiceProcessControl implementation.
 ServiceProcessControl::ServiceProcessControl(Profile* profile)
@@ -120,7 +47,7 @@
   base::Thread* io_thread = g_browser_process->io_thread();
 
   // TODO(hclam): Handle error connecting to channel.
-  const std::string channel_id = GetServiceProcessChannelName();
+  const IPC::ChannelHandle channel_id = GetServiceProcessChannel();
   channel_.reset(
       new IPC::SyncChannel(channel_id, IPC::Channel::MODE_NAMED_CLIENT, this,
                            io_thread->message_loop(), true,
@@ -201,10 +128,19 @@
   if (!logging_level.empty())
     cmd_line->AppendSwitchASCII(switches::kLoggingLevel, logging_level);
 
+  std::string v_level = browser_command_line.GetSwitchValueASCII(
+      switches::kV);
+  if (!v_level.empty())
+    cmd_line->AppendSwitchASCII(switches::kV, v_level);
+
   if (browser_command_line.HasSwitch(switches::kWaitForDebuggerChildren)) {
     cmd_line->AppendSwitch(switches::kWaitForDebugger);
   }
 
+  if (browser_command_line.HasSwitch(switches::kEnableLogging)) {
+    cmd_line->AppendSwitch(switches::kEnableLogging);
+  }
+
   std::string locale = g_browser_process->GetApplicationLocale();
   cmd_line->AppendSwitchASCII(switches::kLang, locale);
 
@@ -341,3 +277,56 @@
 }
 
 DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControl);
+
+ServiceProcessControl::Launcher::Launcher(ServiceProcessControl* process,
+                                          CommandLine* cmd_line)
+    : process_(process),
+      cmd_line_(cmd_line),
+      launched_(false),
+      retry_count_(0) {
+}
+
+// Execute the command line to start the process asynchronously.
+// After the command is executed, |task| is called with the process handle on
+// the UI thread.
+void ServiceProcessControl::Launcher::Run(Task* task) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  notify_task_.reset(task);
+  BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
+                         NewRunnableMethod(this, &Launcher::DoRun));
+}
+
+void ServiceProcessControl::Launcher::Notify() {
+  DCHECK(notify_task_.get());
+  notify_task_->Run();
+  notify_task_.reset();
+}
+
+#if !defined(OS_MACOSX)
+void ServiceProcessControl::Launcher::DoDetectLaunched() {
+  DCHECK(notify_task_.get());
+  const uint32 kMaxLaunchDetectRetries = 10;
+  launched_ = CheckServiceProcessReady();
+  if (launched_ || (retry_count_ >= kMaxLaunchDetectRetries)) {
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+        NewRunnableMethod(this, &Launcher::Notify));
+    return;
+  }
+  retry_count_++;
+
+  // If the service process is not launched yet then check again in 2 seconds.
+  const int kDetectLaunchRetry = 2000;
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      NewRunnableMethod(this, &Launcher::DoDetectLaunched),
+      kDetectLaunchRetry);
+}
+
+void ServiceProcessControl::Launcher::DoRun() {
+  DCHECK(notify_task_.get());
+  base::LaunchApp(*cmd_line_.get(), false, true, NULL);
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      NewRunnableMethod(this, &Launcher::DoDetectLaunched));
+}
+#endif  // !OS_MACOSX
diff --git a/chrome/browser/service/service_process_control.h b/chrome/browser/service/service_process_control.h
index c2f18ba..d5e43e0 100644
--- a/chrome/browser/service/service_process_control.h
+++ b/chrome/browser/service/service_process_control.h
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 
+#include "base/basictypes.h"
 #include "base/id_map.h"
 #include "base/callback.h"
 #include "base/process.h"
@@ -20,6 +21,7 @@
 #include "ipc/ipc_sync_channel.h"
 
 class Profile;
+class CommandLine;
 
 namespace remoting {
 struct ChromotingHostInfo;
@@ -126,7 +128,33 @@
   void RemoveMessageHandler(MessageHandler* message_handler);
 
  private:
-  class Launcher;
+  // This class is responsible for launching the service process on the
+  // PROCESS_LAUNCHER thread.
+  class Launcher
+      : public base::RefCountedThreadSafe<ServiceProcessControl::Launcher> {
+   public:
+    Launcher(ServiceProcessControl* process, CommandLine* cmd_line);
+    // Execute the command line to start the process asynchronously.
+    // After the comamnd is executed |task| is called with the process handle on
+    // the UI thread.
+    void Run(Task* task);
+
+    bool launched() const { return launched_; }
+
+   private:
+#if !defined(OS_MACOSX)
+    void DoDetectLaunched();
+#endif  // !OS_MACOSX
+
+    void DoRun();
+    void Notify();
+    ServiceProcessControl* process_;
+    scoped_ptr<CommandLine> cmd_line_;
+    scoped_ptr<Task> notify_task_;
+    bool launched_;
+    uint32 retry_count_;
+  };
+
   typedef std::vector<Task*> TaskList;
 
   // Helper method to invoke all the callbacks based on success on failure.
diff --git a/chrome/browser/service/service_process_control_browsertest.cc b/chrome/browser/service/service_process_control_browsertest.cc
index a0dee5d..ff6e514e 100644
--- a/chrome/browser/service/service_process_control_browsertest.cc
+++ b/chrome/browser/service/service_process_control_browsertest.cc
@@ -25,6 +25,13 @@
     ServiceProcessControlManager::GetInstance()->Shutdown();
   }
 
+#if defined(OS_MACOSX)
+  virtual void TearDown() {
+    // ForceServiceProcessShutdown removes the process from launchd on Mac.
+    ForceServiceProcessShutdown("", 0);
+  }
+#endif  // OS_MACOSX
+
  protected:
   void LaunchServiceProcessControl() {
     ServiceProcessControl* process =
@@ -72,7 +79,7 @@
 
   void ProcessControlLaunched() {
     base::ProcessId service_pid;
-    EXPECT_TRUE(GetServiceProcessSharedData(NULL, &service_pid));
+    EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
     EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
     EXPECT_TRUE(base::OpenProcessHandleWithAccess(
         service_pid,
@@ -194,7 +201,7 @@
   // Make sure we are connected to the service process.
   EXPECT_TRUE(process()->is_connected());
   base::ProcessId service_pid;
-  EXPECT_TRUE(GetServiceProcessSharedData(NULL, &service_pid));
+  EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
   EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
   chrome::VersionInfo version_info;
   ForceServiceProcessShutdown(version_info.Version(), service_pid);
@@ -203,10 +210,10 @@
 
 IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, CheckPid) {
   base::ProcessId service_pid;
-  EXPECT_FALSE(GetServiceProcessSharedData(NULL, &service_pid));
+  EXPECT_FALSE(GetServiceProcessData(NULL, &service_pid));
   // Launch the service process.
   LaunchServiceProcessControl();
-  EXPECT_TRUE(GetServiceProcessSharedData(NULL, &service_pid));
+  EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
   EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
 }
 
diff --git a/chrome/browser/service/service_process_control_mac.mm b/chrome/browser/service/service_process_control_mac.mm
new file mode 100644
index 0000000..ebb2f2d
--- /dev/null
+++ b/chrome/browser/service/service_process_control_mac.mm
@@ -0,0 +1,25 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/service/service_process_control.h"
+
+#include "base/command_line.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/common/service_process_util_posix.h"
+#include "third_party/GTM/Foundation/GTMServiceManagement.h"
+
+void ServiceProcessControl::Launcher::DoRun() {
+  base::mac::ScopedCFTypeRef<CFDictionaryRef> launchd_plist(
+      CreateServiceProcessLaunchdPlist(cmd_line_.get()));
+  CFErrorRef error = NULL;
+  if (!GTMSMJobSubmit(launchd_plist, &error)) {
+    LOG(ERROR) << error;
+    CFRelease(error);
+  } else {
+    launched_ = true;
+  }
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          NewRunnableMethod(this, &Launcher::Notify));
+}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index b290923..6db074f 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1860,6 +1860,7 @@
         'browser/search_engines/util.cc',
         'browser/search_engines/util.h',
         'browser/service/service_process_control.cc',
+        'browser/service/service_process_control_mac.mm',
         'browser/service/service_process_control.h',
         'browser/service/service_process_control_manager.cc',
         'browser/service/service_process_control_manager.h',
@@ -3697,6 +3698,8 @@
             '../third_party/GTM/Foundation/GTMNSNumber+64Bit.m',
             '../third_party/GTM/Foundation/GTMNSObject+KeyValueObserving.h',
             '../third_party/GTM/Foundation/GTMNSObject+KeyValueObserving.m',
+            '../third_party/GTM/Foundation/GTMServiceManagement.h',
+            '../third_party/GTM/Foundation/GTMServiceManagement.c',
             # MolokoCacao additions
             '../third_party/molokocacao/NSBezierPath+MCAdditions.h',
             '../third_party/molokocacao/NSBezierPath+MCAdditions.m',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index dbdc1c8..37f6cc80 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -363,7 +363,10 @@
         'common/service_messages_internal.h',
         'common/service_process_util.cc',
         'common/service_process_util.h',
+        'common/service_process_util_linux.cc',
+        'common/service_process_util_mac.mm',
         'common/service_process_util_posix.cc',
+        'common/service_process_util_posix.h',
         'common/service_process_util_win.cc',
         'common/socket_stream_dispatcher.cc',
         'common/socket_stream_dispatcher.h',
@@ -488,6 +491,9 @@
               'common/common.sb',
             ],
           },
+          'include_dirs': [
+            '../third_party/GTM',
+          ],
         }],
         ['OS!="win"', {
           'sources!': [
diff --git a/chrome/common/service_process_util.cc b/chrome/common/service_process_util.cc
index 458f662..6a2f02f 100644
--- a/chrome/common/service_process_util.cc
+++ b/chrome/common/service_process_util.cc
@@ -21,6 +21,8 @@
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/service_process_util.h"
 
+#if !defined(OS_MACOSX)
+
 namespace {
 
 // This should be more than enough to hold a version string assuming each part
@@ -49,7 +51,7 @@
 ServiceProcessRunningState GetServiceProcessRunningState(
     std::string* service_version_out, base::ProcessId* pid_out) {
   std::string version;
-  if (!GetServiceProcessSharedData(&version, pid_out))
+  if (!GetServiceProcessData(&version, pid_out))
     return SERVICE_NOT_RUNNING;
 
 #if defined(OS_POSIX)
@@ -125,14 +127,9 @@
   return GetServiceProcessScopedName(versioned_str);
 }
 
-// Gets the name of the service process IPC channel.
-std::string GetServiceProcessChannelName() {
-  return GetServiceProcessScopedVersionedName("_service_ipc");
-}
-
 // Reads the named shared memory to get the shared data. Returns false if no
 // matching shared memory was found.
-bool GetServiceProcessSharedData(std::string* version, base::ProcessId* pid) {
+bool GetServiceProcessData(std::string* version, base::ProcessId* pid) {
   scoped_ptr<base::SharedMemory> shared_mem_service_data;
   shared_mem_service_data.reset(new base::SharedMemory());
   ServiceProcessSharedData* service_data = NULL;
@@ -153,17 +150,22 @@
   return false;
 }
 
+// Gets the name of the service process IPC channel.
+IPC::ChannelHandle GetServiceProcessChannel() {
+  return GetServiceProcessScopedVersionedName("_service_ipc");
+}
+
+#endif  // !OS_MACOSX
+
 ServiceProcessState::ServiceProcessState() : state_(NULL) {
 }
 
 ServiceProcessState::~ServiceProcessState() {
+#if !defined(OS_MACOSX)
   if (shared_mem_service_data_.get()) {
-    // Delete needs a pool wrapped around it because it calls some Obj-C on Mac,
-    // and since ServiceProcessState is a singleton, it gets destructed after
-    // the standard NSAutoreleasePools have already been cleaned up.
-    base::mac::ScopedNSAutoreleasePool pool;
     shared_mem_service_data_->Delete(GetServiceProcessSharedMemName());
   }
+#endif  // !OS_MACOSX
   TearDownState();
 }
 
@@ -172,7 +174,16 @@
   return Singleton<ServiceProcessState>::get();
 }
 
+void ServiceProcessState::SignalStopped() {
+  TearDownState();
+  shared_mem_service_data_.reset();
+}
+
+#if !defined(OS_MACOSX)
 bool ServiceProcessState::Initialize() {
+  if (!InitializeState()) {
+    return false;
+  }
   if (!TakeSingletonLock()) {
     return false;
   }
@@ -242,11 +253,8 @@
   return true;
 }
 
-std::string ServiceProcessState::GetAutoRunKey() {
-  return GetServiceProcessScopedName("_service_run");
+IPC::ChannelHandle ServiceProcessState::GetServiceProcessChannel() {
+  return ::GetServiceProcessChannel();
 }
 
-void ServiceProcessState::SignalStopped() {
-  TearDownState();
-  shared_mem_service_data_.reset();
-}
+#endif  // !OS_MACOSX
diff --git a/chrome/common/service_process_util.h b/chrome/common/service_process_util.h
index 175499d..2ad72d7e 100644
--- a/chrome/common/service_process_util.h
+++ b/chrome/common/service_process_util.h
@@ -7,11 +7,14 @@
 
 #include <string>
 
+#include "base/basictypes.h"
 #include "base/process.h"
 #include "base/scoped_ptr.h"
 #include "base/shared_memory.h"
+#include "ipc/ipc_channel_handle.h"
 
 class Task;
+class CommandLine;
 
 namespace base {
   class MessageLoopProxy;
@@ -20,9 +23,9 @@
 template <typename T> struct DefaultSingletonTraits;
 
 // Return the IPC channel to connect to the service process.
-//
-std::string GetServiceProcessChannelName();
+IPC::ChannelHandle GetServiceProcessChannel();
 
+#if !defined(OS_MACOSX)
 // Return a name that is scoped to this instance of the service process. We
 // use the user-data-dir as a scoping prefix.
 std::string GetServiceProcessScopedName(const std::string& append_str);
@@ -30,6 +33,7 @@
 // Return a name that is scoped to this instance of the service process. We
 // use the user-data-dir and the version as a scoping prefix.
 std::string GetServiceProcessScopedVersionedName(const std::string& append_str);
+#endif  // OS_MACOSX
 
 // The following methods are used in a process that acts as a client to the
 // service process (typically the browser process).
@@ -43,7 +47,7 @@
 // a true return value only means that some process shared data was available,
 // and not that the process is ready to receive IPC commands, or even running.
 // This method is only exposed for testing.
-bool GetServiceProcessSharedData(std::string* version, base::ProcessId* pid);
+bool GetServiceProcessData(std::string* version, base::ProcessId* pid);
 // --------------------------------------------------------------------------
 
 // Forces a service process matching the specified version to shut down.
@@ -76,15 +80,19 @@
   void SignalStopped();
 
   // Register the service process to run on startup.
-  bool AddToAutoRun();
+  bool AddToAutoRun(CommandLine* command_line);
 
   // Unregister the service process to run on startup.
   bool RemoveFromAutoRun();
 
+  // Return the channel handle used for communicating with the service.
+  IPC::ChannelHandle GetServiceProcessChannel();
+
  private:
   ServiceProcessState();
   ~ServiceProcessState();
 
+#if !defined(OS_MACOSX)
   // Create the shared memory data for the service process.
   bool CreateSharedData();
 
@@ -95,9 +103,10 @@
   // Acquires a singleton lock for the service process. A return value of false
   // means that a service process instance is already running.
   bool TakeSingletonLock();
+#endif  // !OS_MACOSX
 
-  // Key used to register the service process to auto-run.
-  std::string GetAutoRunKey();
+  // Initialize the platform specific state.
+  bool InitializeState();
 
   // Tear down the platform specific state.
   void TearDownState();
diff --git a/chrome/common/service_process_util_linux.cc b/chrome/common/service_process_util_linux.cc
new file mode 100644
index 0000000..1a53889
--- /dev/null
+++ b/chrome/common/service_process_util_linux.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/service_process_util_posix.h"
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+#include "chrome/common/multi_process_lock.h"
+
+namespace {
+
+// Attempts to take a lock named |name|. If |waiting| is true then this will
+// make multiple attempts to acquire the lock.
+// Caller is responsible for ownership of the MultiProcessLock.
+MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) {
+  scoped_ptr<MultiProcessLock> lock(MultiProcessLock::Create(name));
+  if (lock == NULL) return NULL;
+  bool got_lock = false;
+  for (int i = 0; i < 10; ++i) {
+    if (lock->TryLock()) {
+      got_lock = true;
+      break;
+    }
+    if (!waiting) break;
+    base::PlatformThread::Sleep(100 * i);
+  }
+  if (!got_lock) {
+    lock.reset();
+  }
+  return lock.release();
+}
+
+MultiProcessLock* TakeServiceInitializingLock(bool waiting) {
+  std::string lock_name =
+      GetServiceProcessScopedName("_service_initializing");
+  return TakeNamedLock(lock_name, waiting);
+}
+
+}  // namespace
+
+MultiProcessLock* TakeServiceRunningLock(bool waiting) {
+  std::string lock_name =
+      GetServiceProcessScopedName("_service_running");
+  return TakeNamedLock(lock_name, waiting);
+}
+
+bool ForceServiceProcessShutdown(const std::string& version,
+                                 base::ProcessId process_id) {
+  if (kill(process_id, SIGTERM) < 0) {
+    PLOG(ERROR) << "kill";
+    return false;
+  }
+  return true;
+}
+
+bool CheckServiceProcessReady() {
+  scoped_ptr<MultiProcessLock> running_lock(TakeServiceRunningLock(false));
+  return running_lock.get() == NULL;
+}
+
+bool ServiceProcessState::TakeSingletonLock() {
+  state_->initializing_lock_.reset(TakeServiceInitializingLock(true));
+  return state_->initializing_lock_.get();
+}
+
+bool ServiceProcessState::AddToAutoRun(CommandLine* cmd_line) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool ServiceProcessState::RemoveFromAutoRun() {
+  NOTIMPLEMENTED();
+  return false;
+}
diff --git a/chrome/common/service_process_util_mac.mm b/chrome/common/service_process_util_mac.mm
new file mode 100644
index 0000000..632538a
--- /dev/null
+++ b/chrome/common/service_process_util_mac.mm
@@ -0,0 +1,228 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/service_process_util_posix.h"
+
+#import <Foundation/Foundation.h>
+#include <launch.h>
+
+#include "base/command_line.h"
+#include "base/file_path.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/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "base/version.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_version_info.h"
+#include "third_party/GTM/Foundation/GTMServiceManagement.h"
+
+namespace {
+
+NSString* GetServiceProcessLaunchDLabel() {
+  NSString *bundle_id = [base::mac::MainAppBundle() bundleIdentifier];
+  NSString *label = [bundle_id stringByAppendingString:@".service_process"];
+  FilePath user_data_dir;
+  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+  std::string user_data_dir_path = user_data_dir.value();
+  NSString *ns_path = base::SysUTF8ToNSString(user_data_dir_path);
+  ns_path = [ns_path stringByReplacingOccurrencesOfString:@" "
+                                               withString:@"_"];
+  label = [label stringByAppendingString:ns_path];
+  return label;
+}
+
+NSString* GetServiceProcessLaunchDSocketKey() {
+  return @"ServiceProcessSocket";
+}
+
+NSString* GetServiceProcessLaunchDSocketEnvVar() {
+  NSString *label = GetServiceProcessLaunchDLabel();
+  NSString *env_var = [label stringByReplacingOccurrencesOfString:@"."
+                                                       withString:@"_"];
+  env_var = [env_var stringByAppendingString:@"_SOCKET"];
+  env_var = [env_var uppercaseString];
+  return env_var;
+}
+
+}
+
+// Gets the name of the service process IPC channel.
+IPC::ChannelHandle GetServiceProcessChannel() {
+  std::string socket_path;
+  scoped_nsobject<NSDictionary> dictionary(
+      base::mac::CFToNSCast(GTMCopyLaunchdExports()));
+  NSString *ns_socket_path =
+      [dictionary objectForKey:GetServiceProcessLaunchDSocketEnvVar()];
+  if (ns_socket_path) {
+    socket_path = base::SysNSStringToUTF8(ns_socket_path);
+  }
+  return IPC::ChannelHandle(socket_path);
+}
+
+bool ForceServiceProcessShutdown(const std::string& /* version */,
+                                 base::ProcessId /* process_id */) {
+  NSString* label = GetServiceProcessLaunchDLabel();
+  CFErrorRef err = NULL;
+  bool ret = GTMSMJobRemove(reinterpret_cast<CFStringRef>(label), &err);
+  if (!ret) {
+    LOG(ERROR) << "ForceServiceProcessShutdown: " << err;
+    CFRelease(err);
+  }
+  return ret;
+}
+
+bool GetServiceProcessData(std::string* version, base::ProcessId* pid) {
+  CFStringRef label =
+      reinterpret_cast<CFStringRef>(GetServiceProcessLaunchDLabel());
+  scoped_nsobject<NSDictionary> launchd_conf(
+      base::mac::CFToNSCast(GTMSMJobCopyDictionary(label)));
+  if (!launchd_conf.get()) {
+    return false;
+  }
+
+  if (version) {
+    NSString *exe_path = [launchd_conf objectForKey:@ LAUNCH_JOBKEY_PROGRAM];
+    if (!exe_path) {
+      NOTREACHED() << "Failed to get exe path";
+      return false;
+    }
+    NSString *bundle_path = [[[exe_path stringByDeletingLastPathComponent]
+                              stringByDeletingLastPathComponent]
+                             stringByDeletingLastPathComponent];
+    NSBundle *bundle = [NSBundle bundleWithPath:bundle_path];
+    if (!bundle) {
+      NOTREACHED() << "Unable to get bundle at: "
+                   << reinterpret_cast<CFStringRef>(bundle_path);
+      return false;
+    }
+    NSString *ns_version =
+        [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
+    if (!ns_version) {
+      NOTREACHED() << "Unable to get version at: "
+                   << reinterpret_cast<CFStringRef>(bundle_path);
+      return false;
+    }
+    *version = base::SysNSStringToUTF8(ns_version);
+  }
+  if (pid) {
+    NSNumber* ns_pid = [launchd_conf objectForKey:@ LAUNCH_JOBKEY_PID];
+    if (ns_pid) {
+     *pid = [ns_pid intValue];
+    } else {
+     *pid = 0;
+    }
+  }
+  return true;
+}
+
+bool ServiceProcessState::Initialize() {
+  if (!InitializeState()) {
+    return false;
+  }
+  CFErrorRef err = NULL;
+  state_->launchd_conf_.reset(GTMSMJobCheckIn(&err));
+  if (!state_->launchd_conf_.get()) {
+    LOG(ERROR) << "InitializePlatformState: " << err;
+    CFRelease(err);
+    return false;
+  }
+  return true;
+}
+
+IPC::ChannelHandle ServiceProcessState::GetServiceProcessChannel() {
+  CHECK(state_);
+  NSDictionary *ns_launchd_conf = base::mac::CFToNSCast(state_->launchd_conf_);
+  NSDictionary* socket_dict =
+      [ns_launchd_conf objectForKey:@ LAUNCH_JOBKEY_SOCKETS];
+  NSArray* sockets =
+      [socket_dict objectForKey:GetServiceProcessLaunchDSocketKey()];
+  CHECK_EQ([sockets count], 1U);
+  int socket = [[sockets objectAtIndex:0] intValue];
+  base::FileDescriptor fd(socket, false);
+  return IPC::ChannelHandle(std::string(), fd);
+}
+
+bool CheckServiceProcessReady() {
+  std::string version;
+  pid_t pid;
+  if (!GetServiceProcessData(&version, &pid)) {
+    return false;
+  }
+  scoped_ptr<Version> service_version(Version::GetVersionFromString(version));
+  bool ready = true;
+  if (!service_version.get()) {
+    ready = false;
+  } else {
+    chrome::VersionInfo version_info;
+    if (!version_info.is_valid()) {
+      // Our own version is invalid. This is an error case. Pretend that we
+      // are out of date.
+      NOTREACHED() << "Failed to get current file version";
+      ready = true;
+    }
+    else {
+      scoped_ptr<Version> running_version(Version::GetVersionFromString(
+          version_info.Version()));
+      if (!running_version.get()) {
+        // Our own version is invalid. This is an error case. Pretend that we
+        // are out of date.
+        NOTREACHED() << "Failed to parse version info";
+        ready = true;
+      } else if (running_version->CompareTo(*service_version) > 0) {
+        ready = false;
+      } else {
+        ready = true;
+      }
+    }
+  }
+  if (!ready) {
+    ForceServiceProcessShutdown(version, pid);
+  }
+  return ready;
+}
+
+bool ServiceProcessState::AddToAutoRun(CommandLine* cmd_line) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool ServiceProcessState::RemoveFromAutoRun() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+CFDictionaryRef CreateServiceProcessLaunchdPlist(CommandLine* cmd_line) {
+  base::mac::ScopedNSAutoreleasePool pool;
+
+  NSString *program =
+      base::SysUTF8ToNSString(cmd_line->GetProgram().value());
+
+  std::vector<std::string> args = cmd_line->argv();
+  NSMutableArray *ns_args = [NSMutableArray arrayWithCapacity:args.size()];
+
+  for (std::vector<std::string>::iterator iter = args.begin();
+       iter < args.end();
+       ++iter) {
+    [ns_args addObject:base::SysUTF8ToNSString(*iter)];
+  }
+
+  NSDictionary *socket =
+      [NSDictionary dictionaryWithObject:GetServiceProcessLaunchDSocketEnvVar()
+                                  forKey:@ LAUNCH_JOBSOCKETKEY_SECUREWITHKEY];
+  NSDictionary *sockets =
+      [NSDictionary dictionaryWithObject:socket
+                                  forKey:GetServiceProcessLaunchDSocketKey()];
+
+  NSDictionary *launchd_plist =
+      [[NSDictionary alloc] initWithObjectsAndKeys:
+        GetServiceProcessLaunchDLabel(), @ LAUNCH_JOBKEY_LABEL,
+        program, @ LAUNCH_JOBKEY_PROGRAM,
+        ns_args, @ LAUNCH_JOBKEY_PROGRAMARGUMENTS,
+        sockets, @ LAUNCH_JOBKEY_SOCKETS,
+        nil];
+  return reinterpret_cast<CFDictionaryRef>(launchd_plist);
+}
diff --git a/chrome/common/service_process_util_posix.cc b/chrome/common/service_process_util_posix.cc
index 7deebaa..88c6db3 100644
--- a/chrome/common/service_process_util_posix.cc
+++ b/chrome/common/service_process_util_posix.cc
@@ -2,93 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/common/service_process_util.h"
+#include "chrome/common/service_process_util_posix.h"
 
-#include <signal.h>
-#include <unistd.h>
-
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
+#include "base/basictypes.h"
 #include "base/message_loop_proxy.h"
-#include "base/message_pump_libevent.h"
-#include "base/path_service.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_version_info.h"
-#include "chrome/common/multi_process_lock.h"
 
 namespace {
-
 int g_signal_socket = -1;
-
-// Gets the name of the lock file for service process.
-FilePath GetServiceProcessLockFilePath() {
-  FilePath user_data_dir;
-  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
-  chrome::VersionInfo version_info;
-  std::string lock_file_name = version_info.Version() + "Service Process Lock";
-  return user_data_dir.Append(lock_file_name);
 }
 
-// Attempts to take a lock named |name|. If |waiting| is true then this will
-// make multiple attempts to acquire the lock.
-// Caller is responsible for ownership of the MultiProcessLock.
-MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) {
-  scoped_ptr<MultiProcessLock> lock(MultiProcessLock::Create(name));
-  if (lock == NULL) return NULL;
-  bool got_lock = false;
-  for (int i = 0; i < 10; ++i) {
-    if (lock->TryLock()) {
-      got_lock = true;
-      break;
-    }
-    if (!waiting) break;
-    base::PlatformThread::Sleep(100 * i);
-  }
-  if (!got_lock) {
-    lock.reset();
-  }
-  return lock.release();
-}
-
-MultiProcessLock* TakeServiceRunningLock(bool waiting) {
-  std::string lock_name =
-      GetServiceProcessScopedName("_service_running");
-  return TakeNamedLock(lock_name, waiting);
-}
-
-MultiProcessLock* TakeServiceInitializingLock(bool waiting) {
-  std::string lock_name =
-      GetServiceProcessScopedName("_service_initializing");
-  return TakeNamedLock(lock_name, waiting);
-}
-
-}  // namespace
-
-// Watches for |kShutDownMessage| to be written to the file descriptor it is
-// watching. When it reads |kShutDownMessage|, it performs |shutdown_task_|.
-// Used here to monitor the socket listening to g_signal_socket.
-class ServiceProcessShutdownMonitor
-    : public base::MessagePumpLibevent::Watcher {
- public:
-
-  enum {
-    kShutDownMessage = 0xdecea5e
-  };
-
-  explicit ServiceProcessShutdownMonitor(Task* shutdown_task)
-      : shutdown_task_(shutdown_task) {
-  }
-
-  virtual ~ServiceProcessShutdownMonitor();
-
-  virtual void OnFileCanReadWithoutBlocking(int fd);
-  virtual void OnFileCanWriteWithoutBlocking(int fd);
-
- private:
-  scoped_ptr<Task> shutdown_task_;
-};
-
 ServiceProcessShutdownMonitor::~ServiceProcessShutdownMonitor() {
 }
 
@@ -125,66 +47,39 @@
   }
 }
 
-// See comment for SigTermHandler.
-bool ForceServiceProcessShutdown(const std::string& version,
-                                 base::ProcessId process_id) {
-  if (kill(process_id, SIGTERM) < 0) {
-    PLOG(ERROR) << "kill";
-    return false;
+void ServiceProcessState::StateData::SignalReady() {
+  CHECK(MessageLoopForIO::current()->WatchFileDescriptor(
+      sockets_[0], true, MessageLoopForIO::WATCH_READ,
+      &watcher_, shut_down_monitor_.get()));
+  g_signal_socket = sockets_[1];
+
+  // Set up signal handler for SIGTERM.
+  struct sigaction action;
+  action.sa_sigaction = SigTermHandler;
+  sigemptyset(&action.sa_mask);
+  action.sa_flags = SA_SIGINFO;
+  if (sigaction(SIGTERM, &action, &old_action_) == 0) {
+    // If the old_action is not default, somebody else has installed a
+    // a competing handler. Our handler is going to override it so it
+    // won't be called. If this occurs it needs to be fixed.
+    DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
+    set_action_ = true;
+#if defined(OS_LINUX)
+    initializing_lock_.reset();
+#endif  // OS_LINUX
+  } else {
+    PLOG(ERROR) << "sigaction";
   }
-  return true;
 }
 
-bool CheckServiceProcessReady() {
-  scoped_ptr<MultiProcessLock> running_lock(TakeServiceRunningLock(false));
-  return running_lock.get() == NULL;
-}
-
-struct ServiceProcessState::StateData
-    : public base::RefCountedThreadSafe<ServiceProcessState::StateData> {
-  scoped_ptr<MultiProcessLock> initializing_lock_;
-  scoped_ptr<MultiProcessLock> running_lock_;
-  scoped_ptr<ServiceProcessShutdownMonitor> shut_down_monitor_;
-  base::MessagePumpLibevent::FileDescriptorWatcher watcher_;
-  int sockets_[2];
-  struct sigaction old_action_;
-  bool set_action_;
-
-  // WatchFileDescriptor needs to be set up by the thread that is going
-  // to be monitoring it.
-  void SignalReady() {
-    CHECK(MessageLoopForIO::current()->WatchFileDescriptor(
-        sockets_[0], true, MessageLoopForIO::WATCH_READ,
-        &watcher_, shut_down_monitor_.get()));
-    g_signal_socket = sockets_[1];
-
-    // Set up signal handler for SIGTERM.
-    struct sigaction action;
-    action.sa_sigaction = SigTermHandler;
-    sigemptyset(&action.sa_mask);
-    action.sa_flags = SA_SIGINFO;
-    if (sigaction(SIGTERM, &action, &old_action_) == 0) {
-      // If the old_action is not default, somebody else has installed a
-      // a competing handler. Our handler is going to override it so it
-      // won't be called. If this occurs it needs to be fixed.
-      DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
-      set_action_ = true;
-      initializing_lock_.reset();
-    } else {
-      PLOG(ERROR) << "sigaction";
-    }
-  }
-};
-
-bool ServiceProcessState::TakeSingletonLock() {
+bool ServiceProcessState::InitializeState() {
   CHECK(!state_);
   state_ = new StateData;
   state_->AddRef();
   state_->sockets_[0] = -1;
   state_->sockets_[1] = -1;
   state_->set_action_ = false;
-  state_->initializing_lock_.reset(TakeServiceInitializingLock(true));
-  return state_->initializing_lock_.get();
+  return true;
 }
 
 bool ServiceProcessState::SignalReady(
@@ -192,10 +87,12 @@
   CHECK(state_);
   CHECK_EQ(g_signal_socket, -1);
 
+#if defined(OS_LINUX)
   state_->running_lock_.reset(TakeServiceRunningLock(true));
   if (state_->running_lock_.get() == NULL) {
     return false;
   }
+#endif // OS_LINUX
   state_->shut_down_monitor_.reset(
       new ServiceProcessShutdownMonitor(shutdown_task));
   if (pipe(state_->sockets_) < 0) {
@@ -207,16 +104,6 @@
   return true;
 }
 
-bool ServiceProcessState::AddToAutoRun() {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool ServiceProcessState::RemoveFromAutoRun() {
-  NOTIMPLEMENTED();
-  return false;
-}
-
 void ServiceProcessState::TearDownState() {
   g_signal_socket = -1;
   if (state_) {
diff --git a/chrome/common/service_process_util_posix.h b/chrome/common/service_process_util_posix.h
new file mode 100644
index 0000000..3263fb56
--- /dev/null
+++ b/chrome/common/service_process_util_posix.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SERVICE_PROCESS_UTIL_POSIX_H_
+#define CHROME_COMMON_SERVICE_PROCESS_UTIL_POSIX_H_
+
+#include "service_process_util.h"
+
+#include <signal.h>
+
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+#include "base/message_pump_libevent.h"
+#include "base/scoped_ptr.h"
+
+#if defined(OS_LINUX)
+#include "chrome/common/multi_process_lock.h"
+MultiProcessLock* TakeServiceRunningLock(bool waiting);
+#endif  // OS_LINUX
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_cftyperef.h"
+class CommandLine;
+CFDictionaryRef CreateServiceProcessLaunchdPlist(CommandLine* cmd_line);
+#endif  // OS_MACOSX
+
+// Watches for |kShutDownMessage| to be written to the file descriptor it is
+// watching. When it reads |kShutDownMessage|, it performs |shutdown_task_|.
+// Used here to monitor the socket listening to g_signal_socket.
+class ServiceProcessShutdownMonitor
+    : public base::MessagePumpLibevent::Watcher {
+ public:
+
+  enum {
+    kShutDownMessage = 0xdecea5e
+  };
+
+  explicit ServiceProcessShutdownMonitor(Task* shutdown_task)
+      : shutdown_task_(shutdown_task) {
+  }
+  virtual ~ServiceProcessShutdownMonitor();
+
+  // base::MessagePumpLibevent::Watcher overrides
+  virtual void OnFileCanReadWithoutBlocking(int fd);
+  virtual void OnFileCanWriteWithoutBlocking(int fd);
+
+ private:
+  scoped_ptr<Task> shutdown_task_;
+};
+
+struct ServiceProcessState::StateData
+    : public base::RefCountedThreadSafe<ServiceProcessState::StateData> {
+#if defined(OS_MACOSX)
+  base::mac::ScopedCFTypeRef<CFDictionaryRef> launchd_conf_;
+#endif  // OS_MACOSX
+#if defined(OS_LINUX)
+  scoped_ptr<MultiProcessLock> initializing_lock_;
+  scoped_ptr<MultiProcessLock> running_lock_;
+#endif  // OS_LINUX
+  scoped_ptr<ServiceProcessShutdownMonitor> shut_down_monitor_;
+  base::MessagePumpLibevent::FileDescriptorWatcher watcher_;
+  int sockets_[2];
+  struct sigaction old_action_;
+  bool set_action_;
+
+  // WatchFileDescriptor needs to be set up by the thread that is going
+  // to be monitoring it.
+  void SignalReady();
+};
+
+#endif  // CHROME_COMMON_SERVICE_PROCESS_UTIL_POSIX_H_
diff --git a/chrome/common/service_process_util_unittest.cc b/chrome/common/service_process_util_unittest.cc
index ad6b257..eadf51f 100644
--- a/chrome/common/service_process_util_unittest.cc
+++ b/chrome/common/service_process_util_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/basictypes.h"
+
+#if !defined(OS_MACOSX)
+// TODO(dmaclach): Figure out tests that will work with launchd on Mac OS.
+
 #include "base/at_exit.h"
 #include "base/process_util.h"
 #include "base/string_util.h"
@@ -95,11 +100,11 @@
   // GetServiceProcessPid to lie. On Windows, we use a named event so we
   // don't have this issue. Until we have a more stable shared memory
   // implementation on Posix, this check will only execute on Windows.
-  ASSERT_FALSE(GetServiceProcessSharedData(&version, &pid));
+  ASSERT_FALSE(GetServiceProcessData(&version, &pid));
 #endif  // defined(OS_WIN)
   ServiceProcessState* state = ServiceProcessState::GetInstance();
   ASSERT_TRUE(state->Initialize());
-  ASSERT_TRUE(GetServiceProcessSharedData(&version, &pid));
+  ASSERT_TRUE(GetServiceProcessData(&version, &pid));
   ASSERT_EQ(base::GetCurrentProcId(), pid);
 }
 
@@ -113,7 +118,7 @@
   ASSERT_TRUE(CheckServiceProcessReady());
   std::string version;
   base::ProcessId pid;
-  ASSERT_TRUE(GetServiceProcessSharedData(&version, &pid));
+  ASSERT_TRUE(GetServiceProcessData(&version, &pid));
   ASSERT_TRUE(ForceServiceProcessShutdown(version, pid));
   int exit_code = 0;
   ASSERT_TRUE(base::WaitForExitCodeWithTimeout(handle,
@@ -157,3 +162,4 @@
   return 0;
 }
 
+#endif  // !OS_MACOSX
diff --git a/chrome/common/service_process_util_win.cc b/chrome/common/service_process_util_win.cc
index f9a18166..b617988 100644
--- a/chrome/common/service_process_util_win.cc
+++ b/chrome/common/service_process_util_win.cc
@@ -28,6 +28,10 @@
       GetServiceProcessScopedVersionedName("_service_shutdown_evt"));
 }
 
+std::string GetServiceProcessAutoRunKey() {
+  return GetServiceProcessScopedName("_service_run");
+}
+
 class ServiceProcessShutdownMonitor
     : public base::win::ObjectWatcher::Delegate {
  public:
@@ -85,8 +89,14 @@
   scoped_ptr<ServiceProcessShutdownMonitor> shutdown_monitor;
 };
 
-bool ServiceProcessState::TakeSingletonLock() {
+bool ServiceProcessState::InitializeState() {
   DCHECK(!state_);
+  state_ = new StateData;
+  return true;
+}
+
+bool ServiceProcessState::TakeSingletonLock() {
+  DCHECK(state_);
   string16 event_name = GetServiceProcessReadyEventName();
   CHECK(event_name.length() <= MAX_PATH);
   base::win::ScopedHandle service_process_ready_event;
@@ -96,7 +106,6 @@
   if ((error == ERROR_ALREADY_EXISTS) || (error == ERROR_ACCESS_DENIED))
     return false;
   DCHECK(service_process_ready_event.IsValid());
-  state_ = new StateData;
   state_->ready_event.Set(service_process_ready_event.Take());
   return true;
 }
@@ -116,25 +125,16 @@
   return true;
 }
 
-bool ServiceProcessState::AddToAutoRun() {
-  FilePath chrome_path;
-  if (PathService::Get(base::FILE_EXE, &chrome_path)) {
-    CommandLine cmd_line(chrome_path);
-    cmd_line.AppendSwitchASCII(switches::kProcessType,
-                               switches::kServiceProcess);
-    // We need a unique name for the command per user-date-dir. Just use the
-    // channel name.
-    return base::win::AddCommandToAutoRun(
-        HKEY_CURRENT_USER,
-        UTF8ToWide(GetAutoRunKey()),
-        cmd_line.command_line_string());
-  }
-  return false;
+bool ServiceProcessState::AddToAutoRun(CommandLine* cmd_line) {
+  return base::win::AddCommandToAutoRun(
+      HKEY_CURRENT_USER,
+      UTF8ToWide(GetServiceProcessAutoRunKey()),
+      cmd_line->command_line_string());
 }
 
 bool ServiceProcessState::RemoveFromAutoRun() {
   return base::win::RemoveCommandFromAutoRun(
-      HKEY_CURRENT_USER, UTF8ToWide(GetAutoRunKey()));
+      HKEY_CURRENT_USER, UTF8ToWide(GetServiceProcessAutoRunKey()));
 }
 
 void ServiceProcessState::TearDownState() {
diff --git a/chrome/service/service_ipc_server.cc b/chrome/service/service_ipc_server.cc
index 5e503c8..5257eec 100644
--- a/chrome/service/service_ipc_server.cc
+++ b/chrome/service/service_ipc_server.cc
@@ -9,8 +9,8 @@
 #include "chrome/service/service_process.h"
 #include "ipc/ipc_logging.h"
 
-ServiceIPCServer::ServiceIPCServer(const std::string& channel_name)
-    : channel_name_(channel_name), client_connected_(false) {
+ServiceIPCServer::ServiceIPCServer(const IPC::ChannelHandle& channel_handle)
+    : channel_handle_(channel_handle), client_connected_(false) {
 }
 
 bool ServiceIPCServer::Init() {
@@ -24,7 +24,7 @@
 }
 
 void ServiceIPCServer::CreateChannel() {
-  channel_.reset(new IPC::SyncChannel(channel_name_,
+  channel_.reset(new IPC::SyncChannel(channel_handle_,
       IPC::Channel::MODE_NAMED_SERVER, this,
       g_service_process->io_thread()->message_loop(), true,
       g_service_process->shutdown_event()));
@@ -63,8 +63,16 @@
   client_connected_ = false;
   // TODO(sanjeevr): Instead of invoking the service process for such handlers,
   // define a Client interface that the ServiceProcess can implement.
-  if (client_was_connected && g_service_process->HandleClientDisconnect()) {
-    CreateChannel();
+  if (client_was_connected) {
+    if (g_service_process->HandleClientDisconnect()) {
+      CreateChannel();
+    }
+  } else {
+    // If the client was never even connected we had an error connecting.
+    if (!client_connected_) {
+      LOG(ERROR) << "Unable to open service ipc channel "
+                 << "named: " << channel_handle_.name;
+    }
   }
 }
 
diff --git a/chrome/service/service_ipc_server.h b/chrome/service/service_ipc_server.h
index 675135e..0777ec80 100644
--- a/chrome/service/service_ipc_server.h
+++ b/chrome/service/service_ipc_server.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/scoped_ptr.h"
+#include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_sync_channel.h"
 #include "ipc/ipc_sync_message_filter.h"
 #include "ipc/ipc_message.h"
@@ -16,7 +17,7 @@
 class ServiceIPCServer : public IPC::Channel::Listener,
                          public IPC::Message::Sender {
  public:
-  explicit ServiceIPCServer(const std::string& channel_name);
+  explicit ServiceIPCServer(const IPC::ChannelHandle& handle);
   virtual ~ServiceIPCServer();
 
   bool Init();
@@ -65,7 +66,7 @@
   // Helper method to create the sync channel.
   void CreateChannel();
 
-  std::string channel_name_;
+  IPC::ChannelHandle channel_handle_;
   scoped_ptr<IPC::SyncChannel> channel_;
   // Indicates whether a client is currently connected to the channel.
   bool client_connected_;
diff --git a/chrome/service/service_process.cc b/chrome/service/service_process.cc
index b49bdb1..9c0a8c8 100644
--- a/chrome/service/service_process.cc
+++ b/chrome/service/service_process.cc
@@ -205,19 +205,21 @@
   }
 
   VLOG(1) << "Starting Service Process IPC Server";
-  ipc_server_.reset(new ServiceIPCServer(GetServiceProcessChannelName()));
+  ServiceProcessState* state = ServiceProcessState::GetInstance();
+  ipc_server_.reset(new ServiceIPCServer(state->GetServiceProcessChannel()));
   ipc_server_->Init();
 
   // After the IPC server has started we signal that the service process is
   // ready.
-  if (!ServiceProcessState::GetInstance()->SignalReady(
-          io_thread_->message_loop_proxy(),
-          NewRunnableMethod(this, &ServiceProcess::Shutdown))) {
+  if (!state->SignalReady(io_thread_->message_loop_proxy(),
+                          NewRunnableMethod(this, &ServiceProcess::Shutdown))) {
     return false;
   }
 
   // See if we need to stay running.
   ScheduleShutdownCheck();
+  command_line_.reset(new CommandLine(command_line));
+
   return true;
 }
 
@@ -307,7 +309,7 @@
 void ServiceProcess::OnServiceEnabled() {
   enabled_services_++;
   if (1 == enabled_services_) {
-    ServiceProcessState::GetInstance()->AddToAutoRun();
+    ServiceProcessState::GetInstance()->AddToAutoRun(command_line_.get());
   }
 }
 
diff --git a/chrome/service/service_process.h b/chrome/service/service_process.h
index 8a84efd..9d4d6f3 100644
--- a/chrome/service/service_process.h
+++ b/chrome/service/service_process.h
@@ -18,6 +18,7 @@
 
 class ServiceProcessPrefs;
 class ServiceIPCServer;
+class CommandLine;
 
 namespace net {
 class NetworkChangeNotifier;
@@ -132,6 +133,7 @@
 #if defined(ENABLE_REMOTING)
   scoped_refptr<remoting::ChromotingHostManager> remoting_host_manager_;
 #endif
+  scoped_ptr<CommandLine> command_line_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceProcess);
 };
diff --git a/ipc/ipc_channel_posix.cc b/ipc/ipc_channel_posix.cc
index 07d205a9b..ab8a06c 100644
--- a/ipc/ipc_channel_posix.cc
+++ b/ipc/ipc_channel_posix.cc
@@ -386,11 +386,11 @@
 #endif   // IPC_USES_READWRITE
   } else if (mode_ & MODE_NAMED_FLAG) {
     // Case 2 from comment above.
-    must_unlink_ = true;
     if (mode_ & MODE_SERVER_FLAG) {
       if (!CreateServerUnixDomainSocket(pipe_name_, &pipe_)) {
         return false;
       }
+      must_unlink_ = true;
     } else if (mode_ & MODE_CLIENT_FLAG) {
       if (!CreateClientUnixDomainSocket(pipe_name_, &pipe_)) {
         return false;