blob: a516a9130030272f62a62b94b2c72ab831271ac1 [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>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <algorithm>
37#include <chrono>
38#include <fstream>
39#include <memory>
40#include <regex>
41#include <vector>
42
43#include <android-base/file.h>
Elliott Hughese8f4b142018-10-19 16:09:39 -070044#include <android-base/mapped_file.h>
Aaron Wisnerdb511202018-06-26 15:38:35 -050045#include <android-base/stringprintf.h>
46#include <android-base/strings.h>
47#include <android-base/unique_fd.h>
Yifan Hong17d469b2021-02-18 15:15:46 -080048#include <storage_literals/storage_literals.h>
Tom Cherry9027af02018-09-24 15:48:09 -070049
50#include "constants.h"
Aaron Wisnerdb511202018-06-26 15:38:35 -050051#include "transport.h"
52
Tom Cherry9027af02018-09-24 15:48:09 -070053using android::base::StringPrintf;
Yifan Hong17d469b2021-02-18 15:15:46 -080054using namespace android::storage_literals;
Tom Cherry9027af02018-09-24 15:48:09 -070055
Aaron Wisnerdb511202018-06-26 15:38:35 -050056namespace fastboot {
57
58/*************************** PUBLIC *******************************/
Tom Cherry9027af02018-09-24 15:48:09 -070059FastBootDriver::FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks,
Aaron Wisnerdb511202018-06-26 15:38:35 -050060 bool no_checks)
Tom Cherry9027af02018-09-24 15:48:09 -070061 : transport_(transport),
62 prolog_(std::move(driver_callbacks.prolog)),
63 epilog_(std::move(driver_callbacks.epilog)),
64 info_(std::move(driver_callbacks.info)),
65 disable_checks_(no_checks) {}
Aaron Wisnerdb511202018-06-26 15:38:35 -050066
David Anderson1d887432018-08-27 16:47:32 -070067FastBootDriver::~FastBootDriver() {
David Anderson1d887432018-08-27 16:47:32 -070068}
69
Aaron Wisnerdb511202018-06-26 15:38:35 -050070RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070071 return RawCommand(FB_CMD_BOOT, "Booting", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050072}
73
74RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070075 return RawCommand(FB_CMD_CONTINUE, "Resuming boot", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050076}
77
Tom Cherry9027af02018-09-24 15:48:09 -070078RetCode FastBootDriver::CreatePartition(const std::string& partition, const std::string& size) {
79 return RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size,
80 "Creating '" + partition + "'");
Aaron Wisnerdb511202018-06-26 15:38:35 -050081}
82
Tom Cherry9027af02018-09-24 15:48:09 -070083RetCode FastBootDriver::DeletePartition(const std::string& partition) {
84 return RawCommand(FB_CMD_DELETE_PARTITION ":" + partition, "Deleting '" + partition + "'");
85}
86
87RetCode FastBootDriver::Erase(const std::string& partition, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -050088 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070089 return RawCommand(FB_CMD_ERASE ":" + partition, "Erasing '" + partition + "'", response, info);
90}
91
92RetCode FastBootDriver::Flash(const std::string& partition, std::string* response,
93 std::vector<std::string>* info) {
94 return RawCommand(FB_CMD_FLASH ":" + partition, "Writing '" + partition + "'", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050095}
96
97RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
98 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070099 return RawCommand(FB_CMD_GETVAR ":" + key, val, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500100}
101
102RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
103 std::string tmp;
104 return GetVar("all", &tmp, response);
105}
106
Aaron Wisnerdb511202018-06-26 15:38:35 -0500107RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700108 return RawCommand(FB_CMD_REBOOT, "Rebooting", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500109}
110
David Anderson1d887432018-08-27 16:47:32 -0700111RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
112 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700113 return RawCommand("reboot-" + target, "Rebooting into " + target, response, info);
114}
115
116RetCode FastBootDriver::ResizePartition(const std::string& partition, const std::string& size) {
117 return RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size,
118 "Resizing '" + partition + "'");
David Anderson1d887432018-08-27 16:47:32 -0700119}
120
Tom Cherry11f12092018-08-29 21:36:28 -0700121RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500122 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700123 return RawCommand(FB_CMD_SET_ACTIVE ":" + slot, "Setting current slot to '" + slot + "'",
124 response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500125}
126
David Andersonab8f4662019-10-21 16:45:59 -0700127RetCode FastBootDriver::SnapshotUpdateCommand(const std::string& command, std::string* response,
128 std::vector<std::string>* info) {
David Anderson220ddb12019-10-31 18:02:41 -0700129 prolog_(StringPrintf("Snapshot %s", command.c_str()));
David Andersonab8f4662019-10-21 16:45:59 -0700130 std::string raw = FB_CMD_SNAPSHOT_UPDATE ":" + command;
David Anderson220ddb12019-10-31 18:02:41 -0700131 auto result = RawCommand(raw, response, info);
132 epilog_(result);
133 return result;
David Andersonab8f4662019-10-21 16:45:59 -0700134}
135
Tom Cherry9027af02018-09-24 15:48:09 -0700136RetCode FastBootDriver::FlashPartition(const std::string& partition,
137 const std::vector<char>& data) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500138 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700139 if ((ret = Download(partition, data))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500140 return ret;
141 }
Tom Cherry9027af02018-09-24 15:48:09 -0700142 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500143}
144
Tom Cherry9027af02018-09-24 15:48:09 -0700145RetCode FastBootDriver::FlashPartition(const std::string& partition, int fd, uint32_t size) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500146 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700147 if ((ret = Download(partition, fd, size))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500148 return ret;
149 }
Tom Cherry9027af02018-09-24 15:48:09 -0700150 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500151}
152
Tom Cherry9027af02018-09-24 15:48:09 -0700153RetCode FastBootDriver::FlashPartition(const std::string& partition, sparse_file* s, uint32_t size,
154 size_t current, size_t total) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500155 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700156 if ((ret = Download(partition, s, size, current, total, false))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500157 return ret;
158 }
Tom Cherry9027af02018-09-24 15:48:09 -0700159 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500160}
161
Tom Cherry9027af02018-09-24 15:48:09 -0700162RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500163 std::vector<std::string> all;
164 RetCode ret;
165 if ((ret = GetVarAll(&all))) {
166 return ret;
167 }
168
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500169 std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)");
Aaron Wisnerdb511202018-06-26 15:38:35 -0500170 std::smatch sm;
171
172 for (auto& s : all) {
173 if (std::regex_match(s, sm, reg)) {
174 std::string m1(sm[1]);
175 std::string m2(sm[2]);
David Anderson6c30f6e2018-09-04 15:57:39 -0700176 uint64_t tmp = strtoll(m2.c_str(), 0, 16);
Tom Cherry9027af02018-09-24 15:48:09 -0700177 partitions->push_back(std::make_tuple(m1, tmp));
Aaron Wisnerdb511202018-06-26 15:38:35 -0500178 }
179 }
180 return SUCCESS;
181}
182
Tom Cherry9027af02018-09-24 15:48:09 -0700183RetCode FastBootDriver::Download(const std::string& name, int fd, size_t size,
184 std::string* response, std::vector<std::string>* info) {
185 prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), size / 1024));
186 auto result = Download(fd, size, response, info);
187 epilog_(result);
188 return result;
189}
190
Aaron Wisnerdb511202018-06-26 15:38:35 -0500191RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
192 std::vector<std::string>* info) {
193 RetCode ret;
194
195 if ((size <= 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
196 error_ = "File is too large to download";
197 return BAD_ARG;
198 }
199
200 uint32_t u32size = static_cast<uint32_t>(size);
201 if ((ret = DownloadCommand(u32size, response, info))) {
202 return ret;
203 }
204
205 // Write the buffer
206 if ((ret = SendBuffer(fd, size))) {
207 return ret;
208 }
209
210 // Wait for response
211 return HandleResponse(response, info);
212}
213
Tom Cherry9027af02018-09-24 15:48:09 -0700214RetCode FastBootDriver::Download(const std::string& name, const std::vector<char>& buf,
215 std::string* response, std::vector<std::string>* info) {
216 prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), buf.size() / 1024));
217 auto result = Download(buf, response, info);
218 epilog_(result);
219 return result;
220}
221
Aaron Wisnerdb511202018-06-26 15:38:35 -0500222RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
223 std::vector<std::string>* info) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500224 RetCode ret;
225 error_ = "";
Tom Cherrydfd85df2018-09-20 14:45:05 -0700226 if ((buf.size() == 0 || buf.size() > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500227 error_ = "Buffer is too large or 0 bytes";
228 return BAD_ARG;
229 }
230
Tom Cherrydfd85df2018-09-20 14:45:05 -0700231 if ((ret = DownloadCommand(buf.size(), response, info))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500232 return ret;
233 }
234
235 // Write the buffer
Tom Cherrydfd85df2018-09-20 14:45:05 -0700236 if ((ret = SendBuffer(buf))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500237 return ret;
238 }
239
240 // Wait for response
241 return HandleResponse(response, info);
242}
243
Tom Cherry9027af02018-09-24 15:48:09 -0700244RetCode FastBootDriver::Download(const std::string& partition, struct sparse_file* s, uint32_t size,
245 size_t current, size_t total, bool use_crc, std::string* response,
246 std::vector<std::string>* info) {
247 prolog_(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
248 size / 1024));
249 auto result = Download(s, use_crc, response, info);
250 epilog_(result);
251 return result;
252}
253
Aaron Wisner9812b582018-08-22 11:01:04 -0500254RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500255 std::vector<std::string>* info) {
256 error_ = "";
Aaron Wisner9812b582018-08-22 11:01:04 -0500257 int64_t size = sparse_file_len(s, true, use_crc);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500258 if (size <= 0 || size > MAX_DOWNLOAD_SIZE) {
259 error_ = "Sparse file is too large or invalid";
260 return BAD_ARG;
261 }
262
263 RetCode ret;
264 uint32_t u32size = static_cast<uint32_t>(size);
265 if ((ret = DownloadCommand(u32size, response, info))) {
266 return ret;
267 }
268
269 struct SparseCBPrivate {
270 FastBootDriver* self;
271 std::vector<char> tpbuf;
272 } cb_priv;
273 cb_priv.self = this;
274
275 auto cb = [](void* priv, const void* buf, size_t len) -> int {
276 SparseCBPrivate* data = static_cast<SparseCBPrivate*>(priv);
277 const char* cbuf = static_cast<const char*>(buf);
278 return data->self->SparseWriteCallback(data->tpbuf, cbuf, len);
279 };
280
Aaron Wisner9812b582018-08-22 11:01:04 -0500281 if (sparse_file_callback(s, true, use_crc, cb, &cb_priv) < 0) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500282 error_ = "Error reading sparse file";
283 return IO_ERROR;
284 }
285
286 // Now flush
287 if (cb_priv.tpbuf.size() && (ret = SendBuffer(cb_priv.tpbuf))) {
288 return ret;
289 }
290
291 return HandleResponse(response, info);
292}
293
294RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
295 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700296 prolog_("Uploading '" + outfile + "'");
297 auto result = UploadInner(outfile, response, info);
298 epilog_(result);
299 return result;
300}
301
Yifan Hongbbf374d2021-02-17 11:16:39 -0800302// This function executes cmd, then expect a "DATA" response with a number N, followed
303// by N bytes, and another response.
304// This is the common way for the device to send data to the driver used by upload and fetch.
305RetCode FastBootDriver::RunAndReadBuffer(
306 const std::string& cmd, std::string* response, std::vector<std::string>* info,
307 const std::function<RetCode(const char* data, uint64_t size)>& write_fn) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500308 RetCode ret;
qiwu chen325ba6f2019-08-29 14:50:51 +0800309 int dsize = 0;
Yifan Hongbbf374d2021-02-17 11:16:39 -0800310 if ((ret = RawCommand(cmd, response, info, &dsize))) {
311 error_ = android::base::StringPrintf("%s request failed: %s", cmd.c_str(), error_.c_str());
Aaron Wisnerdb511202018-06-26 15:38:35 -0500312 return ret;
313 }
314
Yifan Hongbbf374d2021-02-17 11:16:39 -0800315 if (dsize <= 0) {
316 error_ = android::base::StringPrintf("%s request failed, device reports %d bytes available",
317 cmd.c_str(), dsize);
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500318 return BAD_DEV_RESP;
319 }
320
Yifan Hong17d469b2021-02-18 15:15:46 -0800321 const uint64_t total_size = dsize;
322 const uint64_t buf_size = std::min<uint64_t>(total_size, 1_MiB);
323 std::vector<char> data(buf_size);
324 uint64_t current_offset = 0;
325 while (current_offset < total_size) {
326 uint64_t remaining = total_size - current_offset;
327 uint64_t chunk_size = std::min(buf_size, remaining);
328 if ((ret = ReadBuffer(data.data(), chunk_size)) != SUCCESS) {
329 return ret;
330 }
331 if ((ret = write_fn(data.data(), chunk_size)) != SUCCESS) {
332 return ret;
333 }
334 current_offset += chunk_size;
Yifan Hongbbf374d2021-02-17 11:16:39 -0800335 }
336 return HandleResponse(response, info);
337}
Aaron Wisnerdb511202018-06-26 15:38:35 -0500338
Yifan Hongbbf374d2021-02-17 11:16:39 -0800339RetCode FastBootDriver::UploadInner(const std::string& outfile, std::string* response,
340 std::vector<std::string>* info) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500341 std::ofstream ofs;
342 ofs.open(outfile, std::ofstream::out | std::ofstream::binary);
343 if (ofs.fail()) {
344 error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str());
345 return IO_ERROR;
346 }
Yifan Hongbbf374d2021-02-17 11:16:39 -0800347 auto write_fn = [&](const char* data, uint64_t size) {
348 ofs.write(data, size);
349 if (ofs.fail() || ofs.bad()) {
350 error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str());
351 return IO_ERROR;
352 }
353 return SUCCESS;
354 };
355 RetCode ret = RunAndReadBuffer(FB_CMD_UPLOAD, response, info, write_fn);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500356 ofs.close();
Yifan Hongbbf374d2021-02-17 11:16:39 -0800357 return ret;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500358}
359
360// Helpers
Tom Cherry9027af02018-09-24 15:48:09 -0700361void FastBootDriver::SetInfoCallback(std::function<void(const std::string&)> info) {
362 info_ = info;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500363}
364
365const std::string FastBootDriver::RCString(RetCode rc) {
366 switch (rc) {
367 case SUCCESS:
368 return std::string("Success");
369
370 case BAD_ARG:
371 return std::string("Invalid Argument");
372
373 case IO_ERROR:
374 return std::string("I/O Error");
375
376 case BAD_DEV_RESP:
377 return std::string("Invalid Device Response");
378
379 case DEVICE_FAIL:
380 return std::string("Device Error");
381
382 case TIMEOUT:
383 return std::string("Timeout");
384
385 default:
386 return std::string("Unknown Error");
387 }
388}
389
390std::string FastBootDriver::Error() {
391 return error_;
392}
393
394RetCode FastBootDriver::WaitForDisconnect() {
David Anderson1d887432018-08-27 16:47:32 -0700395 return transport_->WaitForDisconnect() ? IO_ERROR : SUCCESS;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500396}
397
398/****************************** PROTECTED *************************************/
Tom Cherry9027af02018-09-24 15:48:09 -0700399RetCode FastBootDriver::RawCommand(const std::string& cmd, const std::string& message,
400 std::string* response, std::vector<std::string>* info,
401 int* dsize) {
402 prolog_(message);
403 auto result = RawCommand(cmd, response, info, dsize);
404 epilog_(result);
405 return result;
406}
407
Aaron Wisnerdb511202018-06-26 15:38:35 -0500408RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
409 std::vector<std::string>* info, int* dsize) {
410 error_ = ""; // Clear any pending error
411 if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) {
412 error_ = "Command length to RawCommand() is too long";
413 return BAD_ARG;
414 }
415
David Anderson1d887432018-08-27 16:47:32 -0700416 if (transport_->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500417 error_ = ErrnoStr("Write to device failed");
418 return IO_ERROR;
419 }
420
421 // Read the response
422 return HandleResponse(response, info, dsize);
423}
424
425RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
426 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700427 std::string cmd(android::base::StringPrintf("%s:%08" PRIx32, FB_CMD_DOWNLOAD, size));
Aaron Wisnerdb511202018-06-26 15:38:35 -0500428 RetCode ret;
429 if ((ret = RawCommand(cmd, response, info))) {
430 return ret;
431 }
432 return SUCCESS;
433}
434
435RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
436 int* dsize) {
437 char status[FB_RESPONSE_SZ + 1];
Dima Zavina5b85a42019-02-28 14:50:25 -0800438 auto start = std::chrono::steady_clock::now();
Aaron Wisnerdb511202018-06-26 15:38:35 -0500439
440 auto set_response = [response](std::string s) {
441 if (response) *response = std::move(s);
442 };
443 auto add_info = [info](std::string s) {
444 if (info) info->push_back(std::move(s));
445 };
446
447 // erase response
448 set_response("");
Dima Zavina5b85a42019-02-28 14:50:25 -0800449 while ((std::chrono::steady_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
David Anderson1d887432018-08-27 16:47:32 -0700450 int r = transport_->Read(status, FB_RESPONSE_SZ);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500451 if (r < 0) {
452 error_ = ErrnoStr("Status read failed");
453 return IO_ERROR;
454 }
455
456 status[r] = '\0'; // Need the null terminator
457 std::string input(status);
458 if (android::base::StartsWith(input, "INFO")) {
459 std::string tmp = input.substr(strlen("INFO"));
Tom Cherry9027af02018-09-24 15:48:09 -0700460 info_(tmp);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500461 add_info(std::move(tmp));
Dima Zavin6d46a492019-02-23 21:14:38 -0800462 // We may receive one or more INFO packets during long operations,
463 // e.g. flash/erase if they are back by slow media like NAND/NOR
464 // flash. In that case, reset the timer since it's not a real
465 // timeout.
466 start = std::chrono::steady_clock::now();
Aaron Wisnerdb511202018-06-26 15:38:35 -0500467 } else if (android::base::StartsWith(input, "OKAY")) {
468 set_response(input.substr(strlen("OKAY")));
469 return SUCCESS;
470 } else if (android::base::StartsWith(input, "FAIL")) {
471 error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
472 set_response(input.substr(strlen("FAIL")));
473 return DEVICE_FAIL;
474 } else if (android::base::StartsWith(input, "DATA")) {
475 std::string tmp = input.substr(strlen("DATA"));
476 uint32_t num = strtol(tmp.c_str(), 0, 16);
477 if (num > MAX_DOWNLOAD_SIZE) {
478 error_ = android::base::StringPrintf("Data size too large (%d)", num);
479 return BAD_DEV_RESP;
480 }
481 if (dsize) *dsize = num;
482 set_response(std::move(tmp));
483 return SUCCESS;
484 } else {
485 error_ = android::base::StringPrintf("Device sent unknown status code: %s", status);
486 return BAD_DEV_RESP;
487 }
488
489 } // End of while loop
490
491 return TIMEOUT;
492}
493
494std::string FastBootDriver::ErrnoStr(const std::string& msg) {
495 return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
496}
497
Aaron Wisnerdb511202018-06-26 15:38:35 -0500498/******************************* PRIVATE **************************************/
499RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
500 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
501 off64_t offset = 0;
502 uint32_t remaining = size;
503 RetCode ret;
504
505 while (remaining) {
506 // Memory map the file
Aaron Wisnerdb511202018-06-26 15:38:35 -0500507 size_t len = std::min(remaining, MAX_MAP_SIZE);
Elliott Hughese8f4b142018-10-19 16:09:39 -0700508 auto mapping{android::base::MappedFile::FromFd(fd, offset, len, PROT_READ)};
509 if (!mapping) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500510 error_ = "Creating filemap failed";
511 return IO_ERROR;
512 }
513
Elliott Hughese8f4b142018-10-19 16:09:39 -0700514 if ((ret = SendBuffer(mapping->data(), mapping->size()))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500515 return ret;
516 }
517
518 remaining -= len;
519 offset += len;
520 }
521
522 return SUCCESS;
523}
524
525RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) {
526 // Write the buffer
527 return SendBuffer(buf.data(), buf.size());
528}
529
530RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500531 // ioctl on 0-length buffer causes freezing
David Anderson0c7bde82018-07-30 12:54:53 -0700532 if (!size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500533 return BAD_ARG;
David Anderson0c7bde82018-07-30 12:54:53 -0700534 }
Aaron Wisnerdb511202018-06-26 15:38:35 -0500535 // Write the buffer
David Anderson1d887432018-08-27 16:47:32 -0700536 ssize_t tmp = transport_->Write(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500537
538 if (tmp < 0) {
539 error_ = ErrnoStr("Write to device failed in SendBuffer()");
540 return IO_ERROR;
541 } else if (static_cast<size_t>(tmp) != size) {
542 error_ = android::base::StringPrintf("Failed to write all %zu bytes", size);
543
544 return IO_ERROR;
545 }
546
547 return SUCCESS;
548}
549
Aaron Wisnerdb511202018-06-26 15:38:35 -0500550RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
551 // Read the buffer
David Anderson1d887432018-08-27 16:47:32 -0700552 ssize_t tmp = transport_->Read(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500553
554 if (tmp < 0) {
555 error_ = ErrnoStr("Read from device failed in ReadBuffer()");
556 return IO_ERROR;
557 } else if (static_cast<size_t>(tmp) != size) {
558 error_ = android::base::StringPrintf("Failed to read all %zu bytes", size);
559 return IO_ERROR;
560 }
561
562 return SUCCESS;
563}
564
565int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) {
566 size_t total = 0;
567 size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len);
568
569 // Handle the residual
570 tpbuf.insert(tpbuf.end(), data, data + to_write);
571 if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) { // Nothing enough to send rn
572 return 0;
573 }
574
575 if (SendBuffer(tpbuf)) {
576 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
577 return -1;
578 }
579 tpbuf.clear();
580 total += to_write;
581
582 // Now we need to send a multiple of chunk size
583 size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
584 size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500585 if (nbytes && SendBuffer(data + total, nbytes)) { // Don't send a ZLP
Aaron Wisnerdb511202018-06-26 15:38:35 -0500586 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
587 return -1;
588 }
589 total += nbytes;
590
591 if (len - total > 0) { // We have residual data to save for next time
592 tpbuf.assign(data + total, data + len);
593 }
594
595 return 0;
596}
597
David Anderson03de6452018-09-04 14:32:54 -0700598Transport* FastBootDriver::set_transport(Transport* transport) {
599 std::swap(transport_, transport);
600 return transport;
David Anderson1d887432018-08-27 16:47:32 -0700601}
602
Aaron Wisnerdb511202018-06-26 15:38:35 -0500603} // End namespace fastboot