blob: e625095fc26591d1abd9204864a0920166eb8582 [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
Jerry Zhang769a9c12018-05-15 17:02:50 -070047#include "constants.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080048#include "fastboot.h"
David Pursell0b156632015-10-30 11:22:01 -070049#include "transport.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080050
Elliott Hughes2810d002016-04-25 14:31:18 -070051static std::string g_error;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080052
Jocelyn Bohr91fefad2017-01-27 14:17:56 -080053using android::base::unique_fd;
54using android::base::WriteStringToFile;
55
Elliott Hughes2810d002016-04-25 14:31:18 -070056const std::string fb_get_error() {
57 return g_error;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080058}
59
Chris Fries6a999712017-04-04 09:52:47 -050060static int64_t check_response(Transport* transport, uint32_t size, char* response) {
Elliott Hughes6ebec932018-04-10 14:22:13 -070061 char status[FB_RESPONSE_SZ + 1];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080062
Elliott Hughesfc797672015-04-07 20:12:50 -070063 while (true) {
Elliott Hughes6ebec932018-04-10 14:22:13 -070064 int r = transport->Read(status, FB_RESPONSE_SZ);
Elliott Hughesfc797672015-04-07 20:12:50 -070065 if (r < 0) {
Elliott Hughes2810d002016-04-25 14:31:18 -070066 g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -070067 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080068 return -1;
69 }
70 status[r] = 0;
71
Jerry Zhang769a9c12018-05-15 17:02:50 -070072 if (static_cast<size_t>(r) < strlen(RESPONSE_OKAY)) {
Elliott Hughes2810d002016-04-25 14:31:18 -070073 g_error = android::base::StringPrintf("status malformed (%d bytes)", r);
David Pursell0b156632015-10-30 11:22:01 -070074 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080075 return -1;
76 }
77
Jerry Zhang769a9c12018-05-15 17:02:50 -070078 if (!memcmp(status, RESPONSE_INFO, strlen(RESPONSE_INFO))) {
79 verbose("received INFO \"%s\"", status + strlen(RESPONSE_INFO));
80 fprintf(stderr, "(bootloader) %s\n", status + strlen(RESPONSE_INFO));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080081 continue;
82 }
83
Jerry Zhang769a9c12018-05-15 17:02:50 -070084 if (!memcmp(status, RESPONSE_OKAY, strlen(RESPONSE_OKAY))) {
85 verbose("received OKAY \"%s\"", status + strlen(RESPONSE_OKAY));
Elliott Hughesfc797672015-04-07 20:12:50 -070086 if (response) {
Jerry Zhang769a9c12018-05-15 17:02:50 -070087 strcpy(response, status + strlen(RESPONSE_OKAY));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080088 }
89 return 0;
90 }
91
Jerry Zhang769a9c12018-05-15 17:02:50 -070092 if (!memcmp(status, RESPONSE_FAIL, strlen(RESPONSE_FAIL))) {
93 verbose("received FAIL \"%s\"", status + strlen(RESPONSE_FAIL));
94 if (static_cast<size_t>(r) > strlen(RESPONSE_FAIL)) {
95 g_error = android::base::StringPrintf("remote: %s", status + strlen(RESPONSE_FAIL));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080096 } else {
Elliott Hughes2810d002016-04-25 14:31:18 -070097 g_error = "remote failure";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080098 }
99 return -1;
100 }
101
Jerry Zhang769a9c12018-05-15 17:02:50 -0700102 if (!memcmp(status, RESPONSE_DATA, strlen(RESPONSE_DATA)) && size > 0){
103 verbose("received DATA %s", status + strlen(RESPONSE_DATA));
104 uint32_t dsize = strtol(status + strlen(RESPONSE_DATA), 0, 16);
Elliott Hughesfc797672015-04-07 20:12:50 -0700105 if (dsize > size) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700106 g_error = android::base::StringPrintf("data size too large (%d)", dsize);
David Pursell0b156632015-10-30 11:22:01 -0700107 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800108 return -1;
109 }
110 return dsize;
111 }
112
Elliott Hughes855cdf82018-04-02 14:24:03 -0700113 verbose("received unknown status code \"%4.4s\"", status);
Elliott Hughes2810d002016-04-25 14:31:18 -0700114 g_error = "unknown status code";
David Pursell0b156632015-10-30 11:22:01 -0700115 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800116 break;
117 }
118
119 return -1;
120}
121
Elliott Hughes5620d222018-03-28 08:20:00 -0700122static int64_t _command_start(Transport* transport, const std::string& cmd, uint32_t size,
123 char* response) {
Elliott Hughes6ebec932018-04-10 14:22:13 -0700124 if (cmd.size() > FB_COMMAND_SZ) {
Elliott Hughes5620d222018-03-28 08:20:00 -0700125 g_error = android::base::StringPrintf("command too large (%zu)", cmd.size());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800126 return -1;
127 }
128
Elliott Hughesfc797672015-04-07 20:12:50 -0700129 if (response) {
130 response[0] = 0;
131 }
132
Elliott Hughes855cdf82018-04-02 14:24:03 -0700133 verbose("sending command \"%s\"", cmd.c_str());
134
Elliott Hughes5620d222018-03-28 08:20:00 -0700135 if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700136 g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -0700137 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800138 return -1;
139 }
140
David Pursell0b156632015-10-30 11:22:01 -0700141 return check_response(transport, size, response);
Colin Crossf8387882012-05-24 17:18:41 -0700142}
143
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800144static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) {
Elliott Hughes855cdf82018-04-02 14:24:03 -0700145 verbose("sending data (%" PRIu32 " bytes)", size);
146
Chris Fries6a999712017-04-04 09:52:47 -0500147 int64_t r = transport->Write(data, size);
Elliott Hughesfc797672015-04-07 20:12:50 -0700148 if (r < 0) {
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800149 g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -0700150 transport->Close();
Colin Crossf8387882012-05-24 17:18:41 -0700151 return -1;
152 }
Chris Fries6a999712017-04-04 09:52:47 -0500153 if (r != static_cast<int64_t>(size)) {
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800154 g_error = "data write failure (short transfer)";
155 transport->Close();
156 return -1;
157 }
158 return r;
159}
160
161static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) {
Elliott Hughes855cdf82018-04-02 14:24:03 -0700162 verbose("reading data (%" PRIu32 " bytes)", size);
163
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800164 int64_t r = transport->Read(data, size);
165 if (r < 0) {
166 g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno));
167 transport->Close();
168 return -1;
169 }
170 if (r != (static_cast<int64_t>(size))) {
171 g_error = "data read failure (short transfer)";
David Pursell0b156632015-10-30 11:22:01 -0700172 transport->Close();
Colin Crossf8387882012-05-24 17:18:41 -0700173 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800174 }
Colin Crossf8387882012-05-24 17:18:41 -0700175 return r;
176}
177
Chris Fries6a999712017-04-04 09:52:47 -0500178static int64_t _command_end(Transport* transport) {
David Pursell0b156632015-10-30 11:22:01 -0700179 return check_response(transport, 0, 0) < 0 ? -1 : 0;
Colin Crossf8387882012-05-24 17:18:41 -0700180}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800181
Elliott Hughes5620d222018-03-28 08:20:00 -0700182static int64_t _command_send(Transport* transport, const std::string& cmd, const void* data,
183 uint32_t size, char* response) {
Colin Crossf8387882012-05-24 17:18:41 -0700184 if (size == 0) {
185 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800186 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800187
Chris Fries6a999712017-04-04 09:52:47 -0500188 int64_t r = _command_start(transport, cmd, size, response);
Colin Crossf8387882012-05-24 17:18:41 -0700189 if (r < 0) {
190 return -1;
191 }
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800192 r = _command_write_data(transport, data, size);
Colin Crossf8387882012-05-24 17:18:41 -0700193 if (r < 0) {
194 return -1;
195 }
196
David Pursell0b156632015-10-30 11:22:01 -0700197 r = _command_end(transport);
Elliott Hughesfc797672015-04-07 20:12:50 -0700198 if (r < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800199 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800200 }
Colin Crossf8387882012-05-24 17:18:41 -0700201
202 return size;
203}
204
Elliott Hughes5620d222018-03-28 08:20:00 -0700205static int64_t _command_send_fd(Transport* transport, const std::string& cmd, int fd, uint32_t size,
Chris Fries0ea946c2017-04-12 10:25:57 -0500206 char* response) {
207 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
208 off64_t offset = 0;
209 uint32_t remaining = size;
210
211 if (_command_start(transport, cmd, size, response) < 0) {
212 return -1;
213 }
214
215 while (remaining) {
216 android::FileMap filemap;
217 size_t len = std::min(remaining, MAX_MAP_SIZE);
218
219 if (!filemap.create(NULL, fd, offset, len, true)) {
220 return -1;
221 }
222
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800223 if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) {
Chris Fries0ea946c2017-04-12 10:25:57 -0500224 return -1;
225 }
226
227 remaining -= len;
228 offset += len;
229 }
230
231 if (_command_end(transport) < 0) {
232 return -1;
233 }
234
235 return size;
236}
237
Elliott Hughes5620d222018-03-28 08:20:00 -0700238static int _command_send_no_data(Transport* transport, const std::string& cmd, char* response) {
David Pursell0b156632015-10-30 11:22:01 -0700239 return _command_start(transport, cmd, 0, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800240}
241
Elliott Hughes5620d222018-03-28 08:20:00 -0700242int fb_command(Transport* transport, const std::string& cmd) {
David Pursell0b156632015-10-30 11:22:01 -0700243 return _command_send_no_data(transport, cmd, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800244}
245
Elliott Hughes5620d222018-03-28 08:20:00 -0700246int fb_command_response(Transport* transport, const std::string& cmd, char* response) {
David Pursell0b156632015-10-30 11:22:01 -0700247 return _command_send_no_data(transport, cmd, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800248}
249
Chris Fries6a999712017-04-04 09:52:47 -0500250int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) {
Jerry Zhang769a9c12018-05-15 17:02:50 -0700251 std::string cmd(android::base::StringPrintf(
252 FB_CMD_DOWNLOAD ":" "%08x", size));
Chris Fries0ea946c2017-04-12 10:25:57 -0500253 return _command_send(transport, cmd.c_str(), data, size, 0) < 0 ? -1 : 0;
254}
255
256int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) {
Jerry Zhang769a9c12018-05-15 17:02:50 -0700257 std::string cmd(android::base::StringPrintf(
258 FB_CMD_DOWNLOAD ":" "%08x", size));
Chris Fries0ea946c2017-04-12 10:25:57 -0500259 return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800260}
261
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800262int64_t fb_upload_data(Transport* transport, const char* outfile) {
263 // positive return value is the upload size sent by the device
Jerry Zhang769a9c12018-05-15 17:02:50 -0700264 int64_t r = _command_start(transport, FB_CMD_UPLOAD,
265 std::numeric_limits<int32_t>::max(), nullptr);
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800266 if (r <= 0) {
267 g_error = android::base::StringPrintf("command start failed (%s)", strerror(errno));
268 return r;
269 }
270
271 std::string data;
272 data.resize(r);
273 if ((r = _command_read_data(transport, &data[0], data.size())) == -1) {
274 return r;
275 }
276
277 if (!WriteStringToFile(data, outfile, true)) {
278 g_error = android::base::StringPrintf("write to '%s' failed", outfile);
279 return -1;
280 }
281
282 return _command_end(transport);
283}
284
Tao Bao7d27ffd2018-04-23 17:24:17 -0700285static constexpr size_t TRANSPORT_BUF_SIZE = 1024;
David Pursell0b156632015-10-30 11:22:01 -0700286static char transport_buf[TRANSPORT_BUF_SIZE];
Tao Bao7d27ffd2018-04-23 17:24:17 -0700287static size_t transport_buf_len;
Colin Crossf8387882012-05-24 17:18:41 -0700288
Tao Bao7d27ffd2018-04-23 17:24:17 -0700289static int fb_download_data_sparse_write(void* priv, const void* data, size_t len) {
290 const char* ptr = static_cast<const char*>(data);
David Pursell0b156632015-10-30 11:22:01 -0700291 if (transport_buf_len) {
Tao Bao7d27ffd2018-04-23 17:24:17 -0700292 size_t to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
Colin Crossf8387882012-05-24 17:18:41 -0700293
David Pursell0b156632015-10-30 11:22:01 -0700294 memcpy(transport_buf + transport_buf_len, ptr, to_write);
295 transport_buf_len += to_write;
Colin Crossf8387882012-05-24 17:18:41 -0700296 ptr += to_write;
297 len -= to_write;
298 }
299
Tao Bao7d27ffd2018-04-23 17:24:17 -0700300 Transport* transport = static_cast<Transport*>(priv);
David Pursell0b156632015-10-30 11:22:01 -0700301 if (transport_buf_len == TRANSPORT_BUF_SIZE) {
Tao Bao7d27ffd2018-04-23 17:24:17 -0700302 int64_t r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
303 if (r != static_cast<int64_t>(TRANSPORT_BUF_SIZE)) {
Colin Crossf8387882012-05-24 17:18:41 -0700304 return -1;
305 }
David Pursell0b156632015-10-30 11:22:01 -0700306 transport_buf_len = 0;
Colin Crossf8387882012-05-24 17:18:41 -0700307 }
308
David Pursell0b156632015-10-30 11:22:01 -0700309 if (len > TRANSPORT_BUF_SIZE) {
310 if (transport_buf_len > 0) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700311 g_error = "internal error: transport_buf not empty";
Colin Crossf8387882012-05-24 17:18:41 -0700312 return -1;
313 }
Tao Bao7d27ffd2018-04-23 17:24:17 -0700314 size_t to_write = round_down(len, TRANSPORT_BUF_SIZE);
315 int64_t r = _command_write_data(transport, ptr, to_write);
316 if (r != static_cast<int64_t>(to_write)) {
Colin Crossf8387882012-05-24 17:18:41 -0700317 return -1;
318 }
319 ptr += to_write;
320 len -= to_write;
321 }
322
323 if (len > 0) {
David Pursell0b156632015-10-30 11:22:01 -0700324 if (len > TRANSPORT_BUF_SIZE) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700325 g_error = "internal error: too much left for transport_buf";
Colin Crossf8387882012-05-24 17:18:41 -0700326 return -1;
327 }
David Pursell0b156632015-10-30 11:22:01 -0700328 memcpy(transport_buf, ptr, len);
329 transport_buf_len = len;
Colin Crossf8387882012-05-24 17:18:41 -0700330 }
331
332 return 0;
333}
334
David Pursell0b156632015-10-30 11:22:01 -0700335static int fb_download_data_sparse_flush(Transport* transport) {
336 if (transport_buf_len > 0) {
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800337 int64_t r = _command_write_data(transport, transport_buf, transport_buf_len);
Chris Fries6a999712017-04-04 09:52:47 -0500338 if (r != static_cast<int64_t>(transport_buf_len)) {
Colin Crossf8387882012-05-24 17:18:41 -0700339 return -1;
340 }
David Pursell0b156632015-10-30 11:22:01 -0700341 transport_buf_len = 0;
Colin Crossf8387882012-05-24 17:18:41 -0700342 }
Colin Crossf8387882012-05-24 17:18:41 -0700343 return 0;
344}
345
David Pursell0b156632015-10-30 11:22:01 -0700346int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
Tao Bao41cf35f2018-04-24 10:54:21 -0700347 int64_t size = sparse_file_len(s, true, false);
348 if (size <= 0 || size > std::numeric_limits<uint32_t>::max()) {
Colin Crossf8387882012-05-24 17:18:41 -0700349 return -1;
350 }
351
Jerry Zhang769a9c12018-05-15 17:02:50 -0700352 std::string cmd(android::base::StringPrintf(
353 FB_CMD_DOWNLOAD ":" "%08" PRIx64, size));
Elliott Hughes5620d222018-03-28 08:20:00 -0700354 int r = _command_start(transport, cmd, size, 0);
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 = sparse_file_callback(s, true, false, fb_download_data_sparse_write, transport);
Colin Crossf8387882012-05-24 17:18:41 -0700360 if (r < 0) {
361 return -1;
362 }
363
David Pursell0b156632015-10-30 11:22:01 -0700364 r = fb_download_data_sparse_flush(transport);
Jeremy Compostella9f0d6bd2015-02-22 10:47:16 +0100365 if (r < 0) {
366 return -1;
367 }
Colin Crossf8387882012-05-24 17:18:41 -0700368
David Pursell0b156632015-10-30 11:22:01 -0700369 return _command_end(transport);
Colin Crossf8387882012-05-24 17:18:41 -0700370}