fastboot: Cap max size sent to libsparse
This is required for large (>INT_MAX) sparse limit reported by
the target.
Also, patch up return chains of "int" that need to deal with sizes
bigger than 2GB as well as return negative error codes.
Test: -S works with large max-download-size
Test: Flash 3GB system.img with max-download-size 2.5GB
Bug: 36810152
Change-Id: I562a50eabd706bd5b97c71a1aef07c1ffd1a2e5c
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 728dcb8..9f7d226 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -328,11 +328,11 @@
queue_action(OP_WAIT_FOR_DISCONNECT, "");
}
-int fb_execute_queue(Transport* transport)
+int64_t fb_execute_queue(Transport* transport)
{
Action *a;
char resp[FB_RESPONSE_SZ+1];
- int status = 0;
+ int64_t status = 0;
a = action_list;
if (!a)
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 704dc43..cb8e5c0 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -78,6 +78,10 @@
static const char* cmdline = nullptr;
static unsigned short vendor_id = 0;
static int long_listing = 0;
+// Don't resparse files in too-big chunks.
+// libsparse will support INT_MAX, but this results in large allocations, so
+// let's keep it at 1GB to avoid memory pressure on the host.
+static constexpr int64_t RESPARSE_LIMIT = 1 * 1024 * 1024 * 1024;
static int64_t sparse_limit = -1;
static int64_t target_sparse_limit = -1;
@@ -789,7 +793,7 @@
}
if (size > limit) {
- return limit;
+ return std::min(limit, RESPARSE_LIMIT);
}
return 0;
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 6699b6a..b62a2d8 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -41,7 +41,7 @@
/* 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_download_data(Transport* transport, const void* data, uint32_t size);
+int64_t fb_download_data(Transport* transport, const void* data, uint32_t size);
int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
const std::string fb_get_error();
@@ -64,7 +64,7 @@
void fb_queue_download(const char *name, void *data, uint32_t size);
void fb_queue_notice(const char *notice);
void fb_queue_wait_for_disconnect(void);
-int fb_execute_queue(Transport* transport);
+int64_t fb_execute_queue(Transport* transport);
void fb_set_active(const char *slot);
/* util stuff */
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index bfa83b0..bf0479e 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -48,7 +48,7 @@
return g_error;
}
-static int check_response(Transport* transport, uint32_t size, char* response) {
+static int64_t check_response(Transport* transport, uint32_t size, char* response) {
char status[65];
while (true) {
@@ -105,7 +105,7 @@
return -1;
}
-static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
+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);
@@ -125,14 +125,14 @@
return check_response(transport, size, response);
}
-static int _command_data(Transport* transport, const void* data, uint32_t size) {
- int r = transport->Write(data, size);
+static int64_t _command_data(Transport* transport, const void* data, uint32_t size) {
+ int64_t r = transport->Write(data, size);
if (r < 0) {
g_error = android::base::StringPrintf("data transfer failure (%s)", strerror(errno));
transport->Close();
return -1;
}
- if (r != ((int) size)) {
+ if (r != static_cast<int64_t>(size)) {
g_error = "data transfer failure (short transfer)";
transport->Close();
return -1;
@@ -140,17 +140,17 @@
return r;
}
-static int _command_end(Transport* transport) {
+static int64_t _command_end(Transport* transport) {
return check_response(transport, 0, 0) < 0 ? -1 : 0;
}
-static int _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size,
+static int64_t _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size,
char* response) {
if (size == 0) {
return -1;
}
- int r = _command_start(transport, cmd, size, response);
+ int64_t r = _command_start(transport, cmd, size, response);
if (r < 0) {
return -1;
}
@@ -180,7 +180,7 @@
return _command_send_no_data(transport, cmd, response);
}
-int fb_download_data(Transport* transport, const void* data, uint32_t size) {
+int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) {
char cmd[64];
snprintf(cmd, sizeof(cmd), "download:%08x", size);
return _command_send(transport, cmd, data, size, 0) < 0 ? -1 : 0;
@@ -242,7 +242,8 @@
static int fb_download_data_sparse_flush(Transport* transport) {
if (transport_buf_len > 0) {
- if (_command_data(transport, transport_buf, transport_buf_len) != transport_buf_len) {
+ int64_t r = _command_data(transport, transport_buf, transport_buf_len);
+ if (r != static_cast<int64_t>(transport_buf_len)) {
return -1;
}
transport_buf_len = 0;