You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
2.0 KiB
Go
99 lines
2.0 KiB
Go
![]()
5 months ago
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||
![]()
5 months ago
|
|
||
![]()
5 months ago
|
// Gratefully borrowed from Gio UI https://gioui.org/ under MIT license
|
||
|
|
||
|
package libtailscale
|
||
![]()
5 months ago
|
|
||
|
/*
|
||
|
#cgo LDFLAGS: -llog
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <android/log.h>
|
||
|
*/
|
||
|
import "C"
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"log"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"runtime"
|
||
![]()
5 months ago
|
"runtime/debug"
|
||
![]()
5 months ago
|
"syscall"
|
||
|
"unsafe"
|
||
|
)
|
||
|
|
||
|
// 1024 is the truncation limit from android/log.h, plus a \n.
|
||
|
const logLineLimit = 1024
|
||
|
|
||
|
var ID = filepath.Base(os.Args[0])
|
||
|
|
||
|
var logTag = C.CString(ID)
|
||
|
|
||
![]()
5 months ago
|
func initLogging(appCtx AppContext) {
|
||
![]()
5 months ago
|
// Android's logcat already includes timestamps.
|
||
|
log.SetFlags(log.Flags() &^ log.LstdFlags)
|
||
![]()
5 months ago
|
log.SetOutput(&androidLogWriter{
|
||
|
appCtx: appCtx,
|
||
|
})
|
||
![]()
5 months ago
|
|
||
|
// Redirect stdout and stderr to the Android logger.
|
||
|
logFd(os.Stdout.Fd())
|
||
|
logFd(os.Stderr.Fd())
|
||
|
}
|
||
|
|
||
|
type androidLogWriter struct {
|
||
![]()
5 months ago
|
appCtx AppContext
|
||
![]()
5 months ago
|
}
|
||
|
|
||
|
func (w *androidLogWriter) Write(data []byte) (int, error) {
|
||
|
n := 0
|
||
|
for len(data) > 0 {
|
||
|
msg := data
|
||
![]()
5 months ago
|
// Truncate the buffer
|
||
|
if len(msg) > logLineLimit {
|
||
|
msg = msg[:logLineLimit]
|
||
![]()
5 months ago
|
}
|
||
![]()
5 months ago
|
w.appCtx.Log(ID, string(msg))
|
||
![]()
5 months ago
|
n += len(msg)
|
||
|
data = data[len(msg):]
|
||
|
}
|
||
|
return n, nil
|
||
|
}
|
||
|
|
||
|
func logFd(fd uintptr) {
|
||
|
r, w, err := os.Pipe()
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
if err := syscall.Dup3(int(w.Fd()), int(fd), syscall.O_CLOEXEC); err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
go func() {
|
||
![]()
5 months ago
|
defer func() {
|
||
|
if p := recover(); p != nil {
|
||
|
log.Printf("panic in logFd %s: %s", p, debug.Stack())
|
||
|
panic(p)
|
||
|
}
|
||
|
}()
|
||
|
|
||
![]()
5 months ago
|
lineBuf := bufio.NewReaderSize(r, logLineLimit)
|
||
|
// The buffer to pass to C, including the terminating '\0'.
|
||
|
buf := make([]byte, lineBuf.Size()+1)
|
||
|
cbuf := (*C.char)(unsafe.Pointer(&buf[0]))
|
||
|
for {
|
||
|
line, _, err := lineBuf.ReadLine()
|
||
|
if err != nil {
|
||
|
break
|
||
|
}
|
||
|
copy(buf, line)
|
||
|
buf[len(line)] = 0
|
||
|
C.__android_log_write(C.ANDROID_LOG_INFO, logTag, cbuf)
|
||
|
}
|
||
|
// The garbage collector doesn't know that w's fd was dup'ed.
|
||
|
// Avoid finalizing w, and thereby avoid its finalizer closing its fd.
|
||
|
runtime.KeepAlive(w)
|
||
|
}()
|
||
|
}
|