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