fastboot: remove command queue
There is little advantage and increasingly much disadvantage to
queueing up fastboot commands before executing them. This change
removes the queue in the most simple way possible to enable further
clean up.
Test: fastboot works
Change-Id: I9abab05df07ed167dbe6a42e1eb9eab8f8d4f157
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index d80e986..0ac57af 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -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 @@
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,
- 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);
+void fb_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
+ size_t current, size_t total) {
+ 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 @@
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);
-}
+void fb_display(const std::string& label, const std::string& var) {
+ std::string value;
+ auto status = fb->GetVar(var, &value);
-static int cb_reject(Action& a, int status, const char* resp) {
- return cb_check(a, status, resp, 1);
-}
-
-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;
+ fprintf(stderr, "getvar:%s FAILED (%s)\n", var.c_str(), fb->Error().c_str());
+ return;
}
- strncpy(reinterpret_cast<char*>(a.data), resp, a.size);
- return 0;
+
+ strncpy(dest, value.c_str(), dest_size);
}
-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;
-}
-
-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_command(const std::string& cmd, const std::string& msg) {
+ Status(msg);
+ RUN_COMMAND(fb->RawCommand(cmd));
}
-void fb_queue_command(const std::string& cmd, const std::string& msg) {
- Action& a = queue_action(OP_COMMAND, cmd);
- a.msg = msg;
+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_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_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_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_upload(const std::string& outfile) {
+ Status("Uploading '" + outfile + "'");
+ RUN_COMMAND(fb->Upload(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_notice(const std::string& notice) {
+ Status(notice);
+ fprintf(stderr, "\n");
}
-void fb_queue_notice(const std::string& notice) {
- Action& a = queue_action(OP_NOTICE, "");
- a.msg = notice;
-}
-
-void fb_queue_wait_for_disconnect() {
- queue_action(OP_WAIT_FOR_DISCONNECT, "");
-}
-
-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) {
- 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;
+void fb_wait_for_disconnect() {
+ fb->WaitForDisconnect();
}
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) {