Source file src/runtime/write_err_android.go

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

View as plain text