diff options
Diffstat (limited to 'fastboot/engine.cpp')
-rw-r--r-- | fastboot/engine.cpp | 323 |
1 files changed, 98 insertions, 225 deletions
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp index d80e98601..0ac57afc5 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 @@ 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, - 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); - - 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); +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)); + + 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; -} - -static int cb_require(Action& a, int status, const char* resp) { - return cb_check(a, status, resp, 0); + die("requirements not met!"); } -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"); -} +void fb_display(const std::string& label, const std::string& var) { + std::string value; + auto status = fb->GetVar(var, &value); -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; -} -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_command(const std::string& cmd, const std::string& msg) { + Status(msg); + RUN_COMMAND(fb->RawCommand(cmd)); } -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(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_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_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_upload(const std::string& outfile) { - Action& a = queue_action(OP_UPLOAD, ""); - a.data = xstrdup(outfile.c_str()); - a.msg = "Uploading '" + outfile + "'"; +void fb_upload(const std::string& outfile) { + Status("Uploading '" + outfile + "'"); + RUN_COMMAND(fb->Upload(outfile)); } -void fb_queue_notice(const std::string& notice) { - Action& a = queue_action(OP_NOTICE, ""); - a.msg = notice; +void fb_notice(const std::string& notice) { + Status(notice); + fprintf(stderr, "\n"); } -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) { |