Loading fastboot/README.md +10 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,16 @@ The various currently defined commands are: space in RAM or "FAIL" if not. The size of the download is remembered. upload Read data from memory which was staged by the last command, e.g. an oem command. The client will reply with "DATA%08x" if it is ready to send %08x bytes of data. If no data was staged in the last command, the client must reply with "FAIL". After the client successfully sends %08x bytes, the client shall send a single packet starting with "OKAY". Clients should not support "upload" unless it supports an oem command that requires "upload" capabilities. verify:%08x Send a digital signature to verify the downloaded data. Required if the bootloader is "secure" otherwise "flash" and "boot" will be ignored. Loading fastboot/engine.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ #define OP_DOWNLOAD_SPARSE 5 #define OP_WAIT_FOR_DISCONNECT 6 #define OP_DOWNLOAD_FD 7 #define OP_UPLOAD 8 typedef struct Action Action; Loading Loading @@ -332,6 +333,22 @@ void fb_queue_download(const char *name, void *data, uint32_t size) a->msg = mkmsg("downloading '%s'", 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_upload(char *outfile) { Action *a = queue_action(OP_UPLOAD, ""); a->data = outfile; a->msg = mkmsg("uploading '%s'", outfile); } void fb_queue_notice(const char *notice) { Action *a = queue_action(OP_NOTICE, ""); Loading Loading @@ -386,6 +403,9 @@ int64_t fb_execute_queue(Transport* transport) 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() : ""); } else { die("bogus action"); } Loading fastboot/fastboot.cpp +21 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,13 @@ static void usage() { " continue Continue with autoboot.\n" " reboot [bootloader|emergency] Reboot device [into bootloader or emergency mode].\n" " reboot-bootloader Reboot device into bootloader.\n" " oem <parameter1> ... <parameterN> Executes oem specific command.\n" " stage <infile> Sends contents of <infile> to stage for\n" " the next command. Supported only on\n" " Android Things devices.\n" " get_staged <outfile> Receives data to <outfile> staged by the\n" " last command. Supported only on Android\n" " Things devices.\n" " help Show this help message.\n" "\n" "options:\n" Loading Loading @@ -1823,6 +1830,20 @@ int main(int argc, char **argv) } fb_set_active(slot.c_str()); skip(2); } else if(!strcmp(*argv, "stage")) { require(2); std::string infile(argv[1]); skip(2); struct fastboot_buffer buf; if (!load_buf(transport, infile.c_str(), &buf) || buf.type != FB_BUFFER_FD) { die("cannot load '%s'", infile.c_str()); } fb_queue_download_fd(infile.c_str(), buf.fd, buf.sz); } else if(!strcmp(*argv, "get_staged")) { require(2); char *outfile = argv[1]; skip(2); fb_queue_upload(outfile); } else if(!strcmp(*argv, "oem")) { argc = do_oem_command(argc, argv); } else if(!strcmp(*argv, "flashing")) { Loading fastboot/fastboot.h +3 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ int fb_command_response(Transport* transport, const char* 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); int64_t fb_upload_data(Transport* transport, const char* outfile); const std::string fb_get_error(); #define FB_COMMAND_SZ 64 Loading @@ -64,6 +65,8 @@ void fb_queue_query_save(const char *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(char *outfile); void fb_queue_notice(const char *notice); void fb_queue_wait_for_disconnect(void); int64_t fb_execute_queue(Transport* transport); Loading fastboot/protocol.cpp +52 −9 Original line number Diff line number Diff line Loading @@ -29,14 +29,18 @@ #define round_down(a, b) \ ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); }) #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <algorithm> #include <vector> #include <android-base/file.h> #include <android-base/stringprintf.h> #include <android-base/unique_fd.h> #include <sparse/sparse.h> #include <utils/FileMap.h> Loading @@ -45,6 +49,9 @@ static std::string g_error; using android::base::unique_fd; using android::base::WriteStringToFile; const std::string fb_get_error() { return g_error; } Loading Loading @@ -126,15 +133,30 @@ static int64_t _command_start(Transport* transport, const char* cmd, uint32_t si return check_response(transport, size, response); } static int64_t _command_data(Transport* transport, const void* data, uint32_t size) { static int64_t _command_write_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)); g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno)); transport->Close(); return -1; } if (r != static_cast<int64_t>(size)) { g_error = "data transfer failure (short transfer)"; g_error = "data write failure (short transfer)"; transport->Close(); return -1; } return r; } static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) { int64_t r = transport->Read(data, size); if (r < 0) { g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno)); transport->Close(); return -1; } if (r != (static_cast<int64_t>(size))) { g_error = "data read failure (short transfer)"; transport->Close(); return -1; } Loading @@ -155,8 +177,7 @@ static int64_t _command_send(Transport* transport, const char* cmd, const void* if (r < 0) { return -1; } r = _command_data(transport, data, size); r = _command_write_data(transport, data, size); if (r < 0) { return -1; } Loading Loading @@ -187,7 +208,7 @@ static int64_t _command_send_fd(Transport* transport, const char* cmd, int fd, u return -1; } if (_command_data(transport, filemap.getDataPtr(), len) < 0) { if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) { return -1; } Loading Loading @@ -224,6 +245,28 @@ int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) { return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0; } int64_t fb_upload_data(Transport* transport, const char* outfile) { // positive return value is the upload size sent by the device int64_t r = _command_start(transport, "upload", std::numeric_limits<int32_t>::max(), nullptr); if (r <= 0) { g_error = android::base::StringPrintf("command start failed (%s)", strerror(errno)); return r; } std::string data; data.resize(r); if ((r = _command_read_data(transport, &data[0], data.size())) == -1) { return r; } if (!WriteStringToFile(data, outfile, true)) { g_error = android::base::StringPrintf("write to '%s' failed", outfile); return -1; } return _command_end(transport); } #define TRANSPORT_BUF_SIZE 1024 static char transport_buf[TRANSPORT_BUF_SIZE]; static int transport_buf_len; Loading @@ -245,7 +288,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len) } if (transport_buf_len == TRANSPORT_BUF_SIZE) { r = _command_data(transport, transport_buf, TRANSPORT_BUF_SIZE); r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE); if (r != TRANSPORT_BUF_SIZE) { return -1; } Loading @@ -258,7 +301,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len) return -1; } to_write = round_down(len, TRANSPORT_BUF_SIZE); r = _command_data(transport, ptr, to_write); r = _command_write_data(transport, ptr, to_write); if (r != to_write) { return -1; } Loading @@ -280,7 +323,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len) static int fb_download_data_sparse_flush(Transport* transport) { if (transport_buf_len > 0) { int64_t r = _command_data(transport, transport_buf, transport_buf_len); int64_t r = _command_write_data(transport, transport_buf, transport_buf_len); if (r != static_cast<int64_t>(transport_buf_len)) { return -1; } Loading Loading
fastboot/README.md +10 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,16 @@ The various currently defined commands are: space in RAM or "FAIL" if not. The size of the download is remembered. upload Read data from memory which was staged by the last command, e.g. an oem command. The client will reply with "DATA%08x" if it is ready to send %08x bytes of data. If no data was staged in the last command, the client must reply with "FAIL". After the client successfully sends %08x bytes, the client shall send a single packet starting with "OKAY". Clients should not support "upload" unless it supports an oem command that requires "upload" capabilities. verify:%08x Send a digital signature to verify the downloaded data. Required if the bootloader is "secure" otherwise "flash" and "boot" will be ignored. Loading
fastboot/engine.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ #define OP_DOWNLOAD_SPARSE 5 #define OP_WAIT_FOR_DISCONNECT 6 #define OP_DOWNLOAD_FD 7 #define OP_UPLOAD 8 typedef struct Action Action; Loading Loading @@ -332,6 +333,22 @@ void fb_queue_download(const char *name, void *data, uint32_t size) a->msg = mkmsg("downloading '%s'", 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_upload(char *outfile) { Action *a = queue_action(OP_UPLOAD, ""); a->data = outfile; a->msg = mkmsg("uploading '%s'", outfile); } void fb_queue_notice(const char *notice) { Action *a = queue_action(OP_NOTICE, ""); Loading Loading @@ -386,6 +403,9 @@ int64_t fb_execute_queue(Transport* transport) 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() : ""); } else { die("bogus action"); } Loading
fastboot/fastboot.cpp +21 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,13 @@ static void usage() { " continue Continue with autoboot.\n" " reboot [bootloader|emergency] Reboot device [into bootloader or emergency mode].\n" " reboot-bootloader Reboot device into bootloader.\n" " oem <parameter1> ... <parameterN> Executes oem specific command.\n" " stage <infile> Sends contents of <infile> to stage for\n" " the next command. Supported only on\n" " Android Things devices.\n" " get_staged <outfile> Receives data to <outfile> staged by the\n" " last command. Supported only on Android\n" " Things devices.\n" " help Show this help message.\n" "\n" "options:\n" Loading Loading @@ -1823,6 +1830,20 @@ int main(int argc, char **argv) } fb_set_active(slot.c_str()); skip(2); } else if(!strcmp(*argv, "stage")) { require(2); std::string infile(argv[1]); skip(2); struct fastboot_buffer buf; if (!load_buf(transport, infile.c_str(), &buf) || buf.type != FB_BUFFER_FD) { die("cannot load '%s'", infile.c_str()); } fb_queue_download_fd(infile.c_str(), buf.fd, buf.sz); } else if(!strcmp(*argv, "get_staged")) { require(2); char *outfile = argv[1]; skip(2); fb_queue_upload(outfile); } else if(!strcmp(*argv, "oem")) { argc = do_oem_command(argc, argv); } else if(!strcmp(*argv, "flashing")) { Loading
fastboot/fastboot.h +3 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ int fb_command_response(Transport* transport, const char* 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); int64_t fb_upload_data(Transport* transport, const char* outfile); const std::string fb_get_error(); #define FB_COMMAND_SZ 64 Loading @@ -64,6 +65,8 @@ void fb_queue_query_save(const char *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(char *outfile); void fb_queue_notice(const char *notice); void fb_queue_wait_for_disconnect(void); int64_t fb_execute_queue(Transport* transport); Loading
fastboot/protocol.cpp +52 −9 Original line number Diff line number Diff line Loading @@ -29,14 +29,18 @@ #define round_down(a, b) \ ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); }) #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <algorithm> #include <vector> #include <android-base/file.h> #include <android-base/stringprintf.h> #include <android-base/unique_fd.h> #include <sparse/sparse.h> #include <utils/FileMap.h> Loading @@ -45,6 +49,9 @@ static std::string g_error; using android::base::unique_fd; using android::base::WriteStringToFile; const std::string fb_get_error() { return g_error; } Loading Loading @@ -126,15 +133,30 @@ static int64_t _command_start(Transport* transport, const char* cmd, uint32_t si return check_response(transport, size, response); } static int64_t _command_data(Transport* transport, const void* data, uint32_t size) { static int64_t _command_write_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)); g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno)); transport->Close(); return -1; } if (r != static_cast<int64_t>(size)) { g_error = "data transfer failure (short transfer)"; g_error = "data write failure (short transfer)"; transport->Close(); return -1; } return r; } static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) { int64_t r = transport->Read(data, size); if (r < 0) { g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno)); transport->Close(); return -1; } if (r != (static_cast<int64_t>(size))) { g_error = "data read failure (short transfer)"; transport->Close(); return -1; } Loading @@ -155,8 +177,7 @@ static int64_t _command_send(Transport* transport, const char* cmd, const void* if (r < 0) { return -1; } r = _command_data(transport, data, size); r = _command_write_data(transport, data, size); if (r < 0) { return -1; } Loading Loading @@ -187,7 +208,7 @@ static int64_t _command_send_fd(Transport* transport, const char* cmd, int fd, u return -1; } if (_command_data(transport, filemap.getDataPtr(), len) < 0) { if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) { return -1; } Loading Loading @@ -224,6 +245,28 @@ int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) { return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0; } int64_t fb_upload_data(Transport* transport, const char* outfile) { // positive return value is the upload size sent by the device int64_t r = _command_start(transport, "upload", std::numeric_limits<int32_t>::max(), nullptr); if (r <= 0) { g_error = android::base::StringPrintf("command start failed (%s)", strerror(errno)); return r; } std::string data; data.resize(r); if ((r = _command_read_data(transport, &data[0], data.size())) == -1) { return r; } if (!WriteStringToFile(data, outfile, true)) { g_error = android::base::StringPrintf("write to '%s' failed", outfile); return -1; } return _command_end(transport); } #define TRANSPORT_BUF_SIZE 1024 static char transport_buf[TRANSPORT_BUF_SIZE]; static int transport_buf_len; Loading @@ -245,7 +288,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len) } if (transport_buf_len == TRANSPORT_BUF_SIZE) { r = _command_data(transport, transport_buf, TRANSPORT_BUF_SIZE); r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE); if (r != TRANSPORT_BUF_SIZE) { return -1; } Loading @@ -258,7 +301,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len) return -1; } to_write = round_down(len, TRANSPORT_BUF_SIZE); r = _command_data(transport, ptr, to_write); r = _command_write_data(transport, ptr, to_write); if (r != to_write) { return -1; } Loading @@ -280,7 +323,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len) static int fb_download_data_sparse_flush(Transport* transport) { if (transport_buf_len > 0) { int64_t r = _command_data(transport, transport_buf, transport_buf_len); int64_t r = _command_write_data(transport, transport_buf, transport_buf_len); if (r != static_cast<int64_t>(transport_buf_len)) { return -1; } Loading