diff options
Diffstat (limited to 'misc/android')
-rw-r--r-- | misc/android/README | 11 | ||||
-rw-r--r-- | misc/android/go_android_exec.go | 96 |
2 files changed, 107 insertions, 0 deletions
diff --git a/misc/android/README b/misc/android/README new file mode 100644 index 000000000..5f24fafc7 --- /dev/null +++ b/misc/android/README @@ -0,0 +1,11 @@ +Android +======= + +For details on developing Go for Android, see the documentation in the +go.mobile subrepository: + + https://code.google.com/p/go/source/browse/README?repo=mobile + +To run the standard library tests, see androidtest.bash. Run it as + + CC_FOR_TARGET=.../ndk-gcc GOARCH=arm GOARM=7 ./androidtest.bash diff --git a/misc/android/go_android_exec.go b/misc/android/go_android_exec.go new file mode 100644 index 000000000..e32a805a8 --- /dev/null +++ b/misc/android/go_android_exec.go @@ -0,0 +1,96 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This program can be used as go_android_GOARCH_exec by the Go tool. +// It executes binaries on an android device using adb. +package main + +import ( + "bytes" + "fmt" + "io" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" +) + +func run(args ...string) string { + buf := new(bytes.Buffer) + cmd := exec.Command("adb", args...) + cmd.Stdout = io.MultiWriter(os.Stdout, buf) + cmd.Stderr = os.Stderr + log.Printf("adb %s", strings.Join(args, " ")) + err := cmd.Run() + if err != nil { + log.Fatalf("adb %s: %v", strings.Join(args, " "), err) + } + return buf.String() +} + +func main() { + log.SetFlags(0) + log.SetPrefix("go_android_exec: ") + + // Determine thepackage by examining the current working + // directory, which will look something like + // "$GOROOT/src/mime/multipart". We extract everything + // after the $GOROOT to run on the same relative directory + // on the target device. + // + // TODO(crawshaw): Pick useful subdir when we are not + // inside a GOROOT, e.g. we are in a GOPATH. + cwd, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + subdir, err := filepath.Rel(runtime.GOROOT(), cwd) + if err != nil { + log.Fatal(err) + } + subdir = filepath.ToSlash(subdir) + + // Binary names can conflict. + // E.g. template.test from the {html,text}/template packages. + binName := filepath.Base(os.Args[1]) + deviceGoroot := "/data/local/tmp/goroot" + deviceBin := fmt.Sprintf("%s/%s-%d", deviceGoroot, binName, os.Getpid()) + + // The push of the binary happens in parallel with other tests. + // Unfortunately, a simultaneous call to adb shell hold open + // file descriptors, so it is necessary to push then move to + // avoid a "text file busy" error on execution. + // https://code.google.com/p/android/issues/detail?id=65857 + run("push", os.Args[1], deviceBin+"-tmp") + run("shell", "cp '"+deviceBin+"-tmp' '"+deviceBin+"'") + run("shell", "rm '"+deviceBin+"-tmp'") + + // The adb shell command will return an exit code of 0 regardless + // of the command run. E.g. + // $ adb shell false + // $ echo $? + // 0 + // https://code.google.com/p/android/issues/detail?id=3254 + // So we append the exitcode to the output and parse it from there. + const exitstr = "exitcode=" + cmd := `export TMPDIR="/data/local/tmp"` + + `; export GOROOT="` + deviceGoroot + `"` + + `; cd "$GOROOT/` + subdir + `"` + + "; '" + deviceBin + "' " + strings.Join(os.Args[2:], " ") + + "; echo -n " + exitstr + "$?" + output := run("shell", cmd) + run("shell", "rm '"+deviceBin+"'") // cleanup + output = output[strings.LastIndex(output, "\n")+1:] + if !strings.HasPrefix(output, exitstr) { + log.Fatalf("no exit code: %q", output) + } + code, err := strconv.Atoi(output[len(exitstr):]) + if err != nil { + log.Fatalf("bad exit code: %v", err) + } + os.Exit(code) +} |