/* 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 double-quotes. Arguments cannot contain double quotes or things 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 contain double quotes. */ func (c *DeviceClient) RunCommand(cmd string, args ...string) (string, error) { cmd, err := prepareCommandLine(cmd, args...) if err != nil { return "", wrapClientError(err, c, "RunCommand") } conn, err := c.dialDevice() if err != nil { return "", wrapClientError(err, c, "RunCommand") } defer conn.Close() req := fmt.Sprintf("shell:%s", cmd) // Shell responses are special, they don't include a length header. // We read until the stream is closed. // So, we can't use conn.RoundTripSingleResponse. if err = conn.SendMessage([]byte(req)); err != nil { return "", wrapClientError(err, c, "RunCommand") } if err = wire.ReadStatusFailureAsError(conn, req); err != nil { return "", wrapClientError(err, c, "RunCommand") } resp, err := conn.ReadUntilEof() return string(resp), wrapClientError(err, c, "RunCommand") }
func (c *DeviceClient) getSyncConn() (*wire.SyncConn, error) { conn, err := c.dialDevice() if err != nil { return nil, err } // Switch the connection to sync mode. if err := wire.SendMessageString(conn, "sync:"); err != nil { return nil, err } if err := wire.ReadStatusFailureAsError(conn, "sync"); err != nil { return nil, err } return conn.NewSyncConn(), nil }
func connectToTrackDevices(dialer Dialer) (wire.Scanner, error) { conn, err := dialer.Dial() if err != nil { return nil, err } if err := wire.SendMessageString(conn, "host:track-devices"); err != nil { conn.Close() return nil, err } if err := wire.ReadStatusFailureAsError(conn, "host:track-devices"); err != nil { conn.Close() return nil, err } return conn, nil }
// dialDevice switches the connection to communicate directly with the device // by requesting the transport defined by the DeviceDescriptor. func (c *DeviceClient) dialDevice() (*wire.Conn, error) { conn, err := c.config.Dialer.Dial() if err != nil { return nil, err } req := fmt.Sprintf("host:%s", c.descriptor.getTransportDescriptor()) if err = wire.SendMessageString(conn, req); err != nil { conn.Close() return nil, util.WrapErrf(err, "error connecting to device '%s'", c.descriptor) } if err = wire.ReadStatusFailureAsError(conn, req); err != nil { conn.Close() return nil, err } return conn, nil }