diff options
Diffstat (limited to 'fastboot/protocol.cpp')
-rw-r--r-- | fastboot/protocol.cpp | 125 |
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 | ||
45 | static std::string g_error; | 50 | static std::string g_error; |
46 | 51 | ||
52 | using android::base::unique_fd; | ||
53 | using android::base::WriteStringToFile; | ||
54 | |||
47 | const std::string fb_get_error() { | 55 | const std::string fb_get_error() { |
48 | return g_error; | 56 | return g_error; |
49 | } | 57 | } |
50 | 58 | ||
51 | static int check_response(Transport* transport, uint32_t size, char* response) { | 59 | static 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 | ||
108 | static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) { | 116 | static 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 | ||
128 | static int _command_data(Transport* transport, const void* data, uint32_t size) { | 136 | static 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 | |||
151 | static 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 | ||
143 | static int _command_end(Transport* transport) { | 166 | static 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 | ||
147 | static int _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size, | 170 | static 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 | ||
193 | static 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 | |||
171 | static int _command_send_no_data(Transport* transport, const char* cmd, char* response) { | 226 | static 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 | ||
183 | int fb_download_data(Transport* transport, const void* data, uint32_t size) { | 238 | int64_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 | |||
243 | int64_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 | |||
248 | int64_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 | ||
243 | static int fb_download_data_sparse_flush(Transport* transport) { | 324 | static 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 | } |