blob: 79305c4141fd366b3fb68037fca233d755c5b9ae [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>
Tom Cherry9027af02018-09-24 15:48:09 -070048
49#include "constants.h"
Aaron Wisnerdb511202018-06-26 15:38:35 -050050#include "transport.h"
51
Tom Cherry9027af02018-09-24 15:48:09 -070052using android::base::StringPrintf;
53
Aaron Wisnerdb511202018-06-26 15:38:35 -050054namespace fastboot {
55
56/*************************** PUBLIC *******************************/
Tom Cherry9027af02018-09-24 15:48:09 -070057FastBootDriver::FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks,
Aaron Wisnerdb511202018-06-26 15:38:35 -050058 bool no_checks)
Tom Cherry9027af02018-09-24 15:48:09 -070059 : transport_(transport),
60 prolog_(std::move(driver_callbacks.prolog)),
61 epilog_(std::move(driver_callbacks.epilog)),
62 info_(std::move(driver_callbacks.info)),
63 disable_checks_(no_checks) {}
Aaron Wisnerdb511202018-06-26 15:38:35 -050064
David Anderson1d887432018-08-27 16:47:32 -070065FastBootDriver::~FastBootDriver() {
David Anderson1d887432018-08-27 16:47:32 -070066}
67
Aaron Wisnerdb511202018-06-26 15:38:35 -050068RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070069 return RawCommand(FB_CMD_BOOT, "Booting", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050070}
71
72RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070073 return RawCommand(FB_CMD_CONTINUE, "Resuming boot", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050074}
75
Tom Cherry9027af02018-09-24 15:48:09 -070076RetCode FastBootDriver::CreatePartition(const std::string& partition, const std::string& size) {
77 return RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size,
78 "Creating '" + partition + "'");
Aaron Wisnerdb511202018-06-26 15:38:35 -050079}
80
Tom Cherry9027af02018-09-24 15:48:09 -070081RetCode FastBootDriver::DeletePartition(const std::string& partition) {
82 return RawCommand(FB_CMD_DELETE_PARTITION ":" + partition, "Deleting '" + partition + "'");
83}
84
85RetCode FastBootDriver::Erase(const std::string& partition, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -050086 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070087 return RawCommand(FB_CMD_ERASE ":" + partition, "Erasing '" + partition + "'", response, info);
88}
89
90RetCode FastBootDriver::Flash(const std::string& partition, std::string* response,
91 std::vector<std::string>* info) {
92 return RawCommand(FB_CMD_FLASH ":" + partition, "Writing '" + partition + "'", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050093}
94
95RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
96 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070097 return RawCommand(FB_CMD_GETVAR ":" + key, val, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050098}
99
100RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
101 std::string tmp;
102 return GetVar("all", &tmp, response);
103}
104
Aaron Wisnerdb511202018-06-26 15:38:35 -0500105RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700106 return RawCommand(FB_CMD_REBOOT, "Rebooting", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500107}
108
David Anderson1d887432018-08-27 16:47:32 -0700109RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
110 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700111 return RawCommand("reboot-" + target, "Rebooting into " + target, response, info);
112}
113
114RetCode FastBootDriver::ResizePartition(const std::string& partition, const std::string& size) {
115 return RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size,
116 "Resizing '" + partition + "'");
David Anderson1d887432018-08-27 16:47:32 -0700117}
118
Tom Cherry11f12092018-08-29 21:36:28 -0700119RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500120 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700121 return RawCommand(FB_CMD_SET_ACTIVE ":" + slot, "Setting current slot to '" + slot + "'",
122 response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500123}
124
David Andersonab8f4662019-10-21 16:45:59 -0700125RetCode FastBootDriver::SnapshotUpdateCommand(const std::string& command, std::string* response,
126 std::vector<std::string>* info) {
David Anderson220ddb12019-10-31 18:02:41 -0700127 prolog_(StringPrintf("Snapshot %s", command.c_str()));
David Andersonab8f4662019-10-21 16:45:59 -0700128 std::string raw = FB_CMD_SNAPSHOT_UPDATE ":" + command;
David Anderson220ddb12019-10-31 18:02:41 -0700129 auto result = RawCommand(raw, response, info);
130 epilog_(result);
131 return result;
David Andersonab8f4662019-10-21 16:45:59 -0700132}
133
Tom Cherry9027af02018-09-24 15:48:09 -0700134RetCode FastBootDriver::FlashPartition(const std::string& partition,
135 const std::vector<char>& data) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500136 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700137 if ((ret = Download(partition, data))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500138 return ret;
139 }
Tom Cherry9027af02018-09-24 15:48:09 -0700140 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500141}
142
Tom Cherry9027af02018-09-24 15:48:09 -0700143RetCode FastBootDriver::FlashPartition(const std::string& partition, int fd, uint32_t size) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500144 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700145 if ((ret = Download(partition, fd, size))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500146 return ret;
147 }
Tom Cherry9027af02018-09-24 15:48:09 -0700148 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500149}
150
Tom Cherry9027af02018-09-24 15:48:09 -0700151RetCode FastBootDriver::FlashPartition(const std::string& partition, sparse_file* s, uint32_t size,
152 size_t current, size_t total) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500153 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700154 if ((ret = Download(partition, s, size, current, total, false))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500155 return ret;
156 }
Tom Cherry9027af02018-09-24 15:48:09 -0700157 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500158}
159
Tom Cherry9027af02018-09-24 15:48:09 -0700160RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500161 std::vector<std::string> all;
162 RetCode ret;
163 if ((ret = GetVarAll(&all))) {
164 return ret;
165 }
166
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500167 std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)");
Aaron Wisnerdb511202018-06-26 15:38:35 -0500168 std::smatch sm;
169
170 for (auto& s : all) {
171 if (std::regex_match(s, sm, reg)) {
172 std::string m1(sm[1]);
173 std::string m2(sm[2]);
David Anderson6c30f6e2018-09-04 15:57:39 -0700174 uint64_t tmp = strtoll(m2.c_str(), 0, 16);
Tom Cherry9027af02018-09-24 15:48:09 -0700175 partitions->push_back(std::make_tuple(m1, tmp));
Aaron Wisnerdb511202018-06-26 15:38:35 -0500176 }
177 }
178 return SUCCESS;
179}
180
Tom Cherry9027af02018-09-24 15:48:09 -0700181RetCode FastBootDriver::Download(const std::string& name, int fd, size_t size,
182 std::string* response, std::vector<std::string>* info) {
183 prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), size / 1024));
184 auto result = Download(fd, size, response, info);
185 epilog_(result);
186 return result;
187}
188
Aaron Wisnerdb511202018-06-26 15:38:35 -0500189RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
190 std::vector<std::string>* info) {
191 RetCode ret;
192
193 if ((size <= 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
194 error_ = "File is too large to download";
195 return BAD_ARG;
196 }
197
198 uint32_t u32size = static_cast<uint32_t>(size);
199 if ((ret = DownloadCommand(u32size, response, info))) {
200 return ret;
201 }
202
203 // Write the buffer
204 if ((ret = SendBuffer(fd, size))) {
205 return ret;
206 }
207
208 // Wait for response
209 return HandleResponse(response, info);
210}
211
Tom Cherry9027af02018-09-24 15:48:09 -0700212RetCode FastBootDriver::Download(const std::string& name, const std::vector<char>& buf,
213 std::string* response, std::vector<std::string>* info) {
214 prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), buf.size() / 1024));
215 auto result = Download(buf, response, info);
216 epilog_(result);
217 return result;
218}
219
Aaron Wisnerdb511202018-06-26 15:38:35 -0500220RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
221 std::vector<std::string>* info) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500222 RetCode ret;
223 error_ = "";
Tom Cherrydfd85df2018-09-20 14:45:05 -0700224 if ((buf.size() == 0 || buf.size() > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500225 error_ = "Buffer is too large or 0 bytes";
226 return BAD_ARG;
227 }
228
Tom Cherrydfd85df2018-09-20 14:45:05 -0700229 if ((ret = DownloadCommand(buf.size(), response, info))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500230 return ret;
231 }
232
233 // Write the buffer
Tom Cherrydfd85df2018-09-20 14:45:05 -0700234 if ((ret = SendBuffer(buf))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500235 return ret;
236 }
237
238 // Wait for response
239 return HandleResponse(response, info);
240}
241
Tom Cherry9027af02018-09-24 15:48:09 -0700242RetCode FastBootDriver::Download(const std::string& partition, struct sparse_file* s, uint32_t size,
243 size_t current, size_t total, bool use_crc, std::string* response,
244 std::vector<std::string>* info) {
245 prolog_(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
246 size / 1024));
247 auto result = Download(s, use_crc, response, info);
248 epilog_(result);
249 return result;
250}
251
Aaron Wisner9812b582018-08-22 11:01:04 -0500252RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500253 std::vector<std::string>* info) {
254 error_ = "";
Aaron Wisner9812b582018-08-22 11:01:04 -0500255 int64_t size = sparse_file_len(s, true, use_crc);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500256 if (size <= 0 || size > MAX_DOWNLOAD_SIZE) {
257 error_ = "Sparse file is too large or invalid";
258 return BAD_ARG;
259 }
260
261 RetCode ret;
262 uint32_t u32size = static_cast<uint32_t>(size);
263 if ((ret = DownloadCommand(u32size, response, info))) {
264 return ret;
265 }
266
267 struct SparseCBPrivate {
268 FastBootDriver* self;
269 std::vector<char> tpbuf;
270 } cb_priv;
271 cb_priv.self = this;
272
273 auto cb = [](void* priv, const void* buf, size_t len) -> int {
274 SparseCBPrivate* data = static_cast<SparseCBPrivate*>(priv);
275 const char* cbuf = static_cast<const char*>(buf);
276 return data->self->SparseWriteCallback(data->tpbuf, cbuf, len);
277 };
278
Aaron Wisner9812b582018-08-22 11:01:04 -0500279 if (sparse_file_callback(s, true, use_crc, cb, &cb_priv) < 0) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500280 error_ = "Error reading sparse file";
281 return IO_ERROR;
282 }
283
284 // Now flush
285 if (cb_priv.tpbuf.size() && (ret = SendBuffer(cb_priv.tpbuf))) {
286 return ret;
287 }
288
289 return HandleResponse(response, info);
290}
291
292RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
293 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700294 prolog_("Uploading '" + outfile + "'");
295 auto result = UploadInner(outfile, response, info);
296 epilog_(result);
297 return result;
298}
299
Yifan Hongbbf374d2021-02-17 11:16:39 -0800300// This function executes cmd, then expect a "DATA" response with a number N, followed
301// by N bytes, and another response.
302// This is the common way for the device to send data to the driver used by upload and fetch.
303RetCode FastBootDriver::RunAndReadBuffer(
304 const std::string& cmd, std::string* response, std::vector<std::string>* info,
305 const std::function<RetCode(const char* data, uint64_t size)>& write_fn) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500306 RetCode ret;
qiwu chen325ba6f2019-08-29 14:50:51 +0800307 int dsize = 0;
Yifan Hongbbf374d2021-02-17 11:16:39 -0800308 if ((ret = RawCommand(cmd, response, info, &dsize))) {
309 error_ = android::base::StringPrintf("%s request failed: %s", cmd.c_str(), error_.c_str());
Aaron Wisnerdb511202018-06-26 15:38:35 -0500310 return ret;
311 }
312
Yifan Hongbbf374d2021-02-17 11:16:39 -0800313 if (dsize <= 0) {
314 error_ = android::base::StringPrintf("%s request failed, device reports %d bytes available",
315 cmd.c_str(), dsize);
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500316 return BAD_DEV_RESP;
317 }
318
Yifan Hongbbf374d2021-02-17 11:16:39 -0800319 std::vector<char> data(dsize);
320 if ((ret = ReadBuffer(data.data(), data.size())) != SUCCESS) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500321 return ret;
322 }
Yifan Hongbbf374d2021-02-17 11:16:39 -0800323 if ((ret = write_fn(data.data(), data.size())) != SUCCESS) {
324 return ret;
325 }
326 return HandleResponse(response, info);
327}
Aaron Wisnerdb511202018-06-26 15:38:35 -0500328
Yifan Hongbbf374d2021-02-17 11:16:39 -0800329RetCode FastBootDriver::UploadInner(const std::string& outfile, std::string* response,
330 std::vector<std::string>* info) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500331 std::ofstream ofs;
332 ofs.open(outfile, std::ofstream::out | std::ofstream::binary);
333 if (ofs.fail()) {
334 error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str());
335 return IO_ERROR;
336 }
Yifan Hongbbf374d2021-02-17 11:16:39 -0800337 auto write_fn = [&](const char* data, uint64_t size) {
338 ofs.write(data, size);
339 if (ofs.fail() || ofs.bad()) {
340 error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str());
341 return IO_ERROR;
342 }
343 return SUCCESS;
344 };
345 RetCode ret = RunAndReadBuffer(FB_CMD_UPLOAD, response, info, write_fn);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500346 ofs.close();
Yifan Hongbbf374d2021-02-17 11:16:39 -0800347 return ret;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500348}
349
350// Helpers
Tom Cherry9027af02018-09-24 15:48:09 -0700351void FastBootDriver::SetInfoCallback(std::function<void(const std::string&)> info) {
352 info_ = info;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500353}
354
355const std::string FastBootDriver::RCString(RetCode rc) {
356 switch (rc) {
357 case SUCCESS:
358 return std::string("Success");
359
360 case BAD_ARG:
361 return std::string("Invalid Argument");
362
363 case IO_ERROR:
364 return std::string("I/O Error");
365
366 case BAD_DEV_RESP:
367 return std::string("Invalid Device Response");
368
369 case DEVICE_FAIL:
370 return std::string("Device Error");
371
372 case TIMEOUT:
373 return std::string("Timeout");
374
375 default:
376 return std::string("Unknown Error");
377 }
378}
379
380std::string FastBootDriver::Error() {
381 return error_;
382}
383
384RetCode FastBootDriver::WaitForDisconnect() {
David Anderson1d887432018-08-27 16:47:32 -0700385 return transport_->WaitForDisconnect() ? IO_ERROR : SUCCESS;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500386}
387
388/****************************** PROTECTED *************************************/
Tom Cherry9027af02018-09-24 15:48:09 -0700389RetCode FastBootDriver::RawCommand(const std::string& cmd, const std::string& message,
390 std::string* response, std::vector<std::string>* info,
391 int* dsize) {
392 prolog_(message);
393 auto result = RawCommand(cmd, response, info, dsize);
394 epilog_(result);
395 return result;
396}
397
Aaron Wisnerdb511202018-06-26 15:38:35 -0500398RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
399 std::vector<std::string>* info, int* dsize) {
400 error_ = ""; // Clear any pending error
401 if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) {
402 error_ = "Command length to RawCommand() is too long";
403 return BAD_ARG;
404 }
405
David Anderson1d887432018-08-27 16:47:32 -0700406 if (transport_->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500407 error_ = ErrnoStr("Write to device failed");
408 return IO_ERROR;
409 }
410
411 // Read the response
412 return HandleResponse(response, info, dsize);
413}
414
415RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
416 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700417 std::string cmd(android::base::StringPrintf("%s:%08" PRIx32, FB_CMD_DOWNLOAD, size));
Aaron Wisnerdb511202018-06-26 15:38:35 -0500418 RetCode ret;
419 if ((ret = RawCommand(cmd, response, info))) {
420 return ret;
421 }
422 return SUCCESS;
423}
424
425RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
426 int* dsize) {
427 char status[FB_RESPONSE_SZ + 1];
Dima Zavina5b85a42019-02-28 14:50:25 -0800428 auto start = std::chrono::steady_clock::now();
Aaron Wisnerdb511202018-06-26 15:38:35 -0500429
430 auto set_response = [response](std::string s) {
431 if (response) *response = std::move(s);
432 };
433 auto add_info = [info](std::string s) {
434 if (info) info->push_back(std::move(s));
435 };
436
437 // erase response
438 set_response("");
Dima Zavina5b85a42019-02-28 14:50:25 -0800439 while ((std::chrono::steady_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
David Anderson1d887432018-08-27 16:47:32 -0700440 int r = transport_->Read(status, FB_RESPONSE_SZ);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500441 if (r < 0) {
442 error_ = ErrnoStr("Status read failed");
443 return IO_ERROR;
444 }
445
446 status[r] = '\0'; // Need the null terminator
447 std::string input(status);
448 if (android::base::StartsWith(input, "INFO")) {
449 std::string tmp = input.substr(strlen("INFO"));
Tom Cherry9027af02018-09-24 15:48:09 -0700450 info_(tmp);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500451 add_info(std::move(tmp));
Dima Zavin6d46a492019-02-23 21:14:38 -0800452 // We may receive one or more INFO packets during long operations,
453 // e.g. flash/erase if they are back by slow media like NAND/NOR
454 // flash. In that case, reset the timer since it's not a real
455 // timeout.
456 start = std::chrono::steady_clock::now();
Aaron Wisnerdb511202018-06-26 15:38:35 -0500457 } else if (android::base::StartsWith(input, "OKAY")) {
458 set_response(input.substr(strlen("OKAY")));
459 return SUCCESS;
460 } else if (android::base::StartsWith(input, "FAIL")) {
461 error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
462 set_response(input.substr(strlen("FAIL")));
463 return DEVICE_FAIL;
464 } else if (android::base::StartsWith(input, "DATA")) {
465 std::string tmp = input.substr(strlen("DATA"));
466 uint32_t num = strtol(tmp.c_str(), 0, 16);
467 if (num > MAX_DOWNLOAD_SIZE) {
468 error_ = android::base::StringPrintf("Data size too large (%d)", num);
469 return BAD_DEV_RESP;
470 }
471 if (dsize) *dsize = num;
472 set_response(std::move(tmp));
473 return SUCCESS;
474 } else {
475 error_ = android::base::StringPrintf("Device sent unknown status code: %s", status);
476 return BAD_DEV_RESP;
477 }
478
479 } // End of while loop
480
481 return TIMEOUT;
482}
483
484std::string FastBootDriver::ErrnoStr(const std::string& msg) {
485 return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
486}
487
Aaron Wisnerdb511202018-06-26 15:38:35 -0500488/******************************* PRIVATE **************************************/
489RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
490 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
491 off64_t offset = 0;
492 uint32_t remaining = size;
493 RetCode ret;
494
495 while (remaining) {
496 // Memory map the file
Aaron Wisnerdb511202018-06-26 15:38:35 -0500497 size_t len = std::min(remaining, MAX_MAP_SIZE);
Elliott Hughese8f4b142018-10-19 16:09:39 -0700498 auto mapping{android::base::MappedFile::FromFd(fd, offset, len, PROT_READ)};
499 if (!mapping) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500500 error_ = "Creating filemap failed";
501 return IO_ERROR;
502 }
503
Elliott Hughese8f4b142018-10-19 16:09:39 -0700504 if ((ret = SendBuffer(mapping->data(), mapping->size()))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500505 return ret;
506 }
507
508 remaining -= len;
509 offset += len;
510 }
511
512 return SUCCESS;
513}
514
515RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) {
516 // Write the buffer
517 return SendBuffer(buf.data(), buf.size());
518}
519
520RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500521 // ioctl on 0-length buffer causes freezing
David Anderson0c7bde82018-07-30 12:54:53 -0700522 if (!size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500523 return BAD_ARG;
David Anderson0c7bde82018-07-30 12:54:53 -0700524 }
Aaron Wisnerdb511202018-06-26 15:38:35 -0500525 // Write the buffer
David Anderson1d887432018-08-27 16:47:32 -0700526 ssize_t tmp = transport_->Write(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500527
528 if (tmp < 0) {
529 error_ = ErrnoStr("Write to device failed in SendBuffer()");
530 return IO_ERROR;
531 } else if (static_cast<size_t>(tmp) != size) {
532 error_ = android::base::StringPrintf("Failed to write all %zu bytes", size);
533
534 return IO_ERROR;
535 }
536
537 return SUCCESS;
538}
539
Aaron Wisnerdb511202018-06-26 15:38:35 -0500540RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
541 // Read the buffer
David Anderson1d887432018-08-27 16:47:32 -0700542 ssize_t tmp = transport_->Read(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500543
544 if (tmp < 0) {
545 error_ = ErrnoStr("Read from device failed in ReadBuffer()");
546 return IO_ERROR;
547 } else if (static_cast<size_t>(tmp) != size) {
548 error_ = android::base::StringPrintf("Failed to read all %zu bytes", size);
549 return IO_ERROR;
550 }
551
552 return SUCCESS;
553}
554
555int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) {
556 size_t total = 0;
557 size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len);
558
559 // Handle the residual
560 tpbuf.insert(tpbuf.end(), data, data + to_write);
561 if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) { // Nothing enough to send rn
562 return 0;
563 }
564
565 if (SendBuffer(tpbuf)) {
566 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
567 return -1;
568 }
569 tpbuf.clear();
570 total += to_write;
571
572 // Now we need to send a multiple of chunk size
573 size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
574 size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500575 if (nbytes && SendBuffer(data + total, nbytes)) { // Don't send a ZLP
Aaron Wisnerdb511202018-06-26 15:38:35 -0500576 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
577 return -1;
578 }
579 total += nbytes;
580
581 if (len - total > 0) { // We have residual data to save for next time
582 tpbuf.assign(data + total, data + len);
583 }
584
585 return 0;
586}
587
David Anderson03de6452018-09-04 14:32:54 -0700588Transport* FastBootDriver::set_transport(Transport* transport) {
589 std::swap(transport_, transport);
590 return transport;
David Anderson1d887432018-08-27 16:47:32 -0700591}
592
Aaron Wisnerdb511202018-06-26 15:38:35 -0500593} // End namespace fastboot