From db511207ed3b2bb4fc422ef83868009b03692e61 Mon Sep 17 00:00:00 2001 From: Aaron Wisner Date: Tue, 26 Jun 2018 15:38:35 -0500 Subject: Refactor libfastboot This change creates a nice and clean API for issuing fastboot commands without using the fastboot tool itself. Test: fastboot tool itself (now using libfastboot2) on sailfish, walleye, and other devices. Test: flash bootloader bootloader.img Test: flash radio radio.img Test: -w update img.zip Test: Manually getvar and reboot commands. Bug: 111126621 Change-Id: I0022536b204ce0c5ad8329367fd522fa3c57877d --- fastboot/Android.bp | 56 +++++ fastboot/Android.mk | 4 +- fastboot/bootimg_utils.cpp | 2 +- fastboot/engine.cpp | 45 ++-- fastboot/engine.h | 84 +++++++ fastboot/fastboot.cpp | 194 ++++++++-------- fastboot/fastboot.h | 94 -------- fastboot/fastboot_driver.cpp | 533 +++++++++++++++++++++++++++++++++++++++++++ fastboot/fastboot_driver.h | 154 +++++++++++++ fastboot/fastboot_test.cpp | 6 +- fastboot/fs.cpp | 1 - fastboot/main.cpp | 4 +- fastboot/protocol.cpp | 370 ------------------------------ fastboot/usb_linux.cpp | 2 +- fastboot/util.cpp | 2 +- fastboot/util.h | 19 ++ 16 files changed, 978 insertions(+), 592 deletions(-) create mode 100644 fastboot/Android.bp create mode 100644 fastboot/engine.h delete mode 100644 fastboot/fastboot.h create mode 100644 fastboot/fastboot_driver.cpp create mode 100644 fastboot/fastboot_driver.h delete mode 100644 fastboot/protocol.cpp create mode 100644 fastboot/util.h diff --git a/fastboot/Android.bp b/fastboot/Android.bp new file mode 100644 index 000000000..2b4a95463 --- /dev/null +++ b/fastboot/Android.bp @@ -0,0 +1,56 @@ +cc_library_host_static { + name: "libfastboot2", + + //host_supported: true, + + compile_multilib: "first", + srcs: [ + "bootimg_utils.cpp", + "fs.cpp", + "socket.cpp", + "tcp.cpp", + "udp.cpp", + "util.cpp", + "fastboot_driver.cpp", + ], + + static_libs: [ + "libziparchive", + "libsparse", + "libutils", + "liblog", + "libz", + "libdiagnose_usb", + "libbase", + "libcutils", + "libgtest", + "libgtest_main", + "libbase", + "libadb_host" + ], + + header_libs: [ + "bootimg_headers" + ], + + export_header_lib_headers: [ + "bootimg_headers" + ], + + + target: { + linux: { + srcs: ["usb_linux.cpp"], + }, + }, + + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-Wunreachable-code", + ], + + export_include_dirs: ["."], + +} diff --git a/fastboot/Android.mk b/fastboot/Android.mk index 983e195dc..60c338c58 100644 --- a/fastboot/Android.mk +++ b/fastboot/Android.mk @@ -50,12 +50,12 @@ LOCAL_SRC_FILES := \ bootimg_utils.cpp \ engine.cpp \ fastboot.cpp \ - fs.cpp\ - protocol.cpp \ + fs.cpp \ socket.cpp \ tcp.cpp \ udp.cpp \ util.cpp \ + fastboot_driver.cpp \ LOCAL_SRC_FILES_darwin := usb_osx.cpp LOCAL_SRC_FILES_linux := usb_linux.cpp diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp index c9814e455..115200797 100644 --- a/fastboot/bootimg_utils.cpp +++ b/fastboot/bootimg_utils.cpp @@ -28,7 +28,7 @@ #include "bootimg_utils.h" -#include "fastboot.h" +#include "util.h" #include #include diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp index 1087573cd..63ee2af5b 100644 --- a/fastboot/engine.cpp +++ b/fastboot/engine.cpp @@ -25,8 +25,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - -#include "fastboot.h" +#include "engine.h" #include #include @@ -78,17 +77,20 @@ struct Action { }; static std::vector> action_list; +static fastboot::FastBootDriver* fb = nullptr; -bool fb_getvar(Transport* transport, const std::string& key, std::string* value) { - std::string cmd = FB_CMD_GETVAR ":" + key; +void fb_init(fastboot::FastBootDriver& fbi) { + fb = &fbi; + auto cb = [](std::string& info) { fprintf(stderr, "(bootloader) %s\n", info.c_str()); }; + fb->SetInfoCallback(cb); +} - char buf[FB_RESPONSE_SZ + 1]; - memset(buf, 0, sizeof(buf)); - if (fb_command_response(transport, cmd, buf)) { - return false; - } - *value = buf; - return true; +const std::string fb_get_error() { + return fb->Error(); +} + +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) { @@ -310,7 +312,7 @@ void fb_queue_wait_for_disconnect() { queue_action(OP_WAIT_FOR_DISCONNECT, ""); } -int64_t fb_execute_queue(Transport* transport) { +int64_t fb_execute_queue() { int64_t status = 0; for (auto& a : action_list) { a->start = now(); @@ -319,33 +321,34 @@ int64_t fb_execute_queue(Transport* transport) { verbose("\n"); } if (a->op == OP_DOWNLOAD) { - status = fb_download_data(transport, a->data, a->size); + char* cbuf = static_cast(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_data_fd(transport, a->fd, a->size); + 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_command(transport, a->cmd); + 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) { - 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); + 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_data_sparse(transport, reinterpret_cast(a->data)); + status = fb->Download(reinterpret_cast(a->data)); status = a->func(*a, status, status ? fb_get_error().c_str() : ""); if (status) break; } else if (a->op == OP_WAIT_FOR_DISCONNECT) { - transport->WaitForDisconnect(); + fb->WaitForDisconnect(); } else if (a->op == OP_UPLOAD) { - status = fb_upload_data(transport, reinterpret_cast(a->data)); + status = fb->Upload(reinterpret_cast(a->data)); status = a->func(*a, status, status ? fb_get_error().c_str() : ""); } else { die("unknown action: %d", a->op); diff --git a/fastboot/engine.h b/fastboot/engine.h new file mode 100644 index 000000000..74aaa6a8b --- /dev/null +++ b/fastboot/engine.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +#include + +#include +#include "fastboot_driver.h" +#include "util.h" + +#include "constants.h" + +class Transport; +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); + +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, + 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 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(); +void fb_set_active(const std::string& slot); + +/* Current product */ +extern char cur_product[FB_RESPONSE_SZ + 1]; + +class FastBootTool { + public: + int Main(int argc, char* argv[]); + + void ParseOsPatchLevel(boot_img_hdr_v1*, const char*); + void ParseOsVersion(boot_img_hdr_v1*, const char*); +}; diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 5aa87d99e..263ea1780 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -60,7 +60,7 @@ #include "bootimg_utils.h" #include "diagnose_usb.h" -#include "fastboot.h" +#include "engine.h" #include "fs.h" #include "tcp.h" #include "transport.h" @@ -592,7 +592,7 @@ static char* strip(char* s) { } #define MAX_OPTIONS 32 -static void check_requirement(Transport* transport, char* line) { +static void check_requirement(char* line) { char *val[MAX_OPTIONS]; unsigned count; char *x; @@ -635,7 +635,7 @@ static void check_requirement(Transport* transport, char* line) { if (!strcmp(name, "partition-exists")) { const char* partition_name = val[0]; std::string has_slot; - if (!fb_getvar(transport, std::string("has-slot:") + partition_name, &has_slot) || + if (!fb_getvar(std::string("has-slot:") + partition_name, &has_slot) || (has_slot != "yes" && has_slot != "no")) { die("device doesn't have required partition %s!", partition_name); } @@ -674,18 +674,18 @@ static void check_requirement(Transport* transport, char* line) { fb_queue_require(product, var, invert, count, out); } -static void check_requirements(Transport* transport, char* data, int64_t sz) { +static void check_requirements(char* data, int64_t sz) { char* s = data; while (sz-- > 0) { if (*s == '\n') { *s++ = 0; - check_requirement(transport, data); + check_requirement(data); data = s; } else { s++; } } - if (fb_execute_queue(transport)) die("requirements not met!"); + if (fb_execute_queue()) die("requirements not met!"); } static void queue_info_dump() { @@ -716,9 +716,9 @@ static struct sparse_file** load_sparse_files(int fd, int64_t max_size) { return out_s; } -static int64_t get_target_sparse_limit(Transport* transport) { +static int64_t get_target_sparse_limit() { std::string max_download_size; - if (!fb_getvar(transport, "max-download-size", &max_download_size) || + if (!fb_getvar("max-download-size", &max_download_size) || max_download_size.empty()) { verbose("target didn't report max-download-size"); return 0; @@ -736,13 +736,13 @@ static int64_t get_target_sparse_limit(Transport* transport) { return limit; } -static int64_t get_sparse_limit(Transport* transport, int64_t size) { +static int64_t get_sparse_limit(int64_t size) { int64_t limit = sparse_limit; if (limit == 0) { // Unlimited, so see what the target device's limit is. // TODO: shouldn't we apply this limit even if you've used -S? if (target_sparse_limit == -1) { - target_sparse_limit = get_target_sparse_limit(transport); + target_sparse_limit = get_target_sparse_limit(); } if (target_sparse_limit > 0) { limit = target_sparse_limit; @@ -758,14 +758,14 @@ static int64_t get_sparse_limit(Transport* transport, int64_t size) { return 0; } -static bool load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) { +static bool load_buf_fd(int fd, struct fastboot_buffer* buf) { int64_t sz = get_file_size(fd); if (sz == -1) { return false; } lseek64(fd, 0, SEEK_SET); - int64_t limit = get_sparse_limit(transport, sz); + int64_t limit = get_sparse_limit(sz); if (limit) { sparse_file** s = load_sparse_files(fd, limit); if (s == nullptr) { @@ -783,7 +783,7 @@ static bool load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* bu return true; } -static bool load_buf(Transport* transport, const char* fname, struct fastboot_buffer* buf) { +static bool load_buf(const char* fname, struct fastboot_buffer* buf) { unique_fd fd(TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_BINARY))); if (fd == -1) { @@ -799,7 +799,7 @@ static bool load_buf(Transport* transport, const char* fname, struct fastboot_bu return false; } - return load_buf_fd(transport, fd.release(), buf); + return load_buf_fd(fd.release(), buf); } static void rewrite_vbmeta_buffer(struct fastboot_buffer* buf) { @@ -871,23 +871,23 @@ static void flash_buf(const std::string& partition, struct fastboot_buffer *buf) } } -static std::string get_current_slot(Transport* transport) { +static std::string get_current_slot() { std::string current_slot; - if (!fb_getvar(transport, "current-slot", ¤t_slot)) return ""; + if (!fb_getvar("current-slot", ¤t_slot)) return ""; return current_slot; } -static int get_slot_count(Transport* transport) { +static int get_slot_count() { std::string var; int count = 0; - if (!fb_getvar(transport, "slot-count", &var) || !android::base::ParseInt(var, &count)) { + if (!fb_getvar("slot-count", &var) || !android::base::ParseInt(var, &count)) { return 0; } return count; } -static bool supports_AB(Transport* transport) { - return get_slot_count(transport) >= 2; +static bool supports_AB() { + return get_slot_count() >= 2; } // Given a current slot, this returns what the 'other' slot is. @@ -898,25 +898,25 @@ static std::string get_other_slot(const std::string& current_slot, int count) { return std::string(1, next); } -static std::string get_other_slot(Transport* transport, const std::string& current_slot) { - return get_other_slot(current_slot, get_slot_count(transport)); +static std::string get_other_slot(const std::string& current_slot) { + return get_other_slot(current_slot, get_slot_count()); } -static std::string get_other_slot(Transport* transport, int count) { - return get_other_slot(get_current_slot(transport), count); +static std::string get_other_slot(int count) { + return get_other_slot(get_current_slot(), count); } -static std::string get_other_slot(Transport* transport) { - return get_other_slot(get_current_slot(transport), get_slot_count(transport)); +static std::string get_other_slot() { + return get_other_slot(get_current_slot(), get_slot_count()); } -static std::string verify_slot(Transport* transport, const std::string& slot_name, bool allow_all) { +static std::string verify_slot(const std::string& slot_name, bool allow_all) { std::string slot = slot_name; if (slot == "all") { if (allow_all) { return "all"; } else { - int count = get_slot_count(transport); + int count = get_slot_count(); if (count > 0) { return "a"; } else { @@ -925,11 +925,11 @@ static std::string verify_slot(Transport* transport, const std::string& slot_nam } } - int count = get_slot_count(transport); + int count = get_slot_count(); if (count == 0) die("Device does not support slots"); if (slot == "other") { - std::string other = get_other_slot(transport, count); + std::string other = get_other_slot( count); if (other == "") { die("No known slots"); } @@ -946,22 +946,22 @@ static std::string verify_slot(Transport* transport, const std::string& slot_nam exit(1); } -static std::string verify_slot(Transport* transport, const std::string& slot) { - return verify_slot(transport, slot, true); +static std::string verify_slot(const std::string& slot) { + return verify_slot(slot, true); } -static void do_for_partition(Transport* transport, const std::string& part, const std::string& slot, +static void do_for_partition(const std::string& part, const std::string& slot, const std::function& func, bool force_slot) { std::string has_slot; std::string current_slot; - if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) { + if (!fb_getvar("has-slot:" + part, &has_slot)) { /* If has-slot is not supported, the answer is no. */ has_slot = "no"; } if (has_slot == "yes") { if (slot == "") { - current_slot = get_current_slot(transport); + current_slot = get_current_slot(); if (current_slot == "") { die("Failed to identify current slot"); } @@ -983,30 +983,30 @@ static void do_for_partition(Transport* transport, const std::string& part, cons * partition names. If force_slot is true, it will fail if a slot is specified, and the given * partition does not support slots. */ -static void do_for_partitions(Transport* transport, const std::string& part, const std::string& slot, +static void do_for_partitions(const std::string& part, const std::string& slot, const std::function& func, bool force_slot) { std::string has_slot; if (slot == "all") { - if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) { + if (!fb_getvar("has-slot:" + part, &has_slot)) { die("Could not check if partition %s has slot %s", part.c_str(), slot.c_str()); } if (has_slot == "yes") { - for (int i=0; i < get_slot_count(transport); i++) { - do_for_partition(transport, part, std::string(1, (char)(i + 'a')), func, force_slot); + for (int i=0; i < get_slot_count(); i++) { + do_for_partition(part, std::string(1, (char)(i + 'a')), func, force_slot); } } else { - do_for_partition(transport, part, "", func, force_slot); + do_for_partition(part, "", func, force_slot); } } else { - do_for_partition(transport, part, slot, func, force_slot); + do_for_partition(part, slot, func, force_slot); } } -static void do_flash(Transport* transport, const char* pname, const char* fname) { +static void do_flash(const char* pname, const char* fname) { struct fastboot_buffer buf; - if (!load_buf(transport, fname, &buf)) { + if (!load_buf(fname, &buf)) { die("cannot load '%s': %s", fname, strerror(errno)); } flash_buf(pname, &buf); @@ -1022,20 +1022,20 @@ static void do_update_signature(ZipArchiveHandle zip, const char* filename) { // Sets slot_override as the active slot. If slot_override is blank, // set current slot as active instead. This clears slot-unbootable. -static void set_active(Transport* transport, const std::string& slot_override) { - if (!supports_AB(transport)) return; +static void set_active(const std::string& slot_override) { + if (!supports_AB()) return; if (slot_override != "") { fb_set_active(slot_override); } else { - std::string current_slot = get_current_slot(transport); + std::string current_slot = get_current_slot(); if (current_slot != "") { fb_set_active(current_slot); } } } -static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool skip_secondary) { +static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) { queue_info_dump(); fb_queue_query_save("product", cur_product, sizeof(cur_product)); @@ -1052,17 +1052,17 @@ static void do_update(Transport* transport, const char* filename, const std::str die("update package '%s' has no android-info.txt", filename); } - check_requirements(transport, reinterpret_cast(data), sz); + check_requirements(reinterpret_cast(data), sz); std::string secondary; if (!skip_secondary) { if (slot_override != "") { - secondary = get_other_slot(transport, slot_override); + secondary = get_other_slot(slot_override); } else { - secondary = get_other_slot(transport); + secondary = get_other_slot(); } if (secondary == "") { - if (supports_AB(transport)) { + if (supports_AB()) { fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n"); } skip_secondary = true; @@ -1087,7 +1087,7 @@ static void do_update(Transport* transport, const char* filename, const std::str } fastboot_buffer buf; - if (!load_buf_fd(transport, fd, &buf)) { + if (!load_buf_fd(fd, &buf)) { die("cannot load %s from flash: %s", images[i].img_name, strerror(errno)); } @@ -1099,13 +1099,13 @@ static void do_update(Transport* transport, const char* filename, const std::str * program exits. */ }; - do_for_partitions(transport, images[i].part_name, slot, update, false); + do_for_partitions(images[i].part_name, slot, update, false); } if (slot_override == "all") { - set_active(transport, "a"); + set_active("a"); } else { - set_active(transport, slot_override); + set_active(slot_override); } CloseArchive(zip); @@ -1125,7 +1125,7 @@ static void do_send_signature(const std::string& fn) { fb_queue_command("signature", "installing signature"); } -static void do_flashall(Transport* transport, const std::string& slot_override, bool skip_secondary) { +static void do_flashall(const std::string& slot_override, bool skip_secondary) { std::string fname; queue_info_dump(); @@ -1138,17 +1138,17 @@ static void do_flashall(Transport* transport, const std::string& slot_override, void* data = load_file(fname.c_str(), &sz); if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno)); - check_requirements(transport, reinterpret_cast(data), sz); + check_requirements(reinterpret_cast(data), sz); std::string secondary; if (!skip_secondary) { if (slot_override != "") { - secondary = get_other_slot(transport, slot_override); + secondary = get_other_slot(slot_override); } else { - secondary = get_other_slot(transport); + secondary = get_other_slot(); } if (secondary == "") { - if (supports_AB(transport)) { + if (supports_AB()) { fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n"); } skip_secondary = true; @@ -1165,7 +1165,7 @@ static void do_flashall(Transport* transport, const std::string& slot_override, if (!slot) continue; fname = find_item_given_name(images[i].img_name); fastboot_buffer buf; - if (!load_buf(transport, fname.c_str(), &buf)) { + if (!load_buf(fname.c_str(), &buf)) { if (images[i].is_optional) continue; die("could not load '%s': %s", images[i].img_name, strerror(errno)); } @@ -1174,13 +1174,13 @@ static void do_flashall(Transport* transport, const std::string& slot_override, do_send_signature(fname.c_str()); flash_buf(partition.c_str(), &buf); }; - do_for_partitions(transport, images[i].part_name, slot, flashall, false); + do_for_partitions(images[i].part_name, slot, flashall, false); } if (slot_override == "all") { - set_active(transport, "a"); + set_active("a"); } else { - set_active(transport, slot_override); + set_active(slot_override); } } @@ -1210,9 +1210,9 @@ static std::string fb_fix_numeric_var(std::string var) { return var; } -static unsigned fb_get_flash_block_size(Transport* transport, std::string name) { +static unsigned fb_get_flash_block_size(std::string name) { std::string sizeString; - if (!fb_getvar(transport, name, &sizeString) || sizeString.empty()) { + if (!fb_getvar(name, &sizeString) || sizeString.empty()) { // This device does not report flash block sizes, so return 0. return 0; } @@ -1230,7 +1230,7 @@ static unsigned fb_get_flash_block_size(Transport* transport, std::string name) return size; } -static void fb_perform_format(Transport* transport, +static void fb_perform_format( const std::string& partition, int skip_if_not_supported, const std::string& type_override, const std::string& size_override, const std::string& initial_dir) { @@ -1250,7 +1250,7 @@ static void fb_perform_format(Transport* transport, limit = sparse_limit; } - if (!fb_getvar(transport, "partition-type:" + partition, &partition_type)) { + if (!fb_getvar("partition-type:" + partition, &partition_type)) { errMsg = "Can't determine partition type.\n"; goto failed; } @@ -1262,7 +1262,7 @@ static void fb_perform_format(Transport* transport, partition_type = type_override; } - if (!fb_getvar(transport, "partition-size:" + partition, &partition_size)) { + if (!fb_getvar("partition-size:" + partition, &partition_size)) { errMsg = "Unable to get partition size\n"; goto failed; } @@ -1294,8 +1294,8 @@ static void fb_perform_format(Transport* transport, } unsigned eraseBlkSize, logicalBlkSize; - eraseBlkSize = fb_get_flash_block_size(transport, "erase-block-size"); - logicalBlkSize = fb_get_flash_block_size(transport, "logical-block-size"); + eraseBlkSize = fb_get_flash_block_size("erase-block-size"); + logicalBlkSize = fb_get_flash_block_size("logical-block-size"); if (fs_generator_generate(gen, output.path, size, initial_dir, eraseBlkSize, logicalBlkSize)) { @@ -1308,7 +1308,7 @@ static void fb_perform_format(Transport* transport, fprintf(stderr, "Cannot open generated image: %s\n", strerror(errno)); return; } - if (!load_buf_fd(transport, fd.release(), &buf)) { + if (!load_buf_fd(fd.release(), &buf)) { fprintf(stderr, "Cannot read image: %s\n", strerror(errno)); return; } @@ -1323,7 +1323,7 @@ failed: fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str()); } -int FastBoot::Main(int argc, char* argv[]) { +int FastBootTool::Main(int argc, char* argv[]) { bool wants_wipe = false; bool wants_reboot = false; bool wants_reboot_bootloader = false; @@ -1470,23 +1470,25 @@ int FastBoot::Main(int argc, char* argv[]) { if (transport == nullptr) { return 1; } + fastboot::FastBootDriver fb(transport); + fb_init(fb); const double start = now(); - if (slot_override != "") slot_override = verify_slot(transport, slot_override); - if (next_active != "") next_active = verify_slot(transport, next_active, false); + if (slot_override != "") slot_override = verify_slot(slot_override); + if (next_active != "") next_active = verify_slot(next_active, false); if (wants_set_active) { if (next_active == "") { if (slot_override == "") { std::string current_slot; - if (fb_getvar(transport, "current-slot", ¤t_slot)) { - next_active = verify_slot(transport, current_slot, false); + if (fb_getvar("current-slot", ¤t_slot)) { + next_active = verify_slot(current_slot, false); } else { wants_set_active = false; } } else { - next_active = verify_slot(transport, slot_override, false); + next_active = verify_slot(slot_override, false); } } } @@ -1502,7 +1504,7 @@ int FastBoot::Main(int argc, char* argv[]) { std::string partition = next_arg(&args); auto erase = [&](const std::string& partition) { std::string partition_type; - if (fb_getvar(transport, std::string("partition-type:") + partition, + if (fb_getvar(std::string("partition-type:") + partition, &partition_type) && fs_get_generator(partition_type) != nullptr) { fprintf(stderr, "******** Did you mean to fastboot format this %s partition?\n", @@ -1511,7 +1513,7 @@ int FastBoot::Main(int argc, char* argv[]) { fb_queue_erase(partition); }; - do_for_partitions(transport, partition, slot_override, erase, true); + do_for_partitions(partition, slot_override, erase, true); } else if (android::base::StartsWith(command, "format")) { // Parsing for: "format[:[type][:[size]]]" // Some valid things: @@ -1529,9 +1531,9 @@ int FastBoot::Main(int argc, char* argv[]) { std::string partition = next_arg(&args); auto format = [&](const std::string& partition) { - fb_perform_format(transport, partition, 0, type_override, size_override, ""); + fb_perform_format(partition, 0, type_override, size_override, ""); }; - do_for_partitions(transport, partition.c_str(), slot_override, format, true); + do_for_partitions(partition.c_str(), slot_override, format, true); } else if (command == "signature") { std::string filename = next_arg(&args); data = load_file(filename.c_str(), &sz); @@ -1579,9 +1581,9 @@ int FastBoot::Main(int argc, char* argv[]) { if (fname.empty()) die("cannot determine image filename for '%s'", pname.c_str()); auto flash = [&](const std::string &partition) { - do_flash(transport, partition.c_str(), fname.c_str()); + do_flash(partition.c_str(), fname.c_str()); }; - do_for_partitions(transport, pname.c_str(), slot_override, flash, true); + do_for_partitions(pname.c_str(), slot_override, flash, true); } else if (command == "flash:raw") { std::string partition = next_arg(&args); std::string kernel = next_arg(&args); @@ -1594,13 +1596,13 @@ int FastBoot::Main(int argc, char* argv[]) { auto flashraw = [&](const std::string& partition) { fb_queue_flash(partition, data, sz); }; - do_for_partitions(transport, partition, slot_override, flashraw, true); + do_for_partitions(partition, slot_override, flashraw, true); } else if (command == "flashall") { if (slot_override == "all") { fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n"); - do_flashall(transport, slot_override, true); + do_flashall(slot_override, true); } else { - do_flashall(transport, slot_override, skip_secondary); + do_flashall(slot_override, skip_secondary); } wants_reboot = true; } else if (command == "update") { @@ -1612,16 +1614,16 @@ int FastBoot::Main(int argc, char* argv[]) { if (!args.empty()) { filename = next_arg(&args); } - do_update(transport, filename.c_str(), slot_override, skip_secondary || slot_all); + do_update(filename.c_str(), slot_override, skip_secondary || slot_all); wants_reboot = true; } else if (command == "set_active") { - std::string slot = verify_slot(transport, next_arg(&args), false); + std::string slot = verify_slot(next_arg(&args), false); fb_set_active(slot); } else if (command == "stage") { std::string filename = next_arg(&args); struct fastboot_buffer buf; - if (!load_buf(transport, filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) { + if (!load_buf(filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) { die("cannot load '%s'", filename.c_str()); } fb_queue_download_fd(filename, buf.fd, buf.sz); @@ -1650,16 +1652,16 @@ int FastBoot::Main(int argc, char* argv[]) { std::vector partitions = { "userdata", "cache", "metadata" }; for (const auto& partition : partitions) { std::string partition_type; - if (!fb_getvar(transport, std::string{"partition-type:"} + partition, &partition_type)) continue; + if (!fb_getvar(std::string{"partition-type:"} + partition, &partition_type)) continue; if (partition_type.empty()) continue; fb_queue_erase(partition); if (partition == "userdata" && set_fbe_marker) { fprintf(stderr, "setting FBE marker on initial userdata...\n"); std::string initial_userdata_dir = create_fbemarker_tmpdir(); - fb_perform_format(transport, partition, 1, "", "", initial_userdata_dir); + fb_perform_format(partition, 1, "", "", initial_userdata_dir); delete_fbemarker_tmpdir(initial_userdata_dir); } else { - fb_perform_format(transport, partition, 1, "", "", ""); + fb_perform_format(partition, 1, "", "", ""); } } } @@ -1674,12 +1676,12 @@ int FastBoot::Main(int argc, char* argv[]) { fb_queue_wait_for_disconnect(); } - int status = fb_execute_queue(transport) ? EXIT_FAILURE : EXIT_SUCCESS; + int status = fb_execute_queue() ? EXIT_FAILURE : EXIT_SUCCESS; fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start)); return status; } -void FastBoot::ParseOsPatchLevel(boot_img_hdr_v1* hdr, const char* arg) { +void FastBootTool::ParseOsPatchLevel(boot_img_hdr_v1* hdr, const char* arg) { unsigned year, month, day; if (sscanf(arg, "%u-%u-%u", &year, &month, &day) != 3) { syntax_error("OS patch level should be YYYY-MM-DD: %s", arg); @@ -1689,7 +1691,7 @@ void FastBoot::ParseOsPatchLevel(boot_img_hdr_v1* hdr, const char* arg) { hdr->SetOsPatchLevel(year, month); } -void FastBoot::ParseOsVersion(boot_img_hdr_v1* hdr, const char* arg) { +void FastBootTool::ParseOsVersion(boot_img_hdr_v1* hdr, const char* arg) { unsigned major = 0, minor = 0, patch = 0; std::vector versions = android::base::Split(arg, "."); if (versions.size() < 1 || versions.size() > 3 || diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h deleted file mode 100644 index a93c0ac51..000000000 --- a/fastboot/fastboot.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#pragma once - -#include -#include - -#include - -#include - -#include "constants.h" - -class Transport; -struct sparse_file; - -/* protocol.c - fastboot protocol */ -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); -int64_t fb_upload_data(Transport* transport, const char* outfile); -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 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 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 std::string& slot); - -/* util stuff */ -double now(); -char* xstrdup(const char*); -void set_verbose(); - -// These printf-like functions are implemented in terms of vsnprintf, so they -// use the same attribute for compile-time format string checking. -void die(const char* fmt, ...) __attribute__((__noreturn__)) -__attribute__((__format__(__printf__, 1, 2))); -void verbose(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))); - -/* Current product */ -extern char cur_product[FB_RESPONSE_SZ + 1]; - -class FastBoot { - public: - int Main(int argc, char* argv[]); - - void ParseOsPatchLevel(boot_img_hdr_v1*, const char*); - void ParseOsVersion(boot_img_hdr_v1*, const char*); -}; diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp new file mode 100644 index 000000000..c30842055 --- /dev/null +++ b/fastboot/fastboot_driver.cpp @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "fastboot_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "fastboot_driver.h" +#include "transport.h" + +namespace fastboot { + +/*************************** PUBLIC *******************************/ +FastBootDriver::FastBootDriver(Transport* transport, std::function info, + bool no_checks) + : transport(transport) { + info_cb_ = info; + disable_checks_ = no_checks; +} + +RetCode FastBootDriver::Boot(std::string* response, std::vector* info) { + return RawCommand(Commands::BOOT, response, info); +} + +RetCode FastBootDriver::Continue(std::string* response, std::vector* info) { + return RawCommand(Commands::CONTINUE, response, info); +} + +RetCode FastBootDriver::Erase(const std::string& part, std::string* response, + std::vector* info) { + return RawCommand(Commands::ERASE + part, response, info); +} + +RetCode FastBootDriver::Flash(const std::string& part, std::string* response, + std::vector* info) { + return RawCommand(Commands::FLASH + part, response, info); +} + +RetCode FastBootDriver::GetVar(const std::string& key, std::string* val, + std::vector* info) { + return RawCommand(Commands::GET_VAR + key, val, info); +} + +RetCode FastBootDriver::GetVarAll(std::vector* response) { + std::string tmp; + return GetVar("all", &tmp, response); +} + +RetCode FastBootDriver::Powerdown(std::string* response, std::vector* info) { + return RawCommand(Commands::POWERDOWN, response, info); +} + +RetCode FastBootDriver::Reboot(std::string* response, std::vector* info) { + return RawCommand(Commands::REBOOT, response, info); +} + +RetCode FastBootDriver::SetActive(const std::string& part, std::string* response, + std::vector* info) { + return RawCommand(Commands::SET_ACTIVE + part, response, info); +} + +RetCode FastBootDriver::Verify(uint32_t num, std::string* response, std::vector* info) { + std::string cmd = android::base::StringPrintf("%s%08" PRIx32, Commands::VERIFY.c_str(), num); + return RawCommand(cmd, response, info); +} + +RetCode FastBootDriver::FlashPartition(const std::string& part, const std::vector& data) { + RetCode ret; + if ((ret = Download(data))) { + return ret; + } + return RawCommand(Commands::FLASH + part); +} + +RetCode FastBootDriver::FlashPartition(const std::string& part, int fd, uint32_t sz) { + RetCode ret; + if ((ret = Download(fd, sz))) { + return ret; + } + return RawCommand(Commands::FLASH + part); +} + +RetCode FastBootDriver::FlashPartition(const std::string& part, sparse_file* s) { + RetCode ret; + if ((ret = Download(s))) { + return ret; + } + return RawCommand(Commands::FLASH + part); +} + +RetCode FastBootDriver::Partitions(std::vector>* parts) { + std::vector all; + RetCode ret; + if ((ret = GetVarAll(&all))) { + return ret; + } + + std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:d:]]+)"); + std::smatch sm; + + for (auto& s : all) { + if (std::regex_match(s, sm, reg)) { + std::string m1(sm[1]); + std::string m2(sm[2]); + uint32_t tmp = strtol(m2.c_str(), 0, 16); + parts->push_back(std::make_tuple(m1, tmp)); + } + } + return SUCCESS; +} + +RetCode FastBootDriver::Require(const std::string& var, const std::vector& allowed, + bool* reqmet, bool invert) { + *reqmet = invert; + RetCode ret; + std::string response; + if ((ret = GetVar(var, &response))) { + return ret; + } + + // Now check if we have a match + for (const auto s : allowed) { + // If it ends in *, and starting substring match + if (response == s || (s.length() && s.back() == '*' && + !response.compare(0, s.length() - 1, s, 0, s.length() - 1))) { + *reqmet = !invert; + break; + } + } + + return SUCCESS; +} + +RetCode FastBootDriver::Download(int fd, size_t size, std::string* response, + std::vector* info) { + RetCode ret; + + if ((size <= 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) { + error_ = "File is too large to download"; + return BAD_ARG; + } + + uint32_t u32size = static_cast(size); + if ((ret = DownloadCommand(u32size, response, info))) { + return ret; + } + + // Write the buffer + if ((ret = SendBuffer(fd, size))) { + return ret; + } + + // Wait for response + return HandleResponse(response, info); +} + +RetCode FastBootDriver::Download(const std::vector& buf, std::string* response, + std::vector* info) { + return Download(buf.data(), buf.size(), response, info); +} + +RetCode FastBootDriver::Download(const char* buf, uint32_t size, std::string* response, + std::vector* info) { + RetCode ret; + error_ = ""; + if ((size == 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) { + error_ = "Buffer is too large or 0 bytes"; + return BAD_ARG; + } + + if ((ret = DownloadCommand(size, response, info))) { + return ret; + } + + // Write the buffer + if ((ret = SendBuffer(buf, size))) { + return ret; + } + + // Wait for response + return HandleResponse(response, info); +} + +RetCode FastBootDriver::Download(sparse_file* s, std::string* response, + std::vector* info) { + error_ = ""; + int64_t size = sparse_file_len(s, true, false); + if (size <= 0 || size > MAX_DOWNLOAD_SIZE) { + error_ = "Sparse file is too large or invalid"; + return BAD_ARG; + } + + RetCode ret; + uint32_t u32size = static_cast(size); + if ((ret = DownloadCommand(u32size, response, info))) { + return ret; + } + + struct SparseCBPrivate { + FastBootDriver* self; + std::vector tpbuf; + } cb_priv; + cb_priv.self = this; + + auto cb = [](void* priv, const void* buf, size_t len) -> int { + SparseCBPrivate* data = static_cast(priv); + const char* cbuf = static_cast(buf); + return data->self->SparseWriteCallback(data->tpbuf, cbuf, len); + }; + + if (sparse_file_callback(s, true, false, cb, &cb_priv) < 0) { + error_ = "Error reading sparse file"; + return IO_ERROR; + } + + // Now flush + if (cb_priv.tpbuf.size() && (ret = SendBuffer(cb_priv.tpbuf))) { + return ret; + } + + return HandleResponse(response, info); +} + +RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response, + std::vector* info) { + RetCode ret; + int dsize; + if ((ret = RawCommand(Commands::UPLOAD, response, info, &dsize)) || dsize == 0) { + error_ = "Upload request failed"; + return ret; + } + + std::vector data; + data.resize(dsize); + + if ((ret = ReadBuffer(data))) { + return ret; + } + + std::ofstream ofs; + ofs.open(outfile, std::ofstream::out | std::ofstream::binary); + if (ofs.fail()) { + error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str()); + return IO_ERROR; + } + ofs.write(data.data(), data.size()); + if (ofs.fail() || ofs.bad()) { + error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str()); + return IO_ERROR; + } + ofs.close(); + + return HandleResponse(response, info); +} + +// Helpers +void FastBootDriver::SetInfoCallback(std::function info) { + info_cb_ = info; +} + +const std::string FastBootDriver::RCString(RetCode rc) { + switch (rc) { + case SUCCESS: + return std::string("Success"); + + case BAD_ARG: + return std::string("Invalid Argument"); + + case IO_ERROR: + return std::string("I/O Error"); + + case BAD_DEV_RESP: + return std::string("Invalid Device Response"); + + case DEVICE_FAIL: + return std::string("Device Error"); + + case TIMEOUT: + return std::string("Timeout"); + + default: + return std::string("Unknown Error"); + } +} + +std::string FastBootDriver::Error() { + return error_; +} + +RetCode FastBootDriver::WaitForDisconnect() { + return transport->WaitForDisconnect() ? IO_ERROR : SUCCESS; +} + +/****************************** PROTECTED *************************************/ +RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response, + std::vector* info, int* dsize) { + error_ = ""; // Clear any pending error + if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) { + error_ = "Command length to RawCommand() is too long"; + return BAD_ARG; + } + + if (transport->Write(cmd.c_str(), cmd.size()) != static_cast(cmd.size())) { + error_ = ErrnoStr("Write to device failed"); + return IO_ERROR; + } + + // Read the response + return HandleResponse(response, info, dsize); +} + +RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response, + std::vector* info) { + std::string cmd(android::base::StringPrintf("%s%08" PRIx32, Commands::DOWNLOAD.c_str(), size)); + RetCode ret; + if ((ret = RawCommand(cmd, response, info))) { + return ret; + } + return SUCCESS; +} + +RetCode FastBootDriver::HandleResponse(std::string* response, std::vector* info, + int* dsize) { + char status[FB_RESPONSE_SZ + 1]; + auto start = std::chrono::system_clock::now(); + + auto set_response = [response](std::string s) { + if (response) *response = std::move(s); + }; + auto add_info = [info](std::string s) { + if (info) info->push_back(std::move(s)); + }; + + // erase response + set_response(""); + while ((std::chrono::system_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) { + int r = transport->Read(status, FB_RESPONSE_SZ); + if (r < 0) { + error_ = ErrnoStr("Status read failed"); + return IO_ERROR; + } + + status[r] = '\0'; // Need the null terminator + std::string input(status); + if (android::base::StartsWith(input, "INFO")) { + std::string tmp = input.substr(strlen("INFO")); + info_cb_(tmp); + add_info(std::move(tmp)); + } else if (android::base::StartsWith(input, "OKAY")) { + set_response(input.substr(strlen("OKAY"))); + return SUCCESS; + } else if (android::base::StartsWith(input, "FAIL")) { + error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL")); + set_response(input.substr(strlen("FAIL"))); + return DEVICE_FAIL; + } else if (android::base::StartsWith(input, "DATA")) { + std::string tmp = input.substr(strlen("DATA")); + uint32_t num = strtol(tmp.c_str(), 0, 16); + if (num > MAX_DOWNLOAD_SIZE) { + error_ = android::base::StringPrintf("Data size too large (%d)", num); + return BAD_DEV_RESP; + } + if (dsize) *dsize = num; + set_response(std::move(tmp)); + return SUCCESS; + } else { + error_ = android::base::StringPrintf("Device sent unknown status code: %s", status); + return BAD_DEV_RESP; + } + + } // End of while loop + + return TIMEOUT; +} + +std::string FastBootDriver::ErrnoStr(const std::string& msg) { + return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno)); +} + +const std::string FastBootDriver::Commands::BOOT = "boot"; +const std::string FastBootDriver::Commands::CONTINUE = "continue"; +const std::string FastBootDriver::Commands::DOWNLOAD = "download:"; +const std::string FastBootDriver::Commands::ERASE = "erase:"; +const std::string FastBootDriver::Commands::FLASH = "flash:"; +const std::string FastBootDriver::Commands::GET_VAR = "getvar:"; +const std::string FastBootDriver::Commands::POWERDOWN = "powerdown"; +const std::string FastBootDriver::Commands::REBOOT = "reboot"; +const std::string FastBootDriver::Commands::SET_ACTIVE = "set_active:"; +const std::string FastBootDriver::Commands::UPLOAD = "upload"; +const std::string FastBootDriver::Commands::VERIFY = "verify:"; + +/******************************* PRIVATE **************************************/ +RetCode FastBootDriver::SendBuffer(int fd, size_t size) { + static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024; + off64_t offset = 0; + uint32_t remaining = size; + RetCode ret; + + while (remaining) { + // Memory map the file + android::FileMap filemap; + size_t len = std::min(remaining, MAX_MAP_SIZE); + + if (!filemap.create(NULL, fd, offset, len, true)) { + error_ = "Creating filemap failed"; + return IO_ERROR; + } + + if ((ret = SendBuffer(filemap.getDataPtr(), len))) { + return ret; + } + + remaining -= len; + offset += len; + } + + return SUCCESS; +} + +RetCode FastBootDriver::SendBuffer(const std::vector& buf) { + // Write the buffer + return SendBuffer(buf.data(), buf.size()); +} + +RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) { + // Write the buffer + ssize_t tmp = transport->Write(buf, size); + + if (tmp < 0) { + error_ = ErrnoStr("Write to device failed in SendBuffer()"); + return IO_ERROR; + } else if (static_cast(tmp) != size) { + error_ = android::base::StringPrintf("Failed to write all %zu bytes", size); + + return IO_ERROR; + } + + return SUCCESS; +} + +RetCode FastBootDriver::ReadBuffer(std::vector& buf) { + // Read the buffer + return ReadBuffer(buf.data(), buf.size()); +} + +RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) { + // Read the buffer + ssize_t tmp = transport->Read(buf, size); + + if (tmp < 0) { + error_ = ErrnoStr("Read from device failed in ReadBuffer()"); + return IO_ERROR; + } else if (static_cast(tmp) != size) { + error_ = android::base::StringPrintf("Failed to read all %zu bytes", size); + return IO_ERROR; + } + + return SUCCESS; +} + +int FastBootDriver::SparseWriteCallback(std::vector& tpbuf, const char* data, size_t len) { + size_t total = 0; + size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len); + + // Handle the residual + tpbuf.insert(tpbuf.end(), data, data + to_write); + if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) { // Nothing enough to send rn + return 0; + } + + if (SendBuffer(tpbuf)) { + error_ = ErrnoStr("Send failed in SparseWriteCallback()"); + return -1; + } + tpbuf.clear(); + total += to_write; + + // Now we need to send a multiple of chunk size + size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE; + size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks; + if (SendBuffer(data + total, nbytes)) { + error_ = ErrnoStr("Send failed in SparseWriteCallback()"); + return -1; + } + total += nbytes; + + if (len - total > 0) { // We have residual data to save for next time + tpbuf.assign(data + total, data + len); + } + + return 0; +} + +} // End namespace fastboot diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h new file mode 100644 index 000000000..9fdd31700 --- /dev/null +++ b/fastboot/fastboot_driver.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#pragma once +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "transport.h" + +class Transport; + +namespace fastboot { + +static constexpr int FB_COMMAND_SZ = 64; +static constexpr int FB_RESPONSE_SZ = 64; + +enum RetCode : int { + SUCCESS = 0, + BAD_ARG, + IO_ERROR, + BAD_DEV_RESP, + DEVICE_FAIL, + TIMEOUT, +}; + +class FastBootDriver { + public: + static constexpr int RESP_TIMEOUT = 10; // 10 seconds + static constexpr uint32_t MAX_DOWNLOAD_SIZE = std::numeric_limits::max(); + static constexpr size_t TRANSPORT_CHUNK_SIZE = 1024; + + FastBootDriver(Transport* transport, + std::function info = [](std::string&) {}, + bool no_checks = false); + + RetCode Boot(std::string* response = nullptr, std::vector* info = nullptr); + RetCode Continue(std::string* response = nullptr, std::vector* info = nullptr); + RetCode Download(int fd, size_t size, std::string* response = nullptr, + std::vector* info = nullptr); + RetCode Download(const std::vector& buf, std::string* response = nullptr, + std::vector* info = nullptr); + // This will be removed after fastboot is modified to use a vector + RetCode Download(const char* buf, uint32_t size, std::string* response = nullptr, + std::vector* info = nullptr); + RetCode Download(sparse_file* s, std::string* response = nullptr, + std::vector* info = nullptr); + RetCode Erase(const std::string& part, std::string* response = nullptr, + std::vector* info = nullptr); + RetCode Flash(const std::string& part, std::string* response = nullptr, + std::vector* info = nullptr); + RetCode GetVar(const std::string& key, std::string* val, + std::vector* info = nullptr); + RetCode GetVarAll(std::vector* response); + RetCode Powerdown(std::string* response = nullptr, std::vector* info = nullptr); + RetCode Reboot(std::string* response = nullptr, std::vector* info = nullptr); + RetCode SetActive(const std::string& part, std::string* response = nullptr, + std::vector* info = nullptr); + RetCode Upload(const std::string& outfile, std::string* response = nullptr, + std::vector* info = nullptr); + RetCode Verify(uint32_t num, std::string* response = nullptr, + std::vector* info = nullptr); + + /* HIGHER LEVEL COMMANDS -- Composed of the commands above */ + RetCode FlashPartition(const std::string& part, const std::vector& data); + RetCode FlashPartition(const std::string& part, int fd, uint32_t sz); + RetCode FlashPartition(const std::string& part, sparse_file* s); + + RetCode Partitions(std::vector>* parts); + RetCode Require(const std::string& var, const std::vector& allowed, bool* reqmet, + bool invert = false); + + /* HELPERS */ + void SetInfoCallback(std::function info); + const std::string RCString(RetCode rc); + std::string Error(); + RetCode WaitForDisconnect(); + + // This is temporarily public for engine.cpp + RetCode RawCommand(const std::string& cmd, std::string* response = nullptr, + std::vector* info = nullptr, int* dsize = nullptr); + + protected: + RetCode DownloadCommand(uint32_t size, std::string* response = nullptr, + std::vector* info = nullptr); + RetCode HandleResponse(std::string* response = nullptr, + std::vector* info = nullptr, int* dsize = nullptr); + + std::string ErrnoStr(const std::string& msg); + + // More like a namespace... + struct Commands { + static const std::string BOOT; + static const std::string CONTINUE; + static const std::string DOWNLOAD; + static const std::string ERASE; + static const std::string FLASH; + static const std::string GET_VAR; + static const std::string POWERDOWN; + static const std::string REBOOT; + static const std::string SET_ACTIVE; + static const std::string UPLOAD; + static const std::string VERIFY; + }; + + Transport* const transport; + + private: + RetCode SendBuffer(int fd, size_t size); + RetCode SendBuffer(const std::vector& buf); + RetCode SendBuffer(const void* buf, size_t size); + + RetCode ReadBuffer(std::vector& buf); + RetCode ReadBuffer(void* buf, size_t size); + + int SparseWriteCallback(std::vector& tpbuf, const char* data, size_t len); + + std::string error_; + std::function info_cb_; + bool disable_checks_; +}; + +} // namespace fastboot diff --git a/fastboot/fastboot_test.cpp b/fastboot/fastboot_test.cpp index 1681427c7..43201face 100644 --- a/fastboot/fastboot_test.cpp +++ b/fastboot/fastboot_test.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "fastboot.h" +#include "engine.h" #include TEST(FastBoot, ParseOsPatchLevel) { - FastBoot fb; + FastBootTool fb; boot_img_hdr_v1 hdr; hdr = {}; @@ -34,7 +34,7 @@ TEST(FastBoot, ParseOsPatchLevel) { } TEST(FastBoot, ParseOsVersion) { - FastBoot fb; + FastBootTool fb; boot_img_hdr_v1 hdr; hdr = {}; diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp index 14dabaa13..cc1714f01 100644 --- a/fastboot/fs.cpp +++ b/fastboot/fs.cpp @@ -1,6 +1,5 @@ #include "fs.h" -#include "fastboot.h" #include #include diff --git a/fastboot/main.cpp b/fastboot/main.cpp index f1c8afb13..c3683f737 100644 --- a/fastboot/main.cpp +++ b/fastboot/main.cpp @@ -26,9 +26,9 @@ * SUCH DAMAGE. */ -#include "fastboot.h" +#include "engine.h" int main(int argc, char* argv[]) { - FastBoot fb; + FastBootTool fb; return fb.Main(argc, argv); } diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp deleted file mode 100644 index e625095fc..000000000 --- a/fastboot/protocol.cpp +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define round_down(a, b) \ - ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); }) - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include "constants.h" -#include "fastboot.h" -#include "transport.h" - -static std::string g_error; - -using android::base::unique_fd; -using android::base::WriteStringToFile; - -const std::string fb_get_error() { - return g_error; -} - -static int64_t check_response(Transport* transport, uint32_t size, char* response) { - char status[FB_RESPONSE_SZ + 1]; - - while (true) { - int r = transport->Read(status, FB_RESPONSE_SZ); - if (r < 0) { - g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno)); - transport->Close(); - return -1; - } - status[r] = 0; - - if (static_cast(r) < strlen(RESPONSE_OKAY)) { - g_error = android::base::StringPrintf("status malformed (%d bytes)", r); - transport->Close(); - return -1; - } - - if (!memcmp(status, RESPONSE_INFO, strlen(RESPONSE_INFO))) { - verbose("received INFO \"%s\"", status + strlen(RESPONSE_INFO)); - fprintf(stderr, "(bootloader) %s\n", status + strlen(RESPONSE_INFO)); - continue; - } - - if (!memcmp(status, RESPONSE_OKAY, strlen(RESPONSE_OKAY))) { - verbose("received OKAY \"%s\"", status + strlen(RESPONSE_OKAY)); - if (response) { - strcpy(response, status + strlen(RESPONSE_OKAY)); - } - return 0; - } - - if (!memcmp(status, RESPONSE_FAIL, strlen(RESPONSE_FAIL))) { - verbose("received FAIL \"%s\"", status + strlen(RESPONSE_FAIL)); - if (static_cast(r) > strlen(RESPONSE_FAIL)) { - g_error = android::base::StringPrintf("remote: %s", status + strlen(RESPONSE_FAIL)); - } else { - g_error = "remote failure"; - } - return -1; - } - - if (!memcmp(status, RESPONSE_DATA, strlen(RESPONSE_DATA)) && size > 0){ - verbose("received DATA %s", status + strlen(RESPONSE_DATA)); - uint32_t dsize = strtol(status + strlen(RESPONSE_DATA), 0, 16); - if (dsize > size) { - g_error = android::base::StringPrintf("data size too large (%d)", dsize); - transport->Close(); - return -1; - } - return dsize; - } - - verbose("received unknown status code \"%4.4s\"", status); - g_error = "unknown status code"; - transport->Close(); - break; - } - - return -1; -} - -static int64_t _command_start(Transport* transport, const std::string& cmd, uint32_t size, - char* response) { - if (cmd.size() > FB_COMMAND_SZ) { - g_error = android::base::StringPrintf("command too large (%zu)", cmd.size()); - return -1; - } - - if (response) { - response[0] = 0; - } - - verbose("sending command \"%s\"", cmd.c_str()); - - if (transport->Write(cmd.c_str(), cmd.size()) != static_cast(cmd.size())) { - g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno)); - transport->Close(); - return -1; - } - - return check_response(transport, size, response); -} - -static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) { - verbose("sending data (%" PRIu32 " bytes)", size); - - int64_t r = transport->Write(data, size); - if (r < 0) { - g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno)); - transport->Close(); - return -1; - } - if (r != static_cast(size)) { - g_error = "data write failure (short transfer)"; - transport->Close(); - return -1; - } - return r; -} - -static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) { - verbose("reading data (%" PRIu32 " bytes)", size); - - int64_t r = transport->Read(data, size); - if (r < 0) { - g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno)); - transport->Close(); - return -1; - } - if (r != (static_cast(size))) { - g_error = "data read failure (short transfer)"; - transport->Close(); - return -1; - } - return r; -} - -static int64_t _command_end(Transport* transport) { - return check_response(transport, 0, 0) < 0 ? -1 : 0; -} - -static int64_t _command_send(Transport* transport, const std::string& cmd, const void* data, - uint32_t size, char* response) { - if (size == 0) { - return -1; - } - - int64_t r = _command_start(transport, cmd, size, response); - if (r < 0) { - return -1; - } - r = _command_write_data(transport, data, size); - if (r < 0) { - return -1; - } - - r = _command_end(transport); - if (r < 0) { - return -1; - } - - return 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; - uint32_t remaining = size; - - if (_command_start(transport, cmd, size, response) < 0) { - return -1; - } - - while (remaining) { - android::FileMap filemap; - size_t len = std::min(remaining, MAX_MAP_SIZE); - - if (!filemap.create(NULL, fd, offset, len, true)) { - return -1; - } - - if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) { - return -1; - } - - remaining -= len; - offset += len; - } - - if (_command_end(transport) < 0) { - return -1; - } - - return size; -} - -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 std::string& cmd) { - return _command_send_no_data(transport, cmd, 0); -} - -int fb_command_response(Transport* transport, const std::string& cmd, char* response) { - return _command_send_no_data(transport, cmd, response); -} - -int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) { - std::string cmd(android::base::StringPrintf( - FB_CMD_DOWNLOAD ":" "%08x", size)); - return _command_send(transport, cmd.c_str(), data, size, 0) < 0 ? -1 : 0; -} - -int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) { - std::string cmd(android::base::StringPrintf( - FB_CMD_DOWNLOAD ":" "%08x", size)); - return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0; -} - -int64_t fb_upload_data(Transport* transport, const char* outfile) { - // positive return value is the upload size sent by the device - int64_t r = _command_start(transport, FB_CMD_UPLOAD, - std::numeric_limits::max(), nullptr); - if (r <= 0) { - g_error = android::base::StringPrintf("command start failed (%s)", strerror(errno)); - return r; - } - - std::string data; - data.resize(r); - if ((r = _command_read_data(transport, &data[0], data.size())) == -1) { - return r; - } - - if (!WriteStringToFile(data, outfile, true)) { - g_error = android::base::StringPrintf("write to '%s' failed", outfile); - return -1; - } - - return _command_end(transport); -} - -static constexpr size_t TRANSPORT_BUF_SIZE = 1024; -static char transport_buf[TRANSPORT_BUF_SIZE]; -static size_t transport_buf_len; - -static int fb_download_data_sparse_write(void* priv, const void* data, size_t len) { - const char* ptr = static_cast(data); - if (transport_buf_len) { - size_t to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len); - - memcpy(transport_buf + transport_buf_len, ptr, to_write); - transport_buf_len += to_write; - ptr += to_write; - len -= to_write; - } - - Transport* transport = static_cast(priv); - if (transport_buf_len == TRANSPORT_BUF_SIZE) { - int64_t r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE); - if (r != static_cast(TRANSPORT_BUF_SIZE)) { - return -1; - } - transport_buf_len = 0; - } - - if (len > TRANSPORT_BUF_SIZE) { - if (transport_buf_len > 0) { - g_error = "internal error: transport_buf not empty"; - return -1; - } - size_t to_write = round_down(len, TRANSPORT_BUF_SIZE); - int64_t r = _command_write_data(transport, ptr, to_write); - if (r != static_cast(to_write)) { - return -1; - } - ptr += to_write; - len -= to_write; - } - - if (len > 0) { - if (len > TRANSPORT_BUF_SIZE) { - g_error = "internal error: too much left for transport_buf"; - return -1; - } - memcpy(transport_buf, ptr, len); - transport_buf_len = len; - } - - return 0; -} - -static int fb_download_data_sparse_flush(Transport* transport) { - if (transport_buf_len > 0) { - int64_t r = _command_write_data(transport, transport_buf, transport_buf_len); - if (r != static_cast(transport_buf_len)) { - return -1; - } - transport_buf_len = 0; - } - return 0; -} - -int fb_download_data_sparse(Transport* transport, struct sparse_file* s) { - int64_t size = sparse_file_len(s, true, false); - if (size <= 0 || size > std::numeric_limits::max()) { - return -1; - } - - std::string cmd(android::base::StringPrintf( - FB_CMD_DOWNLOAD ":" "%08" PRIx64, size)); - int r = _command_start(transport, cmd, size, 0); - if (r < 0) { - return -1; - } - - r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, transport); - if (r < 0) { - return -1; - } - - r = fb_download_data_sparse_flush(transport); - if (r < 0) { - return -1; - } - - return _command_end(transport); -} diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp index cdab4f1d2..386dd300c 100644 --- a/fastboot/usb_linux.cpp +++ b/fastboot/usb_linux.cpp @@ -47,8 +47,8 @@ #include #include -#include "fastboot.h" #include "usb.h" +#include "util.h" using namespace std::chrono_literals; diff --git a/fastboot/util.cpp b/fastboot/util.cpp index 140270fd9..8f6e52afb 100644 --- a/fastboot/util.cpp +++ b/fastboot/util.cpp @@ -33,7 +33,7 @@ #include -#include "fastboot.h" +#include "util.h" static bool g_verbose = false; diff --git a/fastboot/util.h b/fastboot/util.h new file mode 100644 index 000000000..9033f933a --- /dev/null +++ b/fastboot/util.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include + +#include + +/* util stuff */ +double now(); +char* xstrdup(const char*); +void set_verbose(); + +// These printf-like functions are implemented in terms of vsnprintf, so they +// use the same attribute for compile-time format string checking. +void die(const char* fmt, ...) __attribute__((__noreturn__)) +__attribute__((__format__(__printf__, 1, 2))); +void verbose(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))); -- cgit v1.2.3