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

Commit 539f3ddf authored by Elliott Hughes's avatar Elliott Hughes Committed by Gerrit Code Review
Browse files

Merge "Add "require partition-exists=" support."

parents 45562bfb 5620d224
Loading
Loading
Loading
Loading
+152 −217
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@
 */

#include "fastboot.h"
#include "fs.h"

#include <errno.h>
#include <stdarg.h>
@@ -38,150 +37,117 @@
#include <sys/types.h>
#include <unistd.h>

#define OP_DOWNLOAD   1
#define OP_COMMAND    2
#define OP_QUERY      3
#define OP_NOTICE     4
#define OP_DOWNLOAD_SPARSE 5
#define OP_WAIT_FOR_DISCONNECT 6
#define OP_DOWNLOAD_FD 7
#define OP_UPLOAD 8
#include <memory>
#include <vector>

typedef struct Action Action;
#include <android-base/stringprintf.h>

#define CMD_SIZE 64
enum Op {
    OP_DOWNLOAD,
    OP_COMMAND,
    OP_QUERY,
    OP_NOTICE,
    OP_DOWNLOAD_SPARSE,
    OP_WAIT_FOR_DISCONNECT,
    OP_DOWNLOAD_FD,
    OP_UPLOAD,
};

struct Action {
    unsigned op;
    Action* next;

    char cmd[CMD_SIZE];
    const char* prod;
    void* data;
    int fd;
    Action(Op op, const std::string& cmd) : op(op), cmd(cmd) {}

    // The protocol only supports 32-bit sizes, so you'll have to break
    // anything larger into chunks.
    uint32_t size;
    Op op;
    std::string cmd;
    std::string msg;

    const char *msg;
    int (*func)(Action* a, int status, const char* resp);
    std::string product;

    double start;
};
    void* data = nullptr;
    // The protocol only supports 32-bit sizes, so you'll have to break
    // anything larger into multiple chunks.
    uint32_t size = 0;

static Action *action_list = 0;
static Action *action_last = 0;
    int fd = -1;

    int (*func)(Action& a, int status, const char* resp) = nullptr;

    double start = -1;
};

static std::vector<std::unique_ptr<Action>> action_list;

bool fb_getvar(Transport* transport, const std::string& key, std::string* value) {
    std::string cmd = "getvar:";
    cmd += key;
    std::string cmd = "getvar:" + key;

    char buf[FB_RESPONSE_SZ + 1];
    memset(buf, 0, sizeof(buf));
    if (fb_command_response(transport, cmd.c_str(), buf)) {
    if (fb_command_response(transport, cmd, buf)) {
        return false;
    }
    *value = buf;
    return true;
}

static int cb_default(Action* a, int status, const char* resp) {
static int cb_default(Action& a, int status, const char* resp) {
    if (status) {
        fprintf(stderr,"FAILED (%s)\n", resp);
    } else {
        double split = now();
        fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
        a->start = split;
        fprintf(stderr, "OKAY [%7.3fs]\n", (split - a.start));
        a.start = split;
    }
    return status;
}

static Action *queue_action(unsigned op, const char *fmt, ...)
{
    va_list ap;
    size_t cmdsize;

    Action* a = reinterpret_cast<Action*>(calloc(1, sizeof(Action)));
    if (a == nullptr) die("out of memory");

    va_start(ap, fmt);
    cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
    va_end(ap);

    if (cmdsize >= sizeof(a->cmd)) {
        free(a);
        die("Command length (%zu) exceeds maximum size (%zu)", cmdsize, sizeof(a->cmd));
    }

    if (action_last) {
        action_last->next = a;
    } else {
        action_list = a;
    }
    action_last = a;
    a->op = op;
static Action& queue_action(Op op, const std::string& cmd) {
    std::unique_ptr<Action> a{new Action(op, cmd)};
    a->func = cb_default;

    a->start = -1;

    return a;
    action_list.push_back(std::move(a));
    return *action_list.back();
}

void fb_set_active(const char *slot)
{
    Action *a;
    a = queue_action(OP_COMMAND, "set_active:%s", slot);
    a->msg = mkmsg("Setting current slot to '%s'", slot);
void fb_set_active(const std::string& slot) {
    Action& a = queue_action(OP_COMMAND, "set_active:" + slot);
    a.msg = "Setting current slot to '" + slot + "'...";
}

void fb_queue_erase(const char *ptn)
{
    Action *a;
    a = queue_action(OP_COMMAND, "erase:%s", ptn);
    a->msg = mkmsg("erasing '%s'", ptn);
void fb_queue_erase(const std::string& partition) {
    Action& a = queue_action(OP_COMMAND, "erase:" + partition);
    a.msg = "Erasing '" + partition + "'...";
}

void fb_queue_flash_fd(const char *ptn, int fd, uint32_t sz)
{
    Action *a;

    a = queue_action(OP_DOWNLOAD_FD, "");
    a->fd = fd;
    a->size = sz;
    a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz) {
    Action& a = queue_action(OP_DOWNLOAD_FD, "");
    a.fd = fd;
    a.size = sz;
    a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);

    a = queue_action(OP_COMMAND, "flash:%s", ptn);
    a->msg = mkmsg("writing '%s'", ptn);
    Action& b = queue_action(OP_COMMAND, "flash:" + partition);
    b.msg = "Writing '" + partition + "'...";
}

void fb_queue_flash(const char *ptn, void *data, uint32_t sz)
{
    Action *a;
void fb_queue_flash(const std::string& partition, void* data, uint32_t sz) {
    Action& a = queue_action(OP_DOWNLOAD, "");
    a.data = data;
    a.size = sz;
    a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);

    a = queue_action(OP_DOWNLOAD, "");
    a->data = data;
    a->size = sz;
    a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);

    a = queue_action(OP_COMMAND, "flash:%s", ptn);
    a->msg = mkmsg("writing '%s'", ptn);
    Action& b = queue_action(OP_COMMAND, "flash:" + partition);
    b.msg = "Writing '" + partition + "'...";
}

void fb_queue_flash_sparse(const char* ptn, struct sparse_file* s, uint32_t sz, size_t current,
                           size_t total) {
    Action *a;

    a = queue_action(OP_DOWNLOAD_SPARSE, "");
    a->data = s;
    a->size = 0;
    a->msg = mkmsg("sending sparse '%s' %zu/%zu (%d KB)", ptn, current, total, sz / 1024);
void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
                           size_t current, size_t total) {
    Action& a = queue_action(OP_DOWNLOAD_SPARSE, "");
    a.data = s;
    a.size = 0;
    a.msg = android::base::StringPrintf("Sending sparse '%s' %zu/%zu (%d KB)...", partition.c_str(),
                                        current, total, sz / 1024);

    a = queue_action(OP_COMMAND, "flash:%s", ptn);
    a->msg = mkmsg("writing '%s' %zu/%zu", ptn, current, total);
    Action& b = queue_action(OP_COMMAND, "flash:" + partition);
    b.msg =
        android::base::StringPrintf("Writing '%s' %zu/%zu...", partition.c_str(), current, total);
}

static int match(const char* str, const char** value, unsigned count) {
@@ -205,44 +171,39 @@ static int match(const char* str, const char** value, unsigned count) {
    return 0;
}



static int cb_check(Action* a, int status, const char* resp, int invert)
{
    const char** value = reinterpret_cast<const char**>(a->data);
    unsigned count = a->size;
static int cb_check(Action& a, int status, const char* resp, int invert) {
    const char** value = reinterpret_cast<const char**>(a.data);
    unsigned count = a.size;
    unsigned n;
    int yes;

    if (status) {
        fprintf(stderr,"FAILED (%s)\n", resp);
        return status;
    }

    if (a->prod) {
        if (strcmp(a->prod, cur_product) != 0) {
    if (!a.product.empty()) {
        if (a.product != cur_product) {
            double split = now();
            fprintf(stderr,"IGNORE, product is %s required only for %s [%7.3fs]\n",
                    cur_product, a->prod, (split - a->start));
            a->start = split;
            fprintf(stderr, "IGNORE, product is %s required only for %s [%7.3fs]\n", cur_product,
                    a.product.c_str(), (split - a.start));
            a.start = split;
            return 0;
        }
    }

    yes = match(resp, value, count);
    int yes = match(resp, value, count);
    if (invert) yes = !yes;

    if (yes) {
        double split = now();
        fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
        a->start = split;
        fprintf(stderr, "OKAY [%7.3fs]\n", (split - a.start));
        a.start = split;
        return 0;
    }

    fprintf(stderr, "FAILED\n\n");
    fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp);
    fprintf(stderr,"Update %s '%s'",
            invert ? "rejects" : "requires", value[0]);
    fprintf(stderr, "Device %s is '%s'.\n", a.cmd.c_str() + 7, resp);
    fprintf(stderr, "Update %s '%s'", invert ? "rejects" : "requires", value[0]);
    for (n = 1; n < count; n++) {
        fprintf(stderr, " or '%s'", value[n]);
    }
@@ -250,167 +211,141 @@ static int cb_check(Action* a, int status, const char* resp, int invert)
    return -1;
}

static int cb_require(Action*a, int status, const char* resp) {
static int cb_require(Action& a, int status, const char* resp) {
    return cb_check(a, status, resp, 0);
}

static int cb_reject(Action* a, int status, const char* resp) {
static int cb_reject(Action& a, int status, const char* resp) {
    return cb_check(a, status, resp, 1);
}

static char* xstrdup(const char* s) {
    char* result = strdup(s);
    if (!result) die("out of memory");
    return result;
void fb_queue_require(const std::string& product, const std::string& var, bool invert,
                      size_t nvalues, const char** values) {
    Action& a = queue_action(OP_QUERY, "getvar:" + var);
    a.product = product;
    a.data = values;
    a.size = nvalues;
    a.msg = "Checking " + var;
    a.func = invert ? cb_reject : cb_require;
    if (a.data == nullptr) die("out of memory");
}

void fb_queue_require(const char *prod, const char *var,
                      bool invert, size_t nvalues, const char **value)
{
    Action *a;
    a = queue_action(OP_QUERY, "getvar:%s", var);
    a->prod = prod;
    a->data = value;
    a->size = nvalues;
    a->msg = mkmsg("checking %s", var);
    a->func = invert ? cb_reject : cb_require;
    if (a->data == nullptr) die("out of memory");
}

static int cb_display(Action* a, int status, const char* resp) {
static int cb_display(Action& a, int status, const char* resp) {
    if (status) {
        fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
        fprintf(stderr, "%s FAILED (%s)\n", a.cmd.c_str(), resp);
        return status;
    }
    fprintf(stderr, "%s: %s\n", static_cast<const char*>(a->data), resp);
    free(static_cast<char*>(a->data));
    fprintf(stderr, "%s: %s\n", static_cast<const char*>(a.data), resp);
    free(static_cast<char*>(a.data));
    return 0;
}

void fb_queue_display(const char* var, const char* prettyname) {
    Action* a = queue_action(OP_QUERY, "getvar:%s", var);
    a->data = xstrdup(prettyname);
    a->func = cb_display;
void fb_queue_display(const std::string& label, const std::string& var) {
    Action& a = queue_action(OP_QUERY, "getvar:" + var);
    a.data = xstrdup(label.c_str());
    a.func = cb_display;
}

static int cb_save(Action* a, int status, const char* resp) {
static int cb_save(Action& a, int status, const char* resp) {
    if (status) {
        fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
        fprintf(stderr, "%s FAILED (%s)\n", a.cmd.c_str(), resp);
        return status;
    }
    strncpy(reinterpret_cast<char*>(a->data), resp, a->size);
    strncpy(reinterpret_cast<char*>(a.data), resp, a.size);
    return 0;
}

void fb_queue_query_save(const char* var, char* dest, uint32_t dest_size) {
    Action* a = queue_action(OP_QUERY, "getvar:%s", var);
    a->data = dest;
    a->size = dest_size;
    a->func = cb_save;
void fb_queue_query_save(const std::string& var, char* dest, uint32_t dest_size) {
    Action& a = queue_action(OP_QUERY, "getvar:" + var);
    a.data = dest;
    a.size = dest_size;
    a.func = cb_save;
}

static int cb_do_nothing(Action*, int , const char*) {
static int cb_do_nothing(Action&, int, const char*) {
    fprintf(stderr, "\n");
    return 0;
}

void fb_queue_reboot(void)
{
    Action *a = queue_action(OP_COMMAND, "reboot");
    a->func = cb_do_nothing;
    a->msg = "rebooting";
void fb_queue_reboot() {
    Action& a = queue_action(OP_COMMAND, "reboot");
    a.func = cb_do_nothing;
    a.msg = "Rebooting...";
}

void fb_queue_command(const char *cmd, const char *msg)
{
    Action *a = queue_action(OP_COMMAND, cmd);
    a->msg = msg;
void fb_queue_command(const std::string& cmd, const std::string& msg) {
    Action& a = queue_action(OP_COMMAND, cmd);
    a.msg = msg;
}

void fb_queue_download(const char *name, void *data, uint32_t size)
{
    Action *a = queue_action(OP_DOWNLOAD, "");
    a->data = data;
    a->size = size;
    a->msg = mkmsg("downloading '%s'", name);
void fb_queue_download(const std::string& name, void* data, uint32_t size) {
    Action& a = queue_action(OP_DOWNLOAD, "");
    a.data = data;
    a.size = size;
    a.msg = "Downloading '" + name + "'";
}

void fb_queue_download_fd(const char *name, int fd, uint32_t sz)
{
    Action *a;
    a = queue_action(OP_DOWNLOAD_FD, "");
    a->fd = fd;
    a->size = sz;
    a->msg = mkmsg("sending '%s' (%d KB)", name, sz / 1024);
void fb_queue_download_fd(const std::string& name, int fd, uint32_t sz) {
    Action& a = queue_action(OP_DOWNLOAD_FD, "");
    a.fd = fd;
    a.size = sz;
    a.msg = android::base::StringPrintf("Sending '%s' (%d KB)", name.c_str(), sz / 1024);
}

void fb_queue_upload(const char* outfile) {
    Action* a = queue_action(OP_UPLOAD, "");
    a->data = xstrdup(outfile);
    a->msg = mkmsg("uploading '%s'", outfile);
void fb_queue_upload(const std::string& outfile) {
    Action& a = queue_action(OP_UPLOAD, "");
    a.data = xstrdup(outfile.c_str());
    a.msg = "Uploading '" + outfile + "'";
}

void fb_queue_notice(const char* notice) {
    Action *a = queue_action(OP_NOTICE, "");
    a->data = (void*) notice;
void fb_queue_notice(const std::string& notice) {
    Action& a = queue_action(OP_NOTICE, "");
    a.msg = notice;
}

void fb_queue_wait_for_disconnect(void)
{
void fb_queue_wait_for_disconnect() {
    queue_action(OP_WAIT_FOR_DISCONNECT, "");
}

int64_t fb_execute_queue(Transport* transport)
{
    Action *a;
    char resp[FB_RESPONSE_SZ+1];
int64_t fb_execute_queue(Transport* transport) {
    int64_t status = 0;

    a = action_list;
    if (!a)
        return status;
    resp[FB_RESPONSE_SZ] = 0;

    double start = -1;
    for (a = action_list; a; a = a->next) {
    for (auto& a : action_list) {
        a->start = now();
        if (start < 0) start = a->start;
        if (a->msg) {
            // fprintf(stderr,"%30s... ",a->msg);
            fprintf(stderr,"%s...\n",a->msg);
        if (!a->msg.empty()) {
            fprintf(stderr, "%s\n", a->msg.c_str());
        }
        if (a->op == OP_DOWNLOAD) {
            status = fb_download_data(transport, a->data, a->size);
            status = a->func(a, status, status ? fb_get_error().c_str() : "");
            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
            if (status) break;
        } else if (a->op == OP_DOWNLOAD_FD) {
            status = fb_download_data_fd(transport, a->fd, a->size);
            status = a->func(a, status, status ? fb_get_error().c_str() : "");
            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
            if (status) break;
        } else if (a->op == OP_COMMAND) {
            status = fb_command(transport, a->cmd);
            status = a->func(a, status, status ? fb_get_error().c_str() : "");
            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
            if (status) break;
        } else if (a->op == OP_QUERY) {
            char resp[FB_RESPONSE_SZ + 1] = {};
            status = fb_command_response(transport, a->cmd, resp);
            status = a->func(a, status, status ? fb_get_error().c_str() : resp);
            status = a->func(*a, status, status ? fb_get_error().c_str() : resp);
            if (status) break;
        } else if (a->op == OP_NOTICE) {
            fprintf(stderr,"%s\n",(char*)a->data);
            // We already showed the notice because it's in `Action::msg`.
        } else if (a->op == OP_DOWNLOAD_SPARSE) {
            status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
            status = a->func(a, status, status ? fb_get_error().c_str() : "");
            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
            if (status) break;
        } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
            transport->WaitForDisconnect();
        } else if (a->op == OP_UPLOAD) {
            status = fb_upload_data(transport, reinterpret_cast<char*>(a->data));
            status = a->func(a, status, status ? fb_get_error().c_str() : "");
            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
        } else {
            die("bogus action");
            die("unknown action: %d", a->op);
        }
    }

    fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
    action_list.clear();
    return status;
}
+91 −73

File changed.

Preview size limit exceeded, changes collapsed.

+19 −19
Original line number Diff line number Diff line
@@ -39,8 +39,8 @@
struct sparse_file;

/* protocol.c - fastboot protocol */
int fb_command(Transport* transport, const char* cmd);
int fb_command_response(Transport* transport, const char* cmd, char* response);
int fb_command(Transport* transport, const std::string& cmd);
int fb_command_response(Transport* transport, const std::string& cmd, char* response);
int64_t fb_download_data(Transport* transport, const void* data, uint32_t size);
int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size);
int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
@@ -52,29 +52,29 @@ const std::string fb_get_error();

/* engine.c - high level command queue engine */
bool fb_getvar(Transport* transport, const std::string& key, std::string* value);
void fb_queue_flash(const char *ptn, void *data, uint32_t sz);
void fb_queue_flash_fd(const char *ptn, int fd, uint32_t sz);
void fb_queue_flash_sparse(const char* ptn, struct sparse_file* s, uint32_t sz, size_t current,
                           size_t total);
void fb_queue_erase(const char *ptn);
void fb_queue_format(const char *ptn, int skip_if_not_supported, int32_t max_chunk_sz);
void fb_queue_require(const char *prod, const char *var, bool invert,
                      size_t nvalues, const char **value);
void fb_queue_display(const char *var, const char *prettyname);
void fb_queue_query_save(const char *var, char *dest, uint32_t dest_size);
void fb_queue_flash(const std::string& partition, void* data, uint32_t sz);
void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz);
void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
                           size_t current, size_t total);
void fb_queue_erase(const std::string& partition);
void fb_queue_format(const std::string& partition, int skip_if_not_supported, int32_t max_chunk_sz);
void fb_queue_require(const std::string& prod, const std::string& var, bool invert, size_t nvalues,
                      const char** values);
void fb_queue_display(const std::string& label, const std::string& var);
void fb_queue_query_save(const std::string& var, char* dest, uint32_t dest_size);
void fb_queue_reboot(void);
void fb_queue_command(const char *cmd, const char *msg);
void fb_queue_download(const char *name, void *data, uint32_t size);
void fb_queue_download_fd(const char *name, int fd, uint32_t sz);
void fb_queue_upload(const char* outfile);
void fb_queue_notice(const char *notice);
void fb_queue_command(const std::string& cmd, const std::string& msg);
void fb_queue_download(const std::string& name, void* data, uint32_t size);
void fb_queue_download_fd(const std::string& name, int fd, uint32_t sz);
void fb_queue_upload(const std::string& outfile);
void fb_queue_notice(const std::string& notice);
void fb_queue_wait_for_disconnect(void);
int64_t fb_execute_queue(Transport* transport);
void fb_set_active(const char *slot);
void fb_set_active(const std::string& slot);

/* util stuff */
double now();
char *mkmsg(const char *fmt, ...);
char* xstrdup(const char*);

// These printf-like functions are implemented in terms of vsnprintf, so they
// use the same attribute for compile-time format string checking. On Windows,
+12 −12
Original line number Diff line number Diff line
@@ -113,10 +113,10 @@ static int64_t check_response(Transport* transport, uint32_t size, char* respons
    return -1;
}

static int64_t _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
    size_t cmdsize = strlen(cmd);
    if (cmdsize > 64) {
        g_error = android::base::StringPrintf("command too large (%zu)", cmdsize);
static int64_t _command_start(Transport* transport, const std::string& cmd, uint32_t size,
                              char* response) {
    if (cmd.size() > 64) {
        g_error = android::base::StringPrintf("command too large (%zu)", cmd.size());
        return -1;
    }

@@ -124,7 +124,7 @@ static int64_t _command_start(Transport* transport, const char* cmd, uint32_t si
        response[0] = 0;
    }

    if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) {
    if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
        g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
        transport->Close();
        return -1;
@@ -167,8 +167,8 @@ static int64_t _command_end(Transport* transport) {
    return check_response(transport, 0, 0) < 0 ? -1 : 0;
}

static int64_t _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size,
                         char* response) {
static int64_t _command_send(Transport* transport, const std::string& cmd, const void* data,
                             uint32_t size, char* response) {
    if (size == 0) {
        return -1;
    }
@@ -190,7 +190,7 @@ static int64_t _command_send(Transport* transport, const char* cmd, const void*
    return size;
}

static int64_t _command_send_fd(Transport* transport, const char* cmd, int fd, uint32_t size,
static int64_t _command_send_fd(Transport* transport, const std::string& cmd, int fd, uint32_t size,
                                char* response) {
    static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
    off64_t offset = 0;
@@ -223,15 +223,15 @@ static int64_t _command_send_fd(Transport* transport, const char* cmd, int fd, u
    return size;
}

static int _command_send_no_data(Transport* transport, const char* cmd, char* response) {
static int _command_send_no_data(Transport* transport, const std::string& cmd, char* response) {
    return _command_start(transport, cmd, 0, response);
}

int fb_command(Transport* transport, const char* cmd) {
int fb_command(Transport* transport, const std::string& cmd) {
    return _command_send_no_data(transport, cmd, 0);
}

int fb_command_response(Transport* transport, const char* cmd, char* response) {
int fb_command_response(Transport* transport, const std::string& cmd, char* response) {
    return _command_send_no_data(transport, cmd, response);
}

@@ -339,7 +339,7 @@ int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
    }

    std::string cmd(android::base::StringPrintf("download:%08x", size));
    int r = _command_start(transport, cmd.c_str(), size, 0);
    int r = _command_start(transport, cmd, size, 0);
    if (r < 0) {
        return -1;
    }
+9 −20
Original line number Diff line number Diff line
@@ -35,35 +35,24 @@

#include "fastboot.h"

double now()
{
double now() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
}

char *mkmsg(const char *fmt, ...)
{
    char buf[256];
    char *s;
    va_list ap;

    va_start(ap, fmt);
    vsprintf(buf, fmt, ap);
    va_end(ap);

    s = strdup(buf);
    if (s == 0) die("out of memory");
    return s;
}

void die(const char *fmt, ...)
{
void die(const char* fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    fprintf(stderr,"error: ");
    vfprintf(stderr, fmt, ap);
    fprintf(stderr,"\n");
    va_end(ap);
    exit(1);
    exit(EXIT_FAILURE);
}

char* xstrdup(const char* s) {
    char* result = strdup(s);
    if (!result) die("out of memory");
    return result;
}