gadb

repository·master·Indexed 41 days ago

https://github.com/electricbubble/gadb

A pure Golang implementation of an ADB (Android Debug Bridge) client. It allows developers to interact with Android devices from Go applications, providing functionality to list devices, execute shell commands via RunShellCommand, transfer files using Push and Pull, stream logs with Logcat, and manage TCP port forwarding.

Tokens
6.8K
Snippets
37
Records
43
Agent score
100%

What's inside gadb

  1. Use shellTransport for shell protocol communication

    master

    The shellTransport type manages communication over a network connection using a specific shell protocol. It allows sending typed messages (like shellStdout or shellStdin) and reading responses.

    Messages are structured as:

    1. A 1-byte message type (shellMessageType).
    2. A 4-byte little-endian integer representing the length of the data.
    3. The raw data bytes.

    Note: shellTransport is an internal type used by the package to handle the transport layer for executing shell commands and reading their output.

    // Note: shellTransport is unexported (starts with lowercase 's'), 
    // implying it is used internally by other exported components of gadb.
    // Usage pattern involves interacting with the transport via Send and Read.
    
    // Example of the protocol message types:
    // shellStdin: 0
    // shellStdout: 1
    // shellStderr: 2
    // shellExit: 3
    // shellCloseStdin: 4
  2. Use the transport type for ADB protocol communication

    master

    The transport type provides low-level primitives for reading and writing ADB protocol data over a TCP connection. It handles command framing (prepending the 4-character hex length), response verification, and data unpacking.

    Note: While the transport struct itself is unexported (lowercase), it is returned by internal factory functions (not shown in this file) or used as the basis for specialized transports like syncTransport and shellTransport via its methods.

  3. Use syncTransport for synchronous ADB operations

    master

    The syncTransport type provides a mechanism for performing synchronous ADB operations, such as file transfers and directory entry reading, over a network connection (net.Conn). It handles the low-level protocol details including command framing, chunked data streaming, and status verification.

    Note: syncTransport is an unexported type, typically instantiated via an internal constructor or provided through a higher-level API in the gadb package.

  4. Use gadb to push and install an APK

    master

    You can use gadb to interact with connected Android devices. The typical workflow involves:

    1. Initializing a client with gadb.NewClient().
    2. Retrieving a list of devices via adbClient.DeviceList().
    3. Using a device instance to push files with dev.PushFile(file, remotePath).
    4. Executing shell commands with dev.RunShellCommand(command, args...) to perform actions like installing an APK via pm install.
    package main
    
    import (
    	"github.com/electricbubble/gadb"
    	"log"
    	"os"
    	"strings"
    )
    
    func main() {
    	adbClient, err := gadb.NewClient()
    	checkErr(err, "fail to connect adb server")
    
    	devices, err := adbClient.DeviceList()
    	checkErr(err)
    
    	if len(devices) == 0 {
    		log.Fatalln("list of devices is empty")
    	}
    
    	dev := devices[0]
    
    	userHomeDir, _ := os.UserHomeDir()
    	apk, err := os.Open(userHomeDir + "/Desktop/xuexi_android_10002068.apk")
    	checkErr(err)
    
    	log.Println("starting to push apk")
    
    	remotePath := "/data/local/tmp/xuexi_android_10002068.apk"
    	err = dev.PushFile(apk, remotePath)
    	checkErr(err, "adb push")
    
    	log.Println("push completed")
    
    	log.Println("starting to install apk")
    
    	shellOutput, err := dev.RunShellCommand("pm install", remotePath)
    	checkErr(err, "pm install")
    	if !strings.Contains(shellOutput, "Success") {
    		log.Fatalln("fail to install: ", shellOutput)
    	}
    
    	log.Println("install completed")
    }
    
    func checkErr(err error, msg ...string) {
    	if err == nil {
    		return
    	}
    
    	var output string
    	if len(msg) != 0 {
    		output = msg[0] + " "
    	}
    	output += err.Error()
    	log.Fatalln(output)
    }
  5. List files on a device using List

    master

    The List method retrieves directory information from a remote path on the device, returning a slice of DeviceFileInfo objects.

    files, err := device.List("/sdcard/Documents")
    if err != nil {
        log.Fatal(err)
    }
    
    for _, f := range files {
        fmt.Printf("Name: %s, Size: %d, IsDir: %v\n", f.Name, f.Size, f.IsDir())
    }
  6. List connected devices and their details

    master

    The Client provides several ways to retrieve information about connected devices:

    • DeviceSerialList(): Returns a slice of strings containing only the serial numbers of connected devices.
    • DeviceList(): Returns a slice of Device objects. Each Device contains its serial number and a map of attributes (e.g., model, product) parsed from the ADB output.

    Note: Device objects are linked to the Client that discovered them.

    // Get just the serials
    serials, err := client.DeviceSerialList()
    
    // Get full device objects with attributes
    devices, err := client.DeviceList()
    for _, dev := range devices {
    	fmt.Printf("Serial: %s, Attrs: %v\n", dev.Serial, dev.Attrs)
    }
  7. Verify command success with transport.VerifyResponse()

    master

    After sending a command, use VerifyResponse() to check if the ADB server returned an OKAY status.

    If the response is not OKAY, it attempts to unpack the error message using UnpackString() and returns a formatted error: command failed: <error_message>.

    err := t.Send("sync:")
    if err != nil {
        return err
    }
    
    err = t.VerifyResponse()
    if err != nil {
        // command failed
    }
  8. Manage port forwards

    master

    Use these methods to inspect or clear ADB port forwarding rules:

    • ForwardList(): Returns a slice of DeviceForward objects. Each object contains the Serial of the device, the Local address, and the Remote address.
    • ForwardKillAll(): Removes all active port forwards on the ADB server.
    forwards, err := client.ForwardList()
    for _, f := range forwards {
    	fmt.Printf("Device: %s, Local: %s, Remote: %s\n", f.Serial, f.Local, f.Remote)
    }
    
    // Clear all forwards
    err := client.ForwardKillAll()
  9. Create a sync transport via CreateSyncTransport()

    master

    The CreateSyncTransport() method transitions the current transport into a synchronous mode by sending the sync: command and verifying the OKAY response. It returns a syncTransport instance designed for the ADB sync protocol.

    syncTp, err := t.CreateSyncTransport()
    if err != nil {
        // handle error
    }
    // Use syncTp for sync protocol operations
  10. Unpack ADB data with UnpackBytes() and UnpackString()

    master

    ADB protocol often sends data preceded by a 4-character hex length. Use these methods to read and parse that data:

    • UnpackBytes(): Reads the 4-character hex length, converts it to an integer, and then reads that many bytes from the connection.
    • UnpackString(): A wrapper around UnpackBytes() that returns the result as a string.
    // Unpack a string sent by the server
    data, err := t.UnpackString()
    if err != nil {
        // handle error
    }
    fmt.Println("Received:", data)
  11. Create a shell transport via CreateShellTransport()

    master

    The CreateShellTransport() method returns a shellTransport instance, which is specialized for handling the ADB shell protocol.

    shellTp, err := t.CreateShellTransport()
    if err != nil {
        // handle error
    }
    // Use shellTp for shell protocol operations