fastboot: Support larger transfers during flash
Adding methods to queue and download flashable images by fd instead of
by pointer, so that we can deal with sending large (up to 4GB) files
on windows and linux. This gets past limitations on linux to read
more than 2GB from a file at a time, as well as memory limitations
on win32, in order to download up to 4GB in a single transfer.
Test: fastboot -w
Test: "flash-all" from nexus factory images site (incl. fastboot -w update)
Test: fastboot flash with large and small image, large and small max-download-size
Test: Sanity check flashing on win32, darwin, linux.
Test: Sanity check 3GB image download (with 3GB max-download-size)
on win32, darwin, linux.
Bug: 36810152
Change-Id: I528d739d344eb080d59d721dadf3b3b34d4b375e
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index bf0479e..334f81f 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -38,6 +38,7 @@
#include <android-base/stringprintf.h>
#include <sparse/sparse.h>
+#include <utils/FileMap.h>
#include "fastboot.h"
#include "transport.h"
@@ -168,6 +169,39 @@
return size;
}
+static int64_t _command_send_fd(Transport* transport, const char* cmd, int fd, uint32_t size,
+ char* response) {
+ static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
+ off64_t offset = 0;
+ uint32_t remaining = size;
+
+ if (_command_start(transport, cmd, size, response) < 0) {
+ return -1;
+ }
+
+ while (remaining) {
+ android::FileMap filemap;
+ size_t len = std::min(remaining, MAX_MAP_SIZE);
+
+ if (!filemap.create(NULL, fd, offset, len, true)) {
+ return -1;
+ }
+
+ if (_command_data(transport, filemap.getDataPtr(), len) < 0) {
+ return -1;
+ }
+
+ remaining -= len;
+ offset += len;
+ }
+
+ if (_command_end(transport) < 0) {
+ return -1;
+ }
+
+ return size;
+}
+
static int _command_send_no_data(Transport* transport, const char* cmd, char* response) {
return _command_start(transport, cmd, 0, response);
}
@@ -181,9 +215,13 @@
}
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;
+ std::string cmd(android::base::StringPrintf("download:%08x", size));
+ return _command_send(transport, cmd.c_str(), data, size, 0) < 0 ? -1 : 0;
+}
+
+int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) {
+ std::string cmd(android::base::StringPrintf("download:%08x", size));
+ return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0;
}
#define TRANSPORT_BUF_SIZE 1024
@@ -257,9 +295,8 @@
return -1;
}
- char cmd[64];
- snprintf(cmd, sizeof(cmd), "download:%08x", size);
- int r = _command_start(transport, cmd, size, 0);
+ std::string cmd(android::base::StringPrintf("download:%08x", size));
+ int r = _command_start(transport, cmd.c_str(), size, 0);
if (r < 0) {
return -1;
}