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

Unified Diff: base/process_util_posix.cc

Issue 549002: Mac: Other approach for IPCing child task_ts. (Closed)
Patch Set: '' Created 10 years, 11 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
« no previous file with comments | « base/process_util.h ('k') | chrome/browser/child_process_launcher.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
« no previous file with comments | « base/process_util.h ('k') | chrome/browser/child_process_launcher.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698