Merge "fastboot: Use a single codepath for flashall and update."

This commit is contained in:
Treehugger Robot 2018-08-30 20:12:16 +00:00 committed by Gerrit Code Review
commit c47c508dcd
1 changed files with 205 additions and 195 deletions

View File

@ -574,6 +574,7 @@ static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
ZipEntry zip_entry;
if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
fprintf(stderr, "archive does not contain '%s'\n", entry_name);
errno = ENOENT;
return -1;
}
@ -1033,14 +1034,6 @@ static void do_flash(const char* pname, const char* fname) {
flash_buf(pname, &buf);
}
static void do_update_signature(ZipArchiveHandle zip, const char* filename) {
int64_t sz;
void* data = unzip_to_memory(zip, filename, &sz);
if (data == nullptr) return;
fb_queue_download("signature", data, sz);
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(const std::string& slot_override) {
@ -1080,96 +1073,6 @@ static bool if_partition_exists(const std::string& partition, const std::string&
return fb_getvar("partition-size:" + partition_name, &partition_size);
}
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));
ZipArchiveHandle zip;
int error = OpenArchive(filename, &zip);
if (error != 0) {
die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
}
int64_t sz;
void* data = unzip_to_memory(zip, "android-info.txt", &sz);
if (data == nullptr) {
die("update package '%s' has no android-info.txt", filename);
}
check_requirements(reinterpret_cast<char*>(data), sz);
std::string secondary;
if (!skip_secondary) {
if (slot_override != "") {
secondary = get_other_slot(slot_override);
} else {
secondary = get_other_slot();
}
if (secondary == "") {
if (supports_AB()) {
fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
}
skip_secondary = true;
}
}
for (size_t i = 0; i < arraysize(images); ++i) {
const char* slot = slot_override.c_str();
if (images[i].IsSecondary()) {
if (!skip_secondary) {
slot = secondary.c_str();
} else {
continue;
}
}
int fd = unzip_to_file(zip, images[i].img_name);
if (fd == -1) {
if (images[i].optional_if_no_image) {
continue; // An optional file is missing, so ignore it.
}
die("non-optional file %s missing", images[i].img_name);
}
fastboot_buffer buf;
if (!load_buf_fd(fd, &buf)) {
die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
}
auto update = [&](const std::string& partition) {
do_update_signature(zip, images[i].sig_name);
flash_buf(partition.c_str(), &buf);
/* not closing the fd here since the sparse code keeps the fd around
* but hasn't mmaped data yet. The temporary file will get cleaned up when the
* program exits.
*/
};
do_for_partitions(images[i].part_name, slot, update, false);
}
if (slot_override == "all") {
set_active("a");
} else {
set_active(slot_override);
}
CloseArchive(zip);
}
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 fs_sig = fn.substr(0, extension_loc) + ".sig";
int64_t 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 bool is_logical(const std::string& partition) {
std::string value;
return fb_getvar("is-logical:" + partition, &value) && value == "yes";
@ -1186,114 +1089,58 @@ static void reboot_to_userspace_fastboot() {
fb_reinit(open_device());
}
static void update_super_partition(bool force_wipe) {
if (!if_partition_exists("super", "")) {
return;
}
std::string image = find_item_given_name("super_empty.img");
if (access(image.c_str(), R_OK) < 0) {
return;
}
class ImageSource {
public:
virtual void* ReadFile(const std::string& name, int64_t* size) const = 0;
virtual int OpenFile(const std::string& name) const = 0;
};
if (!is_userspace_fastboot()) {
reboot_to_userspace_fastboot();
}
class FlashAllTool {
public:
FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe);
int fd = open(image.c_str(), O_RDONLY);
if (fd < 0) {
die("could not open '%s': %s", image.c_str(), strerror(errno));
}
fb_queue_download_fd("super", fd, get_file_size(fd));
void Flash();
std::string command = "update-super:super";
if (force_wipe) {
command += ":wipe";
}
fb_queue_command(command, "Updating super partition");
private:
void CheckRequirements();
void DetermineSecondarySlot();
void CollectImages();
void FlashImages(const std::vector<std::pair<const Image*, std::string>>& images);
void FlashImage(const Image& image, const std::string& slot, fastboot_buffer* buf);
void UpdateSuperPartition();
// We need these commands to have finished before proceeding, since
// otherwise "getvar is-logical" may not return a correct answer below.
fb_execute_queue();
const ImageSource& source_;
std::string slot_override_;
bool skip_secondary_;
bool wipe_;
std::string secondary_slot_;
std::vector<std::pair<const Image*, std::string>> boot_images_;
std::vector<std::pair<const Image*, std::string>> os_images_;
};
FlashAllTool::FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe)
: source_(source),
slot_override_(slot_override),
skip_secondary_(skip_secondary),
wipe_(wipe)
{
}
static void flash_images(const std::vector<std::pair<const Image*, std::string>>& images) {
// Flash each partition in the list if it has a corresponding image.
for (const auto& [image, slot] : images) {
auto fname = find_item_given_name(image->img_name);
fastboot_buffer buf;
if (!load_buf(fname.c_str(), &buf)) {
if (image->optional_if_no_image) continue;
die("could not load '%s': %s", image->img_name, strerror(errno));
}
auto flashall = [&](const std::string &partition) {
do_send_signature(fname.c_str());
if (is_logical(partition)) {
fb_queue_resize_partition(partition, std::to_string(buf.image_size));
}
flash_buf(partition.c_str(), &buf);
};
do_for_partitions(image->part_name, slot, flashall, false);
}
}
static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) {
std::string fname;
queue_info_dump();
fb_queue_query_save("product", cur_product, sizeof(cur_product));
fname = find_item_given_name("android-info.txt");
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));
check_requirements(reinterpret_cast<char*>(data), sz);
std::string secondary;
if (!skip_secondary) {
if (slot_override != "") {
secondary = get_other_slot(slot_override);
} else {
secondary = get_other_slot();
}
if (secondary == "") {
if (supports_AB()) {
fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
}
skip_secondary = true;
}
}
// List of partitions to flash and their slots.
std::vector<std::pair<const Image*, std::string>> boot_images;
std::vector<std::pair<const Image*, std::string>> os_images;
for (size_t i = 0; i < arraysize(images); i++) {
const char* slot = NULL;
if (images[i].IsSecondary()) {
if (!skip_secondary) slot = secondary.c_str();
} else {
slot = slot_override.c_str();
}
if (!slot) continue;
if (images[i].type == ImageType::BootCritical) {
boot_images.emplace_back(&images[i], slot);
} else if (images[i].type == ImageType::Normal) {
os_images.emplace_back(&images[i], slot);
}
}
void FlashAllTool::Flash() {
CheckRequirements();
DetermineSecondarySlot();
CollectImages();
// First flash boot partitions. We allow this to happen either in userspace
// or in bootloader fastboot.
flash_images(boot_images);
FlashImages(boot_images_);
// Sync the super partition. This will reboot to userspace fastboot if needed.
update_super_partition(wipe);
UpdateSuperPartition();
// Resize any logical partition to 0, so each partition is reset to 0
// extents, and will achieve more optimal allocation.
for (const auto& [image, slot] : os_images) {
for (const auto& [image, slot] : os_images_) {
auto resize_partition = [](const std::string& partition) -> void {
if (is_logical(partition)) {
fb_queue_resize_partition(partition, "0");
@ -1303,15 +1150,178 @@ static void do_flashall(const std::string& slot_override, bool skip_secondary, b
}
// Flash OS images, resizing logical partitions as needed.
flash_images(os_images);
FlashImages(os_images_);
if (slot_override == "all") {
if (slot_override_ == "all") {
set_active("a");
} else {
set_active(slot_override);
set_active(slot_override_);
}
}
void FlashAllTool::CheckRequirements() {
int64_t sz;
void* data = source_.ReadFile("android-info.txt", &sz);
if (data == nullptr) {
die("could not read android-info.txt");
}
check_requirements(reinterpret_cast<char*>(data), sz);
}
void FlashAllTool::DetermineSecondarySlot() {
if (skip_secondary_) {
return;
}
if (slot_override_ != "") {
secondary_slot_ = get_other_slot(slot_override_);
} else {
secondary_slot_ = get_other_slot();
}
if (secondary_slot_ == "") {
if (supports_AB()) {
fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
}
skip_secondary_ = true;
}
}
void FlashAllTool::CollectImages() {
for (size_t i = 0; i < arraysize(images); ++i) {
std::string slot = slot_override_;
if (images[i].IsSecondary()) {
if (skip_secondary_) {
continue;
}
slot = secondary_slot_;
}
if (images[i].type == ImageType::BootCritical) {
boot_images_.emplace_back(&images[i], slot);
} else if (images[i].type == ImageType::Normal) {
os_images_.emplace_back(&images[i], slot);
}
}
}
void FlashAllTool::FlashImages(const std::vector<std::pair<const Image*, std::string>>& images) {
for (const auto& [image, slot] : images) {
fastboot_buffer buf;
int fd = source_.OpenFile(image->img_name);
if (fd < 0 || !load_buf_fd(fd, &buf)) {
if (image->optional_if_no_image) {
continue;
}
die("could not load '%s': %s", image->img_name, strerror(errno));
}
FlashImage(*image, slot, &buf);
}
}
void FlashAllTool::FlashImage(const Image& image, const std::string& slot, fastboot_buffer* buf) {
auto flash = [&, this](const std::string& partition_name) {
int64_t sz;
void* data = source_.ReadFile(image.sig_name, &sz);
if (data) {
fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature");
}
if (is_logical(partition_name)) {
fb_queue_resize_partition(partition_name, std::to_string(buf->image_size));
}
flash_buf(partition_name.c_str(), buf);
};
do_for_partitions(image.part_name, slot, flash, false);
}
void FlashAllTool::UpdateSuperPartition() {
if (!if_partition_exists("super", "")) {
return;
}
int fd = source_.OpenFile("super_empty.img");
if (fd < 0) {
return;
}
if (!is_userspace_fastboot()) {
reboot_to_userspace_fastboot();
}
fb_queue_download_fd("super", fd, get_file_size(fd));
std::string command = "update-super:super";
if (wipe_) {
command += ":wipe";
}
fb_queue_command(command, "Updating super partition");
// We need these commands to have finished before proceeding, since
// otherwise "getvar is-logical" may not return a correct answer below.
fb_execute_queue();
}
class ZipImageSource final : public ImageSource {
public:
explicit ZipImageSource(ZipArchiveHandle zip) : zip_(zip) {}
void* ReadFile(const std::string& name, int64_t* size) const override;
int OpenFile(const std::string& name) const override;
private:
ZipArchiveHandle zip_;
};
void* ZipImageSource::ReadFile(const std::string& name, int64_t* size) const {
return unzip_to_memory(zip_, name.c_str(), size);
}
int ZipImageSource::OpenFile(const std::string& name) const {
return unzip_to_file(zip_, name.c_str());
}
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));
ZipArchiveHandle zip;
int error = OpenArchive(filename, &zip);
if (error != 0) {
die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
}
FlashAllTool tool(ZipImageSource(zip), slot_override, skip_secondary, false);
tool.Flash();
CloseArchive(zip);
}
class LocalImageSource final : public ImageSource {
public:
void* ReadFile(const std::string& name, int64_t* size) const override;
int OpenFile(const std::string& name) const override;
};
void* LocalImageSource::ReadFile(const std::string& name, int64_t* size) const {
auto path = find_item_given_name(name);
if (path.empty()) {
return nullptr;
}
return load_file(path.c_str(), size);
}
int LocalImageSource::OpenFile(const std::string& name) const {
auto path = find_item_given_name(name);
return open(path.c_str(), O_RDONLY);
}
static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) {
std::string fname;
queue_info_dump();
fb_queue_query_save("product", cur_product, sizeof(cur_product));
FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe);
tool.Flash();
}
static std::string next_arg(std::vector<std::string>* args) {
if (args->empty()) syntax_error("expected argument");
std::string result = args->front();