From 13454095374239a807237d3e073bd3ff488bd98d Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 27 Jun 2016 19:43:11 -0700 Subject: [PATCH 1/5] Call set_active after flashall and update If the device has previously failed to boot, and the current slot is marked as unbootable, we must call set_active to reenable the slot. Bug: 29827625 Change-Id: I8b723dda80e246b48e5967aff4503c3d120bfb9b (cherry-picked from commit 9c9a6c62e5a6dde562a291a11602d4f32b2c1c80) --- fastboot/fastboot.cpp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index c097d045e..a2af61a87 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -307,8 +307,11 @@ static void usage() { "\n" "commands:\n" " update Reflash device from update.zip.\n" + " Sets the flashed slot as active.\n" " flashall Flash boot, system, vendor, and --\n" - " if found -- recovery.\n" + " if found -- recovery. If the device\n" + " supports slots, the slot that has\n" + " been flashed to is set as active.\n" " flash [ ] Write a file to a flash partition.\n" " flashing lock Locks the device. Prevents flashing.\n" " flashing unlock Unlocks the device. Allows flashing\n" @@ -907,6 +910,20 @@ static void do_update_signature(ZipArchiveHandle zip, char* fn) { fb_queue_command("signature", "installing signature"); } +// 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 char* slot_override) { + if (slot_override && slot_override[0]) { + fb_set_active(slot_override); + } else { + std::string current_slot; + if (fb_getvar(transport, "current-slot", ¤t_slot)) { + current_slot = verify_slot(transport, current_slot.c_str(), false); + fb_set_active(current_slot.c_str()); + } + } +} + static void do_update(Transport* transport, const char* filename, const char* slot_override, bool erase_first) { queue_info_dump(); @@ -957,6 +974,7 @@ static void do_update(Transport* transport, const char* filename, const char* sl } CloseArchive(zip); + set_active(transport, slot_override); } static void do_send_signature(const char* filename) { @@ -1007,6 +1025,8 @@ static void do_flashall(Transport* transport, const char* slot_override, int era }; do_for_partitions(transport, images[i].part_name, slot_override, flashall, false); } + + set_active(transport, slot_override); } #define skip(n) do { argc -= (n); argv += (n); } while (0) @@ -1327,7 +1347,12 @@ int main(int argc, char **argv) if (wants_set_active) { if (next_active == "") { if (slot_override == "") { - wants_set_active = false; + std::string current_slot; + if (fb_getvar(transport, "current-slot", ¤t_slot)) { + next_active = verify_slot(transport, current_slot.c_str(), false); + } else { + wants_set_active = false; + } } else { next_active = verify_slot(transport, slot_override.c_str(), false); } From ad3d3c184e1f548051e24a1a78ae4dddf5ab34fd Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 27 Jun 2016 23:03:48 -0700 Subject: [PATCH 2/5] Handle invalid suffix lists Some devices will report an error string as a value when unknown variables are queried. This can lead to unexpected behavior, so we attempt to detect this case by seeing if the suffix list doesn't make sense. Change-Id: I939b1e01c40ddc05d881fd54423406db250cc8e5 (cherry-picked from commit 190d968414b3889441843e1bbebdf7acc2dc88c8) --- fastboot/fastboot.cpp | 49 ++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index a2af61a87..3c699646d 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -789,9 +789,30 @@ static std::vector get_suffixes(Transport* transport) { std::vector suffixes; std::string suffix_list; if (!fb_getvar(transport, "slot-suffixes", &suffix_list)) { - die("Could not get suffixes.\n"); + return suffixes; } - return android::base::Split(suffix_list, ","); + suffixes = android::base::Split(suffix_list, ","); + // Unfortunately some devices will return an error message in the + // guise of a valid value. If we only see only one suffix, it's probably + // not real. + if (suffixes.size() == 1) { + suffixes.clear(); + } + return suffixes; +} + +// Given a current slot, this returns what the 'other' slot is. +static std::string get_other_slot(Transport* transport, std::string& current_slot) { + std::vector suffixes = get_suffixes(transport); + + if (!suffixes.empty()) { + for (size_t i = 0; i < suffixes.size(); i++) { + if (current_slot == suffixes[i]) { + return suffixes[(i+1)%suffixes.size()]; + } + } + } + return ""; } static std::string verify_slot(Transport* transport, const char *slot, bool allow_all) { @@ -815,23 +836,24 @@ static std::string verify_slot(Transport* transport, const char *slot, bool allo if (!fb_getvar(transport, "current-slot", ¤t_slot)) { die("Failed to identify current slot."); } - if (!suffixes.empty()) { - for (size_t i = 0; i < suffixes.size(); i++) { - if (current_slot == suffixes[i]) - return suffixes[(i+1)%suffixes.size()]; - } - } else { - die("No known slots."); + std::string other = get_other_slot(transport, current_slot); + if (other == "") { + die("No known slots."); } + return other; } for (const std::string &suffix : suffixes) { if (suffix == slot) return slot; } - fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot); - for (const std::string &suffix : suffixes) { - fprintf(stderr, "%s\n", suffix.c_str()); + if (suffixes.empty()) { + fprintf(stderr, "Device does not support slots.\n"); + } else { + fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot); + for (const std::string &suffix : suffixes) { + fprintf(stderr, "%s\n", suffix.c_str()); + } } exit(1); } @@ -882,6 +904,9 @@ static void do_for_partitions(Transport* transport, const char *part, const char } if (has_slot == "yes") { std::vector suffixes = get_suffixes(transport); + if (suffixes.empty()) { + die("Error reading suffixes.\n"); + } for (std::string &suffix : suffixes) { do_for_partition(transport, part, suffix.c_str(), func, force_slot); } From bb9b8a5abf08eed123ccf3311af290ca84ed9168 Mon Sep 17 00:00:00 2001 From: Alex Light Date: Wed, 29 Jun 2016 09:26:44 -0700 Subject: [PATCH 3/5] Add Fastboot support for flashing secondary images Fastboot update and flashall will now flash secondary images if provided, and if the --slot flag is not set to 'all'. Also added flash-primary to preserve the previous behavior, and flash-secondary to just flash the secondary images. Fixes from: I5bd2de1c1e0e6224a195b566f7dcbe383555a80a Bug: 29278988 Change-Id: Ia870e4be55617c0eefa4e1381287f8cd14affe7e (cherry-picked from commit 6c98509c34d152007cf953c2cacb5750745dd464) --- fastboot/fastboot.cpp | 191 ++++++++++++++++++++++++++++++------------ 1 file changed, 137 insertions(+), 54 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 3c699646d..8714471e1 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -97,19 +97,40 @@ struct fastboot_buffer { }; static struct { - char img_name[13]; - char sig_name[13]; + char img_name[17]; + char sig_name[17]; char part_name[9]; bool is_optional; + bool is_secondary; } images[] = { - {"boot.img", "boot.sig", "boot", false}, - {"recovery.img", "recovery.sig", "recovery", true}, - {"system.img", "system.sig", "system", false}, - {"vendor.img", "vendor.sig", "vendor", true}, + {"boot.img", "boot.sig", "boot", false, false}, + {"boot_other.img", "boot.sig", "boot", true, true}, + {"recovery.img", "recovery.sig", "recovery", true, false}, + {"system.img", "system.sig", "system", false, false}, + {"system_other.img", "system.sig", "system", true, true}, + {"vendor.img", "vendor.sig", "vendor", true, false}, + {"vendor_other.img", "vendor.sig", "vendor", true, true}, }; -static std::string find_item(const char* item, const char* product) { +static std::string find_item_given_name(const char* img_name, const char* product) { + if(product) { + std::string path = get_my_path(); + path.erase(path.find_last_of('/')); + return android::base::StringPrintf("%s/../../../target/product/%s/%s", + path.c_str(), product, img_name); + } + + char *dir = getenv("ANDROID_PRODUCT_OUT"); + if (dir == nullptr || dir[0] == '\0') { + die("neither -p product specified nor ANDROID_PRODUCT_OUT set"); + } + + return android::base::StringPrintf("%s/%s", dir, img_name); +} + +std::string find_item(const char* item, const char* product) { const char *fn; + if (!strcmp(item,"boot")) { fn = "boot.img"; } else if(!strcmp(item,"recovery")) { @@ -127,21 +148,10 @@ static std::string find_item(const char* item, const char* product) { } else { fprintf(stderr,"unknown partition '%s'\n", item); return ""; + } - if (product) { - std::string path = get_my_path(); - path.erase(path.find_last_of('/')); - return android::base::StringPrintf("%s/../../../target/product/%s/%s", - path.c_str(), product, fn); - } - - char* dir = getenv("ANDROID_PRODUCT_OUT"); - if (dir == nullptr || dir[0] == '\0') { - die("neither -p product specified nor ANDROID_PRODUCT_OUT set"); - } - - return android::base::StringPrintf("%s/%s", dir, fn); + return find_item_given_name(fn, product); } static int64_t get_file_size(int fd) { @@ -312,6 +322,11 @@ static void usage() { " if found -- recovery. If the device\n" " supports slots, the slot that has\n" " been flashed to is set as active.\n" + " Secondary images may be flashed to\n" + " an inactive slot.\n" + " flash-primary Same as flashall, but do not flash\n" + " secondary images.\n" + " flash-secondary Only flashes the secondary images.\n" " flash [ ] Write a file to a flash partition.\n" " flashing lock Locks the device. Prevents flashing.\n" " flashing unlock Unlocks the device. Allows flashing\n" @@ -801,8 +816,12 @@ static std::vector get_suffixes(Transport* transport) { return suffixes; } +static bool supports_AB(Transport* transport) { + return !get_suffixes(transport).empty(); +} + // Given a current slot, this returns what the 'other' slot is. -static std::string get_other_slot(Transport* transport, std::string& current_slot) { +static std::string get_other_slot(Transport* transport, const std::string& current_slot) { std::vector suffixes = get_suffixes(transport); if (!suffixes.empty()) { @@ -815,6 +834,12 @@ static std::string get_other_slot(Transport* transport, std::string& current_slo return ""; } +static std::string get_other_slot(Transport* transport) { + std::string current_slot; + fb_getvar(transport, "current-slot", ¤t_slot); + return get_other_slot(transport, current_slot); +} + static std::string verify_slot(Transport* transport, const char *slot, bool allow_all) { if (strcmp(slot, "all") == 0) { if (allow_all) { @@ -937,9 +962,11 @@ static void do_update_signature(ZipArchiveHandle zip, char* fn) { // 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 char* slot_override) { - if (slot_override && slot_override[0]) { - fb_set_active(slot_override); +static void set_active(Transport* transport, const std::string& slot_override) { + if (!supports_AB(transport)) { + return; + } else if (slot_override != "") { + fb_set_active(slot_override.c_str()); } else { std::string current_slot; if (fb_getvar(transport, "current-slot", ¤t_slot)) { @@ -949,7 +976,7 @@ static void set_active(Transport* transport, const char* slot_override) { } } -static void do_update(Transport* transport, const char* filename, const char* slot_override, bool erase_first) { +static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool erase_first) { queue_info_dump(); fb_queue_query_save("product", cur_product, sizeof(cur_product)); @@ -970,7 +997,31 @@ static void do_update(Transport* transport, const char* filename, const char* sl setup_requirements(reinterpret_cast(data), sz); + std::string secondary; + bool update_secondary = slot_override != "all"; + if (update_secondary) { + if (slot_override != "") { + secondary = get_other_slot(transport, slot_override); + } else { + secondary = get_other_slot(transport); + } + if (secondary == "") { + if (supports_AB(transport)) { + fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n"); + } + update_secondary = false; + } + } for (size_t i = 0; i < arraysize(images); ++i) { + const char* slot = slot_override.c_str(); + if (images[i].is_secondary) { + if (update_secondary) { + slot = secondary.c_str(); + } else { + continue; + } + } + int fd = unzip_to_file(zip, images[i].img_name); if (fd == -1) { if (images[i].is_optional) { @@ -995,50 +1046,71 @@ static void do_update(Transport* transport, const char* filename, const char* sl * program exits. */ }; - do_for_partitions(transport, images[i].part_name, slot_override, update, false); + do_for_partitions(transport, images[i].part_name, slot, update, false); } CloseArchive(zip); set_active(transport, slot_override); } -static void do_send_signature(const char* filename) { - if (android::base::EndsWith(filename, ".img") == false) { - return; - } +static void do_send_signature(const std::string& fn) { + std::size_t extension_loc = fn.find(".img"); + if (extension_loc == std::string::npos) return; - std::string sig_path = filename; - sig_path.erase(sig_path.size() - 4); - sig_path += ".sig"; + std::string fs_sig = fn.substr(0, extension_loc) + ".sig"; int64_t sz; - void* data = load_file(sig_path, &sz); + void* data = load_file(fs_sig.c_str(), &sz); if (data == nullptr) return; fb_queue_download("signature", data, sz); fb_queue_command("signature", "installing signature"); } -static void do_flashall(Transport* transport, const char* slot_override, int erase_first) { - queue_info_dump(); +static void do_flashall(Transport* transport, const std::string& slot_override, int erase_first, bool flash_primary, bool flash_secondary) { + std::string fname; + if (flash_primary) { + queue_info_dump(); - fb_queue_query_save("product", cur_product, sizeof(cur_product)); + fb_queue_query_save("product", cur_product, sizeof(cur_product)); - std::string fname = find_item("info", product); - if (fname.empty()) die("cannot find android-info.txt"); + fname = find_item("info", product); + if (fname.empty()) die("cannot find android-info.txt"); - int64_t sz; - void* data = load_file(fname, &sz); - if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno)); + int64_t sz; + void* data = load_file(fname.c_str(), &sz); + if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno)); - setup_requirements(reinterpret_cast(data), sz); + setup_requirements(reinterpret_cast(data), sz); + } + std::string secondary; + if (flash_secondary) { + if (slot_override != "") { + secondary = get_other_slot(transport, slot_override); + } else { + secondary = get_other_slot(transport); + } + if (secondary == "") { + if (supports_AB(transport)) { + fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n"); + } + flash_secondary = false; + } + } for (size_t i = 0; i < arraysize(images); i++) { - fname = find_item(images[i].part_name, product); + const char* slot = NULL; + if (images[i].is_secondary) { + if (flash_secondary) slot = secondary.c_str(); + } else { + if (flash_primary) slot = slot_override.c_str(); + } + if (!slot) continue; + fname = find_item_given_name(images[i].img_name, product); fastboot_buffer buf; if (!load_buf(transport, fname.c_str(), &buf)) { if (images[i].is_optional) continue; - die("could not load '%s': %s", images[i].img_name, strerror(errno)); + die("could not load '%s': %s\n", images[i].img_name, strerror(errno)); } auto flashall = [&](const std::string &partition) { @@ -1048,10 +1120,10 @@ static void do_flashall(Transport* transport, const char* slot_override, int era } flash_buf(partition.c_str(), &buf); }; - do_for_partitions(transport, images[i].part_name, slot_override, flashall, false); + do_for_partitions(transport, images[i].part_name, slot, flashall, false); } - set_active(transport, slot_override); + if (flash_primary) set_active(transport, slot_override); } #define skip(n) do { argc -= (n); argv += (n); } while (0) @@ -1364,10 +1436,8 @@ int main(int argc, char **argv) return 1; } - if (slot_override != "") - slot_override = verify_slot(transport, slot_override.c_str()); - if (next_active != "") - next_active = verify_slot(transport, next_active.c_str(), false); + if (slot_override != "") slot_override = verify_slot(transport, slot_override.c_str()); + if (next_active != "") next_active = verify_slot(transport, next_active.c_str(), false); if (wants_set_active) { if (next_active == "") { @@ -1527,14 +1597,27 @@ int main(int argc, char **argv) do_for_partitions(transport, argv[1], slot_override.c_str(), flashraw, true); } else if(!strcmp(*argv, "flashall")) { skip(1); - do_flashall(transport, slot_override.c_str(), erase_first); + if (slot_override == "all") { + fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed."); + do_flashall(transport, slot_override, erase_first, true, false); + } else { + do_flashall(transport, slot_override, erase_first, true, true); + } + wants_reboot = true; + } else if(!strcmp(*argv, "flash-primary")) { + skip(1); + do_flashall(transport, slot_override, erase_first, true, false); + wants_reboot = true; + } else if(!strcmp(*argv, "flash-secondary")) { + skip(1); + do_flashall(transport, slot_override, erase_first, false, true); wants_reboot = true; } else if(!strcmp(*argv, "update")) { if (argc > 1) { - do_update(transport, argv[1], slot_override.c_str(), erase_first); + do_update(transport, argv[1], slot_override, erase_first); skip(2); } else { - do_update(transport, "update.zip", slot_override.c_str(), erase_first); + do_update(transport, "update.zip", slot_override, erase_first); skip(1); } wants_reboot = 1; From 8091947847d5e5130b09d2ac0a4bdc900f3b77c5 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 30 Jun 2016 19:25:31 -0700 Subject: [PATCH 4/5] Switch fastboot to new A/B spec Slots are now referred to as a and b instead of _a and _b. For the moment, _a and _b will still be supported. For old devices that support A/B, they are assumed to have 2 slots. Bug: 29643845 Change-Id: Ieab6bed7b4977d8386dcec0afa434371f54bd63f (cherry-picked from commit 563fcf6f697c898cf35fa4a1b5672d6b4890c283) --- fastboot/fastboot.cpp | 199 ++++++++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 85 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 8714471e1..fe136058f 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -349,7 +349,7 @@ static void usage() { " override the fs type and/or size\n" " the bootloader reports.\n" " getvar Display a bootloader variable.\n" - " set_active Sets the active slot. If slots are\n" + " set_active Sets the active slot. If slots are\n" " not supported, this does nothing.\n" " boot [ [ ] ] Download and boot kernel.\n" " flash:raw boot [ [ ] ]\n" @@ -386,19 +386,21 @@ static void usage() { " (default: 2048).\n" " -S [K|M|G] Automatically sparse files greater\n" " than 'size'. 0 to disable.\n" - " --slot Specify slot suffix to be used if the\n" - " device supports slots. This will be\n" - " added to all partition names that use\n" - " slots. 'all' can be given to refer\n" - " to all slots. 'other' can be given to\n" - " refer to a non-current slot. If this\n" - " flag is not used, slotted partitions\n" - " will default to the current active slot.\n" - " -a, --set-active[=] Sets the active slot. If no suffix is\n" + " --slot Specify slot name to be used if the\n" + " device supports slots. All operations\n" + " on partitions that support slots will\n" + " be done on the slot specified.\n" + " 'all' can be given to refer to all slots.\n" + " 'other' can be given to refer to a\n" + " non-current slot. If this flag is not\n" + " used, slotted partitions will default\n" + " to the current active slot.\n" + " -a, --set-active[=] Sets the active slot. If no slot is\n" " provided, this will default to the value\n" " given by --slot. If slots are not\n" - " supported, this does nothing. This will\n" - " run after all non-reboot commands.\n" + " supported, this sets the current slot\n" + " to be active. This will run after all\n" + " non-reboot commands.\n" " --unbuffered Do not buffer input or output.\n" " --version Display version.\n" " -h, --help show this message.\n" @@ -800,7 +802,19 @@ static void flash_buf(const char *pname, struct fastboot_buffer *buf) } } -static std::vector get_suffixes(Transport* transport) { +static std::string get_current_slot(Transport* transport) +{ + std::string current_slot; + if (fb_getvar(transport, "current-slot", ¤t_slot)) { + if (current_slot == "_a") return "a"; // Legacy support + if (current_slot == "_b") return "b"; // Legacy support + return current_slot; + } + return ""; +} + +// Legacy support +static std::vector get_suffixes_obsolete(Transport* transport) { std::vector suffixes; std::string suffix_list; if (!fb_getvar(transport, "slot-suffixes", &suffix_list)) { @@ -816,99 +830,110 @@ static std::vector get_suffixes(Transport* transport) { return suffixes; } +// Legacy support +static bool supports_AB_obsolete(Transport* transport) { + return !get_suffixes_obsolete(transport).empty(); +} + +static int get_slot_count(Transport* transport) { + std::string var; + int count; + if (!fb_getvar(transport, "slot-count", &var)) { + if (supports_AB_obsolete(transport)) return 2; // Legacy support + } + if (!android::base::ParseInt(var.c_str(), &count)) return 0; + return count; +} + static bool supports_AB(Transport* transport) { - return !get_suffixes(transport).empty(); + return get_slot_count(transport) >= 2; } // Given a current slot, this returns what the 'other' slot is. -static std::string get_other_slot(Transport* transport, const std::string& current_slot) { - std::vector suffixes = get_suffixes(transport); +static std::string get_other_slot(const std::string& current_slot, int count) { + if (count == 0) return ""; - if (!suffixes.empty()) { - for (size_t i = 0; i < suffixes.size(); i++) { - if (current_slot == suffixes[i]) { - return suffixes[(i+1)%suffixes.size()]; - } - } - } - return ""; + char next = (current_slot[0] - 'a' + 1)%count + 'a'; + 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(Transport* transport, int count) { + return get_other_slot(get_current_slot(transport), count); } static std::string get_other_slot(Transport* transport) { - std::string current_slot; - fb_getvar(transport, "current-slot", ¤t_slot); - return get_other_slot(transport, current_slot); + return get_other_slot(get_current_slot(transport), get_slot_count(transport)); } -static std::string verify_slot(Transport* transport, const char *slot, bool allow_all) { - if (strcmp(slot, "all") == 0) { +static std::string verify_slot(Transport* transport, const std::string& slot_name, bool allow_all) { + std::string slot = slot_name; + if (slot == "_a") slot = "a"; // Legacy support + if (slot == "_b") slot = "b"; // Legacy support + if (slot == "all") { if (allow_all) { return "all"; } else { - std::vector suffixes = get_suffixes(transport); - if (!suffixes.empty()) { - return suffixes[0]; + int count = get_slot_count(transport); + if (count > 0) { + return "a"; } else { die("No known slots."); } } } - std::vector suffixes = get_suffixes(transport); + int count = get_slot_count(transport); + if (count == 0) die("Device does not support slots.\n"); - if (strcmp(slot, "other") == 0) { - std::string current_slot; - if (!fb_getvar(transport, "current-slot", ¤t_slot)) { - die("Failed to identify current slot."); - } - std::string other = get_other_slot(transport, current_slot); + if (slot == "other") { + std::string other = get_other_slot(transport, count); if (other == "") { die("No known slots."); } return other; } - for (const std::string &suffix : suffixes) { - if (suffix == slot) - return slot; - } - if (suffixes.empty()) { - fprintf(stderr, "Device does not support slots.\n"); - } else { - fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot); - for (const std::string &suffix : suffixes) { - fprintf(stderr, "%s\n", suffix.c_str()); - } + if (slot.size() == 1 && (slot[0]-'a' >= 0 && slot[0]-'a' < count)) return slot; + + fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot.c_str()); + for (int i=0; i& func, bool force_slot) { std::string has_slot; std::string current_slot; - if (!fb_getvar(transport, std::string("has-slot:")+part, &has_slot)) { + if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) { /* If has-slot is not supported, the answer is no. */ has_slot = "no"; } if (has_slot == "yes") { - if (!slot || slot[0] == 0) { - if (!fb_getvar(transport, "current-slot", ¤t_slot)) { + if (slot == "") { + current_slot = get_current_slot(transport); + if (current_slot == "") { die("Failed to identify current slot.\n"); } - func(std::string(part) + current_slot); + func(part + "_" + current_slot); } else { - func(std::string(part) + slot); + func(part + '_' + slot); } } else { - if (force_slot && slot && slot[0]) { + if (force_slot && slot != "") { fprintf(stderr, "Warning: %s does not support slots, and slot %s was requested.\n", - part, slot); + part.c_str(), slot.c_str()); } func(part); } @@ -919,21 +944,17 @@ static void do_for_partition(Transport* transport, const char *part, const char * 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 char *part, const char *slot, +static void do_for_partitions(Transport* transport, const std::string& part, const std::string& slot, const std::function& func, bool force_slot) { std::string has_slot; - if (slot && strcmp(slot, "all") == 0) { - if (!fb_getvar(transport, std::string("has-slot:") + part, &has_slot)) { - die("Could not check if partition %s has slot.", part); + if (slot == "all") { + if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) { + die("Could not check if partition %s has slot.", part.c_str()); } if (has_slot == "yes") { - std::vector suffixes = get_suffixes(transport); - if (suffixes.empty()) { - die("Error reading suffixes.\n"); - } - for (std::string &suffix : suffixes) { - do_for_partition(transport, part, suffix.c_str(), func, force_slot); + for (int i=0; i < get_slot_count(transport); i++) { + do_for_partition(transport, part, std::string(1, (char)(i + 'a')), func, force_slot); } } else { do_for_partition(transport, part, "", func, force_slot); @@ -963,15 +984,20 @@ static void do_update_signature(ZipArchiveHandle zip, char* fn) { // 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) { + std::string separator = ""; if (!supports_AB(transport)) { - return; - } else if (slot_override != "") { - fb_set_active(slot_override.c_str()); + if (supports_AB_obsolete(transport)) { + separator = "_"; // Legacy support + } else { + return; + } + } + if (slot_override != "") { + fb_set_active((separator + slot_override).c_str()); } else { - std::string current_slot; - if (fb_getvar(transport, "current-slot", ¤t_slot)) { - current_slot = verify_slot(transport, current_slot.c_str(), false); - fb_set_active(current_slot.c_str()); + std::string current_slot = get_current_slot(transport); + if (current_slot != "") { + fb_set_active((separator + current_slot).c_str()); } } } @@ -1436,20 +1462,23 @@ int main(int argc, char **argv) return 1; } - if (slot_override != "") slot_override = verify_slot(transport, slot_override.c_str()); - if (next_active != "") next_active = verify_slot(transport, next_active.c_str(), false); + if (!supports_AB(transport) && supports_AB_obsolete(transport)) { + fprintf(stderr, "Warning: Device A/B support is outdated. Bootloader update required.\n"); + } + if (slot_override != "") slot_override = verify_slot(transport, slot_override); + if (next_active != "") next_active = verify_slot(transport, 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.c_str(), false); + next_active = verify_slot(transport, current_slot, false); } else { wants_set_active = false; } } else { - next_active = verify_slot(transport, slot_override.c_str(), false); + next_active = verify_slot(transport, slot_override, false); } } } @@ -1472,7 +1501,7 @@ int main(int argc, char **argv) fb_queue_erase(partition.c_str()); }; - do_for_partitions(transport, argv[1], slot_override.c_str(), erase, true); + do_for_partitions(transport, argv[1], slot_override, erase, true); skip(2); } else if(!strncmp(*argv, "format", strlen("format"))) { char *overrides; @@ -1507,7 +1536,7 @@ int main(int argc, char **argv) } fb_perform_format(transport, partition.c_str(), 0, type_override, size_override); }; - do_for_partitions(transport, argv[1], slot_override.c_str(), format, true); + do_for_partitions(transport, argv[1], slot_override, format, true); skip(2); } else if(!strcmp(*argv, "signature")) { require(2); @@ -1574,7 +1603,7 @@ int main(int argc, char **argv) } do_flash(transport, partition.c_str(), fname.c_str()); }; - do_for_partitions(transport, pname, slot_override.c_str(), flash, true); + do_for_partitions(transport, pname, slot_override, flash, true); } else if(!strcmp(*argv, "flash:raw")) { char *kname = argv[2]; char *rname = 0; @@ -1594,7 +1623,7 @@ int main(int argc, char **argv) auto flashraw = [&](const std::string &partition) { fb_queue_flash(partition.c_str(), data, sz); }; - do_for_partitions(transport, argv[1], slot_override.c_str(), flashraw, true); + do_for_partitions(transport, argv[1], slot_override, flashraw, true); } else if(!strcmp(*argv, "flashall")) { skip(1); if (slot_override == "all") { @@ -1623,7 +1652,7 @@ int main(int argc, char **argv) wants_reboot = 1; } else if(!strcmp(*argv, "set_active")) { require(2); - std::string slot = verify_slot(transport, argv[1], false); + std::string slot = verify_slot(transport, std::string(argv[1]), false); fb_set_active(slot.c_str()); skip(2); } else if(!strcmp(*argv, "oem")) { From 92b4476aa0ada2de885b83732ea39ab37c4dd380 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 13 Jul 2016 20:03:25 -0700 Subject: [PATCH 5/5] Add skip-secondary flag The skip-secondary flag now replaces flash-primary. This flag will skip over the secondary images for both flashall and update. Change-Id: I9f380f3195006d325d6c45776bf79ecec17506ad (cherry-picked from commit e180929866b218b901ba2069615794f076d06b13) --- fastboot/fastboot.cpp | 87 ++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index fe136058f..1f2408f9d 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -148,7 +148,6 @@ std::string find_item(const char* item, const char* product) { } else { fprintf(stderr,"unknown partition '%s'\n", item); return ""; - } return find_item_given_name(fn, product); @@ -324,9 +323,6 @@ static void usage() { " been flashed to is set as active.\n" " Secondary images may be flashed to\n" " an inactive slot.\n" - " flash-primary Same as flashall, but do not flash\n" - " secondary images.\n" - " flash-secondary Only flashes the secondary images.\n" " flash [ ] Write a file to a flash partition.\n" " flashing lock Locks the device. Prevents flashing.\n" " flashing unlock Unlocks the device. Allows flashing\n" @@ -401,6 +397,9 @@ static void usage() { " supported, this sets the current slot\n" " to be active. This will run after all\n" " non-reboot commands.\n" + " --skip-secondary Will not flash secondary slots when\n" + " performing a flashall or update. This\n" + " will preserve data on other slots.\n" " --unbuffered Do not buffer input or output.\n" " --version Display version.\n" " -h, --help show this message.\n" @@ -1002,7 +1001,7 @@ static void set_active(Transport* transport, const std::string& slot_override) { } } -static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool erase_first) { +static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool erase_first, bool skip_secondary) { queue_info_dump(); fb_queue_query_save("product", cur_product, sizeof(cur_product)); @@ -1024,8 +1023,7 @@ static void do_update(Transport* transport, const char* filename, const std::str setup_requirements(reinterpret_cast(data), sz); std::string secondary; - bool update_secondary = slot_override != "all"; - if (update_secondary) { + if (!skip_secondary) { if (slot_override != "") { secondary = get_other_slot(transport, slot_override); } else { @@ -1035,13 +1033,13 @@ static void do_update(Transport* transport, const char* filename, const std::str if (supports_AB(transport)) { fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n"); } - update_secondary = false; + skip_secondary = true; } } for (size_t i = 0; i < arraysize(images); ++i) { const char* slot = slot_override.c_str(); if (images[i].is_secondary) { - if (update_secondary) { + if (!skip_secondary) { slot = secondary.c_str(); } else { continue; @@ -1076,7 +1074,11 @@ static void do_update(Transport* transport, const char* filename, const std::str } CloseArchive(zip); - set_active(transport, slot_override); + if (slot_override == "all") { + set_active(transport, "a"); + } else { + set_active(transport, slot_override); + } } static void do_send_signature(const std::string& fn) { @@ -1093,24 +1095,23 @@ 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, int erase_first, bool flash_primary, bool flash_secondary) { +static void do_flashall(Transport* transport, const std::string& slot_override, int erase_first, bool skip_secondary) { std::string fname; - if (flash_primary) { - queue_info_dump(); + queue_info_dump(); - fb_queue_query_save("product", cur_product, sizeof(cur_product)); + fb_queue_query_save("product", cur_product, sizeof(cur_product)); - fname = find_item("info", product); - if (fname.empty()) die("cannot find android-info.txt"); + fname = find_item("info", product); + if (fname.empty()) die("cannot find android-info.txt"); - int64_t sz; - void* data = load_file(fname.c_str(), &sz); - if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno)); + int64_t sz; + void* data = load_file(fname.c_str(), &sz); + if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno)); + + setup_requirements(reinterpret_cast(data), sz); - setup_requirements(reinterpret_cast(data), sz); - } std::string secondary; - if (flash_secondary) { + if (!skip_secondary) { if (slot_override != "") { secondary = get_other_slot(transport, slot_override); } else { @@ -1120,16 +1121,16 @@ static void do_flashall(Transport* transport, const std::string& slot_override, if (supports_AB(transport)) { fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n"); } - flash_secondary = false; + skip_secondary = true; } } for (size_t i = 0; i < arraysize(images); i++) { const char* slot = NULL; if (images[i].is_secondary) { - if (flash_secondary) slot = secondary.c_str(); + if (!skip_secondary) slot = secondary.c_str(); } else { - if (flash_primary) slot = slot_override.c_str(); + slot = slot_override.c_str(); } if (!slot) continue; fname = find_item_given_name(images[i].img_name, product); @@ -1149,7 +1150,11 @@ static void do_flashall(Transport* transport, const std::string& slot_override, do_for_partitions(transport, images[i].part_name, slot, flashall, false); } - if (flash_primary) set_active(transport, slot_override); + if (slot_override == "all") { + set_active(transport, "a"); + } else { + set_active(transport, slot_override); + } } #define skip(n) do { argc -= (n); argv += (n); } while (0) @@ -1327,6 +1332,7 @@ int main(int argc, char **argv) bool wants_reboot = false; bool wants_reboot_bootloader = false; bool wants_set_active = false; + bool skip_secondary = false; bool erase_first = true; void *data; int64_t sz; @@ -1350,6 +1356,7 @@ int main(int argc, char **argv) {"slot", required_argument, 0, 0}, {"set_active", optional_argument, 0, 'a'}, {"set-active", optional_argument, 0, 'a'}, + {"skip-secondary", no_argument, 0, 0}, {0, 0, 0, 0} }; @@ -1431,6 +1438,12 @@ int main(int argc, char **argv) return 0; } else if (strcmp("slot", longopts[longindex].name) == 0) { slot_override = std::string(optarg); + } else if (strcmp("skip-secondary", longopts[longindex].name) == 0 ) { + skip_secondary = true; + } else { + fprintf(stderr, "Internal error in options processing for %s\n", + longopts[longindex].name); + return 1; } break; default: @@ -1627,26 +1640,22 @@ int main(int argc, char **argv) } else if(!strcmp(*argv, "flashall")) { skip(1); if (slot_override == "all") { - fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed."); - do_flashall(transport, slot_override, erase_first, true, false); + fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n"); + do_flashall(transport, slot_override, erase_first, true); } else { - do_flashall(transport, slot_override, erase_first, true, true); + do_flashall(transport, slot_override, erase_first, skip_secondary); } wants_reboot = true; - } else if(!strcmp(*argv, "flash-primary")) { - skip(1); - do_flashall(transport, slot_override, erase_first, true, false); - wants_reboot = true; - } else if(!strcmp(*argv, "flash-secondary")) { - skip(1); - do_flashall(transport, slot_override, erase_first, false, true); - wants_reboot = true; } else if(!strcmp(*argv, "update")) { + bool slot_all = (slot_override == "all"); + if (slot_all) { + fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n"); + } if (argc > 1) { - do_update(transport, argv[1], slot_override, erase_first); + do_update(transport, argv[1], slot_override, erase_first, skip_secondary || slot_all); skip(2); } else { - do_update(transport, "update.zip", slot_override, erase_first); + do_update(transport, "update.zip", slot_override, erase_first, skip_secondary || slot_all); skip(1); } wants_reboot = 1;