summaryrefslogtreecommitdiffstats
path: root/fastboot
diff options
context:
space:
mode:
authorAlex Light <allight@google.com>2016-06-29 09:26:44 -0700
committerDaniel Rosenberg <drosen@google.com>2016-08-19 16:52:26 -0700
commitbb9b8a5abf08eed123ccf3311af290ca84ed9168 (patch)
tree200956eff39c142f7278c2d8fd9c53d93471a5ff /fastboot
parentad3d3c184e1f548051e24a1a78ae4dddf5ab34fd (diff)
downloadcore-bb9b8a5abf08eed123ccf3311af290ca84ed9168.tar.gz
core-bb9b8a5abf08eed123ccf3311af290ca84ed9168.tar.bz2
core-bb9b8a5abf08eed123ccf3311af290ca84ed9168.zip
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)
Diffstat (limited to 'fastboot')
-rw-r--r--fastboot/fastboot.cpp189
1 files changed, 136 insertions, 53 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 <partition> [ <filename> ] 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<std::string> 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<std::string> 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", &current_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", &current_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<char*>(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<char*>(data), sz);
+ setup_requirements(reinterpret_cast<char*>(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;