Merge "Log stderr of secilc"
am: 8b4e7fe486

Change-Id: Ifb78f10609d36e4f20a45745f77e075d439ed861
diff --git a/init/init.cpp b/init/init.cpp
index 28e6008..81f228c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -621,11 +621,21 @@
 
 /*
  * Forks, executes the provided program in the child, and waits for the completion in the parent.
+ * Child's stderr is captured and logged using LOG(ERROR).
  *
  * Returns true if the child exited with status code 0, returns false otherwise.
  */
 static bool fork_execve_and_wait_for_completion(const char* filename, char* const argv[],
                                                 char* const envp[]) {
+    // Create a pipe used for redirecting child process's output.
+    // * pipe_fds[0] is the FD the parent will use for reading.
+    // * pipe_fds[1] is the FD the child will use for writing.
+    int pipe_fds[2];
+    if (pipe(pipe_fds) == -1) {
+        PLOG(ERROR) << "Failed to create pipe";
+        return false;
+    }
+
     pid_t child_pid = fork();
     if (child_pid == -1) {
         PLOG(ERROR) << "Failed to fork for " << filename;
@@ -634,6 +644,18 @@
 
     if (child_pid == 0) {
         // fork succeeded -- this is executing in the child process
+
+        // Close the pipe FD not used by this process
+        TEMP_FAILURE_RETRY(close(pipe_fds[0]));
+
+        // Redirect stderr to the pipe FD provided by the parent
+        if (TEMP_FAILURE_RETRY(dup2(pipe_fds[1], STDERR_FILENO)) == -1) {
+            PLOG(ERROR) << "Failed to redirect stderr of " << filename;
+            _exit(127);
+            return false;
+        }
+        TEMP_FAILURE_RETRY(close(pipe_fds[1]));
+
         if (execve(filename, argv, envp) == -1) {
             PLOG(ERROR) << "Failed to execve " << filename;
             return false;
@@ -644,6 +666,30 @@
         return false;
     } else {
         // fork succeeded -- this is executing in the original/parent process
+
+        // Close the pipe FD not used by this process
+        TEMP_FAILURE_RETRY(close(pipe_fds[1]));
+
+        // Log the redirected output of the child process.
+        // It's unfortunate that there's no standard way to obtain an istream for a file descriptor.
+        // As a result, we're buffering all output and logging it in one go at the end of the
+        // invocation, instead of logging it as it comes in.
+        const int child_out_fd = pipe_fds[0];
+        std::string child_output;
+        if (!android::base::ReadFdToString(child_out_fd, &child_output)) {
+            PLOG(ERROR) << "Failed to capture full output of " << filename;
+        }
+        TEMP_FAILURE_RETRY(close(child_out_fd));
+        if (!child_output.empty()) {
+            // Log captured output, line by line, because LOG expects to be invoked for each line
+            std::istringstream in(child_output);
+            std::string line;
+            while (std::getline(in, line)) {
+                LOG(ERROR) << filename << ": " << line;
+            }
+        }
+
+        // Wait for child to terminate
         int status;
         if (TEMP_FAILURE_RETRY(waitpid(child_pid, &status, 0)) != child_pid) {
             PLOG(ERROR) << "Failed to wait for " << filename;