os/exec: post-process lsof output on Android.

lsof is used to inspect the open file desciptors in exec_test.go.
In order to limit the output of lsof to the tested process, the tests use
lsof with the -p option, but the version of lsof in android seems to ignore
it. This change adds a post-processing step to filter out irrelevant entries.

Fixes golang/go#10206.

Change-Id: Ia789b8f5e1e9b95c7b55deac92d0d1fbf3ee74fb
Reviewed-on: https://go-review.googlesource.com/8025
Reviewed-by: David Crawshaw <crawshaw@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index ebaef99..d3dec57 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -251,6 +251,12 @@
 }
 
 func numOpenFDS(t *testing.T) (n int, lsof []byte) {
+	if runtime.GOOS == "android" {
+		// Android's stock lsof does not obey the -p option,
+		// so extra filtering is needed. (golang.org/issue/10206)
+		return numOpenFDsAndroid(t)
+	}
+
 	lsof, err := exec.Command("lsof", "-b", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
 	if err != nil {
 		t.Skip("skipping test; error finding or running lsof")
@@ -258,6 +264,45 @@
 	return bytes.Count(lsof, []byte("\n")), lsof
 }
 
+func numOpenFDsAndroid(t *testing.T) (n int, lsof []byte) {
+	raw, err := exec.Command("lsof").Output()
+	if err != nil {
+		t.Skip("skipping test; error finding or running lsof")
+	}
+
+	// First find the PID column index by parsing the first line, and
+	// select lines containing pid in the column.
+	pid := []byte(strconv.Itoa(os.Getpid()))
+	pidCol := -1
+
+	s := bufio.NewScanner(bytes.NewReader(raw))
+	for s.Scan() {
+		line := s.Bytes()
+		fields := bytes.Fields(line)
+		if pidCol < 0 {
+			for i, v := range fields {
+				if bytes.Equal(v, []byte("PID")) {
+					pidCol = i
+					break
+				}
+			}
+			lsof = append(lsof, line...)
+			continue
+		}
+		if bytes.Equal(fields[pidCol], pid) {
+			lsof = append(lsof, '\n')
+			lsof = append(lsof, line...)
+		}
+	}
+	if pidCol < 0 {
+		t.Fatal("error processing lsof output: unexpected header format")
+	}
+	if err := s.Err(); err != nil {
+		t.Fatalf("error processing lsof output: %v", err)
+	}
+	return bytes.Count(lsof, []byte("\n")), lsof
+}
+
 var testedAlreadyLeaked = false
 
 // basefds returns the number of expected file descriptors