修改注释及代码重构
This commit is contained in:
104
adb/connect.go
104
adb/connect.go
@@ -12,8 +12,12 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// mu 用于保护 ADB 连接的互斥锁,避免并发连接冲突
|
||||
var mu sync.Mutex
|
||||
|
||||
// DialADB 建立到 ADB 服务器的 TCP 连接
|
||||
// addr 格式为 "host:port",例如 "127.0.0.1:5037"
|
||||
// timeout 为连接超时时间
|
||||
func DialADB(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
@@ -21,6 +25,8 @@ func DialADB(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
return d.Dial("tcp", addr)
|
||||
}
|
||||
|
||||
// WriteAdbCmd 向 ADB 连接发送命令
|
||||
// 协议格式:4 位十六进制长度前缀 + 命令内容
|
||||
func WriteAdbCmd(conn net.Conn, cmd string) error {
|
||||
header := fmt.Sprintf("%04x", len(cmd))
|
||||
conn.SetWriteDeadline(time.Now().Add(2 * time.Second))
|
||||
@@ -28,6 +34,8 @@ func WriteAdbCmd(conn net.Conn, cmd string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// readN 从连接中精确读取 n 个字节
|
||||
// 会持续读取直到收集到足够的字节数,或超时/出错
|
||||
func readN(conn net.Conn, n int, timeout time.Duration) ([]byte, error) {
|
||||
buf := make([]byte, n)
|
||||
total := 0
|
||||
@@ -43,6 +51,7 @@ func readN(conn net.Conn, n int, timeout time.Duration) ([]byte, error) {
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// ReadStatus 读取 ADB 协议的 4 字节状态码(如 "OKAY" 或 "FAIL")
|
||||
func ReadStatus(conn net.Conn) (string, error) {
|
||||
b, err := readN(conn, 4, 3*time.Second)
|
||||
if err != nil {
|
||||
@@ -51,6 +60,8 @@ func ReadStatus(conn net.Conn) (string, error) {
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
// ReadLenFrame 读取一个带长度前缀的数据帧
|
||||
// 先读取 4 字节十六进制长度前缀,再读取相应长度的数据
|
||||
func ReadLenFrame(conn net.Conn) ([]byte, error) {
|
||||
hdr, err := readN(conn, 4, 3*time.Second)
|
||||
if err != nil {
|
||||
@@ -66,7 +77,8 @@ func ReadLenFrame(conn net.Conn) ([]byte, error) {
|
||||
return readN(conn, int(l), 10*time.Second)
|
||||
}
|
||||
|
||||
// transportTo: 指示 adb server 将后续请求路由到指定 serial
|
||||
// TransportTo 指示 ADB 服务器将后续请求路由到指定设备
|
||||
// serial 为设备序列号,例如 "emulator-5556"
|
||||
func TransportTo(conn net.Conn, serial string) error {
|
||||
if err := WriteAdbCmd(conn, "host:transport:"+serial); err != nil {
|
||||
return err
|
||||
@@ -77,15 +89,17 @@ func TransportTo(conn net.Conn, serial string) error {
|
||||
}
|
||||
if status == "FAIL" {
|
||||
msg, _ := ReadLenFrame(conn)
|
||||
return fmt.Errorf("transport FAIL: %s", string(msg))
|
||||
return fmt.Errorf("传输失败: %s", string(msg))
|
||||
}
|
||||
if status != "OKAY" {
|
||||
return fmt.Errorf("unexpected transport status: %s", status)
|
||||
return fmt.Errorf("意外的传输状态: %s", status)
|
||||
}
|
||||
conn.SetWriteDeadline(time.Time{})
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExecShell 在设备上执行 Shell 命令并返回输出结果
|
||||
// shellCmd 为要执行的 Shell 命令字符串
|
||||
func ExecShell(conn net.Conn, shellCmd string) ([]byte, error) {
|
||||
if err := WriteAdbCmd(conn, "shell:"+shellCmd); err != nil {
|
||||
return nil, err
|
||||
@@ -96,7 +110,7 @@ func ExecShell(conn net.Conn, shellCmd string) ([]byte, error) {
|
||||
}
|
||||
if st != "OKAY" {
|
||||
msg, _ := ReadLenFrame(conn)
|
||||
return nil, fmt.Errorf("shell FAIL: %s", string(msg))
|
||||
return nil, fmt.Errorf("Shell 执行失败: %s", string(msg))
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
@@ -120,7 +134,10 @@ func ExecShell(conn net.Conn, shellCmd string) ([]byte, error) {
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// readResponse reads a 4-byte response like OKAY/FAIL and returns it and optional message (for FAIL)
|
||||
// ReadResponse 读取 ADB 协议响应
|
||||
// 返回状态码("OKAY"/"FAIL"/其他)、消息内容和错误
|
||||
// 支持小端 uint32 和 ASCII 十六进制两种长度编码格式
|
||||
// debug 为 true 时会将调试信息输出到 stderr
|
||||
func ReadResponse(conn net.Conn, debug bool) (string, []byte, error) {
|
||||
stb, err := readN(conn, 4, 10*time.Second)
|
||||
if err != nil {
|
||||
@@ -128,97 +145,92 @@ func ReadResponse(conn net.Conn, debug bool) (string, []byte, error) {
|
||||
}
|
||||
st := string(stb)
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "ReadResponseFixed: status raw hex=%x ascii=%q\n", stb, st)
|
||||
fmt.Fprintf(os.Stderr, "ReadResponse: 状态原始 hex=%x ascii=%q\n", stb, st)
|
||||
}
|
||||
if st == "OKAY" {
|
||||
return st, nil, nil
|
||||
}
|
||||
if st == "FAIL" {
|
||||
// read next 4 bytes (may be little-endian uint32 length or ASCII hex)
|
||||
// 读取后续 4 字节(可能是小端 uint32 长度或 ASCII 十六进制长度)
|
||||
hdr, err := readN(conn, 4, 10*time.Second)
|
||||
if err != nil {
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "ReadResponseFixed: no length header after FAIL: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "ReadResponse: FAIL 后无长度头: %v\n", err)
|
||||
}
|
||||
return st, nil, nil
|
||||
}
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "ReadResponseFixed: length header raw hex=%x ascii=%q\n", hdr, string(hdr))
|
||||
fmt.Fprintf(os.Stderr, "ReadResponse: 长度头原始 hex=%x ascii=%q\n", hdr, string(hdr))
|
||||
}
|
||||
|
||||
// try little-endian uint32 first
|
||||
// 优先尝试小端 uint32 解析
|
||||
l := int(binary.LittleEndian.Uint32(hdr))
|
||||
if l > 0 {
|
||||
msg, err := readN(conn, l, 10*time.Second)
|
||||
if err != nil {
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "ReadResponseFixed: failed to read %d bytes message: %v\n", l, err)
|
||||
fmt.Fprintf(os.Stderr, "ReadResponse: 读取 %d 字节消息失败: %v\n", l, err)
|
||||
}
|
||||
return st, nil, nil
|
||||
}
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "ReadResponseFixed: message hex=%x ascii=%q\n", msg, string(msg))
|
||||
fmt.Fprintf(os.Stderr, "ReadResponse: 消息 hex=%x ascii=%q\n", msg, string(msg))
|
||||
}
|
||||
return st, msg, nil
|
||||
}
|
||||
|
||||
// fallback: try ASCII-hex parse (backwards compatibility)
|
||||
// 回退:尝试 ASCII 十六进制解析(向后兼容)
|
||||
if n, perr := strconv.ParseInt(string(hdr), 16, 32); perr == nil && n > 0 {
|
||||
msg, err := readN(conn, int(n), 10*time.Second)
|
||||
if err != nil {
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "ReadResponseFixed: failed to read ascii-hex message of len %d: %v\n", n, err)
|
||||
fmt.Fprintf(os.Stderr, "ReadResponse: 读取 ASCII 十六进制消息(长度 %d)失败: %v\n", n, err)
|
||||
}
|
||||
return st, nil, nil
|
||||
}
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "ReadResponseFixed: ascii-hex message hex=%x ascii=%q\n", msg, string(msg))
|
||||
fmt.Fprintf(os.Stderr, "ReadResponse: ASCII 十六进制消息 hex=%x ascii=%q\n", msg, string(msg))
|
||||
}
|
||||
return st, msg, nil
|
||||
}
|
||||
|
||||
// neither produced a message
|
||||
// 两种方式都未解析出消息
|
||||
return st, nil, nil
|
||||
}
|
||||
|
||||
// unexpected token
|
||||
// 非预期的状态码
|
||||
return st, nil, nil
|
||||
}
|
||||
|
||||
// LaunchUiautomator connects to adb server, transports to device, starts uiautomator2,
|
||||
// and returns an io.Reader for streaming logs.
|
||||
// LaunchUiautomator 连接 ADB 服务器,路由到指定设备,启动 UIAutomator2 服务
|
||||
// 启动后持续将服务日志输出到标准输出
|
||||
// addr 为 ADB 服务器地址,serial 为设备序列号
|
||||
func LaunchUiautomator(addr, serial string) {
|
||||
conn, err := DialADB(addr, 15*time.Second)
|
||||
if err != nil {
|
||||
fmt.Println("dial error:", err)
|
||||
fmt.Println("连接失败:", err)
|
||||
return
|
||||
}
|
||||
// transport
|
||||
// adbSend(conn, "host:transport:"+serial)
|
||||
// resp, _ := adbReadResponse(conn)
|
||||
// fmt.Println("transport resp:", resp)
|
||||
TransportTo(conn, serial)
|
||||
// shell
|
||||
cmd := "shell:CLASSPATH=/data/local/tmp/u2.jar app_process / com.wetest.uia2.Main"
|
||||
adbSend(conn, cmd)
|
||||
resp, _ := adbReadResponse(conn)
|
||||
fmt.Println("shell resp:", resp)
|
||||
|
||||
// 输出流
|
||||
// 路由到目标设备
|
||||
if err := TransportTo(conn, serial); err != nil {
|
||||
fmt.Println("设备路由失败:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 启动 UIAutomator2 服务
|
||||
cmd := "shell:CLASSPATH=/data/local/tmp/u2.jar app_process / com.wetest.uia2.Main"
|
||||
if err := WriteAdbCmd(conn, cmd); err != nil {
|
||||
fmt.Println("发送命令失败:", err)
|
||||
return
|
||||
}
|
||||
status, err := ReadStatus(conn)
|
||||
if err != nil {
|
||||
fmt.Println("读取状态失败:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("UIAutomator2 启动状态:", status)
|
||||
|
||||
// 持续输出 UIAutomator2 服务日志
|
||||
io.Copy(os.Stdout, conn)
|
||||
}
|
||||
|
||||
func adbSend(conn net.Conn, cmd string) error {
|
||||
length := fmt.Sprintf("%04x", len(cmd))
|
||||
_, err := conn.Write([]byte(length + cmd))
|
||||
return err
|
||||
}
|
||||
|
||||
func adbReadResponse(conn net.Conn) (string, error) {
|
||||
buf := make([]byte, 4)
|
||||
_, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user