blob: 14ee78555e909ae7a4bfaab2cd1563842fb8a80d [file] [log] [blame]
Aaron Wisnerdb511202018-06-26 15:38:35 -05001/*
2 * Copyright (C) 2018 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
12 * the documentation and/or other materials provided with the
13 * 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
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * 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 */
Tom Cherry9027af02018-09-24 15:48:09 -070028
Aaron Wisnerdb511202018-06-26 15:38:35 -050029#include "fastboot_driver.h"
30
31#include <errno.h>
32#include <fcntl.h>
Yifan Hongbcd27702021-02-16 19:37:32 -080033#include <inttypes.h>
Aaron Wisnerdb511202018-06-26 15:38:35 -050034#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <algorithm>
38#include <chrono>
39#include <fstream>
40#include <memory>
41#include <regex>
42#include <vector>
43
44#include <android-base/file.h>
Elliott Hughese8f4b142018-10-19 16:09:39 -070045#include <android-base/mapped_file.h>
Yifan Hongbcd27702021-02-16 19:37:32 -080046#include <android-base/parseint.h>
Aaron Wisnerdb511202018-06-26 15:38:35 -050047#include <android-base/stringprintf.h>
48#include <android-base/strings.h>
49#include <android-base/unique_fd.h>
Yifan Hong17d469b2021-02-18 15:15:46 -080050#include <storage_literals/storage_literals.h>
Tom Cherry9027af02018-09-24 15:48:09 -070051
52#include "constants.h"
Aaron Wisnerdb511202018-06-26 15:38:35 -050053#include "transport.h"
54
Tom Cherry9027af02018-09-24 15:48:09 -070055using android::base::StringPrintf;
Yifan Hong17d469b2021-02-18 15:15:46 -080056using namespace android::storage_literals;
Tom Cherry9027af02018-09-24 15:48:09 -070057
Aaron Wisnerdb511202018-06-26 15:38:35 -050058namespace fastboot {
59
60/*************************** PUBLIC *******************************/
Tom Cherry9027af02018-09-24 15:48:09 -070061FastBootDriver::FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks,
Aaron Wisnerdb511202018-06-26 15:38:35 -050062 bool no_checks)
Tom Cherry9027af02018-09-24 15:48:09 -070063 : transport_(transport),
64 prolog_(std::move(driver_callbacks.prolog)),
65 epilog_(std::move(driver_callbacks.epilog)),
66 info_(std::move(driver_callbacks.info)),
67 disable_checks_(no_checks) {}
Aaron Wisnerdb511202018-06-26 15:38:35 -050068
David Anderson1d887432018-08-27 16:47:32 -070069FastBootDriver::~FastBootDriver() {
David Anderson1d887432018-08-27 16:47:32 -070070}
71
Aaron Wisnerdb511202018-06-26 15:38:35 -050072RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070073 return RawCommand(FB_CMD_BOOT, "Booting", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050074}
75
76RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070077 return RawCommand(FB_CMD_CONTINUE, "Resuming boot", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050078}
79
Tom Cherry9027af02018-09-24 15:48:09 -070080RetCode FastBootDriver::CreatePartition(const std::string& partition, const std::string& size) {
81 return RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size,
82 "Creating '" + partition + "'");
Aaron Wisnerdb511202018-06-26 15:38:35 -050083}
84
Tom Cherry9027af02018-09-24 15:48:09 -070085RetCode FastBootDriver::DeletePartition(const std::string& partition) {
86 return RawCommand(FB_CMD_DELETE_PARTITION ":" + partition, "Deleting '" + partition + "'");
87}
88
89RetCode FastBootDriver::Erase(const std::string& partition, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -050090 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070091 return RawCommand(FB_CMD_ERASE ":" + partition, "Erasing '" + partition + "'", response, info);
92}
93
94RetCode FastBootDriver::Flash(const std::string& partition, std::string* response,
95 std::vector<std::string>* info) {
96 return RawCommand(FB_CMD_FLASH ":" + partition, "Writing '" + partition + "'", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050097}
98
99RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
100 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700101 return RawCommand(FB_CMD_GETVAR ":" + key, val, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500102}
103
104RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
105 std::string tmp;
106 return GetVar("all", &tmp, response);
107}
108
Aaron Wisnerdb511202018-06-26 15:38:35 -0500109RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700110 return RawCommand(FB_CMD_REBOOT, "Rebooting", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500111}
112
David Anderson1d887432018-08-27 16:47:32 -0700113RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
114 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700115 return RawCommand("reboot-" + target, "Rebooting into " + target, response, info);
116}
117
118RetCode FastBootDriver::ResizePartition(const std::string& partition, const std::string& size) {
119 return RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size,
120 "Resizing '" + partition + "'");
David Anderson1d887432018-08-27 16:47:32 -0700121}
122
Tom Cherry11f12092018-08-29 21:36:28 -0700123RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500124 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700125 return RawCommand(FB_CMD_SET_ACTIVE ":" + slot, "Setting current slot to '" + slot + "'",
126 response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500127}
128
David Andersonab8f4662019-10-21 16:45:59 -0700129RetCode FastBootDriver::SnapshotUpdateCommand(const std::string& command, std::string* response,
130 std::vector<std::string>* info) {
David Anderson220ddb12019-10-31 18:02:41 -0700131 prolog_(StringPrintf("Snapshot %s", command.c_str()));
David Andersonab8f4662019-10-21 16:45:59 -0700132 std::string raw = FB_CMD_SNAPSHOT_UPDATE ":" + command;
David Anderson220ddb12019-10-31 18:02:41 -0700133 auto result = RawCommand(raw, response, info);
134 epilog_(result);
135 return result;
David Andersonab8f4662019-10-21 16:45:59 -0700136}
137
Tom Cherry9027af02018-09-24 15:48:09 -0700138RetCode FastBootDriver::FlashPartition(const std::string& partition,
139 const std::vector<char>& data) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500140 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700141 if ((ret = Download(partition, data))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500142 return ret;
143 }
Tom Cherry9027af02018-09-24 15:48:09 -0700144 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500145}
146
Tom Cherry9027af02018-09-24 15:48:09 -0700147RetCode FastBootDriver::FlashPartition(const std::string& partition, int fd, uint32_t size) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500148 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700149 if ((ret = Download(partition, fd, size))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500150 return ret;
151 }
Tom Cherry9027af02018-09-24 15:48:09 -0700152 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500153}
154
Tom Cherry9027af02018-09-24 15:48:09 -0700155RetCode FastBootDriver::FlashPartition(const std::string& partition, sparse_file* s, uint32_t size,
156 size_t current, size_t total) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500157 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700158 if ((ret = Download(partition, s, size, current, total, false))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500159 return ret;
160 }
Tom Cherry9027af02018-09-24 15:48:09 -0700161 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500162}
163
Tom Cherry9027af02018-09-24 15:48:09 -0700164RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500165 std::vector<std::string> all;
166 RetCode ret;
167 if ((ret = GetVarAll(&all))) {
168 return ret;
169 }
170
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500171 std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)");
Aaron Wisnerdb511202018-06-26 15:38:35 -0500172 std::smatch sm;
173
174 for (auto& s : all) {
175 if (std::regex_match(s, sm, reg)) {
176 std::string m1(sm[1]);
177 std::string m2(sm[2]);
David Anderson6c30f6e2018-09-04 15:57:39 -0700178 uint64_t tmp = strtoll(m2.c_str(), 0, 16);
Tom Cherry9027af02018-09-24 15:48:09 -0700179 partitions->push_back(std::make_tuple(m1, tmp));
Aaron Wisnerdb511202018-06-26 15:38:35 -0500180 }
181 }
182 return SUCCESS;
183}
184
Tom Cherry9027af02018-09-24 15:48:09 -0700185RetCode FastBootDriver::Download(const std::string& name, int fd, size_t size,
186 std::string* response, std::vector<std::string>* info) {
187 prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), size / 1024));
188 auto result = Download(fd, size, response, info);
189 epilog_(result);
190 return result;
191}
192
Aaron Wisnerdb511202018-06-26 15:38:35 -0500193RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
194 std::vector<std::string>* info) {
195 RetCode ret;
196
197 if ((size <= 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
198 error_ = "File is too large to download";
199 return BAD_ARG;
200 }
201
202 uint32_t u32size = static_cast<uint32_t>(size);
203 if ((ret = DownloadCommand(u32size, response, info))) {
204 return ret;
205 }
206
207 // Write the buffer
208 if ((ret = SendBuffer(fd, size))) {
209 return ret;
210 }
211
212 // Wait for response
213 return HandleResponse(response, info);
214}
215
Tom Cherry9027af02018-09-24 15:48:09 -0700216RetCode FastBootDriver::Download(const std::string& name, const std::vector<char>& buf,
217 std::string* response, std::vector<std::string>* info) {
218 prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), buf.size() / 1024));
219 auto result = Download(buf, response, info);
220 epilog_(result);
221 return result;
222}
223
Aaron Wisnerdb511202018-06-26 15:38:35 -0500224RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
225 std::vector<std::string>* info) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500226 RetCode ret;
227 error_ = "";
Tom Cherrydfd85df2018-09-20 14:45:05 -0700228 if ((buf.size() == 0 || buf.size() > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500229 error_ = "Buffer is too large or 0 bytes";
230 return BAD_ARG;
231 }
232
Tom Cherrydfd85df2018-09-20 14:45:05 -0700233 if ((ret = DownloadCommand(buf.size(), response, info))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500234 return ret;
235 }
236
237 // Write the buffer
Tom Cherrydfd85df2018-09-20 14:45:05 -0700238 if ((ret = SendBuffer(buf))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500239 return ret;
240 }
241
242 // Wait for response
243 return HandleResponse(response, info);
244}
245
Tom Cherry9027af02018-09-24 15:48:09 -0700246RetCode FastBootDriver::Download(const std::string& partition, struct sparse_file* s, uint32_t size,
247 size_t current, size_t total, bool use_crc, std::string* response,
248 std::vector<std::string>* info) {
249 prolog_(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
250 size / 1024));
251 auto result = Download(s, use_crc, response, info);
252 epilog_(result);
253 return result;
254}
255
Aaron Wisner9812b582018-08-22 11:01:04 -0500256RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500257 std::vector<std::string>* info) {
258 error_ = "";
Aaron Wisner9812b582018-08-22 11:01:04 -0500259 int64_t size = sparse_file_len(s, true, use_crc);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500260 if (size <= 0 || size > MAX_DOWNLOAD_SIZE) {
261 error_ = "Sparse file is too large or invalid";
262 return BAD_ARG;
263 }
264
265 RetCode ret;
266 uint32_t u32size = static_cast<uint32_t>(size);
267 if ((ret = DownloadCommand(u32size, response, info))) {
268 return ret;
269 }
270
271 struct SparseCBPrivate {
272 FastBootDriver* self;
273 std::vector<char> tpbuf;
274 } cb_priv;
275 cb_priv.self = this;
276
277 auto cb = [](void* priv, const void* buf, size_t len) -> int {
278 SparseCBPrivate* data = static_cast<SparseCBPrivate*>(priv);
279 const char* cbuf = static_cast<const char*>(buf);
280 return data->self->SparseWriteCallback(data->tpbuf, cbuf, len);
281 };
282
Aaron Wisner9812b582018-08-22 11:01:04 -0500283 if (sparse_file_callback(s, true, use_crc, cb, &cb_priv) < 0) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500284 error_ = "Error reading sparse file";
285 return IO_ERROR;
286 }
287
288 // Now flush
289 if (cb_priv.tpbuf.size() && (ret = SendBuffer(cb_priv.tpbuf))) {
290 return ret;
291 }
292
293 return HandleResponse(response, info);
294}
295
296RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
297 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700298 prolog_("Uploading '" + outfile + "'");
299 auto result = UploadInner(outfile, response, info);
300 epilog_(result);
301 return result;
302}
303
Yifan Hongbbf374d2021-02-17 11:16:39 -0800304// This function executes cmd, then expect a "DATA" response with a number N, followed
305// by N bytes, and another response.
306// This is the common way for the device to send data to the driver used by upload and fetch.
307RetCode FastBootDriver::RunAndReadBuffer(
308 const std::string& cmd, std::string* response, std::vector<std::string>* info,
309 const std::function<RetCode(const char* data, uint64_t size)>& write_fn) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500310 RetCode ret;
qiwu chen325ba6f2019-08-29 14:50:51 +0800311 int dsize = 0;
Yifan Hongbbf374d2021-02-17 11:16:39 -0800312 if ((ret = RawCommand(cmd, response, info, &dsize))) {
313 error_ = android::base::StringPrintf("%s request failed: %s", cmd.c_str(), error_.c_str());
Aaron Wisnerdb511202018-06-26 15:38:35 -0500314 return ret;
315 }
316
Yifan Hongbbf374d2021-02-17 11:16:39 -0800317 if (dsize <= 0) {
318 error_ = android::base::StringPrintf("%s request failed, device reports %d bytes available",
319 cmd.c_str(), dsize);
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500320 return BAD_DEV_RESP;
321 }
322
Yifan Hong17d469b2021-02-18 15:15:46 -0800323 const uint64_t total_size = dsize;
324 const uint64_t buf_size = std::min<uint64_t>(total_size, 1_MiB);
325 std::vector<char> data(buf_size);
326 uint64_t current_offset = 0;
327 while (current_offset < total_size) {
328 uint64_t remaining = total_size - current_offset;
329 uint64_t chunk_size = std::min(buf_size, remaining);
330 if ((ret = ReadBuffer(data.data(), chunk_size)) != SUCCESS) {
331 return ret;
332 }
333 if ((ret = write_fn(data.data(), chunk_size)) != SUCCESS) {
334 return ret;
335 }
336 current_offset += chunk_size;
Yifan Hongbbf374d2021-02-17 11:16:39 -0800337 }
338 return HandleResponse(response, info);
339}
Aaron Wisnerdb511202018-06-26 15:38:35 -0500340
Yifan Hongbbf374d2021-02-17 11:16:39 -0800341RetCode FastBootDriver::UploadInner(const std::string& outfile, std::string* response,
342 std::vector<std::string>* info) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500343 std::ofstream ofs;
344 ofs.open(outfile, std::ofstream::out | std::ofstream::binary);
345 if (ofs.fail()) {
346 error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str());
347 return IO_ERROR;
348 }
Yifan Hongbbf374d2021-02-17 11:16:39 -0800349 auto write_fn = [&](const char* data, uint64_t size) {
350 ofs.write(data, size);
351 if (ofs.fail() || ofs.bad()) {
352 error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str());
353 return IO_ERROR;
354 }
355 return SUCCESS;
356 };
357 RetCode ret = RunAndReadBuffer(FB_CMD_UPLOAD, response, info, write_fn);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500358 ofs.close();
Yifan Hongbbf374d2021-02-17 11:16:39 -0800359 return ret;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500360}
361
Yifan Hongbcd27702021-02-16 19:37:32 -0800362RetCode FastBootDriver::FetchToFd(const std::string& partition, android::base::borrowed_fd fd,
363 int64_t offset, int64_t size, std::string* response,
364 std::vector<std::string>* info) {
365 prolog_(android::base::StringPrintf("Fetching %s (offset=%" PRIx64 ", size=%" PRIx64 ")",
366 partition.c_str(), offset, size));
367 std::string cmd = FB_CMD_FETCH ":" + partition;
368 if (offset >= 0) {
369 cmd += android::base::StringPrintf(":0x%08" PRIx64, offset);
370 if (size >= 0) {
371 cmd += android::base::StringPrintf(":0x%08" PRIx64, size);
372 }
373 }
374 RetCode ret = RunAndReadBuffer(cmd, response, info, [&](const char* data, uint64_t size) {
375 if (!android::base::WriteFully(fd, data, size)) {
376 error_ = android::base::StringPrintf("Cannot write: %s", strerror(errno));
377 return IO_ERROR;
378 }
379 return SUCCESS;
380 });
381 epilog_(ret);
382 return ret;
383}
384
Aaron Wisnerdb511202018-06-26 15:38:35 -0500385// Helpers
Tom Cherry9027af02018-09-24 15:48:09 -0700386void FastBootDriver::SetInfoCallback(std::function<void(const std::string&)> info) {
387 info_ = info;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500388}
389
390const std::string FastBootDriver::RCString(RetCode rc) {
391 switch (rc) {
392 case SUCCESS:
393 return std::string("Success");
394
395 case BAD_ARG:
396 return std::string("Invalid Argument");
397
398 case IO_ERROR:
399 return std::string("I/O Error");
400
401 case BAD_DEV_RESP:
402 return std::string("Invalid Device Response");
403
404 case DEVICE_FAIL:
405 return std::string("Device Error");
406
407 case TIMEOUT:
408 return std::string("Timeout");
409
410 default:
411 return std::string("Unknown Error");
412 }
413}
414
415std::string FastBootDriver::Error() {
416 return error_;
417}
418
419RetCode FastBootDriver::WaitForDisconnect() {
David Anderson1d887432018-08-27 16:47:32 -0700420 return transport_->WaitForDisconnect() ? IO_ERROR : SUCCESS;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500421}
422
423/****************************** PROTECTED *************************************/
Tom Cherry9027af02018-09-24 15:48:09 -0700424RetCode FastBootDriver::RawCommand(const std::string& cmd, const std::string& message,
425 std::string* response, std::vector<std::string>* info,
426 int* dsize) {
427 prolog_(message);
428 auto result = RawCommand(cmd, response, info, dsize);
429 epilog_(result);
430 return result;
431}
432
Aaron Wisnerdb511202018-06-26 15:38:35 -0500433RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
434 std::vector<std::string>* info, int* dsize) {
435 error_ = ""; // Clear any pending error
436 if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) {
437 error_ = "Command length to RawCommand() is too long";
438 return BAD_ARG;
439 }
440
David Anderson1d887432018-08-27 16:47:32 -0700441 if (transport_->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500442 error_ = ErrnoStr("Write to device failed");
443 return IO_ERROR;
444 }
445
446 // Read the response
447 return HandleResponse(response, info, dsize);
448}
449
450RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
451 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700452 std::string cmd(android::base::StringPrintf("%s:%08" PRIx32, FB_CMD_DOWNLOAD, size));
Aaron Wisnerdb511202018-06-26 15:38:35 -0500453 RetCode ret;
454 if ((ret = RawCommand(cmd, response, info))) {
455 return ret;
456 }
457 return SUCCESS;
458}
459
460RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
461 int* dsize) {
462 char status[FB_RESPONSE_SZ + 1];
Dima Zavina5b85a42019-02-28 14:50:25 -0800463 auto start = std::chrono::steady_clock::now();
Aaron Wisnerdb511202018-06-26 15:38:35 -0500464
465 auto set_response = [response](std::string s) {
466 if (response) *response = std::move(s);
467 };
468 auto add_info = [info](std::string s) {
469 if (info) info->push_back(std::move(s));
470 };
471
472 // erase response
473 set_response("");
Dima Zavina5b85a42019-02-28 14:50:25 -0800474 while ((std::chrono::steady_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
David Anderson1d887432018-08-27 16:47:32 -0700475 int r = transport_->Read(status, FB_RESPONSE_SZ);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500476 if (r < 0) {
477 error_ = ErrnoStr("Status read failed");
478 return IO_ERROR;
479 }
480
481 status[r] = '\0'; // Need the null terminator
482 std::string input(status);
483 if (android::base::StartsWith(input, "INFO")) {
484 std::string tmp = input.substr(strlen("INFO"));
Tom Cherry9027af02018-09-24 15:48:09 -0700485 info_(tmp);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500486 add_info(std::move(tmp));
Dima Zavin6d46a492019-02-23 21:14:38 -0800487 // We may receive one or more INFO packets during long operations,
488 // e.g. flash/erase if they are back by slow media like NAND/NOR
489 // flash. In that case, reset the timer since it's not a real
490 // timeout.
491 start = std::chrono::steady_clock::now();
Aaron Wisnerdb511202018-06-26 15:38:35 -0500492 } else if (android::base::StartsWith(input, "OKAY")) {
493 set_response(input.substr(strlen("OKAY")));
494 return SUCCESS;
495 } else if (android::base::StartsWith(input, "FAIL")) {
496 error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
497 set_response(input.substr(strlen("FAIL")));
498 return DEVICE_FAIL;
499 } else if (android::base::StartsWith(input, "DATA")) {
500 std::string tmp = input.substr(strlen("DATA"));
501 uint32_t num = strtol(tmp.c_str(), 0, 16);
502 if (num > MAX_DOWNLOAD_SIZE) {
503 error_ = android::base::StringPrintf("Data size too large (%d)", num);
504 return BAD_DEV_RESP;
505 }
506 if (dsize) *dsize = num;
507 set_response(std::move(tmp));
508 return SUCCESS;
509 } else {
510 error_ = android::base::StringPrintf("Device sent unknown status code: %s", status);
511 return BAD_DEV_RESP;
512 }
513
514 } // End of while loop
515
516 return TIMEOUT;
517}
518
519std::string FastBootDriver::ErrnoStr(const std::string& msg) {
520 return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
521}
522
Aaron Wisnerdb511202018-06-26 15:38:35 -0500523/******************************* PRIVATE **************************************/
524RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
525 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
526 off64_t offset = 0;
527 uint32_t remaining = size;
528 RetCode ret;
529
530 while (remaining) {
531 // Memory map the file
Aaron Wisnerdb511202018-06-26 15:38:35 -0500532 size_t len = std::min(remaining, MAX_MAP_SIZE);
Elliott Hughese8f4b142018-10-19 16:09:39 -0700533 auto mapping{android::base::MappedFile::FromFd(fd, offset, len, PROT_READ)};
534 if (!mapping) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500535 error_ = "Creating filemap failed";
536 return IO_ERROR;
537 }
538
Elliott Hughese8f4b142018-10-19 16:09:39 -0700539 if ((ret = SendBuffer(mapping->data(), mapping->size()))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500540 return ret;
541 }
542
543 remaining -= len;
544 offset += len;
545 }
546
547 return SUCCESS;
548}
549
550RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) {
551 // Write the buffer
552 return SendBuffer(buf.data(), buf.size());
553}
554
555RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500556 // ioctl on 0-length buffer causes freezing
David Anderson0c7bde82018-07-30 12:54:53 -0700557 if (!size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500558 return BAD_ARG;
David Anderson0c7bde82018-07-30 12:54:53 -0700559 }
Aaron Wisnerdb511202018-06-26 15:38:35 -0500560 // Write the buffer
David Anderson1d887432018-08-27 16:47:32 -0700561 ssize_t tmp = transport_->Write(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500562
563 if (tmp < 0) {
564 error_ = ErrnoStr("Write to device failed in SendBuffer()");
565 return IO_ERROR;
566 } else if (static_cast<size_t>(tmp) != size) {
567 error_ = android::base::StringPrintf("Failed to write all %zu bytes", size);
568
569 return IO_ERROR;
570 }
571
572 return SUCCESS;
573}
574
Aaron Wisnerdb511202018-06-26 15:38:35 -0500575RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
576 // Read the buffer
David Anderson1d887432018-08-27 16:47:32 -0700577 ssize_t tmp = transport_->Read(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500578
579 if (tmp < 0) {
580 error_ = ErrnoStr("Read from device failed in ReadBuffer()");
581 return IO_ERROR;
582 } else if (static_cast<size_t>(tmp) != size) {
583 error_ = android::base::StringPrintf("Failed to read all %zu bytes", size);
584 return IO_ERROR;
585 }
586
587 return SUCCESS;
588}
589
590int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) {
591 size_t total = 0;
592 size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len);
593
594 // Handle the residual
595 tpbuf.insert(tpbuf.end(), data, data + to_write);
596 if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) { // Nothing enough to send rn
597 return 0;
598 }
599
600 if (SendBuffer(tpbuf)) {
601 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
602 return -1;
603 }
604 tpbuf.clear();
605 total += to_write;
606
607 // Now we need to send a multiple of chunk size
608 size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
609 size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500610 if (nbytes && SendBuffer(data + total, nbytes)) { // Don't send a ZLP
Aaron Wisnerdb511202018-06-26 15:38:35 -0500611 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
612 return -1;
613 }
614 total += nbytes;
615
616 if (len - total > 0) { // We have residual data to save for next time
617 tpbuf.assign(data + total, data + len);
618 }
619
620 return 0;
621}
622
David Anderson03de6452018-09-04 14:32:54 -0700623Transport* FastBootDriver::set_transport(Transport* transport) {
624 std::swap(transport_, transport);
625 return transport;
David Anderson1d887432018-08-27 16:47:32 -0700626}
627
Aaron Wisnerdb511202018-06-26 15:38:35 -0500628} // End namespace fastboot