]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/write_err_android.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / 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, _ := time_now()
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 }