blob: fda6f5dcbabbc41fe704d7cb24eab57485528252 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080012 * the documentation and/or other materials provided with the
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080013 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080022 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080023 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
Colin Crossf8387882012-05-24 17:18:41 -070029#define round_down(a, b) \
30 ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); })
31
Jocelyn Bohr91fefad2017-01-27 14:17:56 -080032#include <fcntl.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080033#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <errno.h>
37
Elliott Hughesfc797672015-04-07 20:12:50 -070038#include <algorithm>
Jocelyn Bohr91fefad2017-01-27 14:17:56 -080039#include <vector>
Elliott Hughesfc797672015-04-07 20:12:50 -070040
Jocelyn Bohr91fefad2017-01-27 14:17:56 -080041#include <android-base/file.h>
Elliott Hughes2810d002016-04-25 14:31:18 -070042#include <android-base/stringprintf.h>
Jocelyn Bohr91fefad2017-01-27 14:17:56 -080043#include <android-base/unique_fd.h>
Colin Crossf8387882012-05-24 17:18:41 -070044#include <sparse/sparse.h>
Chris Fries0ea946c2017-04-12 10:25:57 -050045#include <utils/FileMap.h>
Colin Crossf8387882012-05-24 17:18:41 -070046
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080047#include "fastboot.h"
David Pursell0b156632015-10-30 11:22:01 -070048#include "transport.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080049
Elliott Hughes2810d002016-04-25 14:31:18 -070050static std::string g_error;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080051
Jocelyn Bohr91fefad2017-01-27 14:17:56 -080052using android::base::unique_fd;
53using android::base::WriteStringToFile;
54
Elliott Hughes2810d002016-04-25 14:31:18 -070055const std::string fb_get_error() {
56 return g_error;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080057}
58
Chris Fries6a999712017-04-04 09:52:47 -050059static int64_t check_response(Transport* transport, uint32_t size, char* response) {
Elliott Hughes6ebec932018-04-10 14:22:13 -070060 char status[FB_RESPONSE_SZ + 1];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080061
Elliott Hughesfc797672015-04-07 20:12:50 -070062 while (true) {
Elliott Hughes6ebec932018-04-10 14:22:13 -070063 int r = transport->Read(status, FB_RESPONSE_SZ);
Elliott Hughesfc797672015-04-07 20:12:50 -070064 if (r < 0) {
Elliott Hughes2810d002016-04-25 14:31:18 -070065 g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -070066 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080067 return -1;
68 }
69 status[r] = 0;
70
Elliott Hughesfc797672015-04-07 20:12:50 -070071 if (r < 4) {
Elliott Hughes2810d002016-04-25 14:31:18 -070072 g_error = android::base::StringPrintf("status malformed (%d bytes)", r);
David Pursell0b156632015-10-30 11:22:01 -070073 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080074 return -1;
75 }
76
Elliott Hughesfc797672015-04-07 20:12:50 -070077 if (!memcmp(status, "INFO", 4)) {
Elliott Hughes234910b2018-04-10 15:34:19 -070078 verbose("received INFO \"%s\"", status + 4);
Elliott Hughes855cdf82018-04-02 14:24:03 -070079 fprintf(stderr, "(bootloader) %s\n", status + 4);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080080 continue;
81 }
82
Elliott Hughesfc797672015-04-07 20:12:50 -070083 if (!memcmp(status, "OKAY", 4)) {
Elliott Hughes234910b2018-04-10 15:34:19 -070084 verbose("received OKAY \"%s\"", status + 4);
Elliott Hughesfc797672015-04-07 20:12:50 -070085 if (response) {
Elliott Hughes855cdf82018-04-02 14:24:03 -070086 strcpy(response, status + 4);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080087 }
88 return 0;
89 }
90
Elliott Hughesfc797672015-04-07 20:12:50 -070091 if (!memcmp(status, "FAIL", 4)) {
Elliott Hughes234910b2018-04-10 15:34:19 -070092 verbose("received FAIL \"%s\"", status + 4);
Elliott Hughesfc797672015-04-07 20:12:50 -070093 if (r > 4) {
Elliott Hughes2810d002016-04-25 14:31:18 -070094 g_error = android::base::StringPrintf("remote: %s", status + 4);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080095 } else {
Elliott Hughes2810d002016-04-25 14:31:18 -070096 g_error = "remote failure";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080097 }
98 return -1;
99 }
100
Elliott Hughesfc797672015-04-07 20:12:50 -0700101 if (!memcmp(status, "DATA", 4) && size > 0){
Elliott Hughes855cdf82018-04-02 14:24:03 -0700102 verbose("received DATA %s", status + 4);
Elliott Hughesfc797672015-04-07 20:12:50 -0700103 uint32_t dsize = strtol(status + 4, 0, 16);
104 if (dsize > size) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700105 g_error = android::base::StringPrintf("data size too large (%d)", dsize);
David Pursell0b156632015-10-30 11:22:01 -0700106 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800107 return -1;
108 }
109 return dsize;
110 }
111
Elliott Hughes855cdf82018-04-02 14:24:03 -0700112 verbose("received unknown status code \"%4.4s\"", status);
Elliott Hughes2810d002016-04-25 14:31:18 -0700113 g_error = "unknown status code";
David Pursell0b156632015-10-30 11:22:01 -0700114 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800115 break;
116 }
117
118 return -1;
119}
120
Elliott Hughes5620d222018-03-28 08:20:00 -0700121static int64_t _command_start(Transport* transport, const std::string& cmd, uint32_t size,
122 char* response) {
Elliott Hughes6ebec932018-04-10 14:22:13 -0700123 if (cmd.size() > FB_COMMAND_SZ) {
Elliott Hughes5620d222018-03-28 08:20:00 -0700124 g_error = android::base::StringPrintf("command too large (%zu)", cmd.size());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800125 return -1;
126 }
127
Elliott Hughesfc797672015-04-07 20:12:50 -0700128 if (response) {
129 response[0] = 0;
130 }
131
Elliott Hughes855cdf82018-04-02 14:24:03 -0700132 verbose("sending command \"%s\"", cmd.c_str());
133
Elliott Hughes5620d222018-03-28 08:20:00 -0700134 if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700135 g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -0700136 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800137 return -1;
138 }
139
David Pursell0b156632015-10-30 11:22:01 -0700140 return check_response(transport, size, response);
Colin Crossf8387882012-05-24 17:18:41 -0700141}
142
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800143static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) {
Elliott Hughes855cdf82018-04-02 14:24:03 -0700144 verbose("sending data (%" PRIu32 " bytes)", size);
145
Chris Fries6a999712017-04-04 09:52:47 -0500146 int64_t r = transport->Write(data, size);
Elliott Hughesfc797672015-04-07 20:12:50 -0700147 if (r < 0) {
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800148 g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -0700149 transport->Close();
Colin Crossf8387882012-05-24 17:18:41 -0700150 return -1;
151 }
Chris Fries6a999712017-04-04 09:52:47 -0500152 if (r != static_cast<int64_t>(size)) {
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800153 g_error = "data write failure (short transfer)";
154 transport->Close();
155 return -1;
156 }
157 return r;
158}
159
160static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) {
Elliott Hughes855cdf82018-04-02 14:24:03 -0700161 verbose("reading data (%" PRIu32 " bytes)", size);
162
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800163 int64_t r = transport->Read(data, size);
164 if (r < 0) {
165 g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno));
166 transport->Close();
167 return -1;
168 }
169 if (r != (static_cast<int64_t>(size))) {
170 g_error = "data read failure (short transfer)";
David Pursell0b156632015-10-30 11:22:01 -0700171 transport->Close();
Colin Crossf8387882012-05-24 17:18:41 -0700172 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800173 }
Colin Crossf8387882012-05-24 17:18:41 -0700174 return r;
175}
176
Chris Fries6a999712017-04-04 09:52:47 -0500177static int64_t _command_end(Transport* transport) {
David Pursell0b156632015-10-30 11:22:01 -0700178 return check_response(transport, 0, 0) < 0 ? -1 : 0;
Colin Crossf8387882012-05-24 17:18:41 -0700179}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800180
Elliott Hughes5620d222018-03-28 08:20:00 -0700181static int64_t _command_send(Transport* transport, const std::string& cmd, const void* data,
182 uint32_t size, char* response) {
Colin Crossf8387882012-05-24 17:18:41 -0700183 if (size == 0) {
184 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800185 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800186
Chris Fries6a999712017-04-04 09:52:47 -0500187 int64_t r = _command_start(transport, cmd, size, response);
Colin Crossf8387882012-05-24 17:18:41 -0700188 if (r < 0) {
189 return -1;
190 }
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800191 r = _command_write_data(transport, data, size);
Colin Crossf8387882012-05-24 17:18:41 -0700192 if (r < 0) {
193 return -1;
194 }
195
David Pursell0b156632015-10-30 11:22:01 -0700196 r = _command_end(transport);
Elliott Hughesfc797672015-04-07 20:12:50 -0700197 if (r < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800198 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800199 }
Colin Crossf8387882012-05-24 17:18:41 -0700200
201 return size;
202}
203
Elliott Hughes5620d222018-03-28 08:20:00 -0700204static int64_t _command_send_fd(Transport* transport, const std::string& cmd, int fd, uint32_t size,
Chris Fries0ea946c2017-04-12 10:25:57 -0500205 char* response) {
206 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
207 off64_t offset = 0;
208 uint32_t remaining = size;
209
210 if (_command_start(transport, cmd, size, response) < 0) {
211 return -1;
212 }
213
214 while (remaining) {
215 android::FileMap filemap;
216 size_t len = std::min(remaining, MAX_MAP_SIZE);
217
218 if (!filemap.create(NULL, fd, offset, len, true)) {
219 return -1;
220 }
221
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800222 if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) {
Chris Fries0ea946c2017-04-12 10:25:57 -0500223 return -1;
224 }
225
226 remaining -= len;
227 offset += len;
228 }
229
230 if (_command_end(transport) < 0) {
231 return -1;
232 }
233
234 return size;
235}
236
Elliott Hughes5620d222018-03-28 08:20:00 -0700237static int _command_send_no_data(Transport* transport, const std::string& cmd, char* response) {
David Pursell0b156632015-10-30 11:22:01 -0700238 return _command_start(transport, cmd, 0, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800239}
240
Elliott Hughes5620d222018-03-28 08:20:00 -0700241int fb_command(Transport* transport, const std::string& cmd) {
David Pursell0b156632015-10-30 11:22:01 -0700242 return _command_send_no_data(transport, cmd, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800243}
244
Elliott Hughes5620d222018-03-28 08:20:00 -0700245int fb_command_response(Transport* transport, const std::string& cmd, char* response) {
David Pursell0b156632015-10-30 11:22:01 -0700246 return _command_send_no_data(transport, cmd, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800247}
248
Chris Fries6a999712017-04-04 09:52:47 -0500249int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) {
Chris Fries0ea946c2017-04-12 10:25:57 -0500250 std::string cmd(android::base::StringPrintf("download:%08x", size));
251 return _command_send(transport, cmd.c_str(), data, size, 0) < 0 ? -1 : 0;
252}
253
254int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) {
255 std::string cmd(android::base::StringPrintf("download:%08x", size));
256 return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800257}
258
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800259int64_t fb_upload_data(Transport* transport, const char* outfile) {
260 // positive return value is the upload size sent by the device
261 int64_t r = _command_start(transport, "upload", std::numeric_limits<int32_t>::max(), nullptr);
262 if (r <= 0) {
263 g_error = android::base::StringPrintf("command start failed (%s)", strerror(errno));
264 return r;
265 }
266
267 std::string data;
268 data.resize(r);
269 if ((r = _command_read_data(transport, &data[0], data.size())) == -1) {
270 return r;
271 }
272
273 if (!WriteStringToFile(data, outfile, true)) {
274 g_error = android::base::StringPrintf("write to '%s' failed", outfile);
275 return -1;
276 }
277
278 return _command_end(transport);
279}
280
Tao Bao7d27ffd2018-04-23 17:24:17 -0700281static constexpr size_t TRANSPORT_BUF_SIZE = 1024;
David Pursell0b156632015-10-30 11:22:01 -0700282static char transport_buf[TRANSPORT_BUF_SIZE];
Tao Bao7d27ffd2018-04-23 17:24:17 -0700283static size_t transport_buf_len;
Colin Crossf8387882012-05-24 17:18:41 -0700284
Tao Bao7d27ffd2018-04-23 17:24:17 -0700285static int fb_download_data_sparse_write(void* priv, const void* data, size_t len) {
286 const char* ptr = static_cast<const char*>(data);
David Pursell0b156632015-10-30 11:22:01 -0700287 if (transport_buf_len) {
Tao Bao7d27ffd2018-04-23 17:24:17 -0700288 size_t to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
Colin Crossf8387882012-05-24 17:18:41 -0700289
David Pursell0b156632015-10-30 11:22:01 -0700290 memcpy(transport_buf + transport_buf_len, ptr, to_write);
291 transport_buf_len += to_write;
Colin Crossf8387882012-05-24 17:18:41 -0700292 ptr += to_write;
293 len -= to_write;
294 }
295
Tao Bao7d27ffd2018-04-23 17:24:17 -0700296 Transport* transport = static_cast<Transport*>(priv);
David Pursell0b156632015-10-30 11:22:01 -0700297 if (transport_buf_len == TRANSPORT_BUF_SIZE) {
Tao Bao7d27ffd2018-04-23 17:24:17 -0700298 int64_t r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
299 if (r != static_cast<int64_t>(TRANSPORT_BUF_SIZE)) {
Colin Crossf8387882012-05-24 17:18:41 -0700300 return -1;
301 }
David Pursell0b156632015-10-30 11:22:01 -0700302 transport_buf_len = 0;
Colin Crossf8387882012-05-24 17:18:41 -0700303 }
304
David Pursell0b156632015-10-30 11:22:01 -0700305 if (len > TRANSPORT_BUF_SIZE) {
306 if (transport_buf_len > 0) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700307 g_error = "internal error: transport_buf not empty";
Colin Crossf8387882012-05-24 17:18:41 -0700308 return -1;
309 }
Tao Bao7d27ffd2018-04-23 17:24:17 -0700310 size_t to_write = round_down(len, TRANSPORT_BUF_SIZE);
311 int64_t r = _command_write_data(transport, ptr, to_write);
312 if (r != static_cast<int64_t>(to_write)) {
Colin Crossf8387882012-05-24 17:18:41 -0700313 return -1;
314 }
315 ptr += to_write;
316 len -= to_write;
317 }
318
319 if (len > 0) {
David Pursell0b156632015-10-30 11:22:01 -0700320 if (len > TRANSPORT_BUF_SIZE) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700321 g_error = "internal error: too much left for transport_buf";
Colin Crossf8387882012-05-24 17:18:41 -0700322 return -1;
323 }
David Pursell0b156632015-10-30 11:22:01 -0700324 memcpy(transport_buf, ptr, len);
325 transport_buf_len = len;
Colin Crossf8387882012-05-24 17:18:41 -0700326 }
327
328 return 0;
329}
330
David Pursell0b156632015-10-30 11:22:01 -0700331static int fb_download_data_sparse_flush(Transport* transport) {
332 if (transport_buf_len > 0) {
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800333 int64_t r = _command_write_data(transport, transport_buf, transport_buf_len);
Chris Fries6a999712017-04-04 09:52:47 -0500334 if (r != static_cast<int64_t>(transport_buf_len)) {
Colin Crossf8387882012-05-24 17:18:41 -0700335 return -1;
336 }
David Pursell0b156632015-10-30 11:22:01 -0700337 transport_buf_len = 0;
Colin Crossf8387882012-05-24 17:18:41 -0700338 }
Colin Crossf8387882012-05-24 17:18:41 -0700339 return 0;
340}
341
David Pursell0b156632015-10-30 11:22:01 -0700342int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
Tao Bao41cf35f2018-04-24 10:54:21 -0700343 int64_t size = sparse_file_len(s, true, false);
344 if (size <= 0 || size > std::numeric_limits<uint32_t>::max()) {
Colin Crossf8387882012-05-24 17:18:41 -0700345 return -1;
346 }
347
Tao Bao41cf35f2018-04-24 10:54:21 -0700348 std::string cmd(android::base::StringPrintf("download:%08" PRIx64, size));
Elliott Hughes5620d222018-03-28 08:20:00 -0700349 int r = _command_start(transport, cmd, size, 0);
Colin Crossf8387882012-05-24 17:18:41 -0700350 if (r < 0) {
351 return -1;
352 }
353
David Pursell0b156632015-10-30 11:22:01 -0700354 r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, transport);
Colin Crossf8387882012-05-24 17:18:41 -0700355 if (r < 0) {
356 return -1;
357 }
358
David Pursell0b156632015-10-30 11:22:01 -0700359 r = fb_download_data_sparse_flush(transport);
Jeremy Compostella9f0d6bd2015-02-22 10:47:16 +0100360 if (r < 0) {
361 return -1;
362 }
Colin Crossf8387882012-05-24 17:18:41 -0700363
David Pursell0b156632015-10-30 11:22:01 -0700364 return _command_end(transport);
Colin Crossf8387882012-05-24 17:18:41 -0700365}