diff --git a/adb/device.go b/adb/device.go index 36d7064..3b0f8b7 100644 --- a/adb/device.go +++ b/adb/device.go @@ -80,6 +80,7 @@ func (c *Device) DeviceInfo() (*DeviceInfo, error) { RunCommand runs the specified commands on a shell on the device. From the Android docs: + Run 'command arg1 arg2 ...' in a shell on the device, and return its output and error streams. Note that arguments must be separated by spaces. If an argument contains a space, it must be quoted with @@ -87,6 +88,7 @@ From the Android docs: will go very wrong. Note that this is the non-interactive version of "adb shell" + Source: https://android.googlesource.com/platform/system/core/+/master/adb/SERVICES.TXT This method quotes the arguments for you, and will return an error if any of them @@ -120,13 +122,84 @@ func (c *Device) RunCommand(cmd string, args ...string) (string, error) { return string(resp), wrapClientError(err, c, "RunCommand") } +/* +Forward, from the official adb command's docs: + + Asks the ADB server to forward local connections from + to the address on a given device. + There, can be one of the + host-serial/host-usb/host-local/host prefixes as described previously + and indicates which device/emulator to target. + the format of is one of: + tcp: -> TCP connection on localhost: + local: -> Unix local domain socket on + the format of is one of: + tcp: -> TCP localhost: on device + local: -> Unix local domain socket on device + jdwp: -> JDWP thread on VM process + vsock:: -> vsock on the given CID and port + or even any one of the local services described below. + +Source: https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/main/SERVICES.TXT +*/ +func (c *Device) Forward(local string, remote string) error { + req := fmt.Sprintf("forward:%s;%s", local, remote) + _, err := c.getAttribute(req) + return wrapClientError(err, c, "Forward") +} + +/* +KillForward, from the official adb command's docs: + + Remove any existing forward local connection from . + +Source: https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/main/SERVICES.TXT +*/ +func (c *Device) KillForward(local string) error { + req := fmt.Sprintf("killforward:%s", local) + _, err := c.getAttribute(req) + return wrapClientError(err, c, "KillForward") +} + +/* +KillForwardAll, from the official adb command's docs: + + Remove all forward network connections. + +Source: https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/main/SERVICES.TXT +*/ +func (c *Device) KillForwardAll() error { + req := fmt.Sprintf("killforward-all") + _, err := c.getAttribute(req) + return wrapClientError(err, c, "KillForward") +} + +/* +KillForwardAll, from the official adb command's docs: + + Remove all forward network connections. + +Source: https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/main/SERVICES.TXT +*/ +func (c *Device) ListForward() ([]Forward, error) { + req := fmt.Sprintf("list-forward") + resp, err := c.getAttribute(req) + if err != nil { + return nil, wrapClientError(err, c, "ListForwards") + } + forwards, err := parseForward(resp, c.descriptor.serial) + return forwards, wrapClientError(err, c, "ListForwards") +} + /* Remount, from the official adb command’s docs: + Ask adbd to remount the device's filesystem in read-write mode, instead of read-only. This is usually necessary before performing an "adb sync" or "adb push" request. This request may not succeed on certain builds which do not allow that. + Source: https://android.googlesource.com/platform/system/core/+/master/adb/SERVICES.TXT */ func (c *Device) Remount() (string, error) { diff --git a/adb/device_forward.go b/adb/device_forward.go new file mode 100644 index 0000000..ad884d0 --- /dev/null +++ b/adb/device_forward.go @@ -0,0 +1,63 @@ +package adb + +import ( + "strings" + + "github.com/timoxa0/goadb/internal/errors" +) + +type ForwardType uint8 + +const ( + TypeInvalid ForwardType = iota + TCP + LOCAL +) + +var forwardTypeStrings = map[string]ForwardType{ + "tcp": TCP, + "local": LOCAL, +} + +type ForwardTarget string + +type ForwardLocal struct { + ftype ForwardType + target ForwardTarget +} + +type ForwardRemote struct { + ftype ForwardType + target ForwardTarget +} + +type Forward struct { + local ForwardLocal + remote ForwardRemote +} + +func parseForward(str string, deviceSerial string) ([]Forward, error) { + var forwards []Forward + for _, forwardStr := range strings.Split(str, "\n") { + if strings.Trim(forwardStr, "\n\t ") == "" { + continue + } + raw_forward := strings.Split(forwardStr, " ") + serial, local, remote := raw_forward[0], raw_forward[1], raw_forward[2] + if serial == deviceSerial { + raw_local := strings.Split(local, ":") + raw_remote := strings.Split(remote, ":") + forwards = append(forwards, Forward{ + local: ForwardLocal{ + ftype: forwardTypeStrings[raw_local[0]], + target: ForwardTarget(raw_local[1]), + }, + remote: ForwardRemote{ + ftype: forwardTypeStrings[raw_remote[0]], + target: ForwardTarget(raw_remote[1]), + }, + }) + } + } + return forwards, errors.Errorf(errors.ParseError, "invalid device forward") +}