Index: platform_tools/android/bin/android_run_app.go |
diff --git a/platform_tools/android/bin/android_run_app.go b/platform_tools/android/bin/android_run_app.go |
deleted file mode 100644 |
index 53ae0fd938d2c34346f1c219db2761989c9a24f6..0000000000000000000000000000000000000000 |
--- a/platform_tools/android/bin/android_run_app.go |
+++ /dev/null |
@@ -1,248 +0,0 @@ |
-// Copyright (c) 2015 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-/* |
- Run a Skia app to completion, piping the log to stdout. |
-*/ |
- |
-package main |
- |
-import ( |
- "flag" |
- "fmt" |
- "io" |
- "os" |
- "os/exec" |
- "os/signal" |
- "strconv" |
- "strings" |
- "time" |
- |
- "github.com/skia-dev/glog" |
- "go.skia.org/infra/go/common" |
-) |
- |
-const ( |
- COM_SKIA = "com.skia" |
-) |
- |
-var ( |
- adbPath = flag.String("adb", "", "Path to the ADB executable.") |
- app = flag.String("app", "VisualBench", "Name of the app to run.") |
- serial = flag.String("s", "", "Serial number for the Android device to use.") |
-) |
- |
-// Struct used for running ADB commands. |
-type ADB struct { |
- path string |
- serial string |
-} |
- |
-// ADBFromFlags returns an ADB instance based on flags passed to the program. |
-func ADBFromFlags() *ADB { |
- rv := &ADB{ |
- path: *adbPath, |
- serial: *serial, |
- } |
- if rv.path == "" { |
- rv.path = "adb" |
- } |
- return rv |
-} |
- |
-// Cmd creates an exec.Cmd object for the given ADB command. |
-func (adb *ADB) Cmd(log bool, args ...string) *exec.Cmd { |
- cmd := []string{} |
- if adb.serial != "" { |
- cmd = append(cmd, "-s", adb.serial) |
- } |
- cmd = append(cmd, args...) |
- if log { |
- glog.Infof("Exec `%s %s`", adb.path, strings.Join(cmd, " ")) |
- } |
- return exec.Command(adb.path, cmd...) |
-} |
- |
-// KillSkia kills any running process. |
-func (adb *ADB) Kill(proc string) error { |
- return adb.Cmd(false, "shell", "am", "force-stop", proc).Run() |
-} |
- |
-// PollSkia checks to see if the given process is running. If so, return the pid, otherwise return -1. |
-func (adb *ADB) Poll(proc string) (int64, error) { |
- output, err := adb.Cmd(false, "shell", "ps").Output() |
- if err != nil { |
- return -1, fmt.Errorf("Failed to check the running processes on the device: %v", err) |
- } |
- for _, line := range strings.Split(string(output), "\n") { |
- if strings.Contains(line, proc) { |
- fields := strings.Fields(line) |
- pid, err := strconv.ParseInt(fields[1], 10, 32) |
- if err != nil { |
- return -1, fmt.Errorf("Failed to parse \"%s\" to an integer: %v", fields[1], err) |
- } |
- return pid, nil |
- } |
- } |
- return -1, nil |
-} |
- |
-// ReadLinesFromPipe reads from the given pipe and logs its output. |
-func ReadLinesFromPipe(pipe io.Reader, lines chan string) { |
- buf := []byte{} |
- |
- // writeLine recovers from a panic when writing to the channel. |
- writeLine := func(s string) { |
- defer func() { |
- if r := recover(); r != nil { |
- glog.Warningf("Panic writing to channel... are we exiting?") |
- } |
- }() |
- lines <- s |
- } |
- |
- // readLines reads output lines from the buffer and pushes them into the channel. |
- readlines := func() { |
- readIdx := 0 |
- // Read lines from buf. |
- for i, b := range buf { |
- if b == '\n' { |
- s := string(buf[readIdx:i]) |
- writeLine(s) |
- readIdx = i + 1 |
- } |
- } |
- // Remove the lines we read. |
- buf = buf[readIdx:] |
- } |
- |
- // Loop forever, reading bytes from the pipe. |
- readbuf := make([]byte, 4096) |
- for { |
- read, err := pipe.Read(readbuf) |
- if read > 0 { |
- buf = append(buf, readbuf[:read]...) |
- |
- // Read lines from the buffers. |
- readlines() |
- } |
- if err != nil { |
- if err == io.EOF { |
- break |
- } else { |
- glog.Error(err) |
- } |
- } else if read == 0 { |
- time.Sleep(20 * time.Millisecond) |
- } |
- } |
- // Read any remaining lines from the buffers. |
- readlines() |
- // "Flush" any incomplete lines from the buffers. |
- writeLine(string(buf)) |
-} |
- |
-// RunApp launches the given app on the device, pipes its log output to stdout, |
-// and returns when the app finishes running, with an error if the app did not |
-// complete successfully. |
-func RunApp(adb *ADB, appName string, args []string) error { |
- // Kill any running instances of the app. |
- if err := adb.Kill(COM_SKIA); err != nil { |
- return fmt.Errorf("Failed to kill app: %v", err) |
- } |
- |
- // Clear the ADB log. |
- if err := adb.Cmd(false, "logcat", "-c").Run(); err != nil { |
- return fmt.Errorf("Failed to clear ADB log: %v", err) |
- } |
- |
- // Prepare to read the subprocess output. |
- logProc := adb.Cmd(false, "logcat") |
- defer func() { |
- // Cleanup. |
- if err := logProc.Process.Kill(); err != nil { |
- glog.Errorf("Failed to kill logcat process: %v", err) |
- } |
- }() |
- |
- stdout, err := logProc.StdoutPipe() |
- if err != nil { |
- return fmt.Errorf("Failed to obtain stdout pipe: %v", err) |
- } |
- stdoutLines := make(chan string) |
- stderr, err := logProc.StderrPipe() |
- if err != nil { |
- return fmt.Errorf("Failed to obtain stderr pipe: %v", err) |
- } |
- stderrLines := make(chan string) |
- |
- go ReadLinesFromPipe(stdout, stdoutLines) |
- go ReadLinesFromPipe(stderr, stderrLines) |
- if err := logProc.Start(); err != nil { |
- return fmt.Errorf("Failed to start logcat process.") |
- } |
- |
- // Launch the app. |
- stop := make(chan bool, 1) |
- activity := fmt.Sprintf("%s.%s/%s.%sActivity", COM_SKIA, strings.ToLower(appName), COM_SKIA, appName) |
- flags := strings.Join(args, " ") |
- cmd := []string{"shell", "am", "start", "-S", "-n", activity, "--es", "cmdLineFlags", flags} |
- output, err := adb.Cmd(true, cmd...).Output() |
- if err != nil { |
- return fmt.Errorf("Failed to launch app: %v", err) |
- } |
- glog.Info(string(output)) |
- // Make a handler for SIGINT so that we can kill the app if this script is interrupted. |
- go func() { |
- interrupt := make(chan os.Signal, 1) |
- signal.Notify(interrupt, os.Interrupt) |
- for _ = range interrupt { |
- glog.Infof("Received SIGINT; killing app.") |
- stop <- true |
- close(stdoutLines) |
- close(stderrLines) |
- if err := adb.Kill(COM_SKIA); err != nil { |
- glog.Errorf("Failed to kill app: %v", err) |
- } |
- if err := logProc.Process.Kill(); err != nil { |
- glog.Errorf("Failed to kill logcat process: %v", err) |
- } |
- } |
- }() |
- |
- // Loop until the app finishes or we're interrupted, writing output as appropriate. |
- // TODO(borenet): VisualBench should print its exit code. This script should exit |
- // with that code, or a non-zero code if the process ended without printing any code. |
- second := time.Tick(time.Second) |
-PollLoop: |
- for { |
- select { |
- case <-second: |
- // Poll the Skia process every second to make sure it's still running. |
- pid, err := adb.Poll(COM_SKIA) |
- if err != nil { |
- glog.Errorf("Failed to poll Skia process: %v", err) |
- } else if pid < 0 { |
- glog.Infof("Skia process is no longer running!") |
- break PollLoop |
- } |
- case <-stop: |
- break PollLoop |
- case line := <-stdoutLines: |
- glog.Info(line) |
- case line := <-stderrLines: |
- glog.Error(line) |
- } |
- } |
- |
- return nil |
-} |
- |
-func main() { |
- common.Init() |
- args := flag.Args() |
- if err := RunApp(ADBFromFlags(), *app, args); err != nil { |
- glog.Fatal(err) |
- } |
-} |