Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7df14ef3 authored by Doug Zongker's avatar Doug Zongker Committed by Android (Google) Code Review
Browse files

Merge "add sideload-host mode to adb"

parents 42461b7a 71fe584a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@
#define ADB_VERSION_MAJOR 1         // Used for help/version information
#define ADB_VERSION_MINOR 0         // Used for help/version information

#define ADB_SERVER_VERSION    31    // Increment this when we want to force users to start a new adb server
#define ADB_SERVER_VERSION    32    // Increment this when we want to force users to start a new adb server

typedef struct amessage amessage;
typedef struct apacket apacket;
+2 −1
Original line number Diff line number Diff line
@@ -279,7 +279,7 @@ int adb_connect(const char *service)

    fd = _adb_connect(service);
    if(fd == -1) {
        fprintf(stderr,"error: %s\n", __adb_error);
        D("_adb_connect error: %s\n", __adb_error);
    } else if(fd == -2) {
        fprintf(stderr,"** daemon still not running\n");
    }
@@ -296,6 +296,7 @@ int adb_command(const char *service)
{
    int fd = adb_connect(service);
    if(fd < 0) {
        fprintf(stderr, "error: %s\n", adb_error());
        return -1;
    }

+110 −1
Original line number Diff line number Diff line
@@ -501,6 +501,115 @@ int adb_download(const char *service, const char *fn, unsigned progress)
    return status;
}

#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)

/*
 * The sideload-host protocol serves the data in a file (given on the
 * command line) to the client, using a simple protocol:
 *
 * - The connect message includes the total number of bytes in the
 *   file and a block size chosen by us.
 *
 * - The other side sends the desired block number as eight decimal
 *   digits (eg "00000023" for block 23).  Blocks are numbered from
 *   zero.
 *
 * - We send back the data of the requested block.  The last block is
 *   likely to be partial; when the last block is requested we only
 *   send the part of the block that exists, it's not padded up to the
 *   block size.
 *
 * - When the other side sends "DONEDONE" instead of a block number,
 *   we hang up.
 */
int adb_sideload_host(const char* fn) {
    uint8_t* data;
    unsigned sz;
    size_t xfer = 0;
    int status;

    printf("loading: '%s'", fn);
    fflush(stdout);
    data = load_file(fn, &sz);
    if (data == 0) {
        printf("\n");
        fprintf(stderr, "* cannot read '%s' *\n", fn);
        return -1;
    }

    char buf[100];
    sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
    int fd = adb_connect(buf);
    if (fd < 0) {
        // Try falling back to the older sideload method.  Maybe this
        // is an older device that doesn't support sideload-host.
        printf("\n");
        status = adb_download_buffer("sideload", fn, data, sz, 1);
        goto done;
    }

    int opt = SIDELOAD_HOST_BLOCK_SIZE;
    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));

    int last_percent = -1;
    while (true) {
        if (readx(fd, buf, 8)) {
            fprintf(stderr, "* failed to read command: %s\n", adb_error());
            status = -1;
            goto done;
        }

        if (strncmp("DONEDONE", buf, 8) == 0) {
            status = 0;
            break;
        }

        buf[8] = '\0';
        int block = strtol(buf, NULL, 10);

        size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
        if (offset >= sz) {
            fprintf(stderr, "* attempt to read past end: %s\n", adb_error());
            status = -1;
            goto done;
        }
        uint8_t* start = data + offset;
        size_t offset_end = offset + SIDELOAD_HOST_BLOCK_SIZE;
        size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
        if (offset_end > sz) {
            to_write = sz - offset;
        }

        if(writex(fd, start, to_write)) {
            adb_status(fd);
            fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
            status = -1;
            goto done;
        }
        xfer += to_write;

        // For normal OTA packages, we expect to transfer every byte
        // twice, plus a bit of overhead (one read during
        // verification, one read of each byte for installation, plus
        // extra access to things like the zip central directory).
        // This estimate of the completion becomes 100% when we've
        // transferred ~2.13 (=100/47) times the package size.
        int percent = (int)(xfer * 47LL / (sz ? sz : 1));
        if (percent != last_percent) {
            printf("\rserving: '%s'  (~%d%%)    ", fn, percent);
            fflush(stdout);
            last_percent = percent;
        }
    }

    printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), strlen(fn)+10, "");

  done:
    if (fd >= 0) adb_close(fd);
    free(data);
    return status;
}

static void status_window(transport_type ttype, const char* serial)
{
    char command[4096];
@@ -1291,7 +1400,7 @@ top:

    if(!strcmp(argv[0], "sideload")) {
        if(argc != 2) return usage();
        if(adb_download("sideload", argv[1], 1)) {
        if (adb_sideload_host(argv[1])) {
            return 1;
        } else {
            return 0;