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