runtime: send android stderr to /dev/log/main

I tried to submit this in Go 1.4 as cl/107540044 but tripped over the
changes for getting C off the G stack. This is a rewritten version that
avoids cgo and works directly with the underlying log device.

Change-Id: I14c227dbb4202690c2c67c5a613d6c6689a6662a
Reviewed-on: https://go-review.googlesource.com/1285
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/runtime/print1.go b/src/runtime/print1.go
index 3d812bd..7bec559 100644
--- a/src/runtime/print1.go
+++ b/src/runtime/print1.go
@@ -75,7 +75,7 @@
 	}
 	gp := getg()
 	if gp == nil || gp.writebuf == nil {
-		write(2, unsafe.Pointer(&b[0]), int32(len(b)))
+		writeErr(b)
 		return
 	}
 
diff --git a/src/runtime/print1_write.go b/src/runtime/print1_write.go
new file mode 100644
index 0000000..5fd7d65
--- /dev/null
+++ b/src/runtime/print1_write.go
@@ -0,0 +1,9 @@
+// +build !android
+
+package runtime
+
+import "unsafe"
+
+func writeErr(b []byte) {
+	write(2, unsafe.Pointer(&b[0]), int32(len(b)))
+}
diff --git a/src/runtime/print1_write_android.go b/src/runtime/print1_write_android.go
new file mode 100644
index 0000000..d086e84
--- /dev/null
+++ b/src/runtime/print1_write_android.go
@@ -0,0 +1,44 @@
+package runtime
+
+import "unsafe"
+
+var (
+	writeHeader = []byte{6 /* ANDROID_LOG_ERROR */, 'G', 'o', 0}
+	writePath   = []byte("/dev/log/main\x00")
+	writeFD     uintptr
+	writeBuf    [1024]byte
+	writePos    int
+)
+
+func writeErr(b []byte) {
+	// Log format: "<priority 1 byte><tag n bytes>\x00<message m bytes>\x00"
+	// The entire log needs to be delivered in a single syscall (the NDK
+	// does this with writev). Each log is its own line, so we need to
+	// buffer writes until we see a newline.
+	if writeFD == 0 {
+		writeFD = uintptr(open(&writePath[0], 0x1 /* O_WRONLY */, 0))
+		if writeFD == 0 {
+			// It is hard to do anything here. Write to stderr just
+			// in case user has root on device and has run
+			//	adb shell setprop log.redirect-stdio true
+			msg := []byte("runtime: cannot open /dev/log/main\x00")
+			write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
+			exit(2)
+		}
+		copy(writeBuf[:], writeHeader)
+	}
+	dst := writeBuf[len(writeHeader):]
+	for _, v := range b {
+		if v == 0 { // android logging won't print a zero byte
+			v = '0'
+		}
+		dst[writePos] = v
+		writePos++
+		if v == '\n' || writePos == len(dst)-1 {
+			dst[writePos] = 0
+			write(writeFD, unsafe.Pointer(&writeBuf[0]), int32(len(writeHeader)+writePos))
+			memclrBytes(dst)
+			writePos = 0
+		}
+	}
+}