github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/src/runtime/write_err_android.go (about) 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 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 }