...

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 "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/+/refs/tags/android-6.0.1_r78/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				for i := range dst {
    79					dst[i] = 0
    80				}
    81				writePos = 0
    82			}
    83		}
    84	}
    85	
    86	func initLegacy() {
    87		// In legacy mode, logs are written to /dev/log/main
    88		writeFD = uintptr(open(&writePath[0], 0x1 /* O_WRONLY */, 0))
    89		if writeFD == 0 {
    90			// It is hard to do anything here. Write to stderr just
    91			// in case user has root on device and has run
    92			//	adb shell setprop log.redirect-stdio true
    93			msg := []byte("runtime: cannot open /dev/log/main\x00")
    94			write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
    95			exit(2)
    96		}
    97	
    98		// Prepopulate the invariant header part.
    99		copy(writeBuf[:len(writeHeader)], writeHeader)
   100	}
   101	
   102	// used in initLogdWrite but defined here to avoid heap allocation.
   103	var logdAddr sockaddr_un
   104	
   105	func initLogd() {
   106		// In logd mode, logs are sent to the logd via a unix domain socket.
   107		logdAddr.family = _AF_UNIX
   108		copy(logdAddr.path[:], writeLogd)
   109	
   110		// We are not using non-blocking I/O because writes taking this path
   111		// are most likely triggered by panic, we cannot think of the advantage of
   112		// non-blocking I/O for panic but see disadvantage (dropping panic message),
   113		// and blocking I/O simplifies the code a lot.
   114		fd := socket(_AF_UNIX, _SOCK_DGRAM|_O_CLOEXEC, 0)
   115		if fd < 0 {
   116			msg := []byte("runtime: cannot create a socket for logging\x00")
   117			write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
   118			exit(2)
   119		}
   120	
   121		errno := connect(fd, unsafe.Pointer(&logdAddr), int32(unsafe.Sizeof(logdAddr)))
   122		if errno < 0 {
   123			msg := []byte("runtime: cannot connect to /dev/socket/logdw\x00")
   124			write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
   125			// TODO(hakim): or should we just close fd and hope for better luck next time?
   126			exit(2)
   127		}
   128		writeFD = uintptr(fd)
   129	
   130		// Prepopulate invariant part of the header.
   131		// The first 11 bytes will be populated later in writeLogdHeader.
   132		copy(writeBuf[11:11+len(writeHeader)], writeHeader)
   133	}
   134	
   135	// writeLogdHeader populates the header and returns the length of the payload.
   136	func writeLogdHeader() int {
   137		hdr := writeBuf[:11]
   138	
   139		// The first 11 bytes of the header corresponds to android_log_header_t
   140		// as defined in system/core/include/private/android_logger.h
   141		//   hdr[0] log type id (unsigned char), defined in <log/log.h>
   142		//   hdr[1:2] tid (uint16_t)
   143		//   hdr[3:11] log_time defined in <log/log_read.h>
   144		//      hdr[3:7] sec unsigned uint32, little endian.
   145		//      hdr[7:11] nsec unsigned uint32, little endian.
   146		hdr[0] = 0 // LOG_ID_MAIN
   147		sec, nsec := walltime()
   148		packUint32(hdr[3:7], uint32(sec))
   149		packUint32(hdr[7:11], uint32(nsec))
   150	
   151		// TODO(hakim):  hdr[1:2] = gettid?
   152	
   153		return 11 + len(writeHeader)
   154	}
   155	
   156	func packUint32(b []byte, v uint32) {
   157		// little-endian.
   158		b[0] = byte(v)
   159		b[1] = byte(v >> 8)
   160		b[2] = byte(v >> 16)
   161		b[3] = byte(v >> 24)
   162	}
   163	

View as plain text