From 3d4dffbd0be5496076b20fa8aee261c740c96ff4 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Thu, 13 Apr 2023 22:41:45 +0800 Subject: [PATCH 1/3] refactor: replace gadb with optimized version authoried by @appl3s --- hrp/cmd/adb/devices.go | 2 +- hrp/pkg/gadb/README.md | 8 +- hrp/pkg/gadb/client.go | 16 +- hrp/pkg/gadb/client_test.go | 20 ++ hrp/pkg/gadb/device.go | 316 ++++++++++++++++++++++++++--- hrp/pkg/gadb/device_test.go | 128 ++++++++++++ hrp/pkg/gadb/features.go | 26 +++ hrp/pkg/gadb/sync_transport.go | 1 + hrp/pkg/gadb/transport.go | 10 + hrp/pkg/gadb/transport_test.go | 1 - hrp/pkg/gadb/utils.go | 9 + hrp/pkg/uixt/android_adb_driver.go | 2 +- hrp/pkg/uixt/android_device.go | 4 +- 13 files changed, 509 insertions(+), 34 deletions(-) create mode 100644 hrp/pkg/gadb/features.go create mode 100644 hrp/pkg/gadb/utils.go diff --git a/hrp/cmd/adb/devices.go b/hrp/cmd/adb/devices.go index 86c93608..28eb8bad 100644 --- a/hrp/cmd/adb/devices.go +++ b/hrp/cmd/adb/devices.go @@ -26,7 +26,7 @@ var listAndroidDevicesCmd = &cobra.Command{ return errors.Wrap(err, "list android devices failed") } - var deviceList []gadb.Device + var deviceList []*gadb.Device // filter by serial for _, d := range devices { if serial != "" && serial != d.Serial() { diff --git a/hrp/pkg/gadb/README.md b/hrp/pkg/gadb/README.md index dc67b810..2027cea5 100644 --- a/hrp/pkg/gadb/README.md +++ b/hrp/pkg/gadb/README.md @@ -1,5 +1,11 @@ # gadb -This module is initially forked from [electricbubble/gadb@v0.0.7]. +This module is initially forked from [electricbubble/gadb@v0.0.7] and optimized by [@appl3s]. + +- feat: add reverse forward command +- feat: add `RunShellCommandV2` which supports running nohup +- feat: add `InstallAPK` with feature judgment +- feat: add `Uninstall` for specified package name [electricbubble/gadb@v0.0.7]: https://github.com/electricbubble/gadb/tree/v0.0.7 +[@appl3s]: https://github.com/appl3s diff --git a/hrp/pkg/gadb/client.go b/hrp/pkg/gadb/client.go index 4543484a..bc0349ff 100644 --- a/hrp/pkg/gadb/client.go +++ b/hrp/pkg/gadb/client.go @@ -38,6 +38,16 @@ func NewClientWith(host string, port ...int) (adbClient Client, err error) { return } +func NewClientWithoutTransport(host string, port ...int) (adbClient Client, err error) { + if len(port) == 0 { + port = []int{AdbServerPort} + } + adbClient.host = host + adbClient.port = port[0] + + return +} + func (c Client) ServerVersion() (version int, err error) { var resp string if resp, err = c.executeCommand("host:version"); err != nil { @@ -73,14 +83,14 @@ func (c Client) DeviceSerialList() (serials []string, err error) { return } -func (c Client) DeviceList() (devices []Device, err error) { +func (c Client) DeviceList() (devices []*Device, err error) { var resp string if resp, err = c.executeCommand("host:devices-l"); err != nil { return } lines := strings.Split(resp, "\n") - devices = make([]Device, 0, len(lines)) + devices = make([]*Device, 0, len(lines)) for i := range lines { line := strings.TrimSpace(lines[i]) @@ -101,7 +111,7 @@ func (c Client) DeviceList() (devices []Device, err error) { key, val := split[0], split[1] mapAttrs[key] = val } - devices = append(devices, Device{adbClient: c, serial: fields[0], attrs: mapAttrs}) + devices = append(devices, &Device{adbClient: c, serial: fields[0], attrs: mapAttrs}) } return diff --git a/hrp/pkg/gadb/client_test.go b/hrp/pkg/gadb/client_test.go index 404af6a8..dff28e38 100644 --- a/hrp/pkg/gadb/client_test.go +++ b/hrp/pkg/gadb/client_test.go @@ -3,6 +3,7 @@ package gadb import ( + "io/ioutil" "testing" ) @@ -127,3 +128,22 @@ func TestClient_KillServer(t *testing.T) { t.Fatal(err) } } + +func TestScreenCap(t *testing.T) { + adbClient, err := NewClient() + if err != nil { + t.Fatal(err) + } + + dl, err := adbClient.DeviceList() + if err != nil { + t.Error(err) + } + d := dl[0] + res, err := d.RunShellCommandV2WithBytes("screencap", "-p") + if err != nil { + t.Error(err) + } + t.Log(len(res)) + ioutil.WriteFile("/tmp/1.png", res, 0o644) +} diff --git a/hrp/pkg/gadb/device.go b/hrp/pkg/gadb/device.go index 59c4d1e6..b9911272 100644 --- a/hrp/pkg/gadb/device.go +++ b/hrp/pkg/gadb/device.go @@ -1,6 +1,8 @@ package gadb import ( + "bytes" + "encoding/binary" "errors" "fmt" "io" @@ -48,9 +50,10 @@ func deviceStateConv(k string) (deviceState DeviceState) { } type DeviceForward struct { - Serial string - Local string - Remote string + Serial string + Local string + Remote string + Reverse bool // LocalProtocol string // RemoteProtocol string } @@ -59,51 +62,92 @@ type Device struct { adbClient Client serial string attrs map[string]string + feat Features } -func (d Device) Product() string { +func (d *Device) HasFeature(name Feature) bool { + feats, err := d.GetFeatures() + if err != nil || len(feats) == 0 { + return false + } + return feats.HasFeature(name) +} + +func (d *Device) GetFeatures() (features Features, err error) { + if len(d.feat) > 0 { + return d.feat, nil + } + return d.features() +} + +func (d *Device) features() (features Features, err error) { + res, err := d.executeCommand("host:features") + if err != nil { + return nil, err + } + if len(res) > 4 { + // stip hash + res = res[4:] + } + fs := strings.Split(string(res), ",") + features = make(Features, len(fs)) + for _, f := range fs { + features[Feature(f)] = struct{}{} + } + d.feat = features + return features, nil +} + +func (d *Device) Product() string { return d.attrs["product"] } -func (d Device) Model() string { +func (d *Device) Model() string { return d.attrs["model"] } -func (d Device) Usb() string { +func (d *Device) Usb() string { return d.attrs["usb"] } -func (d Device) transportId() string { +func (d *Device) transportId() string { return d.attrs["transport_id"] } -func (d Device) DeviceInfo() map[string]string { +func (d *Device) DeviceInfo() map[string]string { return d.attrs } -func (d Device) Serial() string { +func (d *Device) Serial() string { // resp, err := d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:get-serialno", d.serial)) return d.serial } -func (d Device) IsUsb() bool { +func (d *Device) IsUsb() bool { return d.Usb() != "" } -func (d Device) State() (DeviceState, error) { +func (d *Device) State() (DeviceState, error) { resp, err := d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:get-state", d.serial)) return deviceStateConv(resp), err } -func (d Device) DevicePath() (string, error) { +func (d *Device) DevicePath() (string, error) { resp, err := d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:get-devpath", d.serial)) return resp, err } -func (d Device) Forward(localPort, remotePort int, noRebind ...bool) (err error) { +func (d *Device) Forward(localPort int, remoteInterface interface{}, noRebind ...bool) (err error) { command := "" + var remote string local := fmt.Sprintf("tcp:%d", localPort) - remote := fmt.Sprintf("tcp:%d", remotePort) + switch r := remoteInterface.(type) { + // for unix sockets + case string: + remote = r + case int: + remote = fmt.Sprintf("tcp:%d", r) + } if len(noRebind) != 0 && noRebind[0] { command = fmt.Sprintf("host-serial:%s:forward:norebind:%s;%s", d.serial, local, remote) @@ -115,7 +159,7 @@ func (d Device) Forward(localPort, remotePort int, noRebind ...bool) (err error) return } -func (d Device) ForwardList() (deviceForwardList []DeviceForward, err error) { +func (d *Device) ForwardList() (deviceForwardList []DeviceForward, err error) { var forwardList []DeviceForward if forwardList, err = d.adbClient.ForwardList(); err != nil { return nil, err @@ -131,18 +175,81 @@ func (d Device) ForwardList() (deviceForwardList []DeviceForward, err error) { return } -func (d Device) ForwardKill(localPort int) (err error) { +func (d *Device) ForwardKill(localPort int) (err error) { local := fmt.Sprintf("tcp:%d", localPort) _, err = d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:killforward:%s", d.serial, local), true) return } -func (d Device) RunShellCommand(cmd string, args ...string) (string, error) { +func (d *Device) ReverseForward(localPort int, remoteInterface interface{}, noRebind ...bool) (err error) { + var command string + var remote string + local := fmt.Sprintf("tcp:%d", localPort) + switch r := remoteInterface.(type) { + // for unix sockets + case string: + remote = r + case int: + remote = fmt.Sprintf("tcp:%d", r) + } + + if len(noRebind) != 0 && noRebind[0] { + command = fmt.Sprintf("reverse:forward:norebind:%s;%s", remote, local) + } else { + command = fmt.Sprintf("reverse:forward:%s;%s", remote, local) + } + _, err = d.executeCommand(command, true) + return +} + +func (d *Device) ReverseForwardList() (deviceForwardList []DeviceForward, err error) { + res, err := d.executeCommand("reverse:list-forward") + if err != nil { + return nil, err + } + resStr := string(res) + lines := strings.Split(resStr, "\n") + for _, line := range lines { + groups := strings.Split(line, " ") + if len(groups) == 3 { + deviceForwardList = append(deviceForwardList, DeviceForward{ + Reverse: true, + Serial: d.serial, + Remote: groups[1], + Local: groups[2], + }) + } + } + return +} + +func (d *Device) ReverseForwardKill(remoteInterface interface{}) error { + remote := "" + switch r := remoteInterface.(type) { + case string: + remote = r + case int: + remote = fmt.Sprintf("tcp:%d", r) + } + _, err := d.executeCommand(fmt.Sprintf("reverse:killforward:%s", remote), true) + return err +} + +func (d *Device) ReverseForwardKillAll() error { + _, err := d.executeCommand("reverse:killforward-all") + return err +} + +func (d *Device) RunShellCommand(cmd string, args ...string) (string, error) { raw, err := d.RunShellCommandWithBytes(cmd, args...) return string(raw), err } -func (d Device) RunShellCommandWithBytes(cmd string, args ...string) ([]byte, error) { +func (d *Device) RunShellCommandWithBytes(cmd string, args ...string) ([]byte, error) { + if d.HasFeature(FeatShellV2) { + raw, err := d.RunShellCommandV2WithBytes(cmd, args...) + return raw, err + } if len(args) > 0 { cmd = fmt.Sprintf("%s %s", cmd, strings.Join(args, " ")) } @@ -156,7 +263,86 @@ func (d Device) RunShellCommandWithBytes(cmd string, args ...string) ([]byte, er return raw, err } -func (d Device) EnableAdbOverTCP(port ...int) (err error) { +func (d *Device) RunShellCommandV2(cmd string, args ...string) (string, error) { + raw, err := d.RunShellCommandV2WithBytes(cmd, args...) + return string(raw), err +} + +// RunShellCommandV2WithBytes shell v2, 支持后台运行而不会阻断 +func (d *Device) RunShellCommandV2WithBytes(cmd string, args ...string) ([]byte, error) { + if len(args) > 0 { + cmd = fmt.Sprintf("%s %s", cmd, strings.Join(args, " ")) + } + if strings.TrimSpace(cmd) == "" { + return nil, errors.New("adb shell: command cannot be empty") + } + log.Debug().Str("cmd", + fmt.Sprintf("adb -s %s shell %s", d.serial, cmd)). + Msg("run adb command") + raw, err := d.executeCommand(fmt.Sprintf("shell,v2,raw:%s", cmd)) + if err != nil { + return raw, err + } + return d.parseV2CommandWithBytes(raw) +} + +func (d *Device) parseV2CommandWithBytes(input []byte) (res []byte, err error) { + if len(input) == 0 { + return input, nil + } + reader := bytes.NewReader(input) + sizeBuf := make([]byte, 4) + var ( + resBuf []byte + exitCode int + ) +loop: + for { + msgCode, err := reader.ReadByte() + if err != nil { + return input, err + } + switch msgCode { + case 0x01, 0x02: // STDOUT, STDERR + _, err = io.ReadFull(reader, sizeBuf) + if err != nil { + return input, err + } + size := binary.LittleEndian.Uint32(sizeBuf) + if cap(resBuf) < int(size) { + resBuf = make([]byte, int(size)) + } + _, err = io.ReadFull(reader, resBuf[:size]) + if err != nil { + return input, err + } + res = append(res, resBuf[:size]...) + case 0x03: // EXIT + _, err = io.ReadFull(reader, sizeBuf) + if err != nil { + return input, err + } + size := binary.LittleEndian.Uint32(sizeBuf) + if cap(resBuf) < int(size) { + resBuf = make([]byte, int(size)) + } + ec, err := reader.ReadByte() + if err != nil { + return input, err + } + exitCode = int(ec) + break loop + default: + return input, nil + } + } + if exitCode != 0 { + return nil, errors.New(string(res)) + } + return res, nil +} + +func (d *Device) EnableAdbOverTCP(port ...int) (err error) { if len(port) == 0 { port = []int{AdbDaemonPort} } @@ -168,7 +354,7 @@ func (d Device) EnableAdbOverTCP(port ...int) (err error) { return } -func (d Device) createDeviceTransport() (tp transport, err error) { +func (d *Device) createDeviceTransport() (tp transport, err error) { if tp, err = newTransport(fmt.Sprintf("%s:%d", d.adbClient.host, d.adbClient.port)); err != nil { return transport{}, err } @@ -180,7 +366,7 @@ func (d Device) createDeviceTransport() (tp transport, err error) { return } -func (d Device) executeCommand(command string, onlyVerifyResponse ...bool) (raw []byte, err error) { +func (d *Device) executeCommand(command string, onlyVerifyResponse ...bool) (raw []byte, err error) { if len(onlyVerifyResponse) == 0 { onlyVerifyResponse = []bool{false} } @@ -207,7 +393,7 @@ func (d Device) executeCommand(command string, onlyVerifyResponse ...bool) (raw return } -func (d Device) List(remotePath string) (devFileInfos []DeviceFileInfo, err error) { +func (d *Device) List(remotePath string) (devFileInfos []DeviceFileInfo, err error) { var tp transport if tp, err = d.createDeviceTransport(); err != nil { return nil, err @@ -237,7 +423,7 @@ func (d Device) List(remotePath string) (devFileInfos []DeviceFileInfo, err erro return } -func (d Device) PushFile(local *os.File, remotePath string, modification ...time.Time) (err error) { +func (d *Device) PushFile(local *os.File, remotePath string, modification ...time.Time) (err error) { if len(modification) == 0 { var stat os.FileInfo if stat, err = local.Stat(); err != nil { @@ -249,7 +435,7 @@ func (d Device) PushFile(local *os.File, remotePath string, modification ...time return d.Push(local, remotePath, modification[0], DefaultFileMode) } -func (d Device) Push(source io.Reader, remotePath string, modification time.Time, mode ...os.FileMode) (err error) { +func (d *Device) Push(source io.Reader, remotePath string, modification time.Time, mode ...os.FileMode) (err error) { if len(mode) == 0 { mode = []os.FileMode{DefaultFileMode} } @@ -285,7 +471,7 @@ func (d Device) Push(source io.Reader, remotePath string, modification time.Time return } -func (d Device) Pull(remotePath string, dest io.Writer) (err error) { +func (d *Device) Pull(remotePath string, dest io.Writer) (err error) { var tp transport if tp, err = d.createDeviceTransport(); err != nil { return err @@ -305,3 +491,83 @@ func (d Device) Pull(remotePath string, dest io.Writer) (err error) { err = sync.WriteStream(dest) return } + +func (d *Device) installViaABBExec(apk io.ReadSeeker) (raw []byte, err error) { + var ( + tp transport + filesize int64 + ) + filesize, err = apk.Seek(0, io.SeekEnd) + if err != nil { + return nil, err + } + if tp, err = d.createDeviceTransport(); err != nil { + return nil, err + } + defer func() { _ = tp.Close() }() + if err = tp.Send(fmt.Sprintf("abb_exec:package\x00install\x00-t\x00-S\x00%d", filesize)); err != nil { + return nil, err + } + + if err = tp.VerifyResponse(); err != nil { + return nil, err + } + _, err = apk.Seek(0, io.SeekStart) + if err != nil { + return nil, err + } + _, err = io.Copy(tp.Conn(), apk) + if err != nil { + return nil, err + } + raw, err = tp.ReadBytesAll() + return +} + +func (d *Device) InstallAPK(apk io.ReadSeeker) (string, error) { + haserr := func(ret string) bool { + return strings.Contains(ret, "Failure") + } + if d.HasFeature(FeatAbbExec) { + raw, err := d.installViaABBExec(apk) + if err != nil { + return "", fmt.Errorf("error installing: %v", err) + } + if haserr(string(raw)) { + return "", errors.New(string(raw)) + } + return string(raw), err + } + + remote := fmt.Sprintf("/data/local/tmp/gadb_remote_%d.apk", time.Now().Unix()) + err := d.Push(apk, remote, time.Now()) + if err != nil { + return "", fmt.Errorf("error pushing: %v", err) + } + + res, err := d.RunShellCommand("pm", "install", "-f", remote) + if err != nil { + return "", fmt.Errorf("error installing: %v", err) + } + if haserr(res) { + return "", errors.New(res) + } + + return res, nil +} + +func (d *Device) Uninstall(packageName string, keepData ...bool) (string, error) { + if len(keepData) == 0 { + keepData = []bool{false} + } + packageName = strings.ReplaceAll(packageName, " ", "") + if len(packageName) == 0 { + return "", fmt.Errorf("invalid package name") + } + args := []string{"uninstall"} + if keepData[0] { + args = append(args, "-k") + } + args = append(args, packageName) + return d.RunShellCommandV2("pm", args...) +} diff --git a/hrp/pkg/gadb/device_test.go b/hrp/pkg/gadb/device_test.go index 70ae4889..29f48b4d 100644 --- a/hrp/pkg/gadb/device_test.go +++ b/hrp/pkg/gadb/device_test.go @@ -6,6 +6,7 @@ import ( "bytes" "io/ioutil" "os" + "reflect" "strings" "testing" "time" @@ -145,6 +146,42 @@ func TestDevice_Forward(t *testing.T) { } } +func TestDevice_ReverseForward(t *testing.T) { + adbClient, err := NewClient() + if err != nil { + t.Fatal(err) + } + + devices, err := adbClient.DeviceList() + if err != nil { + t.Fatal(err) + } + + localPort := 5005 + err = devices[0].ReverseForward(localPort, "localabstract:scrcpy") + if err != nil { + t.Fatal(err) + } + err = devices[0].ReverseForward(localPort, "localabstract:scrcpy1") + if err != nil { + t.Fatal(err) + } + + _, err = devices[0].ReverseForwardList() + if err != nil { + t.Fatal(err) + } + + err = devices[0].ReverseForwardKill("localabstract:scrcpy1") + if err != nil { + t.Fatal(err) + } + err = devices[0].ReverseForwardKillAll() + if err != nil { + t.Fatal(err) + } +} + func TestDevice_ForwardList(t *testing.T) { adbClient, err := NewClient() if err != nil { @@ -314,3 +351,94 @@ func TestDevice_Pull(t *testing.T) { t.Fatal(err) } } + +func TestDevice_RunShellCommandBackgroundWithBytes(t *testing.T) { + type fields struct { + adbClient Client + serial string + attrs map[string]string + } + type args struct { + cmd string + args []string + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "runShellCommandBackground", + fields: fields{ + adbClient: func() Client { + c, _ := NewClient() + return c + }(), + serial: "63c1ee94", + }, + args: args{ + cmd: "nohup sleep 10 2>/dev/null 1>/dev/null &", + // cmd: "sleep 10", + + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := Device{ + adbClient: tt.fields.adbClient, + serial: tt.fields.serial, + attrs: tt.fields.attrs, + } + got, err := d.RunShellCommandV2WithBytes(tt.args.cmd, tt.args.args...) + if (err != nil) != tt.wantErr { + t.Errorf("Device.RunShellCommandBackgroundWithBytes() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Device.RunShellCommandBackgroundWithBytes() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDevice_InstallAPK(t *testing.T) { + apk, _ := os.Open("test.apk") + adbClient, err := NewClient() + if err != nil { + t.Fatal(err) + } + + devices, err := adbClient.DeviceList() + if err != nil { + t.Fatal(err) + } + + dev := devices[len(devices)-1] + dev = devices[0] + + res, err := dev.InstallAPK(apk) + if err != nil { + t.Fatal(err) + } + t.Log(res) +} + +func TestDevice_HasFeature(t *testing.T) { + adbClient, err := NewClient() + if err != nil { + t.Fatal(err) + } + + devices, err := adbClient.DeviceList() + if err != nil { + t.Fatal(err) + } + + dev := devices[len(devices)-1] + dev = devices[0] + + t.Log(dev.GetFeatures()) +} diff --git a/hrp/pkg/gadb/features.go b/hrp/pkg/gadb/features.go new file mode 100644 index 00000000..806f175c --- /dev/null +++ b/hrp/pkg/gadb/features.go @@ -0,0 +1,26 @@ +package gadb + +type ( + Feature string + Features map[Feature]struct{} +) + +var ( + FeatSendrecvV2Brotli = Feature("sendrecv_v2_brotli") + FeatRemountShell = Feature("remount_shell") + FeatSendrecvV2 = Feature("sendrecv_v2") + FeatAbbExec = Feature("abb_exec") + FeatFixedPushMkdir = Feature("fixed_push_mkdir") + FeatFixedPushSymlinkTimestamp = Feature("fixed_push_symlink_timestamp") + FeatAbb = Feature("abb") + FeatShellV2 = Feature("shell_v2") + FeatCmd = Feature("cmd") + FeatLsV2 = Feature("ls_v2") + FeatApex = Feature("apex") + FeatStatV2 = Feature("stat_v2") +) + +func (fs Features) HasFeature(name Feature) bool { + _, has := fs[name] + return has +} diff --git a/hrp/pkg/gadb/sync_transport.go b/hrp/pkg/gadb/sync_transport.go index 6e55df6b..ff7346a4 100644 --- a/hrp/pkg/gadb/sync_transport.go +++ b/hrp/pkg/gadb/sync_transport.go @@ -250,5 +250,6 @@ func (sync syncTransport) Close() (err error) { if sync.sock == nil { return nil } + _ = DisableTimeWait(sync.sock.(*net.TCPConn)) return sync.sock.Close() } diff --git a/hrp/pkg/gadb/transport.go b/hrp/pkg/gadb/transport.go index ae900429..8c54089e 100644 --- a/hrp/pkg/gadb/transport.go +++ b/hrp/pkg/gadb/transport.go @@ -34,9 +34,18 @@ func newTransport(address string, readTimeout ...time.Duration) (tp transport, e func (t transport) Send(command string) (err error) { msg := fmt.Sprintf("%04x%s", len(command), command) + log.Debug().Str("cmd", command).Msg("run adb command") return _send(t.sock, []byte(msg)) } +func (t transport) SendBytes(b []byte) (err error) { + return _send(t.sock, b) +} + +func (t transport) Conn() net.Conn { + return t.sock +} + func (t transport) VerifyResponse() (err error) { var status string if status, err = t.ReadStringN(4); err != nil { @@ -103,6 +112,7 @@ func (t transport) Close() (err error) { if t.sock == nil { return nil } + _ = DisableTimeWait(t.sock.(*net.TCPConn)) return t.sock.Close() } diff --git a/hrp/pkg/gadb/transport_test.go b/hrp/pkg/gadb/transport_test.go index 143cd438..2610a19e 100644 --- a/hrp/pkg/gadb/transport_test.go +++ b/hrp/pkg/gadb/transport_test.go @@ -13,7 +13,6 @@ func Test_transport_VerifyResponse(t *testing.T) { } defer transport.Close() - // err = transport.Send("host:123version") err = transport.Send("host:version") if err != nil { t.Fatal(err) diff --git a/hrp/pkg/gadb/utils.go b/hrp/pkg/gadb/utils.go new file mode 100644 index 00000000..e6536c37 --- /dev/null +++ b/hrp/pkg/gadb/utils.go @@ -0,0 +1,9 @@ +package gadb + +import ( + "net" +) + +func DisableTimeWait(conn *net.TCPConn) error { + return conn.SetLinger(0) +} diff --git a/hrp/pkg/uixt/android_adb_driver.go b/hrp/pkg/uixt/android_adb_driver.go index 394bf14e..e9a35b38 100644 --- a/hrp/pkg/uixt/android_adb_driver.go +++ b/hrp/pkg/uixt/android_adb_driver.go @@ -17,7 +17,7 @@ import ( type adbDriver struct { Driver - adbClient gadb.Device + adbClient *gadb.Device logcat *AdbLogcat } diff --git a/hrp/pkg/uixt/android_device.go b/hrp/pkg/uixt/android_device.go index 83a46d27..ad80f6e1 100644 --- a/hrp/pkg/uixt/android_device.go +++ b/hrp/pkg/uixt/android_device.go @@ -115,7 +115,7 @@ func NewAndroidDevice(options ...AndroidDeviceOption) (device *AndroidDevice, er fmt.Sprintf("device %s not found", device.SerialNumber)) } -func DeviceList() (devices []gadb.Device, err error) { +func DeviceList() (devices []*gadb.Device, err error) { var adbClient gadb.Client if adbClient, err = gadb.NewClientWith(AdbServerHost, AdbServerPort); err != nil { return nil, errors.Wrap(code.AndroidDeviceConnectionError, err.Error()) @@ -125,7 +125,7 @@ func DeviceList() (devices []gadb.Device, err error) { } type AndroidDevice struct { - d gadb.Device + d *gadb.Device logcat *AdbLogcat SerialNumber string `json:"serial,omitempty" yaml:"serial,omitempty"` UIA2 bool `json:"uia2,omitempty" yaml:"uia2,omitempty"` // use uiautomator2 From ef784709af5863b2023a5b2722b19006e929e467 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Thu, 13 Apr 2023 22:48:40 +0800 Subject: [PATCH 2/3] faet: add ScreenCap for gadb --- hrp/pkg/gadb/client_test.go | 2 +- hrp/pkg/gadb/device.go | 4 ++++ hrp/pkg/uixt/android_adb_driver.go | 4 +--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hrp/pkg/gadb/client_test.go b/hrp/pkg/gadb/client_test.go index dff28e38..56dd1a94 100644 --- a/hrp/pkg/gadb/client_test.go +++ b/hrp/pkg/gadb/client_test.go @@ -140,7 +140,7 @@ func TestScreenCap(t *testing.T) { t.Error(err) } d := dl[0] - res, err := d.RunShellCommandV2WithBytes("screencap", "-p") + res, err := d.ScreenCap() if err != nil { t.Error(err) } diff --git a/hrp/pkg/gadb/device.go b/hrp/pkg/gadb/device.go index b9911272..4b296396 100644 --- a/hrp/pkg/gadb/device.go +++ b/hrp/pkg/gadb/device.go @@ -571,3 +571,7 @@ func (d *Device) Uninstall(packageName string, keepData ...bool) (string, error) args = append(args, packageName) return d.RunShellCommandV2("pm", args...) } + +func (d *Device) ScreenCap() ([]byte, error) { + return d.RunShellCommandV2WithBytes("screencap", "-p") +} diff --git a/hrp/pkg/uixt/android_adb_driver.go b/hrp/pkg/uixt/android_adb_driver.go index e9a35b38..fbf89eb2 100644 --- a/hrp/pkg/uixt/android_adb_driver.go +++ b/hrp/pkg/uixt/android_adb_driver.go @@ -280,9 +280,7 @@ func (ad *adbDriver) SetRotation(rotation Rotation) (err error) { func (ad *adbDriver) Screenshot() (raw *bytes.Buffer, err error) { // adb shell screencap -p - resp, err := ad.adbClient.RunShellCommandWithBytes( - "screencap", "-p", - ) + resp, err := ad.adbClient.ScreenCap() if err == nil { return bytes.NewBuffer(resp), nil } From ba5222a30ae4725df2026e619b8590cbb91bfb69 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Thu, 13 Apr 2023 23:08:43 +0800 Subject: [PATCH 3/3] change: remove debug log --- hrp/pkg/gadb/device.go | 5 ++--- hrp/pkg/gadb/transport.go | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/hrp/pkg/gadb/device.go b/hrp/pkg/gadb/device.go index 4b296396..97bb08db 100644 --- a/hrp/pkg/gadb/device.go +++ b/hrp/pkg/gadb/device.go @@ -247,8 +247,7 @@ func (d *Device) RunShellCommand(cmd string, args ...string) (string, error) { func (d *Device) RunShellCommandWithBytes(cmd string, args ...string) ([]byte, error) { if d.HasFeature(FeatShellV2) { - raw, err := d.RunShellCommandV2WithBytes(cmd, args...) - return raw, err + return d.RunShellCommandV2WithBytes(cmd, args...) } if len(args) > 0 { cmd = fmt.Sprintf("%s %s", cmd, strings.Join(args, " ")) @@ -278,7 +277,7 @@ func (d *Device) RunShellCommandV2WithBytes(cmd string, args ...string) ([]byte, } log.Debug().Str("cmd", fmt.Sprintf("adb -s %s shell %s", d.serial, cmd)). - Msg("run adb command") + Msg("run adb command in v2") raw, err := d.executeCommand(fmt.Sprintf("shell,v2,raw:%s", cmd)) if err != nil { return raw, err diff --git a/hrp/pkg/gadb/transport.go b/hrp/pkg/gadb/transport.go index 8c54089e..c450d053 100644 --- a/hrp/pkg/gadb/transport.go +++ b/hrp/pkg/gadb/transport.go @@ -34,7 +34,6 @@ func newTransport(address string, readTimeout ...time.Duration) (tp transport, e func (t transport) Send(command string) (err error) { msg := fmt.Sprintf("%04x%s", len(command), command) - log.Debug().Str("cmd", command).Msg("run adb command") return _send(t.sock, []byte(msg)) }