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