| Index: base/process_util_posix.cc | 
| diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc | 
| index 21626732b8c23eac4a1d59bfea816dca70c35fc8..a771fa25293cc810026157c129b03a04931cfd80 100644 | 
| --- a/base/process_util_posix.cc | 
| +++ b/base/process_util_posix.cc | 
| @@ -21,11 +21,16 @@ | 
| #include "base/logging.h" | 
| #include "base/platform_thread.h" | 
| #include "base/process_util.h" | 
| +#include "base/rand_util.h" | 
| #include "base/scoped_ptr.h" | 
| #include "base/sys_info.h" | 
| #include "base/time.h" | 
| #include "base/waitable_event.h" | 
|  | 
| +#if defined(OS_MACOSX) | 
| +#include "base/mach_ipc_mac.h" | 
| +#endif | 
| + | 
| const int kMicrosecondsPerSecond = 1000000; | 
|  | 
| namespace base { | 
| @@ -280,11 +285,148 @@ void SetAllFDsToCloseOnExec() { | 
| } | 
| } | 
|  | 
| +#if defined(OS_MACOSX) | 
| +static std::string MachErrorCode(kern_return_t err) { | 
| +  return StringPrintf("0x%x %s", err, mach_error_string(err)); | 
| +} | 
| + | 
| +// Forks the current process and returns the child's |task_t| in the parent | 
| +// process. | 
| +static pid_t fork_and_get_task(task_t* child_task) { | 
| +  const int kTimeoutMs = 100; | 
| +  kern_return_t err; | 
| + | 
| +  // Put a random number into the channel name, so that a compromised renderer | 
| +  // can't pretend being the child that's forked off. | 
| +  std::string mach_connection_name = StringPrintf( | 
| +      "com.google.Chrome.samplingfork.%p.%d", | 
| +      child_task, base::RandInt(0, std::numeric_limits<int>::max())); | 
| +  ReceivePort parent_recv_port(mach_connection_name.c_str()); | 
| + | 
| +  // Error handling philosophy: If Mach IPC fails, don't touch |child_task| but | 
| +  // return a valid pid. If IPC fails in the child, the parent will have to wait | 
| +  // until kTimeoutMs is over. This is not optimal, but I've never seen it | 
| +  // happen, and stuff should still mostly work. | 
| +  pid_t pid = fork(); | 
| +  switch (pid) { | 
| +    case -1: | 
| +      return pid; | 
| +    case 0: {  // child | 
| +      ReceivePort child_recv_port; | 
| + | 
| +      MachSendMessage child_message(/* id= */0); | 
| +      if (!child_message.AddDescriptor(mach_task_self())) { | 
| +        LOG(ERROR) << "child AddDescriptor(mach_task_self()) failed."; | 
| +        return pid; | 
| +      } | 
| +      mach_port_t raw_child_recv_port = child_recv_port.GetPort(); | 
| +      if (!child_message.AddDescriptor(raw_child_recv_port)) { | 
| +        LOG(ERROR) << "child AddDescriptor(" << raw_child_recv_port | 
| +                   << ") failed."; | 
| +        return pid; | 
| +      } | 
| + | 
| +      MachPortSender child_sender(mach_connection_name.c_str()); | 
| +      err = child_sender.SendMessage(child_message, kTimeoutMs); | 
| +      if (err != KERN_SUCCESS) { | 
| +        LOG(ERROR) << "child SendMessage() failed: " << MachErrorCode(err); | 
| +        return pid; | 
| +      } | 
| + | 
| +      MachReceiveMessage parent_message; | 
| +      err = child_recv_port.WaitForMessage(&parent_message, kTimeoutMs); | 
| +      if (err != KERN_SUCCESS) { | 
| +        LOG(ERROR) << "child WaitForMessage() failed: " << MachErrorCode(err); | 
| +        return pid; | 
| +      } | 
| + | 
| +      if (parent_message.GetTranslatedPort(0) == MACH_PORT_NULL) { | 
| +        LOG(ERROR) << "child GetTranslatedPort(0) failed."; | 
| +        return pid; | 
| +      } | 
| +      err = task_set_bootstrap_port(mach_task_self(), | 
| +                                    parent_message.GetTranslatedPort(0)); | 
| +      if (err != KERN_SUCCESS) { | 
| +        LOG(ERROR) << "child task_set_bootstrap_port() failed: " | 
| +                   << MachErrorCode(err); | 
| +        return pid; | 
| +      } | 
| +      break; | 
| +    } | 
| +    default: {  // parent | 
| +      MachReceiveMessage child_message; | 
| +      err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs); | 
| +      if (err != KERN_SUCCESS) { | 
| +        LOG(ERROR) << "parent WaitForMessage() failed: " << MachErrorCode(err); | 
| +        return pid; | 
| +      } | 
| + | 
| +      if (child_message.GetTranslatedPort(0) == MACH_PORT_NULL) { | 
| +        LOG(ERROR) << "parent GetTranslatedPort(0) failed."; | 
| +        return pid; | 
| +      } | 
| +      *child_task = child_message.GetTranslatedPort(0); | 
| + | 
| +      if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) { | 
| +        LOG(ERROR) << "parent GetTranslatedPort(1) failed."; | 
| +        return pid; | 
| +      } | 
| +      MachPortSender parent_sender(child_message.GetTranslatedPort(1)); | 
| + | 
| +      MachSendMessage parent_message(/* id= */0); | 
| +      if (!parent_message.AddDescriptor(bootstrap_port)) { | 
| +        LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed."; | 
| +        return pid; | 
| +      } | 
| + | 
| +      err = parent_sender.SendMessage(parent_message, kTimeoutMs); | 
| +      if (err != KERN_SUCCESS) { | 
| +        LOG(ERROR) << "parent SendMessage() failed: " << MachErrorCode(err); | 
| +        return pid; | 
| +      } | 
| +      break; | 
| +    } | 
| +  } | 
| +  return pid; | 
| +} | 
| + | 
| bool LaunchApp(const std::vector<std::string>& argv, | 
| const environment_vector& environ, | 
| const file_handle_mapping_vector& fds_to_remap, | 
| bool wait, ProcessHandle* process_handle) { | 
| -  pid_t pid = fork(); | 
| +  return LaunchAppAndGetTask( | 
| +      argv, environ, fds_to_remap, wait, NULL, process_handle); | 
| +} | 
| +#endif  // defined(OS_MACOSX) | 
| + | 
| +#if defined(OS_MACOSX) | 
| +bool LaunchAppAndGetTask( | 
| +#else | 
| +bool LaunchApp( | 
| +#endif | 
| +    const std::vector<std::string>& argv, | 
| +    const environment_vector& environ, | 
| +    const file_handle_mapping_vector& fds_to_remap, | 
| +    bool wait, | 
| +#if defined(OS_MACOSX) | 
| +    task_t* task_handle, | 
| +#endif | 
| +    ProcessHandle* process_handle) { | 
| +  pid_t pid; | 
| +#if defined(OS_MACOSX) | 
| +  if (task_handle == NULL) { | 
| +    pid = fork(); | 
| +  } else { | 
| +    // On OS X, the task_t for a process is needed for several reasons. Sadly, | 
| +    // the function task_for_pid() requires privileges a normal user doesn't | 
| +    // have. Instead, a short-lived Mach IPC connection is opened between parent | 
| +    // and child, and the child sends its task_t to the parent at fork time. | 
| +    *task_handle = MACH_PORT_NULL; | 
| +    pid = fork_and_get_task(task_handle); | 
| +  } | 
| +#else | 
| +  pid = fork(); | 
| +#endif | 
| if (pid < 0) | 
| return false; | 
|  | 
|  |