summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'fastboot/protocol.cpp')
-rw-r--r--fastboot/protocol.cpp125
1 files changed, 103 insertions, 22 deletions
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index bfa83b041..dcdf8f0c1 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -29,26 +29,34 @@
29#define round_down(a, b) \ 29#define round_down(a, b) \
30 ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); }) 30 ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); })
31 31
32#include <fcntl.h>
32#include <stdio.h> 33#include <stdio.h>
33#include <stdlib.h> 34#include <stdlib.h>
34#include <string.h> 35#include <string.h>
35#include <errno.h> 36#include <errno.h>
36 37
37#include <algorithm> 38#include <algorithm>
39#include <vector>
38 40
41#include <android-base/file.h>
39#include <android-base/stringprintf.h> 42#include <android-base/stringprintf.h>
43#include <android-base/unique_fd.h>
40#include <sparse/sparse.h> 44#include <sparse/sparse.h>
45#include <utils/FileMap.h>
41 46
42#include "fastboot.h" 47#include "fastboot.h"
43#include "transport.h" 48#include "transport.h"
44 49
45static std::string g_error; 50static std::string g_error;
46 51
52using android::base::unique_fd;
53using android::base::WriteStringToFile;
54
47const std::string fb_get_error() { 55const std::string fb_get_error() {
48 return g_error; 56 return g_error;
49} 57}
50 58
51static int check_response(Transport* transport, uint32_t size, char* response) { 59static int64_t check_response(Transport* transport, uint32_t size, char* response) {
52 char status[65]; 60 char status[65];
53 61
54 while (true) { 62 while (true) {
@@ -105,7 +113,7 @@ static int check_response(Transport* transport, uint32_t size, char* response) {
105 return -1; 113 return -1;
106} 114}
107 115
108static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) { 116static int64_t _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
109 size_t cmdsize = strlen(cmd); 117 size_t cmdsize = strlen(cmd);
110 if (cmdsize > 64) { 118 if (cmdsize > 64) {
111 g_error = android::base::StringPrintf("command too large (%zu)", cmdsize); 119 g_error = android::base::StringPrintf("command too large (%zu)", cmdsize);
@@ -125,37 +133,51 @@ static int _command_start(Transport* transport, const char* cmd, uint32_t size,
125 return check_response(transport, size, response); 133 return check_response(transport, size, response);
126} 134}
127 135
128static int _command_data(Transport* transport, const void* data, uint32_t size) { 136static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) {
129 int r = transport->Write(data, size); 137 int64_t r = transport->Write(data, size);
138 if (r < 0) {
139 g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno));
140 transport->Close();
141 return -1;
142 }
143 if (r != static_cast<int64_t>(size)) {
144 g_error = "data write failure (short transfer)";
145 transport->Close();
146 return -1;
147 }
148 return r;
149}
150
151static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) {
152 int64_t r = transport->Read(data, size);
130 if (r < 0) { 153 if (r < 0) {
131 g_error = android::base::StringPrintf("data transfer failure (%s)", strerror(errno)); 154 g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno));
132 transport->Close(); 155 transport->Close();
133 return -1; 156 return -1;
134 } 157 }
135 if (r != ((int) size)) { 158 if (r != (static_cast<int64_t>(size))) {
136 g_error = "data transfer failure (short transfer)"; 159 g_error = "data read failure (short transfer)";
137 transport->Close(); 160 transport->Close();
138 return -1; 161 return -1;
139 } 162 }
140 return r; 163 return r;
141} 164}
142 165
143static int _command_end(Transport* transport) { 166static int64_t _command_end(Transport* transport) {
144 return check_response(transport, 0, 0) < 0 ? -1 : 0; 167 return check_response(transport, 0, 0) < 0 ? -1 : 0;
145} 168}
146 169
147static int _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size, 170static int64_t _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size,
148 char* response) { 171 char* response) {
149 if (size == 0) { 172 if (size == 0) {
150 return -1; 173 return -1;
151 } 174 }
152 175
153 int r = _command_start(transport, cmd, size, response); 176 int64_t r = _command_start(transport, cmd, size, response);
154 if (r < 0) { 177 if (r < 0) {
155 return -1; 178 return -1;
156 } 179 }
157 180 r = _command_write_data(transport, data, size);
158 r = _command_data(transport, data, size);
159 if (r < 0) { 181 if (r < 0) {
160 return -1; 182 return -1;
161 } 183 }
@@ -168,6 +190,39 @@ static int _command_send(Transport* transport, const char* cmd, const void* data
168 return size; 190 return size;
169} 191}
170 192
193static int64_t _command_send_fd(Transport* transport, const char* cmd, int fd, uint32_t size,
194 char* response) {
195 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
196 off64_t offset = 0;
197 uint32_t remaining = size;
198
199 if (_command_start(transport, cmd, size, response) < 0) {
200 return -1;
201 }
202
203 while (remaining) {
204 android::FileMap filemap;
205 size_t len = std::min(remaining, MAX_MAP_SIZE);
206
207 if (!filemap.create(NULL, fd, offset, len, true)) {
208 return -1;
209 }
210
211 if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) {
212 return -1;
213 }
214
215 remaining -= len;
216 offset += len;
217 }
218
219 if (_command_end(transport) < 0) {
220 return -1;
221 }
222
223 return size;
224}
225
171static int _command_send_no_data(Transport* transport, const char* cmd, char* response) { 226static int _command_send_no_data(Transport* transport, const char* cmd, char* response) {
172 return _command_start(transport, cmd, 0, response); 227 return _command_start(transport, cmd, 0, response);
173} 228}
@@ -180,10 +235,36 @@ int fb_command_response(Transport* transport, const char* cmd, char* response) {
180 return _command_send_no_data(transport, cmd, response); 235 return _command_send_no_data(transport, cmd, response);
181} 236}
182 237
183int fb_download_data(Transport* transport, const void* data, uint32_t size) { 238int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) {
184 char cmd[64]; 239 std::string cmd(android::base::StringPrintf("download:%08x", size));
185 snprintf(cmd, sizeof(cmd), "download:%08x", size); 240 return _command_send(transport, cmd.c_str(), data, size, 0) < 0 ? -1 : 0;
186 return _command_send(transport, cmd, data, size, 0) < 0 ? -1 : 0; 241}
242
243int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) {
244 std::string cmd(android::base::StringPrintf("download:%08x", size));
245 return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0;
246}
247
248int64_t fb_upload_data(Transport* transport, const char* outfile) {
249 // positive return value is the upload size sent by the device
250 int64_t r = _command_start(transport, "upload", std::numeric_limits<int32_t>::max(), nullptr);
251 if (r <= 0) {
252 g_error = android::base::StringPrintf("command start failed (%s)", strerror(errno));
253 return r;
254 }
255
256 std::string data;
257 data.resize(r);
258 if ((r = _command_read_data(transport, &data[0], data.size())) == -1) {
259 return r;
260 }
261
262 if (!WriteStringToFile(data, outfile, true)) {
263 g_error = android::base::StringPrintf("write to '%s' failed", outfile);
264 return -1;
265 }
266
267 return _command_end(transport);
187} 268}
188 269
189#define TRANSPORT_BUF_SIZE 1024 270#define TRANSPORT_BUF_SIZE 1024
@@ -207,7 +288,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len)
207 } 288 }
208 289
209 if (transport_buf_len == TRANSPORT_BUF_SIZE) { 290 if (transport_buf_len == TRANSPORT_BUF_SIZE) {
210 r = _command_data(transport, transport_buf, TRANSPORT_BUF_SIZE); 291 r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
211 if (r != TRANSPORT_BUF_SIZE) { 292 if (r != TRANSPORT_BUF_SIZE) {
212 return -1; 293 return -1;
213 } 294 }
@@ -220,7 +301,7 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len)
220 return -1; 301 return -1;
221 } 302 }
222 to_write = round_down(len, TRANSPORT_BUF_SIZE); 303 to_write = round_down(len, TRANSPORT_BUF_SIZE);
223 r = _command_data(transport, ptr, to_write); 304 r = _command_write_data(transport, ptr, to_write);
224 if (r != to_write) { 305 if (r != to_write) {
225 return -1; 306 return -1;
226 } 307 }
@@ -242,7 +323,8 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len)
242 323
243static int fb_download_data_sparse_flush(Transport* transport) { 324static int fb_download_data_sparse_flush(Transport* transport) {
244 if (transport_buf_len > 0) { 325 if (transport_buf_len > 0) {
245 if (_command_data(transport, transport_buf, transport_buf_len) != transport_buf_len) { 326 int64_t r = _command_write_data(transport, transport_buf, transport_buf_len);
327 if (r != static_cast<int64_t>(transport_buf_len)) {
246 return -1; 328 return -1;
247 } 329 }
248 transport_buf_len = 0; 330 transport_buf_len = 0;
@@ -256,9 +338,8 @@ int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
256 return -1; 338 return -1;
257 } 339 }
258 340
259 char cmd[64]; 341 std::string cmd(android::base::StringPrintf("download:%08x", size));
260 snprintf(cmd, sizeof(cmd), "download:%08x", size); 342 int r = _command_start(transport, cmd.c_str(), size, 0);
261 int r = _command_start(transport, cmd, size, 0);
262 if (r < 0) { 343 if (r < 0) {
263 return -1; 344 return -1;
264 } 345 }