diff --git a/vm/adb/adb.go b/vm/adb/adb.go index e914acded50f..8889f7397c75 100644 --- a/vm/adb/adb.go +++ b/vm/adb/adb.go @@ -33,8 +33,9 @@ func init() { } type Device struct { - Serial string `json:"serial"` // device serial to connect - Console string `json:"console"` // console device name (e.g. "/dev/pts/0") + Serial string `json:"serial"` // device serial to connect + Console string `json:"console"` // console device name (e.g. "/dev/pts/0") + ConsoleCmd []string `json:"console_cmd"` // command to obtain device console log } type Config struct { @@ -60,13 +61,14 @@ type Pool struct { } type instance struct { - cfg *Config - adbBin string - device string - console string - closed chan bool - debug bool - timeouts targets.Timeouts + cfg *Config + adbBin string + device string + console string + consoleCmd []string + closed chan bool + debug bool + timeouts targets.Timeouts } var ( @@ -132,13 +134,14 @@ func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) { return nil, err } inst := &instance{ - cfg: pool.cfg, - adbBin: pool.cfg.Adb, - device: device.Serial, - console: device.Console, - closed: make(chan bool), - debug: pool.env.Debug, - timeouts: pool.env.Timeouts, + cfg: pool.cfg, + adbBin: pool.cfg.Adb, + device: device.Serial, + console: device.Console, + consoleCmd: device.ConsoleCmd, + closed: make(chan bool), + debug: pool.env.Debug, + timeouts: pool.env.Timeouts, } closeInst := inst defer func() { @@ -149,10 +152,14 @@ func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) { if err := inst.repair(); err != nil { return nil, err } - if inst.console == "" { - inst.console = findConsole(inst.adbBin, inst.device) + if len(inst.consoleCmd) > 0 { + log.Logf(0, "associating adb device %v with console cmd `%v`", inst.device, inst.consoleCmd) + } else { + if inst.console == "" { + inst.console = findConsole(inst.adbBin, inst.device) + } + log.Logf(0, "associating adb device %v with console %v", inst.device, inst.console) } - log.Logf(0, "associating adb device %v with console %v", inst.device, inst.console) if pool.cfg.BatteryCheck { if err := inst.checkBatteryLevel(); err != nil { return nil, err @@ -517,7 +524,9 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin var tty io.ReadCloser var err error - if ok, ip := isRemoteCuttlefish(inst.device); ok { + if len(inst.consoleCmd) > 0 { + tty, err = vmimpl.OpenConsoleByCmd(inst.consoleCmd[0], inst.consoleCmd[1:]) + } else if ok, ip := isRemoteCuttlefish(inst.device); ok { tty, err = vmimpl.OpenRemoteKernelLog(ip, inst.console) } else if inst.console == "adb" { tty, err = vmimpl.OpenAdbConsole(inst.adbBin, inst.device) diff --git a/vm/vmimpl/console.go b/vm/vmimpl/console.go index 200c44f73bab..7ae680f262ce 100644 --- a/vm/vmimpl/console.go +++ b/vm/vmimpl/console.go @@ -77,46 +77,45 @@ func (t *tty) Close() error { // OpenRemoteKernelLog accesses to the host where Android VM runs on, not Android VM itself. // The host stores all kernel outputs of Android VM so in case of crashes nothing will be lost. func OpenRemoteKernelLog(ip, console string) (rc io.ReadCloser, err error) { - rpipe, wpipe, err := osutil.LongPipe() - if err != nil { - return nil, err - } conAddr := "vsoc-01@" + ip - cmd := osutil.Command("ssh", conAddr, "tail", "-f", console) - cmd.Stdout = wpipe - cmd.Stderr = wpipe - if _, err := cmd.StdinPipe(); err != nil { - rpipe.Close() - wpipe.Close() - return nil, err - } - if err := cmd.Start(); err != nil { - rpipe.Close() - wpipe.Close() - return nil, fmt.Errorf("failed to connect to console server: %w", err) - } - wpipe.Close() - con := &remoteCon{ - cmd: cmd, - rpipe: rpipe, + args := []string{ + conAddr, + "tail", + "-f", + console, } - return con, nil + return OpenConsoleByCmd("ssh", args) } // Open dmesg remotely. func OpenRemoteConsole(bin string, args ...string) (rc io.ReadCloser, err error) { + args = append(args, "dmesg -w") + return OpenConsoleByCmd(bin, args) +} + +// OpenAdbConsole provides fallback console output using 'adb shell dmesg -w'. +func OpenAdbConsole(bin, dev string) (rc io.ReadCloser, err error) { + return OpenRemoteConsole(bin, "-s", dev, "shell") +} + +// Open console log by cmd. +func OpenConsoleByCmd(bin string, args []string) (rc io.ReadCloser, err error) { rpipe, wpipe, err := osutil.LongPipe() if err != nil { return nil, err } - args = append(args, "dmesg -w") cmd := osutil.Command(bin, args...) cmd.Stdout = wpipe cmd.Stderr = wpipe + if _, err := cmd.StdinPipe(); err != nil { + rpipe.Close() + wpipe.Close() + return nil, err + } if err := cmd.Start(); err != nil { rpipe.Close() wpipe.Close() - return nil, fmt.Errorf("failed to start adb: %w", err) + return nil, fmt.Errorf("failed to open console: %w", err) } wpipe.Close() con := &remoteCon{ @@ -126,11 +125,6 @@ func OpenRemoteConsole(bin string, args ...string) (rc io.ReadCloser, err error) return con, err } -// OpenAdbConsole provides fallback console output using 'adb shell dmesg -w'. -func OpenAdbConsole(bin, dev string) (rc io.ReadCloser, err error) { - return OpenRemoteConsole(bin, "-s", dev, "shell") -} - type remoteCon struct { closeMu sync.Mutex readMu sync.Mutex