Honor exit codes in run_android_tests.go.

adb kindly doesn't forward exit codes until N
(https://code.google.com/p/android/issues/detail?id=3254), so we need to work
around it. Otherwise all our test failures have been silently ignored (oops!).

Change-Id: I03440db7dd77e6b9af5445b309b67dc719cea054
Reviewed-on: https://boringssl-review.googlesource.com/8190
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/util/run_android_tests.go b/util/run_android_tests.go
index fc94d33..6502a16 100644
--- a/util/run_android_tests.go
+++ b/util/run_android_tests.go
@@ -15,6 +15,7 @@
 package main
 
 import (
+	"bytes"
 	"encoding/json"
 	"flag"
 	"fmt"
@@ -23,6 +24,7 @@
 	"os"
 	"os/exec"
 	"path/filepath"
+	"strconv"
 	"strings"
 )
 
@@ -56,6 +58,55 @@
 	return cmd.Run()
 }
 
+func adbShell(shellCmd string) (int, error) {
+	var args []string
+	if len(*device) > 0 {
+		args = append([]string{"-s", *device}, args...)
+	}
+	args = append(args, "shell")
+
+	const delimiter = "___EXIT_CODE___"
+
+	// Older versions of adb and Android do not preserve the exit
+	// code, so work around this.
+	// https://code.google.com/p/android/issues/detail?id=3254
+	shellCmd += "; echo " + delimiter + " $?"
+	args = append(args, shellCmd)
+
+	cmd := exec.Command(*adbPath, args...)
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		return 0, err
+	}
+	cmd.Stderr = os.Stderr
+	if err := cmd.Start(); err != nil {
+		return 0, err
+	}
+
+	var stdoutBytes bytes.Buffer
+	for {
+		var buf [1024]byte
+		n, err := stdout.Read(buf[:])
+		stdoutBytes.Write(buf[:n])
+		os.Stdout.Write(buf[:n])
+		if err != nil {
+			break
+		}
+	}
+
+	if err := cmd.Wait(); err != nil {
+		return 0, err
+	}
+
+	stdoutStr := stdoutBytes.String()
+	idx := strings.LastIndex(stdoutStr, delimiter)
+	if idx < 0 {
+		return 0, fmt.Errorf("Could not find delimiter in output.")
+	}
+
+	return strconv.Atoi(strings.TrimSpace(stdoutStr[idx+len(delimiter):]))
+}
+
 func goTool(args ...string) error {
 	cmd := exec.Command("go", args...)
 	cmd.Stdout = os.Stdout
@@ -227,17 +278,21 @@
 		os.Exit(1)
 	}
 
+	var unitTestExit int
 	if enableUnitTests() {
 		fmt.Printf("Running unit tests...\n")
-		if err := adb("shell", fmt.Sprintf("cd /data/local/tmp/boringssl-tmp && ./util/all_tests -json-output results.json %s", *allTestsArgs)); err != nil {
+		unitTestExit, err = adbShell(fmt.Sprintf("cd /data/local/tmp/boringssl-tmp && ./util/all_tests -json-output results.json %s", *allTestsArgs))
+		if err != nil {
 			fmt.Printf("Failed to run unit tests: %s\n", err)
 			os.Exit(1)
 		}
 	}
 
+	var sslTestExit int
 	if enableSSLTests() {
 		fmt.Printf("Running SSL tests...\n")
-		if err := adb("shell", fmt.Sprintf("cd /data/local/tmp/boringssl-tmp/ssl/test/runner && ./runner -json-output ../../../results.json %s", *runnerArgs)); err != nil {
+		sslTestExit, err = adbShell(fmt.Sprintf("cd /data/local/tmp/boringssl-tmp/ssl/test/runner && ./runner -json-output ../../../results.json %s", *runnerArgs))
+		if err != nil {
 			fmt.Printf("Failed to run SSL tests: %s\n", err)
 			os.Exit(1)
 		}
@@ -249,4 +304,12 @@
 			os.Exit(1)
 		}
 	}
+
+	if unitTestExit != 0 {
+		os.Exit(unitTestExit)
+	}
+
+	if sslTestExit != 0 {
+		os.Exit(sslTestExit)
+	}
 }