blob: dcdf8f0c1bd0eb1575b6cfc8af3ee788d977433b [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 Hughesfc797672015-04-07 20:12:50 -070060 char status[65];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080061
Elliott Hughesfc797672015-04-07 20:12:50 -070062 while (true) {
David Pursell0b156632015-10-30 11:22:01 -070063 int r = transport->Read(status, 64);
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)) {
Brian Swetland63e52052010-06-28 11:14:26 -070078 fprintf(stderr,"(bootloader) %s\n", status + 4);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080079 continue;
80 }
81
Elliott Hughesfc797672015-04-07 20:12:50 -070082 if (!memcmp(status, "OKAY", 4)) {
83 if (response) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080084 strcpy(response, (char*) status + 4);
85 }
86 return 0;
87 }
88
Elliott Hughesfc797672015-04-07 20:12:50 -070089 if (!memcmp(status, "FAIL", 4)) {
90 if (r > 4) {
Elliott Hughes2810d002016-04-25 14:31:18 -070091 g_error = android::base::StringPrintf("remote: %s", status + 4);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080092 } else {
Elliott Hughes2810d002016-04-25 14:31:18 -070093 g_error = "remote failure";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080094 }
95 return -1;
96 }
97
Elliott Hughesfc797672015-04-07 20:12:50 -070098 if (!memcmp(status, "DATA", 4) && size > 0){
99 uint32_t dsize = strtol(status + 4, 0, 16);
100 if (dsize > size) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700101 g_error = android::base::StringPrintf("data size too large (%d)", dsize);
David Pursell0b156632015-10-30 11:22:01 -0700102 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800103 return -1;
104 }
105 return dsize;
106 }
107
Elliott Hughes2810d002016-04-25 14:31:18 -0700108 g_error = "unknown status code";
David Pursell0b156632015-10-30 11:22:01 -0700109 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800110 break;
111 }
112
113 return -1;
114}
115
Chris Fries6a999712017-04-04 09:52:47 -0500116static int64_t _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
Elliott Hughesfc797672015-04-07 20:12:50 -0700117 size_t cmdsize = strlen(cmd);
118 if (cmdsize > 64) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700119 g_error = android::base::StringPrintf("command too large (%zu)", cmdsize);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800120 return -1;
121 }
122
Elliott Hughesfc797672015-04-07 20:12:50 -0700123 if (response) {
124 response[0] = 0;
125 }
126
David Pursell0b156632015-10-30 11:22:01 -0700127 if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700128 g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -0700129 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800130 return -1;
131 }
132
David Pursell0b156632015-10-30 11:22:01 -0700133 return check_response(transport, size, response);
Colin Crossf8387882012-05-24 17:18:41 -0700134}
135
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800136static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) {
Chris Fries6a999712017-04-04 09:52:47 -0500137 int64_t r = transport->Write(data, size);
Elliott Hughesfc797672015-04-07 20:12:50 -0700138 if (r < 0) {
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800139 g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -0700140 transport->Close();
Colin Crossf8387882012-05-24 17:18:41 -0700141 return -1;
142 }
Chris Fries6a999712017-04-04 09:52:47 -0500143 if (r != static_cast<int64_t>(size)) {
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800144 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);
153 if (r < 0) {
154 g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno));
155 transport->Close();
156 return -1;
157 }
158 if (r != (static_cast<int64_t>(size))) {
159 g_error = "data read failure (short transfer)";
David Pursell0b156632015-10-30 11:22:01 -0700160 transport->Close();
Colin Crossf8387882012-05-24 17:18:41 -0700161 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800162 }
Colin Crossf8387882012-05-24 17:18:41 -0700163 return r;
164}
165
Chris Fries6a999712017-04-04 09:52:47 -0500166static int64_t _command_end(Transport* transport) {
David Pursell0b156632015-10-30 11:22:01 -0700167 return check_response(transport, 0, 0) < 0 ? -1 : 0;
Colin Crossf8387882012-05-24 17:18:41 -0700168}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800169
Chris Fries6a999712017-04-04 09:52:47 -0500170static int64_t _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size,
Elliott Hughesfc797672015-04-07 20:12:50 -0700171 char* response) {
Colin Crossf8387882012-05-24 17:18:41 -0700172 if (size == 0) {
173 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800174 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800175
Chris Fries6a999712017-04-04 09:52:47 -0500176 int64_t r = _command_start(transport, cmd, size, response);
Colin Crossf8387882012-05-24 17:18:41 -0700177 if (r < 0) {
178 return -1;
179 }
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800180 r = _command_write_data(transport, data, size);
Colin Crossf8387882012-05-24 17:18:41 -0700181 if (r < 0) {
182 return -1;
183 }
184
David Pursell0b156632015-10-30 11:22:01 -0700185 r = _command_end(transport);
Elliott Hughesfc797672015-04-07 20:12:50 -0700186 if (r < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800187 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800188 }
Colin Crossf8387882012-05-24 17:18:41 -0700189
190 return size;
191}
192
Chris Fries0ea946c2017-04-12 10:25:57 -0500193static 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
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800211 if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) {
Chris Fries0ea946c2017-04-12 10:25:57 -0500212 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
David Pursell0b156632015-10-30 11:22:01 -0700226static int _command_send_no_data(Transport* transport, const char* cmd, char* response) {
227 return _command_start(transport, cmd, 0, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800228}
229
David Pursell0b156632015-10-30 11:22:01 -0700230int fb_command(Transport* transport, const char* cmd) {
231 return _command_send_no_data(transport, cmd, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800232}
233
David Pursell0b156632015-10-30 11:22:01 -0700234int fb_command_response(Transport* transport, const char* cmd, char* response) {
235 return _command_send_no_data(transport, cmd, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800236}
237
Chris Fries6a999712017-04-04 09:52:47 -0500238int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) {
Chris Fries0ea946c2017-04-12 10:25:57 -0500239 std::string cmd(android::base::StringPrintf("download:%08x", size));
240 return _command_send(transport, cmd.c_str(), 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;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800246}
247
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800248int64_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);
268}
269
David Pursell0b156632015-10-30 11:22:01 -0700270#define TRANSPORT_BUF_SIZE 1024
271static char transport_buf[TRANSPORT_BUF_SIZE];
272static int transport_buf_len;
Colin Crossf8387882012-05-24 17:18:41 -0700273
274static int fb_download_data_sparse_write(void *priv, const void *data, int len)
275{
276 int r;
David Pursell0b156632015-10-30 11:22:01 -0700277 Transport* transport = reinterpret_cast<Transport*>(priv);
Colin Crossf8387882012-05-24 17:18:41 -0700278 int to_write;
Elliott Hughesb3748de2015-06-23 20:27:58 -0700279 const char* ptr = reinterpret_cast<const char*>(data);
Colin Crossf8387882012-05-24 17:18:41 -0700280
David Pursell0b156632015-10-30 11:22:01 -0700281 if (transport_buf_len) {
282 to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
Colin Crossf8387882012-05-24 17:18:41 -0700283
David Pursell0b156632015-10-30 11:22:01 -0700284 memcpy(transport_buf + transport_buf_len, ptr, to_write);
285 transport_buf_len += to_write;
Colin Crossf8387882012-05-24 17:18:41 -0700286 ptr += to_write;
287 len -= to_write;
288 }
289
David Pursell0b156632015-10-30 11:22:01 -0700290 if (transport_buf_len == TRANSPORT_BUF_SIZE) {
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800291 r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
David Pursell0b156632015-10-30 11:22:01 -0700292 if (r != TRANSPORT_BUF_SIZE) {
Colin Crossf8387882012-05-24 17:18:41 -0700293 return -1;
294 }
David Pursell0b156632015-10-30 11:22:01 -0700295 transport_buf_len = 0;
Colin Crossf8387882012-05-24 17:18:41 -0700296 }
297
David Pursell0b156632015-10-30 11:22:01 -0700298 if (len > TRANSPORT_BUF_SIZE) {
299 if (transport_buf_len > 0) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700300 g_error = "internal error: transport_buf not empty";
Colin Crossf8387882012-05-24 17:18:41 -0700301 return -1;
302 }
David Pursell0b156632015-10-30 11:22:01 -0700303 to_write = round_down(len, TRANSPORT_BUF_SIZE);
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800304 r = _command_write_data(transport, ptr, to_write);
Colin Crossf8387882012-05-24 17:18:41 -0700305 if (r != to_write) {
306 return -1;
307 }
308 ptr += to_write;
309 len -= to_write;
310 }
311
312 if (len > 0) {
David Pursell0b156632015-10-30 11:22:01 -0700313 if (len > TRANSPORT_BUF_SIZE) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700314 g_error = "internal error: too much left for transport_buf";
Colin Crossf8387882012-05-24 17:18:41 -0700315 return -1;
316 }
David Pursell0b156632015-10-30 11:22:01 -0700317 memcpy(transport_buf, ptr, len);
318 transport_buf_len = len;
Colin Crossf8387882012-05-24 17:18:41 -0700319 }
320
321 return 0;
322}
323
David Pursell0b156632015-10-30 11:22:01 -0700324static int fb_download_data_sparse_flush(Transport* transport) {
325 if (transport_buf_len > 0) {
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800326 int64_t r = _command_write_data(transport, transport_buf, transport_buf_len);
Chris Fries6a999712017-04-04 09:52:47 -0500327 if (r != static_cast<int64_t>(transport_buf_len)) {
Colin Crossf8387882012-05-24 17:18:41 -0700328 return -1;
329 }
David Pursell0b156632015-10-30 11:22:01 -0700330 transport_buf_len = 0;
Colin Crossf8387882012-05-24 17:18:41 -0700331 }
Colin Crossf8387882012-05-24 17:18:41 -0700332 return 0;
333}
334
David Pursell0b156632015-10-30 11:22:01 -0700335int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
Colin Crossf8387882012-05-24 17:18:41 -0700336 int size = sparse_file_len(s, true, false);
337 if (size <= 0) {
338 return -1;
339 }
340
Chris Fries0ea946c2017-04-12 10:25:57 -0500341 std::string cmd(android::base::StringPrintf("download:%08x", size));
342 int r = _command_start(transport, cmd.c_str(), size, 0);
Colin Crossf8387882012-05-24 17:18:41 -0700343 if (r < 0) {
344 return -1;
345 }
346
David Pursell0b156632015-10-30 11:22:01 -0700347 r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, transport);
Colin Crossf8387882012-05-24 17:18:41 -0700348 if (r < 0) {
349 return -1;
350 }
351
David Pursell0b156632015-10-30 11:22:01 -0700352 r = fb_download_data_sparse_flush(transport);
Jeremy Compostella9f0d6bd2015-02-22 10:47:16 +0100353 if (r < 0) {
354 return -1;
355 }
Colin Crossf8387882012-05-24 17:18:41 -0700356
David Pursell0b156632015-10-30 11:22:01 -0700357 return _command_end(transport);
Colin Crossf8387882012-05-24 17:18:41 -0700358}