Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb9b8a5a authored by Alex Light's avatar Alex Light Committed by Daniel Rosenberg
Browse files

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 6c98509c)
parent ad3d3c18
Loading
Loading
Loading
Loading
+136 −53
Original line number Diff line number Diff line
@@ -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) {
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));

    std::string fname = find_item("info", product);
        fname = find_item("info", product);
        if (fname.empty()) die("cannot find android-info.txt");

        int64_t sz;
    void* data = load_file(fname, &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);
    }
    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;