fastboot: remove engine.cpp/engine.h

Replace the remnants of engine.cpp with better functionality in
FastBootDriver.  Particularly, add prolog() and epilog()
callbacks to FastBootDriver for printing actions and their result to
the console.  Then clean up the rest of fastboot.cpp to directly use
FastBootDriver.

Test: fastboot works
Change-Id: I0ff01d6a10f75e9dc1c82b46c6e9bb3bc4c68638
This commit is contained in:
Tom Cherry 2018-09-24 15:48:09 -07:00
parent 4aa60b382c
commit 9027af0d40
11 changed files with 260 additions and 399 deletions

View file

@ -202,7 +202,6 @@ cc_library_host_static {
cpp_std: "c++17",
srcs: [
"bootimg_utils.cpp",
"engine.cpp",
"fastboot.cpp",
"fs.cpp",
"socket.cpp",

View file

@ -1,197 +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.
*/
#include "engine.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
#include <vector>
#include <android-base/stringprintf.h>
#include "constants.h"
#include "transport.h"
using android::base::StringPrintf;
static fastboot::FastBootDriver* fb = nullptr;
void fb_init(fastboot::FastBootDriver& fbi) {
fb = &fbi;
auto cb = [](std::string& info) { fprintf(stderr, "(bootloader) %s\n", info.c_str()); };
fb->SetInfoCallback(cb);
}
void fb_reinit(Transport* transport) {
if (Transport* old_transport = fb->set_transport(transport)) {
delete old_transport;
}
}
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 void HandleResult(double start, int status) {
if (status) {
fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
die("Command failed");
} else {
double split = now();
fprintf(stderr, "OKAY [%7.3fs]\n", (split - start));
}
}
#define RUN_COMMAND(command) \
{ \
double start = now(); \
auto status = (command); \
HandleResult(start, status); \
}
void fb_set_active(const std::string& slot) {
Status("Setting current slot to '" + slot + "'");
RUN_COMMAND(fb->SetActive(slot));
}
void fb_erase(const std::string& partition) {
Status("Erasing '" + partition + "'");
RUN_COMMAND(fb->Erase(partition));
}
void fb_flash_fd(const std::string& partition, int fd, uint32_t sz) {
Status(StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024));
RUN_COMMAND(fb->Download(fd, sz));
Status("Writing '" + partition + "'");
RUN_COMMAND(fb->Flash(partition));
}
void fb_flash(const std::string& partition, const std::vector<char>& data) {
Status(StringPrintf("Sending '%s' (%zu KB)", partition.c_str(), data.size() / 1024));
RUN_COMMAND(fb->Download(data));
Status("Writing '" + partition + "'");
RUN_COMMAND(fb->Flash(partition));
}
void fb_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
size_t current, size_t total) {
Status(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
sz / 1024));
RUN_COMMAND(fb->Download(s));
Status(StringPrintf("Writing sparse '%s' %zu/%zu", partition.c_str(), current, total));
RUN_COMMAND(fb->Flash(partition));
}
void fb_create_partition(const std::string& partition, const std::string& size) {
Status("Creating '" + partition + "'");
RUN_COMMAND(fb->RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size));
}
void fb_delete_partition(const std::string& partition) {
Status("Deleting '" + partition + "'");
RUN_COMMAND(fb->RawCommand(FB_CMD_DELETE_PARTITION ":" + partition));
}
void fb_resize_partition(const std::string& partition, const std::string& size) {
Status("Resizing '" + partition + "'");
RUN_COMMAND(fb->RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size));
}
void fb_display(const std::string& label, const std::string& var) {
std::string value;
auto status = fb->GetVar(var, &value);
if (status) {
fprintf(stderr, "getvar:%s FAILED (%s)\n", var.c_str(), fb->Error().c_str());
return;
}
fprintf(stderr, "%s: %s\n", label.c_str(), value.c_str());
}
void fb_reboot() {
fprintf(stderr, "Rebooting");
fb->Reboot();
fprintf(stderr, "\n");
}
void fb_command(const std::string& cmd, const std::string& msg) {
Status(msg);
RUN_COMMAND(fb->RawCommand(cmd));
}
void fb_download(const std::string& name, const std::vector<char>& data) {
Status("Downloading '" + name + "'");
RUN_COMMAND(fb->Download(data));
}
void fb_download_fd(const std::string& name, int fd, uint32_t sz) {
Status(StringPrintf("Sending '%s' (%u KB)", name.c_str(), sz / 1024));
RUN_COMMAND(fb->Download(fd, sz));
}
void fb_upload(const std::string& outfile) {
Status("Uploading '" + outfile + "'");
RUN_COMMAND(fb->Upload(outfile));
}
void fb_notice(const std::string& notice) {
Status(notice);
fprintf(stderr, "\n");
}
void fb_wait_for_disconnect() {
fb->WaitForDisconnect();
}
bool fb_reboot_to_userspace() {
Status("Rebooting to userspace fastboot");
verbose("\n");
if (fb->RebootTo("fastboot") != fastboot::RetCode::SUCCESS) {
fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
return false;
}
fprintf(stderr, "OKAY\n");
fb_reinit(nullptr);
return true;
}

View file

@ -26,6 +26,8 @@
* SUCH DAMAGE.
*/
#include "fastboot.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@ -63,12 +65,13 @@
#include "bootimg_utils.h"
#include "diagnose_usb.h"
#include "engine.h"
#include "fastboot_driver.h"
#include "fs.h"
#include "tcp.h"
#include "transport.h"
#include "udp.h"
#include "usb.h"
#include "util.h"
using android::base::ReadFully;
using android::base::Split;
@ -98,6 +101,8 @@ static bool g_disable_verification = false;
static const std::string convert_fbe_marker_filename("convert_fbe");
fastboot::FastBootDriver* fb = nullptr;
enum fb_buffer_type {
FB_BUFFER_FD,
FB_BUFFER_SPARSE,
@ -179,6 +184,28 @@ static std::string find_item(const std::string& item) {
return "";
}
double last_start_time;
static void Status(const std::string& message) {
static constexpr char kStatusFormat[] = "%-50s ";
fprintf(stderr, kStatusFormat, message.c_str());
last_start_time = now();
}
static void Epilog(int status) {
if (status) {
fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
die("Command failed");
} else {
double split = now();
fprintf(stderr, "OKAY [%7.3fs]\n", (split - last_start_time));
}
}
static void InfoMessage(const std::string& info) {
fprintf(stderr, "(bootloader) %s\n", info.c_str());
}
static int64_t get_file_size(int fd) {
struct stat sb;
if (fstat(fd, &sb) == -1) {
@ -606,9 +633,10 @@ static void CheckRequirement(const std::string& cur_product, const std::string&
}
std::string var_value;
if (!fb_getvar(var, &var_value)) {
if (fb->GetVar(var, &var_value) != fastboot::SUCCESS) {
fprintf(stderr, "FAILED\n\n");
fprintf(stderr, "Could not getvar for '%s' (%s)\n\n", var.c_str(), fb_get_error().c_str());
fprintf(stderr, "Could not getvar for '%s' (%s)\n\n", var.c_str(),
fb->Error().c_str());
die("requirements not met!");
}
@ -686,7 +714,7 @@ bool ParseRequirementLine(const std::string& line, std::string* name, std::strin
static void HandlePartitionExists(const std::vector<std::string>& options) {
const std::string& partition_name = options[0];
std::string has_slot;
if (!fb_getvar("has-slot:" + partition_name, &has_slot) ||
if (fb->GetVar("has-slot:" + partition_name, &has_slot) != fastboot::SUCCESS ||
(has_slot != "yes" && has_slot != "no")) {
die("device doesn't have required partition %s!", partition_name.c_str());
}
@ -705,8 +733,8 @@ static void HandlePartitionExists(const std::vector<std::string>& options) {
static void CheckRequirements(const std::string& data) {
std::string cur_product;
if (!fb_getvar("product", &cur_product)) {
fprintf(stderr, "getvar:product FAILED (%s)\n", fb_get_error().c_str());
if (fb->GetVar("product", &cur_product) != fastboot::SUCCESS) {
fprintf(stderr, "getvar:product FAILED (%s)\n", fb->Error().c_str());
}
auto lines = Split(data, "\n");
@ -732,12 +760,24 @@ static void CheckRequirements(const std::string& data) {
}
}
static void dump_info() {
fb_notice("--------------------------------------------");
fb_display("Bootloader Version...", "version-bootloader");
fb_display("Baseband Version.....", "version-baseband");
fb_display("Serial Number........", "serialno");
fb_notice("--------------------------------------------");
static void DisplayVarOrError(const std::string& label, const std::string& var) {
std::string value;
if (fb->GetVar(var, &value) != fastboot::SUCCESS) {
Status("getvar:" + var);
fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
return;
}
fprintf(stderr, "%s: %s\n", label.c_str(), value.c_str());
}
static void DumpInfo() {
fprintf(stderr, "--------------------------------------------\n");
DisplayVarOrError("Bootloader Version...", "version-bootloader");
DisplayVarOrError("Baseband Version.....", "version-baseband");
DisplayVarOrError("Serial Number........", "serialno");
fprintf(stderr, "--------------------------------------------\n");
}
static struct sparse_file** load_sparse_files(int fd, int64_t max_size) {
@ -762,7 +802,7 @@ static struct sparse_file** load_sparse_files(int fd, int64_t max_size) {
static int64_t get_target_sparse_limit() {
std::string max_download_size;
if (!fb_getvar("max-download-size", &max_download_size) ||
if (fb->GetVar("max-download-size", &max_download_size) != fastboot::SUCCESS ||
max_download_size.empty()) {
verbose("target didn't report max-download-size");
return 0;
@ -910,12 +950,12 @@ static void flash_buf(const std::string& partition, struct fastboot_buffer *buf)
for (size_t i = 0; i < sparse_files.size(); ++i) {
const auto& pair = sparse_files[i];
fb_flash_sparse(partition, pair.first, pair.second, i + 1, sparse_files.size());
fb->FlashPartition(partition, pair.first, pair.second, i + 1, sparse_files.size());
}
break;
}
case FB_BUFFER_FD:
fb_flash_fd(partition, buf->fd, buf->sz);
fb->FlashPartition(partition, buf->fd, buf->sz);
break;
default:
die("unknown buffer type: %d", buf->type);
@ -924,14 +964,15 @@ static void flash_buf(const std::string& partition, struct fastboot_buffer *buf)
static std::string get_current_slot() {
std::string current_slot;
if (!fb_getvar("current-slot", &current_slot)) return "";
if (fb->GetVar("current-slot", &current_slot) != fastboot::SUCCESS) return "";
return current_slot;
}
static int get_slot_count() {
std::string var;
int count = 0;
if (!fb_getvar("slot-count", &var) || !android::base::ParseInt(var, &count)) {
if (fb->GetVar("slot-count", &var) != fastboot::SUCCESS ||
!android::base::ParseInt(var, &count)) {
return 0;
}
return count;
@ -1006,7 +1047,7 @@ static void do_for_partition(const std::string& part, const std::string& slot,
std::string has_slot;
std::string current_slot;
if (!fb_getvar("has-slot:" + part, &has_slot)) {
if (fb->GetVar("has-slot:" + part, &has_slot) != fastboot::SUCCESS) {
/* If has-slot is not supported, the answer is no. */
has_slot = "no";
}
@ -1039,7 +1080,7 @@ static void do_for_partitions(const std::string& part, const std::string& slot,
std::string has_slot;
if (slot == "all") {
if (!fb_getvar("has-slot:" + part, &has_slot)) {
if (fb->GetVar("has-slot:" + part, &has_slot) != fastboot::SUCCESS) {
die("Could not check if partition %s has slot %s", part.c_str(), slot.c_str());
}
if (has_slot == "yes") {
@ -1069,25 +1110,25 @@ static void set_active(const std::string& slot_override) {
if (!supports_AB()) return;
if (slot_override != "") {
fb_set_active(slot_override);
fb->SetActive(slot_override);
} else {
std::string current_slot = get_current_slot();
if (current_slot != "") {
fb_set_active(current_slot);
fb->SetActive(current_slot);
}
}
}
static bool is_userspace_fastboot() {
std::string value;
return fb_getvar("is-userspace", &value) && value == "yes";
return fb->GetVar("is-userspace", &value) == fastboot::SUCCESS && value == "yes";
}
static bool if_partition_exists(const std::string& partition, const std::string& slot) {
std::string has_slot;
std::string partition_name = partition;
if (fb_getvar("has-slot:" + partition, &has_slot) && has_slot == "yes") {
if (fb->GetVar("has-slot:" + partition, &has_slot) == fastboot::SUCCESS && has_slot == "yes") {
if (slot == "") {
std::string current_slot = get_current_slot();
if (current_slot == "") {
@ -1099,23 +1140,24 @@ static bool if_partition_exists(const std::string& partition, const std::string&
}
}
std::string partition_size;
return fb_getvar("partition-size:" + partition_name, &partition_size);
return fb->GetVar("partition-size:" + partition_name, &partition_size) == fastboot::SUCCESS;
}
static bool is_logical(const std::string& partition) {
std::string value;
return fb_getvar("is-logical:" + partition, &value) && value == "yes";
return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes";
}
static void reboot_to_userspace_fastboot() {
if (!fb_reboot_to_userspace()) {
die("Must reboot to userspace fastboot to flash logical partitions");
}
fb->RebootTo("fastboot");
auto* old_transport = fb->set_transport(nullptr);
delete old_transport;
// Give the current connection time to close.
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
fb_reinit(open_device());
fb->set_transport(open_device());
}
class ImageSource {
@ -1156,6 +1198,7 @@ FlashAllTool::FlashAllTool(const ImageSource& source, const std::string& slot_ov
}
void FlashAllTool::Flash() {
DumpInfo();
CheckRequirements();
DetermineSecondarySlot();
CollectImages();
@ -1172,7 +1215,7 @@ void FlashAllTool::Flash() {
for (const auto& [image, slot] : os_images_) {
auto resize_partition = [](const std::string& partition) -> void {
if (is_logical(partition)) {
fb_resize_partition(partition, "0");
fb->ResizePartition(partition, "0");
}
};
do_for_partitions(image->part_name, slot, resize_partition, false);
@ -1248,12 +1291,12 @@ void FlashAllTool::FlashImage(const Image& image, const std::string& slot, fastb
auto flash = [&, this](const std::string& partition_name) {
std::vector<char> signature_data;
if (source_.ReadFile(image.sig_name, &signature_data)) {
fb_download("signature", signature_data);
fb_command("signature", "installing signature");
fb->Download("signature", signature_data);
fb->RawCommand("signature", "installing signature");
}
if (is_logical(partition_name)) {
fb_resize_partition(partition_name, std::to_string(buf->image_size));
fb->ResizePartition(partition_name, std::to_string(buf->image_size));
}
flash_buf(partition_name.c_str(), buf);
};
@ -1272,13 +1315,13 @@ void FlashAllTool::UpdateSuperPartition() {
if (!is_userspace_fastboot()) {
reboot_to_userspace_fastboot();
}
fb_download_fd("super", fd, get_file_size(fd));
fb->Download("super", fd, get_file_size(fd));
std::string command = "update-super:super";
if (wipe_) {
command += ":wipe";
}
fb_command(command, "Updating super partition");
fb->RawCommand(command, "Updating super partition");
}
class ZipImageSource final : public ImageSource {
@ -1300,8 +1343,6 @@ int ZipImageSource::OpenFile(const std::string& name) const {
}
static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) {
dump_info();
ZipArchiveHandle zip;
int error = OpenArchive(filename, &zip);
if (error != 0) {
@ -1334,9 +1375,6 @@ int LocalImageSource::OpenFile(const std::string& name) const {
}
static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) {
std::string fname;
dump_info();
FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe);
tool.Flash();
}
@ -1355,7 +1393,7 @@ static void do_oem_command(const std::string& cmd, std::vector<std::string>* arg
while (!args->empty()) {
command += " " + next_arg(args);
}
fb_command(command, "");
fb->RawCommand(command, "");
}
static std::string fb_fix_numeric_var(std::string var) {
@ -1369,7 +1407,7 @@ static std::string fb_fix_numeric_var(std::string var) {
static unsigned fb_get_flash_block_size(std::string name) {
std::string sizeString;
if (!fb_getvar(name, &sizeString) || sizeString.empty()) {
if (fb->GetVar(name, &sizeString) != fastboot::SUCCESS || sizeString.empty()) {
// This device does not report flash block sizes, so return 0.
return 0;
}
@ -1407,7 +1445,7 @@ static void fb_perform_format(
limit = sparse_limit;
}
if (!fb_getvar("partition-type:" + partition, &partition_type)) {
if (fb->GetVar("partition-type:" + partition, &partition_type) != fastboot::SUCCESS) {
errMsg = "Can't determine partition type.\n";
goto failed;
}
@ -1419,7 +1457,7 @@ static void fb_perform_format(
partition_type = type_override;
}
if (!fb_getvar("partition-size:" + partition, &partition_size)) {
if (fb->GetVar("partition-size:" + partition, &partition_size) != fastboot::SUCCESS) {
errMsg = "Unable to get partition size\n";
goto failed;
}
@ -1477,7 +1515,7 @@ failed:
fprintf(stderr, "Erase successful, but not automatically formatting.\n");
if (errMsg) fprintf(stderr, "%s", errMsg);
}
fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str());
fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
}
int FastBootTool::Main(int argc, char* argv[]) {
@ -1627,8 +1665,13 @@ int FastBootTool::Main(int argc, char* argv[]) {
if (transport == nullptr) {
return 1;
}
fastboot::FastBootDriver fb(transport);
fb_init(fb);
fastboot::DriverCallbacks driver_callbacks = {
.prolog = Status,
.epilog = Epilog,
.info = InfoMessage,
};
fastboot::FastBootDriver fastboot_driver(transport, driver_callbacks, false);
fb = &fastboot_driver;
const double start = now();
@ -1639,7 +1682,7 @@ int FastBootTool::Main(int argc, char* argv[]) {
if (next_active == "") {
if (slot_override == "") {
std::string current_slot;
if (fb_getvar("current-slot", &current_slot)) {
if (fb->GetVar("current-slot", &current_slot) == fastboot::SUCCESS) {
next_active = verify_slot(current_slot, false);
} else {
wants_set_active = false;
@ -1656,19 +1699,18 @@ int FastBootTool::Main(int argc, char* argv[]) {
if (command == "getvar") {
std::string variable = next_arg(&args);
fb_display(variable, variable);
DisplayVarOrError(variable, variable);
} else if (command == "erase") {
std::string partition = next_arg(&args);
auto erase = [&](const std::string& partition) {
std::string partition_type;
if (fb_getvar(std::string("partition-type:") + partition,
&partition_type) &&
if (fb->GetVar("partition-type:" + partition, &partition_type) == fastboot::SUCCESS &&
fs_get_generator(partition_type) != nullptr) {
fprintf(stderr, "******** Did you mean to fastboot format this %s partition?\n",
partition_type.c_str());
}
fb_erase(partition);
fb->Erase(partition);
};
do_for_partitions(partition, slot_override, erase, true);
} else if (android::base::StartsWith(command, "format")) {
@ -1698,8 +1740,8 @@ int FastBootTool::Main(int argc, char* argv[]) {
die("could not load '%s': %s", filename.c_str(), strerror(errno));
}
if (data.size() != 256) die("signature must be 256 bytes (got %zu)", data.size());
fb_download("signature", data);
fb_command("signature", "installing signature");
fb->Download("signature", data);
fb->RawCommand("signature", "installing signature");
} else if (command == "reboot") {
wants_reboot = true;
@ -1727,7 +1769,7 @@ int FastBootTool::Main(int argc, char* argv[]) {
} else if (command == "reboot-fastboot") {
wants_reboot_fastboot = true;
} else if (command == "continue") {
fb_command("continue", "resuming boot");
fb->Continue();
} else if (command == "boot") {
std::string kernel = next_arg(&args);
std::string ramdisk;
@ -1736,8 +1778,8 @@ int FastBootTool::Main(int argc, char* argv[]) {
if (!args.empty()) second_stage = next_arg(&args);
auto data = LoadBootableImage(kernel, ramdisk, second_stage);
fb_download("boot.img", data);
fb_command("boot", "booting");
fb->Download("boot.img", data);
fb->Boot();
} else if (command == "flash") {
std::string pname = next_arg(&args);
@ -1763,7 +1805,7 @@ int FastBootTool::Main(int argc, char* argv[]) {
auto data = LoadBootableImage(kernel, ramdisk, second_stage);
auto flashraw = [&data](const std::string& partition) {
fb_flash(partition, data);
fb->FlashPartition(partition, data);
};
do_for_partitions(partition, slot_override, flashraw, true);
} else if (command == "flashall") {
@ -1787,7 +1829,7 @@ int FastBootTool::Main(int argc, char* argv[]) {
wants_reboot = true;
} else if (command == "set_active") {
std::string slot = verify_slot(next_arg(&args), false);
fb_set_active(slot);
fb->SetActive(slot);
} else if (command == "stage") {
std::string filename = next_arg(&args);
@ -1795,10 +1837,10 @@ int FastBootTool::Main(int argc, char* argv[]) {
if (!load_buf(filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
die("cannot load '%s'", filename.c_str());
}
fb_download_fd(filename, buf.fd, buf.sz);
fb->Download(filename, buf.fd, buf.sz);
} else if (command == "get_staged") {
std::string filename = next_arg(&args);
fb_upload(filename);
fb->Upload(filename);
} else if (command == "oem") {
do_oem_command("oem", &args);
} else if (command == "flashing") {
@ -1815,14 +1857,14 @@ int FastBootTool::Main(int argc, char* argv[]) {
} else if (command == "create-logical-partition") {
std::string partition = next_arg(&args);
std::string size = next_arg(&args);
fb_create_partition(partition, size);
fb->CreatePartition(partition, size);
} else if (command == "delete-logical-partition") {
std::string partition = next_arg(&args);
fb_delete_partition(partition);
fb->DeletePartition(partition);
} else if (command == "resize-logical-partition") {
std::string partition = next_arg(&args);
std::string size = next_arg(&args);
fb_resize_partition(partition, size);
fb->ResizePartition(partition, size);
} else {
syntax_error("unknown command %s", command.c_str());
}
@ -1832,9 +1874,11 @@ int FastBootTool::Main(int argc, char* argv[]) {
std::vector<std::string> partitions = { "userdata", "cache", "metadata" };
for (const auto& partition : partitions) {
std::string partition_type;
if (!fb_getvar(std::string{"partition-type:"} + partition, &partition_type)) continue;
if (fb->GetVar("partition-type:" + partition, &partition_type) != fastboot::SUCCESS) {
continue;
}
if (partition_type.empty()) continue;
fb_erase(partition);
fb->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();
@ -1846,27 +1890,27 @@ int FastBootTool::Main(int argc, char* argv[]) {
}
}
if (wants_set_active) {
fb_set_active(next_active);
fb->SetActive(next_active);
}
if (wants_reboot && !skip_reboot) {
fb_reboot();
fb_wait_for_disconnect();
fb->Reboot();
fb->WaitForDisconnect();
} else if (wants_reboot_bootloader) {
fb_command("reboot-bootloader", "rebooting into bootloader");
fb_wait_for_disconnect();
fb->RebootTo("bootloader");
fb->WaitForDisconnect();
} else if (wants_reboot_recovery) {
fb_command("reboot-recovery", "rebooting into recovery");
fb_wait_for_disconnect();
fb->RebootTo("recovery");
fb->WaitForDisconnect();
} else if (wants_reboot_fastboot) {
fb_command("reboot-fastboot", "rebooting into fastboot");
fb_wait_for_disconnect();
fb->RebootTo("fastboot");
fb->WaitForDisconnect();
}
fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start));
if (Transport* old_transport = fb.set_transport(nullptr)) {
delete old_transport;
}
auto* old_transport = fb->set_transport(nullptr);
delete old_transport;
return 0;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (C) 2018 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -26,49 +26,7 @@
* SUCH DAMAGE.
*/
#pragma once
#include <inttypes.h>
#include <stdlib.h>
#include <string>
#include <bootimg.h>
#include "fastboot_driver.h"
#include "util.h"
#include "constants.h"
class Transport;
struct sparse_file;
const std::string fb_get_error();
void fb_init(fastboot::FastBootDriver& fbi);
void fb_reinit(Transport* transport);
bool fb_getvar(const std::string& key, std::string* value);
void fb_flash(const std::string& partition, const std::vector<char>& data);
void fb_flash_fd(const std::string& partition, int fd, uint32_t sz);
void fb_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
size_t current, size_t total);
void fb_erase(const std::string& partition);
void fb_display(const std::string& label, const std::string& var);
void fb_reboot();
void fb_command(const std::string& cmd, const std::string& msg);
void fb_download(const std::string& name, const std::vector<char>& data);
void fb_download_fd(const std::string& name, int fd, uint32_t sz);
void fb_upload(const std::string& outfile);
void fb_notice(const std::string& notice);
void fb_wait_for_disconnect(void);
void fb_create_partition(const std::string& partition, const std::string& size);
void fb_delete_partition(const std::string& partition);
void fb_resize_partition(const std::string& partition, const std::string& size);
void fb_set_active(const std::string& slot);
bool fb_reboot_to_userspace();
/* Current product */
extern char cur_product[FB_RESPONSE_SZ + 1];
class FastBootTool {
public:

View file

@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "fastboot_driver.h"
#include <errno.h>
@ -44,43 +45,56 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <utils/FileMap.h>
#include "fastboot_driver.h"
#include "constants.h"
#include "transport.h"
using android::base::StringPrintf;
namespace fastboot {
/*************************** PUBLIC *******************************/
FastBootDriver::FastBootDriver(Transport* transport, std::function<void(std::string&)> info,
FastBootDriver::FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks,
bool no_checks)
: transport_(transport) {
info_cb_ = info;
disable_checks_ = no_checks;
}
: transport_(transport),
prolog_(std::move(driver_callbacks.prolog)),
epilog_(std::move(driver_callbacks.epilog)),
info_(std::move(driver_callbacks.info)),
disable_checks_(no_checks) {}
FastBootDriver::~FastBootDriver() {
}
RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
return RawCommand(Commands::BOOT, response, info);
return RawCommand(FB_CMD_BOOT, "Booting", response, info);
}
RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
return RawCommand(Commands::CONTINUE, response, info);
return RawCommand(FB_CMD_CONTINUE, "Resuming boot", response, info);
}
RetCode FastBootDriver::Erase(const std::string& part, std::string* response,
std::vector<std::string>* info) {
return RawCommand(Commands::ERASE + part, response, info);
RetCode FastBootDriver::CreatePartition(const std::string& partition, const std::string& size) {
return RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size,
"Creating '" + partition + "'");
}
RetCode FastBootDriver::Flash(const std::string& part, std::string* response,
RetCode FastBootDriver::DeletePartition(const std::string& partition) {
return RawCommand(FB_CMD_DELETE_PARTITION ":" + partition, "Deleting '" + partition + "'");
}
RetCode FastBootDriver::Erase(const std::string& partition, std::string* response,
std::vector<std::string>* info) {
return RawCommand(Commands::FLASH + part, response, info);
return RawCommand(FB_CMD_ERASE ":" + partition, "Erasing '" + partition + "'", response, info);
}
RetCode FastBootDriver::Flash(const std::string& partition, std::string* response,
std::vector<std::string>* info) {
return RawCommand(FB_CMD_FLASH ":" + partition, "Writing '" + partition + "'", response, info);
}
RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
std::vector<std::string>* info) {
return RawCommand(Commands::GET_VAR + key, val, info);
return RawCommand(FB_CMD_GETVAR ":" + key, val, info);
}
RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
@ -89,44 +103,52 @@ RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
}
RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
return RawCommand(Commands::REBOOT, response, info);
return RawCommand(FB_CMD_REBOOT, "Rebooting", response, info);
}
RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
std::vector<std::string>* info) {
return RawCommand("reboot-" + target, response, info);
return RawCommand("reboot-" + target, "Rebooting into " + target, response, info);
}
RetCode FastBootDriver::ResizePartition(const std::string& partition, const std::string& size) {
return RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size,
"Resizing '" + partition + "'");
}
RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response,
std::vector<std::string>* info) {
return RawCommand(Commands::SET_ACTIVE + slot, response, info);
return RawCommand(FB_CMD_SET_ACTIVE ":" + slot, "Setting current slot to '" + slot + "'",
response, info);
}
RetCode FastBootDriver::FlashPartition(const std::string& part, const std::vector<char>& data) {
RetCode FastBootDriver::FlashPartition(const std::string& partition,
const std::vector<char>& data) {
RetCode ret;
if ((ret = Download(data))) {
if ((ret = Download(partition, data))) {
return ret;
}
return RawCommand(Commands::FLASH + part);
return Flash(partition);
}
RetCode FastBootDriver::FlashPartition(const std::string& part, int fd, uint32_t sz) {
RetCode FastBootDriver::FlashPartition(const std::string& partition, int fd, uint32_t size) {
RetCode ret;
if ((ret = Download(fd, sz))) {
if ((ret = Download(partition, fd, size))) {
return ret;
}
return RawCommand(Commands::FLASH + part);
return Flash(partition);
}
RetCode FastBootDriver::FlashPartition(const std::string& part, sparse_file* s) {
RetCode FastBootDriver::FlashPartition(const std::string& partition, sparse_file* s, uint32_t size,
size_t current, size_t total) {
RetCode ret;
if ((ret = Download(s))) {
if ((ret = Download(partition, s, size, current, total, false))) {
return ret;
}
return RawCommand(Commands::FLASH + part);
return Flash(partition);
}
RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* parts) {
RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions) {
std::vector<std::string> all;
RetCode ret;
if ((ret = GetVarAll(&all))) {
@ -141,12 +163,20 @@ RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>
std::string m1(sm[1]);
std::string m2(sm[2]);
uint64_t tmp = strtoll(m2.c_str(), 0, 16);
parts->push_back(std::make_tuple(m1, tmp));
partitions->push_back(std::make_tuple(m1, tmp));
}
}
return SUCCESS;
}
RetCode FastBootDriver::Download(const std::string& name, int fd, size_t size,
std::string* response, std::vector<std::string>* info) {
prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), size / 1024));
auto result = Download(fd, size, response, info);
epilog_(result);
return result;
}
RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
std::vector<std::string>* info) {
RetCode ret;
@ -170,6 +200,14 @@ RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
return HandleResponse(response, info);
}
RetCode FastBootDriver::Download(const std::string& name, const std::vector<char>& buf,
std::string* response, std::vector<std::string>* info) {
prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), buf.size() / 1024));
auto result = Download(buf, response, info);
epilog_(result);
return result;
}
RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
std::vector<std::string>* info) {
RetCode ret;
@ -192,6 +230,16 @@ RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* resp
return HandleResponse(response, info);
}
RetCode FastBootDriver::Download(const std::string& partition, struct sparse_file* s, uint32_t size,
size_t current, size_t total, bool use_crc, std::string* response,
std::vector<std::string>* info) {
prolog_(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
size / 1024));
auto result = Download(s, use_crc, response, info);
epilog_(result);
return result;
}
RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response,
std::vector<std::string>* info) {
error_ = "";
@ -234,9 +282,17 @@ RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* resp
RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
std::vector<std::string>* info) {
prolog_("Uploading '" + outfile + "'");
auto result = UploadInner(outfile, response, info);
epilog_(result);
return result;
}
RetCode FastBootDriver::UploadInner(const std::string& outfile, std::string* response,
std::vector<std::string>* info) {
RetCode ret;
int dsize;
if ((ret = RawCommand(Commands::UPLOAD, response, info, &dsize))) {
if ((ret = RawCommand(FB_CMD_UPLOAD, response, info, &dsize))) {
error_ = "Upload request failed: " + error_;
return ret;
}
@ -270,8 +326,8 @@ RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response
}
// Helpers
void FastBootDriver::SetInfoCallback(std::function<void(std::string&)> info) {
info_cb_ = info;
void FastBootDriver::SetInfoCallback(std::function<void(const std::string&)> info) {
info_ = info;
}
const std::string FastBootDriver::RCString(RetCode rc) {
@ -308,6 +364,15 @@ RetCode FastBootDriver::WaitForDisconnect() {
}
/****************************** PROTECTED *************************************/
RetCode FastBootDriver::RawCommand(const std::string& cmd, const std::string& message,
std::string* response, std::vector<std::string>* info,
int* dsize) {
prolog_(message);
auto result = RawCommand(cmd, response, info, dsize);
epilog_(result);
return result;
}
RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
std::vector<std::string>* info, int* dsize) {
error_ = ""; // Clear any pending error
@ -327,7 +392,7 @@ RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response
RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
std::vector<std::string>* info) {
std::string cmd(android::base::StringPrintf("%s%08" PRIx32, Commands::DOWNLOAD.c_str(), size));
std::string cmd(android::base::StringPrintf("%s:%08" PRIx32, FB_CMD_DOWNLOAD, size));
RetCode ret;
if ((ret = RawCommand(cmd, response, info))) {
return ret;
@ -360,7 +425,7 @@ RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::s
std::string input(status);
if (android::base::StartsWith(input, "INFO")) {
std::string tmp = input.substr(strlen("INFO"));
info_cb_(tmp);
info_(tmp);
add_info(std::move(tmp));
} else if (android::base::StartsWith(input, "OKAY")) {
set_response(input.substr(strlen("OKAY")));
@ -393,16 +458,6 @@ 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::REBOOT = "reboot";
const std::string FastBootDriver::Commands::SET_ACTIVE = "set_active:";
const std::string FastBootDriver::Commands::UPLOAD = "upload";
/******************************* PRIVATE **************************************/
RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;

View file

@ -55,6 +55,12 @@ enum RetCode : int {
TIMEOUT,
};
struct DriverCallbacks {
std::function<void(const std::string&)> prolog = [](const std::string&) {};
std::function<void(int)> epilog = [](int) {};
std::function<void(const std::string&)> info = [](const std::string&) {};
};
class FastBootDriver {
friend class FastBootTest;
@ -63,22 +69,30 @@ class FastBootDriver {
static constexpr uint32_t MAX_DOWNLOAD_SIZE = std::numeric_limits<uint32_t>::max();
static constexpr size_t TRANSPORT_CHUNK_SIZE = 1024;
FastBootDriver(Transport* transport,
std::function<void(std::string&)> info = [](std::string&) {},
FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks = {},
bool no_checks = false);
~FastBootDriver();
RetCode Boot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
RetCode Continue(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
RetCode CreatePartition(const std::string& partition, const std::string& size);
RetCode DeletePartition(const std::string& partition);
RetCode Download(const std::string& name, int fd, size_t size, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode Download(int fd, size_t size, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode Download(const std::string& name, const std::vector<char>& buf,
std::string* response = nullptr, std::vector<std::string>* info = nullptr);
RetCode Download(const std::vector<char>& buf, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode Download(const std::string& partition, struct sparse_file* s, uint32_t sz,
size_t current, size_t total, bool use_crc, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode Download(sparse_file* s, bool use_crc = false, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode Erase(const std::string& part, std::string* response = nullptr,
RetCode Erase(const std::string& partition, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode Flash(const std::string& part, std::string* response = nullptr,
RetCode Flash(const std::string& partition, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode GetVar(const std::string& key, std::string* val,
std::vector<std::string>* info = nullptr);
@ -86,22 +100,24 @@ class FastBootDriver {
RetCode Reboot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
RetCode RebootTo(std::string target, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode ResizePartition(const std::string& partition, const std::string& size);
RetCode SetActive(const std::string& slot, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode Upload(const std::string& outfile, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
/* HIGHER LEVEL COMMANDS -- Composed of the commands above */
RetCode FlashPartition(const std::string& part, const std::vector<char>& data);
RetCode FlashPartition(const std::string& part, int fd, uint32_t sz);
RetCode FlashPartition(const std::string& part, sparse_file* s);
RetCode FlashPartition(const std::string& partition, const std::vector<char>& data);
RetCode FlashPartition(const std::string& partition, int fd, uint32_t sz);
RetCode FlashPartition(const std::string& partition, sparse_file* s, uint32_t sz,
size_t current, size_t total);
RetCode Partitions(std::vector<std::tuple<std::string, uint64_t>>* parts);
RetCode Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions);
RetCode Require(const std::string& var, const std::vector<std::string>& allowed, bool* reqmet,
bool invert = false);
/* HELPERS */
void SetInfoCallback(std::function<void(std::string&)> info);
void SetInfoCallback(std::function<void(const std::string&)> info);
static const std::string RCString(RetCode rc);
std::string Error();
RetCode WaitForDisconnect();
@ -110,7 +126,10 @@ class FastBootDriver {
Transport* set_transport(Transport* transport);
Transport* transport() const { return transport_; }
// This is temporarily public for engine.cpp
RetCode RawCommand(const std::string& cmd, const std::string& message,
std::string* response = nullptr, std::vector<std::string>* info = nullptr,
int* dsize = nullptr);
RetCode RawCommand(const std::string& cmd, std::string* response = nullptr,
std::vector<std::string>* info = nullptr, int* dsize = nullptr);
@ -122,19 +141,6 @@ class FastBootDriver {
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 REBOOT;
static const std::string SET_ACTIVE;
static const std::string UPLOAD;
};
Transport* transport_;
private:
@ -145,10 +151,15 @@ class FastBootDriver {
RetCode ReadBuffer(std::vector<char>& buf);
RetCode ReadBuffer(void* buf, size_t size);
RetCode UploadInner(const std::string& outfile, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
int SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len);
std::string error_;
std::function<void(std::string&)> info_cb_;
std::function<void(const std::string&)> prolog_;
std::function<void(int)> epilog_;
std::function<void(const std::string&)> info_;
bool disable_checks_;
};

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
#include "engine.h"
#include "fastboot.h"
#include <gtest/gtest.h>

View file

@ -121,8 +121,7 @@ void FastBootTest::SetUp() {
} else {
ASSERT_EQ(device_path, cb_scratch); // The path can not change
}
fb = std::unique_ptr<FastBootDriver>(
new FastBootDriver(transport.get(), [](std::string&) {}, true));
fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
}
void FastBootTest::TearDown() {
@ -204,8 +203,7 @@ void FastBootTest::SetLockState(bool unlock, bool assert_change) {
putchar('.');
}
device_path = cb_scratch;
fb = std::unique_ptr<FastBootDriver>(
new FastBootDriver(transport.get(), [](std::string&) {}, true));
fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
if (assert_change) {
ASSERT_EQ(fb->GetVar("unlocked", &resp), SUCCESS) << "getvar:unlocked failed";
ASSERT_EQ(resp, unlock ? "yes" : "no")

View file

@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
#include "engine.h"
#include "fastboot.h"
int main(int argc, char* argv[]) {
FastBootTool fb;

View file

@ -69,8 +69,3 @@ void verbose(const char* fmt, ...) {
}
fprintf(stderr, "\n");
}
void Status(const std::string& message) {
static constexpr char kStatusFormat[] = "%-50s ";
fprintf(stderr, kStatusFormat, message.c_str());
}

View file

@ -11,8 +11,6 @@
double now();
void set_verbose();
void Status(const std::string& message);
// 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__))