- // Now set-up this process to be tracked by the Zygote.
- if (process_info_map_.find(real_pid) != process_info_map_.end()) {
- LOG(ERROR) << "Already tracking PID " << real_pid;
- NOTREACHED();
- }
- process_info_map_[real_pid].internal_pid = pid;
- process_info_map_[real_pid].started_from_helper = use_helper;
-
- if (use_helper) {
- if (!helper_->AckChild(pipe_fds[1], channel_switch)) {
- LOG(ERROR) << "Failed to synchronise with zygote fork helper";
- goto error;
- }
- } else {
- int written =
- HANDLE_EINTR(write(pipe_fds[1], &real_pid, sizeof(real_pid)));
- if (written != sizeof(real_pid)) {
- LOG(ERROR) << "Failed to synchronise with child process";
- goto error;
- }
+ // In the parent process.
+ read_pipe.reset();
+ pid_oracle.reset();
+
+ // Always receive a real PID from the zygote host, though it might
+ // be invalid (see below).
+ base::ProcessId real_pid;
+ {
+ ScopedVector<base::ScopedFD> recv_fds;
+ char buf[kZygoteMaxMessageLength];
+ const ssize_t len = UnixDomainSocket::RecvMsg(
+ kZygoteSocketPairFd, buf, sizeof(buf), &recv_fds);
+ CHECK_GT(len, 0);
+ CHECK(recv_fds.empty());
+
+ Pickle pickle(buf, len);
+ PickleIterator iter(pickle);
+
+ int kind;
+ CHECK(pickle.ReadInt(&iter, &kind));
+ CHECK(kind == kZygoteCommandForkRealPID);
+ CHECK(pickle.ReadInt(&iter, &real_pid));
+ }
+
+ // Fork failed.
+ if (pid < 0) {
+ return -1;
+ }
+
+ // If we successfully forked a child, but it crashed without sending
+ // a message to the browser, the browser won't have found its PID.
+ if (real_pid < 0) {
+ KillAndReap(pid, use_helper);
+ return -1;
+ }
+
+ // If we're not using a helper, send the PID back to the child process.
+ if (!use_helper) {
+ ssize_t written =
+ HANDLE_EINTR(write(write_pipe.get(), &real_pid, sizeof(real_pid)));
+ if (written != sizeof(real_pid)) {
+ KillAndReap(pid, use_helper);
+ return -1;