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

Commit 04ccbfd6 authored by Tom Cherry's avatar Tom Cherry Committed by Gerrit Code Review
Browse files

Merge "fastboot: remove command queue"

parents 50fe7eab 11f12099
Loading
Loading
Loading
Loading
+98 −225
Original line number Diff line number Diff line
@@ -44,43 +44,10 @@
#include "constants.h"
#include "transport.h"

enum Op {
    OP_DOWNLOAD,
    OP_COMMAND,
    OP_QUERY,
    OP_NOTICE,
    OP_DOWNLOAD_SPARSE,
    OP_WAIT_FOR_DISCONNECT,
    OP_DOWNLOAD_FD,
    OP_UPLOAD,
};
using android::base::StringPrintf;

struct Action {
    Action(Op op, const std::string& cmd) : op(op), cmd(cmd) {}

    Op op;
    std::string cmd;
    std::string msg;

    std::string product;

    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;

    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;
static fastboot::FastBootDriver* fb = nullptr;

static constexpr char kStatusFormat[] = "%-50s ";

void fb_init(fastboot::FastBootDriver& fbi) {
    fb = &fbi;
    auto cb = [](std::string& info) { fprintf(stderr, "(bootloader) %s\n", info.c_str()); };
@@ -101,81 +68,72 @@ bool fb_getvar(const std::string& key, std::string* value) {
    return !fb->GetVar(key, value);
}

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

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

    action_list.push_back(std::move(a));
    return *action_list.back();
#define RUN_COMMAND(command)         \
    {                                \
        double start = now();        \
        auto status = (command);     \
        HandleResult(start, status); \
    }

void fb_set_active(const std::string& slot) {
    Action& a = queue_action(OP_COMMAND, FB_CMD_SET_ACTIVE ":" + slot);
    a.msg = "Setting current slot to '" + slot + "'";
    Status("Setting current slot to '" + slot + "'");
    RUN_COMMAND(fb->SetActive(slot));
}

void fb_queue_erase(const std::string& partition) {
    Action& a = queue_action(OP_COMMAND, FB_CMD_ERASE ":" + partition);
    a.msg = "Erasing '" + partition + "'";
void fb_erase(const std::string& partition) {
    Status("Erasing '" + partition + "'");
    RUN_COMMAND(fb->Erase(partition));
}

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' (%u KB)", partition.c_str(), sz / 1024);
void fb_flash_fd(const std::string& partition, int fd, uint32_t sz) {
    Status(StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024));
    RUN_COMMAND(fb->Download(fd, sz));

    Action& b = queue_action(OP_COMMAND, FB_CMD_FLASH ":" + partition);
    b.msg = "Writing '" + partition + "'";
    Status("Writing '" + partition + "'");
    RUN_COMMAND(fb->Flash(partition));
}

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' (%u KB)", partition.c_str(), sz / 1024);
void fb_flash(const std::string& partition, void* data, uint32_t sz) {
    Status(StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024));
    RUN_COMMAND(fb->Download(static_cast<char*>(data), sz));

    Action& b = queue_action(OP_COMMAND, FB_CMD_FLASH ":" + partition);
    b.msg = "Writing '" + partition + "'";
    Status("Writing '" + partition + "'");
    RUN_COMMAND(fb->Flash(partition));
}

void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
void fb_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 (%u KB)", partition.c_str(),
                                        current, total, sz / 1024);
    Status(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
                        sz / 1024));
    RUN_COMMAND(fb->Download(s));

    Action& b = queue_action(OP_COMMAND, FB_CMD_FLASH ":" + partition);
    b.msg = android::base::StringPrintf("Writing sparse '%s' %zu/%zu", partition.c_str(), current,
                                        total);
    Status(StringPrintf("Writing sparse '%s' %zu/%zu", partition.c_str(), current, total));
    RUN_COMMAND(fb->Flash(partition));
}

void fb_queue_create_partition(const std::string& partition, const std::string& size) {
    Action& a = queue_action(OP_COMMAND, FB_CMD_CREATE_PARTITION ":" + partition + ":" + size);
    a.msg = "Creating '" + partition + "'";
void fb_create_partition(const std::string& partition, const std::string& size) {
    Status("Creating '" + partition + "'");
    RUN_COMMAND(fb->RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size));
}

void fb_queue_delete_partition(const std::string& partition) {
    Action& a = queue_action(OP_COMMAND, FB_CMD_DELETE_PARTITION ":" + partition);
    a.msg = "Deleting '" + partition + "'";
void fb_delete_partition(const std::string& partition) {
    Status("Deleting '" + partition + "'");
    RUN_COMMAND(fb->RawCommand(FB_CMD_DELETE_PARTITION ":" + partition));
}

void fb_queue_resize_partition(const std::string& partition, const std::string& size) {
    Action& a = queue_action(OP_COMMAND, FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size);
    a.msg = "Resizing '" + partition + "'";
void fb_resize_partition(const std::string& partition, const std::string& size) {
    Status("Resizing '" + partition + "'");
    RUN_COMMAND(fb->RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size));
}

static int match(const char* str, const char** value, unsigned count) {
@@ -199,193 +157,108 @@ 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;
    unsigned n;
void fb_require(const std::string& product, const std::string& var, bool invert, size_t count,
                const char** values) {
    Status("Checking '" + var + "'");

    double start = now();

    std::string var_value;
    auto status = fb->GetVar(var, &var_value);

    if (status) {
        fprintf(stderr,"FAILED (%s)\n", resp);
        return status;
        fprintf(stderr, "getvar:%s FAILED (%s)\n", var.c_str(), fb->Error().c_str());
        die("requirements not met!");
    }

    if (!a.product.empty()) {
        if (a.product != cur_product) {
    if (!product.empty()) {
        if (product != cur_product) {
            double split = now();
            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;
                    product.c_str(), (split - start));
            return;
        }
    }

    int yes = match(resp, value, count);
    int yes = match(var_value.c_str(), values, count);
    if (invert) yes = !yes;

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

    fprintf(stderr, "FAILED\n\n");
    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]);
    fprintf(stderr, "Device %s is '%s'.\n", var.c_str(), var_value.c_str());
    fprintf(stderr, "Update %s '%s'", invert ? "rejects" : "requires", values[0]);
    for (size_t n = 1; n < count; n++) {
        fprintf(stderr, " or '%s'", values[n]);
    }
    fprintf(stderr, ".\n\n");
    return -1;
    die("requirements not met!");
}

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) {
    return cb_check(a, status, resp, 1);
}
void fb_display(const std::string& label, const std::string& var) {
    std::string value;
    auto status = fb->GetVar(var, &value);

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, FB_CMD_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");
}

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

void fb_queue_display(const std::string& label, const std::string& var) {
    Action& a = queue_action(OP_QUERY, FB_CMD_GETVAR ":" + var);
    a.data = xstrdup(label.c_str());
    a.func = cb_display;
}
void fb_query_save(const std::string& var, char* dest, uint32_t dest_size) {
    std::string value;
    auto status = fb->GetVar(var, &value);

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

void fb_queue_query_save(const std::string& var, char* dest, uint32_t dest_size) {
    Action& a = queue_action(OP_QUERY, FB_CMD_GETVAR ":" + var);
    a.data = dest;
    a.size = dest_size;
    a.func = cb_save;
    strncpy(dest, value.c_str(), dest_size);
}

static int cb_do_nothing(Action&, int, const char*) {
void fb_reboot() {
    fprintf(stderr, "Rebooting");
    fb->Reboot();
    fprintf(stderr, "\n");
    return 0;
}

void fb_queue_reboot() {
    Action& a = queue_action(OP_COMMAND, FB_CMD_REBOOT);
    a.func = cb_do_nothing;
    a.msg = "Rebooting";
}

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 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_command(const std::string& cmd, const std::string& msg) {
    Status(msg);
    RUN_COMMAND(fb->RawCommand(cmd));
}

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' (%u KB)", name.c_str(), sz / 1024);
void fb_download(const std::string& name, void* data, uint32_t size) {
    Status("Downloading '" + name + "'");
    RUN_COMMAND(fb->Download(static_cast<char*>(data), size));
}

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_download_fd(const std::string& name, int fd, uint32_t sz) {
    Status(StringPrintf("Sending '%s' (%u KB)", name.c_str(), sz / 1024));
    RUN_COMMAND(fb->Download(fd, sz));
}

void fb_queue_notice(const std::string& notice) {
    Action& a = queue_action(OP_NOTICE, "");
    a.msg = notice;
void fb_upload(const std::string& outfile) {
    Status("Uploading '" + outfile + "'");
    RUN_COMMAND(fb->Upload(outfile));
}

void fb_queue_wait_for_disconnect() {
    queue_action(OP_WAIT_FOR_DISCONNECT, "");
void fb_notice(const std::string& notice) {
    Status(notice);
    fprintf(stderr, "\n");
}

int64_t fb_execute_queue() {
    int64_t status = 0;
    for (auto& a : action_list) {
        a->start = now();
        if (!a->msg.empty()) {
            fprintf(stderr, kStatusFormat, a->msg.c_str());
            verbose("\n");
        }
        if (a->op == OP_DOWNLOAD) {
            char* cbuf = static_cast<char*>(a->data);
            status = fb->Download(cbuf, a->size);
            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
            if (status) break;
        } else if (a->op == OP_DOWNLOAD_FD) {
            status = fb->Download(a->fd, a->size);
            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
            if (status) break;
        } else if (a->op == OP_COMMAND) {
            status = fb->RawCommand(a->cmd);
            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
            if (status) break;
        } else if (a->op == OP_QUERY) {
            std::string resp;
            status = fb->RawCommand(a->cmd, &resp);
            status = a->func(*a, status, status ? fb_get_error().c_str() : resp.c_str());
            if (status) break;
        } else if (a->op == OP_NOTICE) {
            // We already showed the notice because it's in `Action::msg`.
            fprintf(stderr, "\n");
        } else if (a->op == OP_DOWNLOAD_SPARSE) {
            status = fb->Download(reinterpret_cast<sparse_file*>(a->data));
            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
            if (status) break;
        } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
void fb_wait_for_disconnect() {
    fb->WaitForDisconnect();
        } else if (a->op == OP_UPLOAD) {
            status = fb->Upload(reinterpret_cast<const char*>(a->data));
            status = a->func(*a, status, status ? fb_get_error().c_str() : "");
        } else {
            die("unknown action: %d", a->op);
        }
    }
    action_list.clear();
    return status;
}

bool fb_reboot_to_userspace() {
    // First ensure that the queue is flushed.
    fb_execute_queue();

    fprintf(stderr, kStatusFormat, "Rebooting to userspace fastboot");
    Status("Rebooting to userspace fastboot");
    verbose("\n");

    if (fb->RebootTo("fastboot") != fastboot::RetCode::SUCCESS) {
+19 −26
Original line number Diff line number Diff line
@@ -44,36 +44,29 @@ struct sparse_file;

const std::string fb_get_error();

//#define FB_COMMAND_SZ (fastboot::FB_COMMAND_SZ)
//#define FB_RESPONSE_SZ (fastboot::FB_RESPONSE_SZ)

/* engine.c - high level command queue engine */

void fb_init(fastboot::FastBootDriver& fbi);
void fb_reinit(Transport* transport);

bool fb_getvar(const std::string& key, std::string* value);
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,
void fb_flash(const std::string& partition, void* data, uint32_t sz);
void fb_flash_fd(const std::string& partition, int fd, uint32_t sz);
void fb_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,
void fb_erase(const std::string& partition);
void fb_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 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);
void fb_queue_create_partition(const std::string& partition, const std::string& size);
void fb_queue_delete_partition(const std::string& partition);
void fb_queue_resize_partition(const std::string& partition, const std::string& size);
int64_t fb_execute_queue();
void fb_display(const std::string& label, const std::string& var);
void fb_query_save(const std::string& var, char* dest, uint32_t dest_size);
void fb_reboot();
void fb_command(const std::string& cmd, const std::string& msg);
void fb_download(const std::string& name, void* data, uint32_t size);
void fb_download_fd(const std::string& name, int fd, uint32_t sz);
void fb_upload(const std::string& outfile);
void fb_notice(const std::string& notice);
void fb_wait_for_disconnect(void);
void fb_create_partition(const std::string& partition, const std::string& size);
void fb_delete_partition(const std::string& partition);
void fb_resize_partition(const std::string& partition, const std::string& size);
void fb_set_active(const std::string& slot);
bool fb_reboot_to_userspace();

+43 −49

File changed.

Preview size limit exceeded, changes collapsed.

+2 −2
Original line number Diff line number Diff line
@@ -97,9 +97,9 @@ RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
    return RawCommand("reboot-" + target, response, info);
}

RetCode FastBootDriver::SetActive(const std::string& part, std::string* response,
RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response,
                                  std::vector<std::string>* info) {
    return RawCommand(Commands::SET_ACTIVE + part, response, info);
    return RawCommand(Commands::SET_ACTIVE + slot, response, info);
}

RetCode FastBootDriver::FlashPartition(const std::string& part, const std::vector<char>& data) {
+1 −1
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ class FastBootDriver {
    RetCode Reboot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
    RetCode RebootTo(std::string target, std::string* response = nullptr,
                     std::vector<std::string>* info = nullptr);
    RetCode SetActive(const std::string& part, std::string* response = nullptr,
    RetCode SetActive(const std::string& slot, std::string* response = nullptr,
                      std::vector<std::string>* info = nullptr);
    RetCode Upload(const std::string& outfile, std::string* response = nullptr,
                   std::vector<std::string>* info = nullptr);
Loading