Home | History | Annotate | Download | only in runtime
      1 // Copyright 2014 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package runtime
      6 
      7 import "unsafe"
      8 
      9 var (
     10 	writeHeader = []byte{6 /* ANDROID_LOG_ERROR */, 'G', 'o', 0}
     11 	writePath   = []byte("/dev/log/main\x00")
     12 	writeLogd   = []byte("/dev/socket/logdw\x00")
     13 
     14 	// guarded by printlock/printunlock.
     15 	writeFD  uintptr
     16 	writeBuf [1024]byte
     17 	writePos int
     18 )
     19 
     20 // Prior to Android-L, logging was done through writes to /dev/log files implemented
     21 // in kernel ring buffers. In Android-L, those /dev/log files are no longer
     22 // accessible and logging is done through a centralized user-mode logger, logd.
     23 //
     24 // https://android.googlesource.com/platform/system/core/+/master/liblog/logd_write.c
     25 type loggerType int32
     26 
     27 const (
     28 	unknown loggerType = iota
     29 	legacy
     30 	logd
     31 	// TODO(hakim): logging for emulator?
     32 )
     33 
     34 var logger loggerType
     35 
     36 func writeErr(b []byte) {
     37 	if logger == unknown {
     38 		// Use logd if /dev/socket/logdw is available.
     39 		if v := uintptr(access(&writeLogd[0], 0x02 /* W_OK */)); v == 0 {
     40 			logger = logd
     41 			initLogd()
     42 		} else {
     43 			logger = legacy
     44 			initLegacy()
     45 		}
     46 	}
     47 
     48 	// Write to stderr for command-line programs.
     49 	write(2, unsafe.Pointer(&b[0]), int32(len(b)))
     50 
     51 	// Log format: "<header>\x00<message m bytes>\x00"
     52 	//
     53 	// <header>
     54 	//   In legacy mode: "<priority 1 byte><tag n bytes>".
     55 	//   In logd mode: "<android_log_header_t 11 bytes><priority 1 byte><tag n bytes>"
     56 	//
     57 	// The entire log needs to be delivered in a single syscall (the NDK
     58 	// does this with writev). Each log is its own line, so we need to
     59 	// buffer writes until we see a newline.
     60 	var hlen int
     61 	switch logger {
     62 	case logd:
     63 		hlen = writeLogdHeader()
     64 	case legacy:
     65 		hlen = len(writeHeader)
     66 	}
     67 
     68 	dst := writeBuf[hlen:]
     69 	for _, v := range b {
     70 		if v == 0 { // android logging won't print a zero byte
     71 			v = '0'
     72 		}
     73 		dst[writePos] = v
     74 		writePos++
     75 		if v == '\n' || writePos == len(dst)-1 {
     76 			dst[writePos] = 0
     77 			write(writeFD, unsafe.Pointer(&writeBuf[0]), int32(hlen+writePos))
     78 			memclrBytes(dst)
     79 			writePos = 0
     80 		}
     81 	}
     82 }
     83 
     84 func initLegacy() {
     85 	// In legacy mode, logs are written to /dev/log/main
     86 	writeFD = uintptr(open(&writePath[0], 0x1 /* O_WRONLY */, 0))
     87 	if writeFD == 0 {
     88 		// It is hard to do anything here. Write to stderr just
     89 		// in case user has root on device and has run
     90 		//	adb shell setprop log.redirect-stdio true
     91 		msg := []byte("runtime: cannot open /dev/log/main\x00")
     92 		write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
     93 		exit(2)
     94 	}
     95 
     96 	// Prepopulate the invariant header part.
     97 	copy(writeBuf[:len(writeHeader)], writeHeader)
     98 }
     99 
    100 // used in initLogdWrite but defined here to avoid heap allocation.
    101 var logdAddr sockaddr_un
    102 
    103 func initLogd() {
    104 	// In logd mode, logs are sent to the logd via a unix domain socket.
    105 	logdAddr.family = _AF_UNIX
    106 	copy(logdAddr.path[:], writeLogd)
    107 
    108 	// We are not using non-blocking I/O because writes taking this path
    109 	// are most likely triggered by panic, we cannot think of the advantage of
    110 	// non-blocking I/O for panic but see disadvantage (dropping panic message),
    111 	// and blocking I/O simplifies the code a lot.
    112 	fd := socket(_AF_UNIX, _SOCK_DGRAM|_O_CLOEXEC, 0)
    113 	if fd < 0 {
    114 		msg := []byte("runtime: cannot create a socket for logging\x00")
    115 		write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
    116 		exit(2)
    117 	}
    118 
    119 	errno := connect(uintptr(fd), unsafe.Pointer(&logdAddr), int32(unsafe.Sizeof(logdAddr)))
    120 	if errno < 0 {
    121 		msg := []byte("runtime: cannot connect to /dev/socket/logdw\x00")
    122 		write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
    123 		// TODO(hakim): or should we just close fd and hope for better luck next time?
    124 		exit(2)
    125 	}
    126 	writeFD = uintptr(fd)
    127 
    128 	// Prepopulate invariant part of the header.
    129 	// The first 11 bytes will be populated later in writeLogdHeader.
    130 	copy(writeBuf[11:11+len(writeHeader)], writeHeader)
    131 }
    132 
    133 // writeLogdHeader populates the header and returns the length of the payload.
    134 func writeLogdHeader() int {
    135 	hdr := writeBuf[:11]
    136 
    137 	// The first 11 bytes of the header corresponds to android_log_header_t
    138 	// as defined in system/core/include/private/android_logger.h
    139 	//   hdr[0] log type id (unsigned char), defined in <log/log.h>
    140 	//   hdr[1:2] tid (uint16_t)
    141 	//   hdr[3:11] log_time defined in <log/log_read.h>
    142 	//      hdr[3:7] sec unsigned uint32, little endian.
    143 	//      hdr[7:11] nsec unsigned uint32, little endian.
    144 	hdr[0] = 0 // LOG_ID_MAIN
    145 	sec, nsec := time_now()
    146 	packUint32(hdr[3:7], uint32(sec))
    147 	packUint32(hdr[7:11], uint32(nsec))
    148 
    149 	// TODO(hakim):  hdr[1:2] = gettid?
    150 
    151 	return 11 + len(writeHeader)
    152 }
    153 
    154 func packUint32(b []byte, v uint32) {
    155 	// little-endian.
    156 	b[0] = byte(v)
    157 	b[1] = byte(v >> 8)
    158 	b[2] = byte(v >> 16)
    159 	b[3] = byte(v >> 24)
    160 }
    161