Merge "Add "require partition-exists=" support."

am: 539f3ddff5

Change-Id: If07bf31027fab8c4b341c9bc6de907cff94e2c7f
This commit is contained in:
Elliott Hughes 2018-03-29 00:27:36 +00:00 committed by android-build-merger
commit fea8b41aa1
5 changed files with 286 additions and 344 deletions

View File

@ -27,7 +27,6 @@
*/
#include "fastboot.h"
#include "fs.h"
#include <errno.h>
#include <stdarg.h>
@ -38,150 +37,117 @@
#include <sys/types.h>
#include <unistd.h>
#define OP_DOWNLOAD 1
#define OP_COMMAND 2
#define OP_QUERY 3
#define OP_NOTICE 4
#define OP_DOWNLOAD_SPARSE 5
#define OP_WAIT_FOR_DISCONNECT 6
#define OP_DOWNLOAD_FD 7
#define OP_UPLOAD 8
#include <memory>
#include <vector>
typedef struct Action Action;
#include <android-base/stringprintf.h>
#define CMD_SIZE 64
struct Action {
unsigned op;
Action* next;
char cmd[CMD_SIZE];
const char* prod;
void* data;
int fd;
// The protocol only supports 32-bit sizes, so you'll have to break
// anything larger into chunks.
uint32_t size;
const char *msg;
int (*func)(Action* a, int status, const char* resp);
double start;
enum Op {
OP_DOWNLOAD,
OP_COMMAND,
OP_QUERY,
OP_NOTICE,
OP_DOWNLOAD_SPARSE,
OP_WAIT_FOR_DISCONNECT,
OP_DOWNLOAD_FD,
OP_UPLOAD,
};
static Action *action_list = 0;
static Action *action_last = 0;
struct Action {
Action(Op op, const std::string& cmd) : op(op), cmd(cmd) {}
Op op;
std::string cmd;
std::string msg;
std::string product;
void* data = nullptr;
// The protocol only supports 32-bit sizes, so you'll have to break
// anything larger into multiple chunks.
uint32_t size = 0;
int fd = -1;
int (*func)(Action& a, int status, const char* resp) = nullptr;
double start = -1;
};
static std::vector<std::unique_ptr<Action>> action_list;
bool fb_getvar(Transport* transport, const std::string& key, std::string* value) {
std::string cmd = "getvar:";
cmd += key;
std::string cmd = "getvar:" + key;
char buf[FB_RESPONSE_SZ + 1];
memset(buf, 0, sizeof(buf));
if (fb_command_response(transport, cmd.c_str(), buf)) {
return false;
if (fb_command_response(transport, cmd, buf)) {
return false;
}
*value = buf;
return true;
}
static int cb_default(Action* a, int status, const char* resp) {
static int cb_default(Action& a, int status, const char* resp) {
if (status) {
fprintf(stderr,"FAILED (%s)\n", resp);
} else {
double split = now();
fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
a->start = split;
fprintf(stderr, "OKAY [%7.3fs]\n", (split - a.start));
a.start = split;
}
return status;
}
static Action *queue_action(unsigned op, const char *fmt, ...)
{
va_list ap;
size_t cmdsize;
Action* a = reinterpret_cast<Action*>(calloc(1, sizeof(Action)));
if (a == nullptr) die("out of memory");
va_start(ap, fmt);
cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
va_end(ap);
if (cmdsize >= sizeof(a->cmd)) {
free(a);
die("Command length (%zu) exceeds maximum size (%zu)", cmdsize, sizeof(a->cmd));
}
if (action_last) {
action_last->next = a;
} else {
action_list = a;
}
action_last = a;
a->op = op;
static Action& queue_action(Op op, const std::string& cmd) {
std::unique_ptr<Action> a{new Action(op, cmd)};
a->func = cb_default;
a->start = -1;
return a;
action_list.push_back(std::move(a));
return *action_list.back();
}
void fb_set_active(const char *slot)
{
Action *a;
a = queue_action(OP_COMMAND, "set_active:%s", slot);
a->msg = mkmsg("Setting current slot to '%s'", slot);
void fb_set_active(const std::string& slot) {
Action& a = queue_action(OP_COMMAND, "set_active:" + slot);
a.msg = "Setting current slot to '" + slot + "'...";
}
void fb_queue_erase(const char *ptn)
{
Action *a;
a = queue_action(OP_COMMAND, "erase:%s", ptn);
a->msg = mkmsg("erasing '%s'", ptn);
void fb_queue_erase(const std::string& partition) {
Action& a = queue_action(OP_COMMAND, "erase:" + partition);
a.msg = "Erasing '" + partition + "'...";
}
void fb_queue_flash_fd(const char *ptn, int fd, uint32_t sz)
{
Action *a;
void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz) {
Action& a = queue_action(OP_DOWNLOAD_FD, "");
a.fd = fd;
a.size = sz;
a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);
a = queue_action(OP_DOWNLOAD_FD, "");
a->fd = fd;
a->size = sz;
a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
a = queue_action(OP_COMMAND, "flash:%s", ptn);
a->msg = mkmsg("writing '%s'", ptn);
Action& b = queue_action(OP_COMMAND, "flash:" + partition);
b.msg = "Writing '" + partition + "'...";
}
void fb_queue_flash(const char *ptn, void *data, uint32_t sz)
{
Action *a;
void fb_queue_flash(const std::string& partition, void* data, uint32_t sz) {
Action& a = queue_action(OP_DOWNLOAD, "");
a.data = data;
a.size = sz;
a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);
a = queue_action(OP_DOWNLOAD, "");
a->data = data;
a->size = sz;
a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
a = queue_action(OP_COMMAND, "flash:%s", ptn);
a->msg = mkmsg("writing '%s'", ptn);
Action& b = queue_action(OP_COMMAND, "flash:" + partition);
b.msg = "Writing '" + partition + "'...";
}
void fb_queue_flash_sparse(const char* ptn, struct sparse_file* s, uint32_t sz, size_t current,
size_t total) {
Action *a;
void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
size_t current, size_t total) {
Action& a = queue_action(OP_DOWNLOAD_SPARSE, "");
a.data = s;
a.size = 0;
a.msg = android::base::StringPrintf("Sending sparse '%s' %zu/%zu (%d KB)...", partition.c_str(),
current, total, sz / 1024);
a = queue_action(OP_DOWNLOAD_SPARSE, "");
a->data = s;
a->size = 0;
a->msg = mkmsg("sending sparse '%s' %zu/%zu (%d KB)", ptn, current, total, sz / 1024);
a = queue_action(OP_COMMAND, "flash:%s", ptn);
a->msg = mkmsg("writing '%s' %zu/%zu", ptn, current, total);
Action& b = queue_action(OP_COMMAND, "flash:" + partition);
b.msg =
android::base::StringPrintf("Writing '%s' %zu/%zu...", partition.c_str(), current, total);
}
static int match(const char* str, const char** value, unsigned count) {
@ -205,212 +171,181 @@ static int match(const char* str, const char** value, unsigned count) {
return 0;
}
static int cb_check(Action* a, int status, const char* resp, int invert)
{
const char** value = reinterpret_cast<const char**>(a->data);
unsigned count = a->size;
static int cb_check(Action& a, int status, const char* resp, int invert) {
const char** value = reinterpret_cast<const char**>(a.data);
unsigned count = a.size;
unsigned n;
int yes;
if (status) {
fprintf(stderr,"FAILED (%s)\n", resp);
return status;
}
if (a->prod) {
if (strcmp(a->prod, cur_product) != 0) {
if (!a.product.empty()) {
if (a.product != cur_product) {
double split = now();
fprintf(stderr,"IGNORE, product is %s required only for %s [%7.3fs]\n",
cur_product, a->prod, (split - a->start));
a->start = split;
fprintf(stderr, "IGNORE, product is %s required only for %s [%7.3fs]\n", cur_product,
a.product.c_str(), (split - a.start));
a.start = split;
return 0;
}
}
yes = match(resp, value, count);
int yes = match(resp, value, count);
if (invert) yes = !yes;
if (yes) {
double split = now();
fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
a->start = split;
fprintf(stderr, "OKAY [%7.3fs]\n", (split - a.start));
a.start = split;
return 0;
}
fprintf(stderr,"FAILED\n\n");
fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp);
fprintf(stderr,"Update %s '%s'",
invert ? "rejects" : "requires", value[0]);
fprintf(stderr, "FAILED\n\n");
fprintf(stderr, "Device %s is '%s'.\n", a.cmd.c_str() + 7, resp);
fprintf(stderr, "Update %s '%s'", invert ? "rejects" : "requires", value[0]);
for (n = 1; n < count; n++) {
fprintf(stderr," or '%s'", value[n]);
fprintf(stderr, " or '%s'", value[n]);
}
fprintf(stderr,".\n\n");
fprintf(stderr, ".\n\n");
return -1;
}
static int cb_require(Action*a, int status, const char* resp) {
static int cb_require(Action& a, int status, const char* resp) {
return cb_check(a, status, resp, 0);
}
static int cb_reject(Action* a, int status, const char* resp) {
static int cb_reject(Action& a, int status, const char* resp) {
return cb_check(a, status, resp, 1);
}
static char* xstrdup(const char* s) {
char* result = strdup(s);
if (!result) die("out of memory");
return result;
void fb_queue_require(const std::string& product, const std::string& var, bool invert,
size_t nvalues, const char** values) {
Action& a = queue_action(OP_QUERY, "getvar:" + var);
a.product = product;
a.data = values;
a.size = nvalues;
a.msg = "Checking " + var;
a.func = invert ? cb_reject : cb_require;
if (a.data == nullptr) die("out of memory");
}
void fb_queue_require(const char *prod, const char *var,
bool invert, size_t nvalues, const char **value)
{
Action *a;
a = queue_action(OP_QUERY, "getvar:%s", var);
a->prod = prod;
a->data = value;
a->size = nvalues;
a->msg = mkmsg("checking %s", var);
a->func = invert ? cb_reject : cb_require;
if (a->data == nullptr) die("out of memory");
}
static int cb_display(Action* a, int status, const char* resp) {
static int cb_display(Action& a, int status, const char* resp) {
if (status) {
fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
fprintf(stderr, "%s FAILED (%s)\n", a.cmd.c_str(), resp);
return status;
}
fprintf(stderr, "%s: %s\n", static_cast<const char*>(a->data), resp);
free(static_cast<char*>(a->data));
fprintf(stderr, "%s: %s\n", static_cast<const char*>(a.data), resp);
free(static_cast<char*>(a.data));
return 0;
}
void fb_queue_display(const char* var, const char* prettyname) {
Action* a = queue_action(OP_QUERY, "getvar:%s", var);
a->data = xstrdup(prettyname);
a->func = cb_display;
void fb_queue_display(const std::string& label, const std::string& var) {
Action& a = queue_action(OP_QUERY, "getvar:" + var);
a.data = xstrdup(label.c_str());
a.func = cb_display;
}
static int cb_save(Action* a, int status, const char* resp) {
static int cb_save(Action& a, int status, const char* resp) {
if (status) {
fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
fprintf(stderr, "%s FAILED (%s)\n", a.cmd.c_str(), resp);
return status;
}
strncpy(reinterpret_cast<char*>(a->data), resp, a->size);
strncpy(reinterpret_cast<char*>(a.data), resp, a.size);
return 0;
}
void fb_queue_query_save(const char* var, char* dest, uint32_t dest_size) {
Action* a = queue_action(OP_QUERY, "getvar:%s", var);
a->data = dest;
a->size = dest_size;
a->func = cb_save;
void fb_queue_query_save(const std::string& var, char* dest, uint32_t dest_size) {
Action& a = queue_action(OP_QUERY, "getvar:" + var);
a.data = dest;
a.size = dest_size;
a.func = cb_save;
}
static int cb_do_nothing(Action*, int , const char*) {
fprintf(stderr,"\n");
static int cb_do_nothing(Action&, int, const char*) {
fprintf(stderr, "\n");
return 0;
}
void fb_queue_reboot(void)
{
Action *a = queue_action(OP_COMMAND, "reboot");
a->func = cb_do_nothing;
a->msg = "rebooting";
void fb_queue_reboot() {
Action& a = queue_action(OP_COMMAND, "reboot");
a.func = cb_do_nothing;
a.msg = "Rebooting...";
}
void fb_queue_command(const char *cmd, const char *msg)
{
Action *a = queue_action(OP_COMMAND, cmd);
a->msg = msg;
void fb_queue_command(const std::string& cmd, const std::string& msg) {
Action& a = queue_action(OP_COMMAND, cmd);
a.msg = msg;
}
void fb_queue_download(const char *name, void *data, uint32_t size)
{
Action *a = queue_action(OP_DOWNLOAD, "");
a->data = data;
a->size = size;
a->msg = mkmsg("downloading '%s'", name);
void fb_queue_download(const std::string& name, void* data, uint32_t size) {
Action& a = queue_action(OP_DOWNLOAD, "");
a.data = data;
a.size = size;
a.msg = "Downloading '" + name + "'";
}
void fb_queue_download_fd(const char *name, int fd, uint32_t sz)
{
Action *a;
a = queue_action(OP_DOWNLOAD_FD, "");
a->fd = fd;
a->size = sz;
a->msg = mkmsg("sending '%s' (%d KB)", name, sz / 1024);
void fb_queue_download_fd(const std::string& name, int fd, uint32_t sz) {
Action& a = queue_action(OP_DOWNLOAD_FD, "");
a.fd = fd;
a.size = sz;
a.msg = android::base::StringPrintf("Sending '%s' (%d KB)", name.c_str(), sz / 1024);
}
void fb_queue_upload(const char* outfile) {
Action* a = queue_action(OP_UPLOAD, "");
a->data = xstrdup(outfile);
a->msg = mkmsg("uploading '%s'", outfile);
void fb_queue_upload(const std::string& outfile) {
Action& a = queue_action(OP_UPLOAD, "");
a.data = xstrdup(outfile.c_str());
a.msg = "Uploading '" + outfile + "'";
}
void fb_queue_notice(const char* notice) {
Action *a = queue_action(OP_NOTICE, "");
a->data = (void*) notice;
void fb_queue_notice(const std::string& notice) {
Action& a = queue_action(OP_NOTICE, "");
a.msg = notice;
}
void fb_queue_wait_for_disconnect(void)
{
void fb_queue_wait_for_disconnect() {
queue_action(OP_WAIT_FOR_DISCONNECT, "");
}
int64_t fb_execute_queue(Transport* transport)
{
Action *a;
char resp[FB_RESPONSE_SZ+1];
int64_t fb_execute_queue(Transport* transport) {
int64_t status = 0;
a = action_list;
if (!a)
return status;
resp[FB_RESPONSE_SZ] = 0;
double start = -1;
for (a = action_list; a; a = a->next) {
for (auto& a : action_list) {
a->start = now();
if (start < 0) start = a->start;
if (a->msg) {
// fprintf(stderr,"%30s... ",a->msg);
fprintf(stderr,"%s...\n",a->msg);
if (!a->msg.empty()) {
fprintf(stderr, "%s\n", a->msg.c_str());
}
if (a->op == OP_DOWNLOAD) {
status = fb_download_data(transport, a->data, a->size);
status = a->func(a, status, status ? fb_get_error().c_str() : "");
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_DOWNLOAD_FD) {
status = fb_download_data_fd(transport, a->fd, a->size);
status = a->func(a, status, status ? fb_get_error().c_str() : "");
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_COMMAND) {
status = fb_command(transport, a->cmd);
status = a->func(a, status, status ? fb_get_error().c_str() : "");
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_QUERY) {
char resp[FB_RESPONSE_SZ + 1] = {};
status = fb_command_response(transport, a->cmd, resp);
status = a->func(a, status, status ? fb_get_error().c_str() : resp);
status = a->func(*a, status, status ? fb_get_error().c_str() : resp);
if (status) break;
} else if (a->op == OP_NOTICE) {
fprintf(stderr,"%s\n",(char*)a->data);
// We already showed the notice because it's in `Action::msg`.
} else if (a->op == OP_DOWNLOAD_SPARSE) {
status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
status = a->func(a, status, status ? fb_get_error().c_str() : "");
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_WAIT_FOR_DISCONNECT) {
transport->WaitForDisconnect();
} else if (a->op == OP_UPLOAD) {
status = fb_upload_data(transport, reinterpret_cast<char*>(a->data));
status = a->func(a, status, status ? fb_get_error().c_str() : "");
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
} else {
die("bogus action");
die("unknown action: %d", a->op);
}
}
fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
action_list.clear();
return status;
}

View File

@ -635,27 +635,31 @@ static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
return fd.release();
}
static char *strip(char *s)
{
int n;
while(*s && isspace(*s)) s++;
n = strlen(s);
while(n-- > 0) {
if(!isspace(s[n])) break;
static char* strip(char* s) {
while (*s && isspace(*s)) s++;
int n = strlen(s);
while (n-- > 0) {
if (!isspace(s[n])) break;
s[n] = 0;
}
return s;
}
#define MAX_OPTIONS 32
static int setup_requirement_line(char *name)
{
static void check_requirement(Transport* transport, char* line) {
char *val[MAX_OPTIONS];
char *prod = nullptr;
unsigned n, count;
unsigned count;
char *x;
int invert = 0;
// "require product=alpha|beta|gamma"
// "require version-bootloader=1234"
// "require-for-product:gamma version-bootloader=istanbul|constantinople"
// "require partition-exists=vendor"
char* name = line;
const char* product = "";
if (!strncmp(name, "reject ", 7)) {
name += 7;
invert = 1;
@ -664,19 +668,46 @@ static int setup_requirement_line(char *name)
invert = 0;
} else if (!strncmp(name, "require-for-product:", 20)) {
// Get the product and point name past it
prod = name + 20;
product = name + 20;
name = strchr(name, ' ');
if (!name) return -1;
if (!name) die("android-info.txt syntax error: %s", line);
*name = 0;
name += 1;
invert = 0;
}
x = strchr(name, '=');
if (x == 0) return 0;
if (x == 0) return;
*x = 0;
val[0] = x + 1;
name = strip(name);
// "require partition-exists=x" is a special case, added because of the trouble we had when
// Pixel 2 shipped with new partitions and users used old versions of fastboot to flash them,
// missing out new partitions. A device with new partitions can use "partition-exists" to
// override the `is_optional` field in the `images` array.
if (!strcmp(name, "partition-exists")) {
const char* partition_name = val[0];
std::string has_slot;
if (!fb_getvar(transport, std::string("has-slot:") + partition_name, &has_slot) ||
(has_slot != "yes" && has_slot != "no")) {
die("device doesn't have required partition %s!", partition_name);
}
bool known_partition = false;
for (size_t i = 0; i < arraysize(images); ++i) {
if (images[i].nickname && !strcmp(images[i].nickname, partition_name)) {
images[i].is_optional = false;
known_partition = true;
}
}
if (!known_partition) {
die("device requires partition %s which is not known to this version of fastboot",
partition_name);
}
return;
}
for(count = 1; count < MAX_OPTIONS; count++) {
x = strchr(val[count - 1],'|');
if (x == 0) break;
@ -684,54 +715,39 @@ static int setup_requirement_line(char *name)
val[count] = x + 1;
}
name = strip(name);
for(n = 0; n < count; n++) val[n] = strip(val[n]);
name = strip(name);
if (name == 0) return -1;
const char* var = name;
// Work around an unfortunate name mismatch.
if (!strcmp(name,"board")) var = "product";
const char* var = name;
if (!strcmp(name, "board")) var = "product";
const char** out = reinterpret_cast<const char**>(malloc(sizeof(char*) * count));
if (out == 0) return -1;
if (out == nullptr) die("out of memory");
for(n = 0; n < count; n++) {
out[n] = strdup(strip(val[n]));
if (out[n] == 0) {
for(size_t i = 0; i < n; ++i) {
free((char*) out[i]);
}
free(out);
return -1;
}
for (size_t i = 0; i < count; ++i) {
out[i] = xstrdup(strip(val[i]));
}
fb_queue_require(prod, var, invert, n, out);
return 0;
fb_queue_require(product, var, invert, count, out);
}
static void setup_requirements(char* data, int64_t sz) {
static void check_requirements(Transport* transport, char* data, int64_t sz) {
char* s = data;
while (sz-- > 0) {
if (*s == '\n') {
*s++ = 0;
if (setup_requirement_line(data)) {
die("out of memory");
}
check_requirement(transport, data);
data = s;
} else {
s++;
}
}
if (fb_execute_queue(transport)) die("requirements not met!");
}
static void queue_info_dump() {
fb_queue_notice("--------------------------------------------");
fb_queue_display("version-bootloader", "Bootloader Version...");
fb_queue_display("version-baseband", "Baseband Version.....");
fb_queue_display("serialno", "Serial Number........");
fb_queue_display("Bootloader Version...", "version-bootloader");
fb_queue_display("Baseband Version.....", "version-baseband");
fb_queue_display("Serial Number........", "serialno");
fb_queue_notice("--------------------------------------------");
}
@ -891,14 +907,13 @@ static void rewrite_vbmeta_buffer(struct fastboot_buffer* buf) {
lseek(fd, 0, SEEK_SET);
}
static void flash_buf(const char *pname, struct fastboot_buffer *buf)
static void flash_buf(const std::string& partition, struct fastboot_buffer *buf)
{
sparse_file** s;
// Rewrite vbmeta if that's what we're flashing and modification has been requested.
if ((g_disable_verity || g_disable_verification) &&
(strcmp(pname, "vbmeta") == 0 || strcmp(pname, "vbmeta_a") == 0 ||
strcmp(pname, "vbmeta_b") == 0)) {
(partition == "vbmeta" || partition == "vbmeta_a" || partition == "vbmeta_b")) {
rewrite_vbmeta_buffer(buf);
}
@ -914,12 +929,12 @@ static void flash_buf(const char *pname, struct fastboot_buffer *buf)
for (size_t i = 0; i < sparse_files.size(); ++i) {
const auto& pair = sparse_files[i];
fb_queue_flash_sparse(pname, pair.first, pair.second, i + 1, sparse_files.size());
fb_queue_flash_sparse(partition, pair.first, pair.second, i + 1, sparse_files.size());
}
break;
}
case FB_BUFFER_FD:
fb_queue_flash_fd(pname, buf->fd, buf->sz);
fb_queue_flash_fd(partition, buf->fd, buf->sz);
break;
default:
die("unknown buffer type: %d", buf->type);
@ -1117,11 +1132,11 @@ static void set_active(Transport* transport, const std::string& slot_override) {
}
}
if (slot_override != "") {
fb_set_active((separator + slot_override).c_str());
fb_set_active(separator + slot_override);
} else {
std::string current_slot = get_current_slot(transport);
if (current_slot != "") {
fb_set_active((separator + current_slot).c_str());
fb_set_active(separator + current_slot);
}
}
}
@ -1143,7 +1158,7 @@ static void do_update(Transport* transport, const char* filename, const std::str
die("update package '%s' has no android-info.txt", filename);
}
setup_requirements(reinterpret_cast<char*>(data), sz);
check_requirements(transport, reinterpret_cast<char*>(data), sz);
std::string secondary;
if (!skip_secondary) {
@ -1185,7 +1200,7 @@ static void do_update(Transport* transport, const char* filename, const std::str
auto update = [&](const std::string& partition) {
do_update_signature(zip, images[i].sig_name);
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
fb_queue_erase(partition);
}
flash_buf(partition.c_str(), &buf);
/* not closing the fd here since the sparse code keeps the fd around
@ -1232,7 +1247,7 @@ static void do_flashall(Transport* transport, const std::string& slot_override,
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);
check_requirements(transport, reinterpret_cast<char*>(data), sz);
std::string secondary;
if (!skip_secondary) {
@ -1267,7 +1282,7 @@ static void do_flashall(Transport* transport, const std::string& slot_override,
auto flashall = [&](const std::string &partition) {
do_send_signature(fname.c_str());
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
fb_queue_erase(partition);
}
flash_buf(partition.c_str(), &buf);
};
@ -1307,7 +1322,7 @@ static void do_oem_command(const std::string& cmd, std::vector<std::string>* arg
while (!args->empty()) {
command += " " + next_arg(args);
}
fb_queue_command(command.c_str(), "");
fb_queue_command(command, "");
}
static int64_t parse_num(const char *arg)
@ -1362,8 +1377,8 @@ static std::string fb_fix_numeric_var(std::string var) {
static unsigned fb_get_flash_block_size(Transport* transport, std::string name) {
std::string sizeString;
if (!fb_getvar(transport, name.c_str(), &sizeString) || sizeString.empty()) {
/* This device does not report flash block sizes, so return 0 */
if (!fb_getvar(transport, name, &sizeString) || sizeString.empty()) {
// This device does not report flash block sizes, so return 0.
return 0;
}
sizeString = fb_fix_numeric_var(sizeString);
@ -1381,7 +1396,7 @@ static unsigned fb_get_flash_block_size(Transport* transport, std::string name)
}
static void fb_perform_format(Transport* transport,
const char* partition, int skip_if_not_supported,
const std::string& partition, int skip_if_not_supported,
const std::string& type_override, const std::string& size_override,
const std::string& initial_dir) {
std::string partition_type, partition_size;
@ -1400,26 +1415,26 @@ static void fb_perform_format(Transport* transport,
limit = sparse_limit;
}
if (!fb_getvar(transport, std::string("partition-type:") + partition, &partition_type)) {
if (!fb_getvar(transport, "partition-type:" + partition, &partition_type)) {
errMsg = "Can't determine partition type.\n";
goto failed;
}
if (!type_override.empty()) {
if (partition_type != type_override) {
fprintf(stderr, "Warning: %s type is %s, but %s was requested for formatting.\n",
partition, partition_type.c_str(), type_override.c_str());
partition.c_str(), partition_type.c_str(), type_override.c_str());
}
partition_type = type_override;
}
if (!fb_getvar(transport, std::string("partition-size:") + partition, &partition_size)) {
if (!fb_getvar(transport, "partition-size:" + partition, &partition_size)) {
errMsg = "Unable to get partition size\n";
goto failed;
}
if (!size_override.empty()) {
if (partition_size != size_override) {
fprintf(stderr, "Warning: %s size is %s, but %s was requested for formatting.\n",
partition, partition_size.c_str(), size_override.c_str());
partition.c_str(), partition_size.c_str(), size_override.c_str());
}
partition_size = size_override;
}
@ -1449,7 +1464,7 @@ static void fb_perform_format(Transport* transport,
if (fs_generator_generate(gen, output.path, size, initial_dir,
eraseBlkSize, logicalBlkSize)) {
die("Cannot generate image for %s", partition);
die("Cannot generate image for %s", partition.c_str());
return;
}
@ -1632,6 +1647,8 @@ int main(int argc, char **argv)
return 1;
}
const double start = now();
if (!supports_AB(transport) && supports_AB_obsolete(transport)) {
fprintf(stderr, "Warning: Device A/B support is outdated. Bootloader update required.\n");
}
@ -1659,7 +1676,7 @@ int main(int argc, char **argv)
if (command == "getvar") {
std::string variable = next_arg(&args);
fb_queue_display(variable.c_str(), variable.c_str());
fb_queue_display(variable, variable);
} else if (command == "erase") {
std::string partition = next_arg(&args);
auto erase = [&](const std::string& partition) {
@ -1671,7 +1688,7 @@ int main(int argc, char **argv)
partition_type.c_str());
}
fb_queue_erase(partition.c_str());
fb_queue_erase(partition);
};
do_for_partitions(transport, partition, slot_override, erase, true);
} else if (android::base::StartsWith(command, "format")) {
@ -1692,10 +1709,9 @@ int main(int argc, char **argv)
auto format = [&](const std::string& partition) {
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
fb_queue_erase(partition);
}
fb_perform_format(transport, partition.c_str(), 0, type_override, size_override,
"");
fb_perform_format(transport, partition, 0, type_override, size_override, "");
};
do_for_partitions(transport, partition.c_str(), slot_override, format, true);
} else if (command == "signature") {
@ -1749,7 +1765,7 @@ int main(int argc, char **argv)
auto flash = [&](const std::string &partition) {
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
fb_queue_erase(partition);
}
do_flash(transport, partition.c_str(), fname.c_str());
};
@ -1764,7 +1780,7 @@ int main(int argc, char **argv)
data = load_bootable_image(kernel, ramdisk, second_stage, &sz, cmdline);
auto flashraw = [&](const std::string& partition) {
fb_queue_flash(partition.c_str(), data, sz);
fb_queue_flash(partition, data, sz);
};
do_for_partitions(transport, partition, slot_override, flashraw, true);
} else if (command == "flashall") {
@ -1798,7 +1814,7 @@ int main(int argc, char **argv)
fb_getvar(transport, "slot-suffixes", &var)) {
slot = "_" + slot;
}
fb_set_active(slot.c_str());
fb_set_active(slot);
} else if (command == "stage") {
std::string filename = next_arg(&args);
@ -1806,10 +1822,10 @@ int main(int argc, char **argv)
if (!load_buf(transport, filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
die("cannot load '%s'", filename.c_str());
}
fb_queue_download_fd(filename.c_str(), buf.fd, buf.sz);
fb_queue_download_fd(filename, buf.fd, buf.sz);
} else if (command == "get_staged") {
std::string filename = next_arg(&args);
fb_queue_upload(filename.c_str());
fb_queue_upload(filename);
} else if (command == "oem") {
do_oem_command("oem", &args);
} else if (command == "flashing") {
@ -1855,7 +1871,7 @@ int main(int argc, char **argv)
}
}
if (wants_set_active) {
fb_set_active(next_active.c_str());
fb_set_active(next_active);
}
if (wants_reboot && !skip_reboot) {
fb_queue_reboot();
@ -1868,5 +1884,7 @@ int main(int argc, char **argv)
fb_queue_wait_for_disconnect();
}
return fb_execute_queue(transport) ? EXIT_FAILURE : EXIT_SUCCESS;
int status = fb_execute_queue(transport) ? EXIT_FAILURE : EXIT_SUCCESS;
fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start));
return status;
}

View File

@ -39,8 +39,8 @@
struct sparse_file;
/* protocol.c - fastboot protocol */
int fb_command(Transport* transport, const char* cmd);
int fb_command_response(Transport* transport, const char* cmd, char* response);
int fb_command(Transport* transport, const std::string& cmd);
int fb_command_response(Transport* transport, const std::string& cmd, char* response);
int64_t fb_download_data(Transport* transport, const void* data, uint32_t size);
int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size);
int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
@ -52,29 +52,29 @@ const std::string fb_get_error();
/* engine.c - high level command queue engine */
bool fb_getvar(Transport* transport, const std::string& key, std::string* value);
void fb_queue_flash(const char *ptn, void *data, uint32_t sz);
void fb_queue_flash_fd(const char *ptn, int fd, uint32_t sz);
void fb_queue_flash_sparse(const char* ptn, struct sparse_file* s, uint32_t sz, size_t current,
size_t total);
void fb_queue_erase(const char *ptn);
void fb_queue_format(const char *ptn, int skip_if_not_supported, int32_t max_chunk_sz);
void fb_queue_require(const char *prod, const char *var, bool invert,
size_t nvalues, const char **value);
void fb_queue_display(const char *var, const char *prettyname);
void fb_queue_query_save(const char *var, char *dest, uint32_t dest_size);
void fb_queue_flash(const std::string& partition, void* data, uint32_t sz);
void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz);
void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
size_t current, size_t total);
void fb_queue_erase(const std::string& partition);
void fb_queue_format(const std::string& partition, int skip_if_not_supported, int32_t max_chunk_sz);
void fb_queue_require(const std::string& prod, const std::string& var, bool invert, size_t nvalues,
const char** values);
void fb_queue_display(const std::string& label, const std::string& var);
void fb_queue_query_save(const std::string& var, char* dest, uint32_t dest_size);
void fb_queue_reboot(void);
void fb_queue_command(const char *cmd, const char *msg);
void fb_queue_download(const char *name, void *data, uint32_t size);
void fb_queue_download_fd(const char *name, int fd, uint32_t sz);
void fb_queue_upload(const char* outfile);
void fb_queue_notice(const char *notice);
void fb_queue_command(const std::string& cmd, const std::string& msg);
void fb_queue_download(const std::string& name, void* data, uint32_t size);
void fb_queue_download_fd(const std::string& name, int fd, uint32_t sz);
void fb_queue_upload(const std::string& outfile);
void fb_queue_notice(const std::string& notice);
void fb_queue_wait_for_disconnect(void);
int64_t fb_execute_queue(Transport* transport);
void fb_set_active(const char *slot);
void fb_set_active(const std::string& slot);
/* util stuff */
double now();
char *mkmsg(const char *fmt, ...);
char* xstrdup(const char*);
// These printf-like functions are implemented in terms of vsnprintf, so they
// use the same attribute for compile-time format string checking. On Windows,

View File

@ -113,10 +113,10 @@ static int64_t check_response(Transport* transport, uint32_t size, char* respons
return -1;
}
static int64_t _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
size_t cmdsize = strlen(cmd);
if (cmdsize > 64) {
g_error = android::base::StringPrintf("command too large (%zu)", cmdsize);
static int64_t _command_start(Transport* transport, const std::string& cmd, uint32_t size,
char* response) {
if (cmd.size() > 64) {
g_error = android::base::StringPrintf("command too large (%zu)", cmd.size());
return -1;
}
@ -124,7 +124,7 @@ static int64_t _command_start(Transport* transport, const char* cmd, uint32_t si
response[0] = 0;
}
if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) {
if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
transport->Close();
return -1;
@ -167,8 +167,8 @@ static int64_t _command_end(Transport* transport) {
return check_response(transport, 0, 0) < 0 ? -1 : 0;
}
static int64_t _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size,
char* response) {
static int64_t _command_send(Transport* transport, const std::string& cmd, const void* data,
uint32_t size, char* response) {
if (size == 0) {
return -1;
}
@ -190,7 +190,7 @@ static int64_t _command_send(Transport* transport, const char* cmd, const void*
return size;
}
static int64_t _command_send_fd(Transport* transport, const char* cmd, int fd, uint32_t size,
static int64_t _command_send_fd(Transport* transport, const std::string& cmd, int fd, uint32_t size,
char* response) {
static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
off64_t offset = 0;
@ -223,15 +223,15 @@ static int64_t _command_send_fd(Transport* transport, const char* cmd, int fd, u
return size;
}
static int _command_send_no_data(Transport* transport, const char* cmd, char* response) {
static int _command_send_no_data(Transport* transport, const std::string& cmd, char* response) {
return _command_start(transport, cmd, 0, response);
}
int fb_command(Transport* transport, const char* cmd) {
int fb_command(Transport* transport, const std::string& cmd) {
return _command_send_no_data(transport, cmd, 0);
}
int fb_command_response(Transport* transport, const char* cmd, char* response) {
int fb_command_response(Transport* transport, const std::string& cmd, char* response) {
return _command_send_no_data(transport, cmd, response);
}
@ -339,7 +339,7 @@ int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
}
std::string cmd(android::base::StringPrintf("download:%08x", size));
int r = _command_start(transport, cmd.c_str(), size, 0);
int r = _command_start(transport, cmd, size, 0);
if (r < 0) {
return -1;
}

View File

@ -35,35 +35,24 @@
#include "fastboot.h"
double now()
{
double now() {
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
}
char *mkmsg(const char *fmt, ...)
{
char buf[256];
char *s;
va_list ap;
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
s = strdup(buf);
if (s == 0) die("out of memory");
return s;
}
void die(const char *fmt, ...)
{
void die(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
fprintf(stderr,"error: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr,"\n");
va_end(ap);
exit(1);
exit(EXIT_FAILURE);
}
char* xstrdup(const char* s) {
char* result = strdup(s);
if (!result) die("out of memory");
return result;
}