Skip to content
This repository has been archived by the owner on May 27, 2024. It is now read-only.

Commit

Permalink
complete /minicap/broadcast api
Browse files Browse the repository at this point in the history
  • Loading branch information
codeskyblue committed Mar 9, 2020
1 parent 0460135 commit c30596a
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 51 deletions.
2 changes: 1 addition & 1 deletion cmdctrl/cmdctrl.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ func (p *processKeeper) start() error {
p.cmd.Stdin = p.cmdInfo.Stdin
p.cmd.Stdout = p.cmdInfo.Stdout
p.cmd.Stderr = p.cmdInfo.Stderr
log.Printf("start args: %v, env: %v", cmdArgs, p.cmdInfo.Environ)
log.Printf("[%s] args: %v, env: %v", p.name, cmdArgs, p.cmdInfo.Environ)
if err := p.cmd.Start(); err != nil {
goto CMD_DONE
}
Expand Down
24 changes: 13 additions & 11 deletions hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ type Hub struct {
broadcast chan []byte // Inbound messages from the clients.
register chan *Client // Register requests from the clients.
unregister chan *Client // Unregister requests from clients.
_quit chan bool
}

func newHub() *Hub {
Expand All @@ -29,30 +28,33 @@ func newHub() *Hub {
}
}

func (h *Hub) _startScrcpyAgent(ctx context.Context) {
h.broadcast <- []byte("welcome new client, scrcpy is launching")
service.Start("scrcpy")
func (h *Hub) _startTranslate(ctx context.Context) {
h.broadcast <- []byte("welcome")
if minicapSocketPath == "@minicap" {
service.Start("minicap")
}

log.Printf("Receive images from %s", minicapSocketPath)
retries := 0
for {
if retries > 10 {
log.Println("unix @scrcpy connect failed")
h.broadcast <- []byte("@scrcpy listen timeout, possibly scrcpy not installed")
log.Printf("unix %s connect failed", minicapSocketPath)
h.broadcast <- []byte("@minicapagent listen timeout")
break
}

conn, err := net.Dial("unix", "@scrcpy")
conn, err := net.Dial("unix", minicapSocketPath)
if err != nil {
retries++
log.Printf("dial @scrcpy err: %v, wait 0.5s", err)
log.Printf("dial %s err: %v, wait 0.5s", minicapSocketPath, err)
select {
case <-ctx.Done():
return
case <-time.After(500 * time.Millisecond):
}
continue
}
h.broadcast <- []byte("rotation " + strconv.Itoa(deviceRotation))

retries = 0 // connected, reset retries
if er := translateMinicap(conn, h.broadcast, ctx); er == nil {
conn.Close()
Expand All @@ -77,15 +79,15 @@ func (h *Hub) run() {
h.broadcast <- []byte("rotation " + strconv.Itoa(deviceRotation))
if len(h.clients) == 1 {
ctx, cancel = context.WithCancel(context.Background())
go h._startScrcpyAgent(ctx)
go h._startTranslate(ctx)
}
case client := <-h.unregister:
if _, ok := h.clients[client]; ok {
delete(h.clients, client)
close(client.send)
}
if len(h.clients) == 0 {
log.Println("client quit, all gone")
log.Println("All client quited, context stop minicap service")
cancel()
}
case message := <-h.broadcast:
Expand Down
96 changes: 61 additions & 35 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ var (
listenPort int
daemonLogPath = "/sdcard/atx-agent.log"

rotationPublisher = broadcast.NewBroadcaster(1)
rotationPublisher = broadcast.NewBroadcaster(1)
minicapSocketPath = "@minicap"
minitouchSocketPath = "@minitouch"
)

const (
Expand Down Expand Up @@ -191,10 +193,18 @@ var (
)

func updateMinicapRotation(rotation int) {
running := service.Running("minicap")
if running {
service.Stop("minicap")
killProcessByName("minicap") // kill not controlled minicap
}
devInfo := getDeviceInfo()
width, height := devInfo.Display.Width, devInfo.Display.Height
service.UpdateArgs("minicap", "/data/local/tmp/minicap", "-S", "-P",
fmt.Sprintf("%dx%d@%dx%d/%d", width, height, displayMaxWidthHeight, displayMaxWidthHeight, rotation))
if running {
service.Start("minicap")
}
}

func checkUiautomatorInstalled() (ok bool) {
Expand Down Expand Up @@ -428,6 +438,44 @@ func init() {
}
time.Local = time.FixedZone(tz, offset*3600)
}

// watch rotation and send to rotatinPublisher
go _watchRotation()
if !isMinicapSupported() {
minicapSocketPath = "@minicapagent"
}
if !fileExists("/data/local/tmp/minitouch") {
minitouchSocketPath = "@minitouchagent"
} else if sdk, _ := strconv.Atoi(getCachedProperty("ro.build.version.sdk")); sdk > 28 { // Android Q..
minitouchSocketPath = "@minitouchagent"
}
}

func _watchRotation() {
for {
conn, err := net.Dial("unix", "@rotationagent")
if err != nil {
time.Sleep(2 * time.Second)
continue
}
func() {
defer conn.Close()
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
rotation, err := strconv.Atoi(scanner.Text())
if err != nil {
continue
}
deviceRotation = rotation
if minicapSocketPath == "@minicap" {
updateMinicapRotation(deviceRotation)
}
rotationPublisher.Submit(rotation)
log.Println("Rotation -->", rotation)
}
}()
time.Sleep(1 * time.Second)
}
}

func killAgentProcess() error {
Expand Down Expand Up @@ -577,51 +625,29 @@ func main() {
fmt.Sprintf("%dx%d@%dx%d/0", width, height, displayMaxWidthHeight, displayMaxWidthHeight)},
})

service.Add("scrcpy", cmdctrl.CommandInfo{
service.Add("apkagent", cmdctrl.CommandInfo{
MaxRetries: 2,
Shell: true,
OnStart: func() error {
log.Println("killProcessByName scrcpy.cli")
// killProcessByName("scrcpy.cli")
log.Println("killProcessByName apk-agent.cli")
killProcessByName("apkagent.cli")
return nil
},
ArgsFunc: func() ([]string, error) {
pmPathOutput, err := Command{
Args: []string{"pm", "path", "com.github.uiautomator"},
Shell: true,
}.CombinedOutputString()
packagePath, err := getPackagePath("com.github.uiautomator")
if err != nil {
return nil, err
}
if !strings.HasPrefix(pmPathOutput, "package:") {
return nil, errors.New("invalid pm path output: " + pmPathOutput)
}
packagePath := strings.TrimSpace(pmPathOutput[len("package:"):])
return []string{"CLASSPATH=" + packagePath, "exec", "app_process", "/system/bin", "com.github.uiautomator.ScrcpyAgent"}, nil
return []string{"CLASSPATH=" + packagePath, "exec", "app_process", "/system/bin", "com.github.uiautomator.Console"}, nil
},
Shell: true,
})

service.Start("apkagent")

service.Add("minitouch", cmdctrl.CommandInfo{
MaxRetries: 2,
ArgsFunc: func() ([]string, error) {
sdk, err := strconv.Atoi(getCachedProperty("ro.build.version.sdk"))
if err != nil || sdk <= 28 { // Android P(sdk:28)
minitouchSocketPath = "@minitouch"
return []string{"/data/local/tmp/minitouch"}, nil
}
minitouchSocketPath = "@minitouchagent"
pmPathOutput, err := Command{
Args: []string{"pm", "path", "com.github.uiautomator"},
Shell: true,
}.CombinedOutputString()
if err != nil {
return nil, err
}
if !strings.HasPrefix(pmPathOutput, "package:") {
return nil, errors.New("invalid pm path output: " + pmPathOutput)
}
packagePath := strings.TrimSpace(pmPathOutput[len("package:"):])
return []string{"CLASSPATH=" + packagePath, "exec", "app_process", "/system/bin", "com.github.uiautomator.MinitouchAgent"}, nil
},
Shell: true,
Args: []string{"/data/local/tmp/minitouch"},
Shell: true,
})

// uiautomator 1.0
Expand Down
2 changes: 0 additions & 2 deletions minitouch.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import (
"github.com/qiniu/log"
)

var minitouchSocketPath = "@minitouch"

type toucher struct {
width, height int
rotation int
Expand Down
21 changes: 21 additions & 0 deletions screenshot.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"bytes"
"encoding/json"
"fmt"

Expand Down Expand Up @@ -36,3 +37,23 @@ func screenshotWithScreencap(filename string) (err error) {
err = errors.Wrap(err, "screencap")
return
}

func isMinicapSupported() bool {
output, err := runShellOutput("LD_LIBRARY_PATH=/data/local/tmp", "/data/local/tmp/minicap", "-i")
if err != nil {
return false
}
var f MinicapInfo
if er := json.Unmarshal([]byte(output), &f); er != nil {
return false
}
output, err = runShell(
"LD_LIBRARY_PATH=/data/local/tmp",
"/data/local/tmp/minicap",
"-P", fmt.Sprintf("%dx%d@%dx%d/%d", f.Width, f.Height, f.Width, f.Height, f.Rotation),
"-s", "2>/dev/null")
if err != nil {
return false
}
return bytes.Equal(output[:2], []byte("\xff\xd8")) // JpegFormat
}
21 changes: 19 additions & 2 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,8 @@ func killProcessByName(processName string) bool {
if err != nil {
return false
}

killed := false
for _, p := range procs {
cmdline, _ := p.CmdLine()
var name string
Expand All @@ -672,9 +674,24 @@ func killProcessByName(processName string) bool {
process, err := os.FindProcess(p.PID)
if err == nil {
process.Kill()
return true
killed = true
}
}
}
return false
return killed
}

func getPackagePath(packageName string) (string, error) {
pmPathOutput, err := Command{
Args: []string{"pm", "path", "com.github.uiautomator"},
Shell: true,
}.CombinedOutputString()
if err != nil {
return "", err
}
if !strings.HasPrefix(pmPathOutput, "package:") {
return "", errors.New("invalid pm path output: " + pmPathOutput)
}
packagePath := strings.TrimSpace(pmPathOutput[len("package:"):])
return packagePath, nil
}

0 comments on commit c30596a

Please sign in to comment.