blob: e5ef66bafe90c0a4f4b4d8040f6467be3763577c [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 *******************************/
Dmitrii Merkurev0b627d92023-09-03 17:30:46 +010061FastBootDriver::FastBootDriver(std::unique_ptr<Transport> transport,
62 DriverCallbacks driver_callbacks,
Aaron Wisnerdb511202018-06-26 15:38:35 -050063 bool no_checks)
Dmitrii Merkurev0b627d92023-09-03 17:30:46 +010064 : transport_(std::move(transport)),
Tom Cherry9027af02018-09-24 15:48:09 -070065 prolog_(std::move(driver_callbacks.prolog)),
66 epilog_(std::move(driver_callbacks.epilog)),
67 info_(std::move(driver_callbacks.info)),
Raphael Herouart99097cc2022-12-30 11:51:54 +000068 text_(std::move(driver_callbacks.text)),
Tom Cherry9027af02018-09-24 15:48:09 -070069 disable_checks_(no_checks) {}
Aaron Wisnerdb511202018-06-26 15:38:35 -050070
David Anderson1d887432018-08-27 16:47:32 -070071FastBootDriver::~FastBootDriver() {
David Anderson1d887432018-08-27 16:47:32 -070072}
73
Aaron Wisnerdb511202018-06-26 15:38:35 -050074RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070075 return RawCommand(FB_CMD_BOOT, "Booting", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050076}
77
78RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070079 return RawCommand(FB_CMD_CONTINUE, "Resuming boot", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050080}
81
Tom Cherry9027af02018-09-24 15:48:09 -070082RetCode FastBootDriver::CreatePartition(const std::string& partition, const std::string& size) {
83 return RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size,
84 "Creating '" + partition + "'");
Aaron Wisnerdb511202018-06-26 15:38:35 -050085}
86
Tom Cherry9027af02018-09-24 15:48:09 -070087RetCode FastBootDriver::DeletePartition(const std::string& partition) {
88 return RawCommand(FB_CMD_DELETE_PARTITION ":" + partition, "Deleting '" + partition + "'");
89}
90
91RetCode FastBootDriver::Erase(const std::string& partition, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -050092 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -070093 return RawCommand(FB_CMD_ERASE ":" + partition, "Erasing '" + partition + "'", response, info);
94}
95
96RetCode FastBootDriver::Flash(const std::string& partition, std::string* response,
97 std::vector<std::string>* info) {
98 return RawCommand(FB_CMD_FLASH ":" + partition, "Writing '" + partition + "'", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -050099}
100
101RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
102 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700103 return RawCommand(FB_CMD_GETVAR ":" + key, val, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500104}
105
106RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
107 std::string tmp;
108 return GetVar("all", &tmp, response);
109}
110
Aaron Wisnerdb511202018-06-26 15:38:35 -0500111RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700112 return RawCommand(FB_CMD_REBOOT, "Rebooting", response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500113}
114
David Anderson1d887432018-08-27 16:47:32 -0700115RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
116 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700117 return RawCommand("reboot-" + target, "Rebooting into " + target, response, info);
118}
119
120RetCode FastBootDriver::ResizePartition(const std::string& partition, const std::string& size) {
121 return RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size,
122 "Resizing '" + partition + "'");
David Anderson1d887432018-08-27 16:47:32 -0700123}
124
Tom Cherry11f12092018-08-29 21:36:28 -0700125RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500126 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700127 return RawCommand(FB_CMD_SET_ACTIVE ":" + slot, "Setting current slot to '" + slot + "'",
128 response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500129}
130
David Andersonab8f4662019-10-21 16:45:59 -0700131RetCode FastBootDriver::SnapshotUpdateCommand(const std::string& command, std::string* response,
132 std::vector<std::string>* info) {
David Anderson220ddb12019-10-31 18:02:41 -0700133 prolog_(StringPrintf("Snapshot %s", command.c_str()));
David Andersonab8f4662019-10-21 16:45:59 -0700134 std::string raw = FB_CMD_SNAPSHOT_UPDATE ":" + command;
David Anderson220ddb12019-10-31 18:02:41 -0700135 auto result = RawCommand(raw, response, info);
136 epilog_(result);
137 return result;
David Andersonab8f4662019-10-21 16:45:59 -0700138}
139
Tom Cherry9027af02018-09-24 15:48:09 -0700140RetCode FastBootDriver::FlashPartition(const std::string& partition,
141 const std::vector<char>& data) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500142 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700143 if ((ret = Download(partition, data))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500144 return ret;
145 }
Tom Cherry9027af02018-09-24 15:48:09 -0700146 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500147}
148
Yifan Hong58532df2021-03-22 16:39:13 -0700149RetCode FastBootDriver::FlashPartition(const std::string& partition, android::base::borrowed_fd fd,
150 uint32_t size) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500151 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700152 if ((ret = Download(partition, fd, size))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500153 return ret;
154 }
Tom Cherry9027af02018-09-24 15:48:09 -0700155 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500156}
157
Tom Cherry9027af02018-09-24 15:48:09 -0700158RetCode FastBootDriver::FlashPartition(const std::string& partition, sparse_file* s, uint32_t size,
159 size_t current, size_t total) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500160 RetCode ret;
Tom Cherry9027af02018-09-24 15:48:09 -0700161 if ((ret = Download(partition, s, size, current, total, false))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500162 return ret;
163 }
Tom Cherry9027af02018-09-24 15:48:09 -0700164 return Flash(partition);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500165}
166
Tom Cherry9027af02018-09-24 15:48:09 -0700167RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500168 std::vector<std::string> all;
169 RetCode ret;
170 if ((ret = GetVarAll(&all))) {
171 return ret;
172 }
173
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500174 std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)");
Aaron Wisnerdb511202018-06-26 15:38:35 -0500175 std::smatch sm;
176
177 for (auto& s : all) {
178 if (std::regex_match(s, sm, reg)) {
179 std::string m1(sm[1]);
180 std::string m2(sm[2]);
David Anderson6c30f6e2018-09-04 15:57:39 -0700181 uint64_t tmp = strtoll(m2.c_str(), 0, 16);
Tom Cherry9027af02018-09-24 15:48:09 -0700182 partitions->push_back(std::make_tuple(m1, tmp));
Aaron Wisnerdb511202018-06-26 15:38:35 -0500183 }
184 }
185 return SUCCESS;
186}
187
Yifan Hong58532df2021-03-22 16:39:13 -0700188RetCode FastBootDriver::Download(const std::string& name, android::base::borrowed_fd fd,
189 size_t size, std::string* response,
190 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700191 prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), size / 1024));
192 auto result = Download(fd, size, response, info);
193 epilog_(result);
194 return result;
195}
196
Yifan Hong58532df2021-03-22 16:39:13 -0700197RetCode FastBootDriver::Download(android::base::borrowed_fd fd, size_t size, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500198 std::vector<std::string>* info) {
199 RetCode ret;
200
201 if ((size <= 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
202 error_ = "File is too large to download";
203 return BAD_ARG;
204 }
205
206 uint32_t u32size = static_cast<uint32_t>(size);
207 if ((ret = DownloadCommand(u32size, response, info))) {
208 return ret;
209 }
210
211 // Write the buffer
212 if ((ret = SendBuffer(fd, size))) {
213 return ret;
214 }
215
216 // Wait for response
217 return HandleResponse(response, info);
218}
219
Tom Cherry9027af02018-09-24 15:48:09 -0700220RetCode FastBootDriver::Download(const std::string& name, const std::vector<char>& buf,
221 std::string* response, std::vector<std::string>* info) {
222 prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), buf.size() / 1024));
223 auto result = Download(buf, response, info);
224 epilog_(result);
225 return result;
226}
227
Aaron Wisnerdb511202018-06-26 15:38:35 -0500228RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
229 std::vector<std::string>* info) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500230 RetCode ret;
231 error_ = "";
Tom Cherrydfd85df2018-09-20 14:45:05 -0700232 if ((buf.size() == 0 || buf.size() > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500233 error_ = "Buffer is too large or 0 bytes";
234 return BAD_ARG;
235 }
236
Tom Cherrydfd85df2018-09-20 14:45:05 -0700237 if ((ret = DownloadCommand(buf.size(), response, info))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500238 return ret;
239 }
240
241 // Write the buffer
Tom Cherrydfd85df2018-09-20 14:45:05 -0700242 if ((ret = SendBuffer(buf))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500243 return ret;
244 }
245
246 // Wait for response
247 return HandleResponse(response, info);
248}
249
Tom Cherry9027af02018-09-24 15:48:09 -0700250RetCode FastBootDriver::Download(const std::string& partition, struct sparse_file* s, uint32_t size,
251 size_t current, size_t total, bool use_crc, std::string* response,
252 std::vector<std::string>* info) {
253 prolog_(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
254 size / 1024));
255 auto result = Download(s, use_crc, response, info);
256 epilog_(result);
257 return result;
258}
259
Aaron Wisner9812b582018-08-22 11:01:04 -0500260RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500261 std::vector<std::string>* info) {
262 error_ = "";
Aaron Wisner9812b582018-08-22 11:01:04 -0500263 int64_t size = sparse_file_len(s, true, use_crc);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500264 if (size <= 0 || size > MAX_DOWNLOAD_SIZE) {
265 error_ = "Sparse file is too large or invalid";
266 return BAD_ARG;
267 }
268
269 RetCode ret;
270 uint32_t u32size = static_cast<uint32_t>(size);
271 if ((ret = DownloadCommand(u32size, response, info))) {
272 return ret;
273 }
274
275 struct SparseCBPrivate {
276 FastBootDriver* self;
277 std::vector<char> tpbuf;
278 } cb_priv;
279 cb_priv.self = this;
280
281 auto cb = [](void* priv, const void* buf, size_t len) -> int {
282 SparseCBPrivate* data = static_cast<SparseCBPrivate*>(priv);
283 const char* cbuf = static_cast<const char*>(buf);
284 return data->self->SparseWriteCallback(data->tpbuf, cbuf, len);
285 };
286
Aaron Wisner9812b582018-08-22 11:01:04 -0500287 if (sparse_file_callback(s, true, use_crc, cb, &cb_priv) < 0) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500288 error_ = "Error reading sparse file";
289 return IO_ERROR;
290 }
291
292 // Now flush
293 if (cb_priv.tpbuf.size() && (ret = SendBuffer(cb_priv.tpbuf))) {
294 return ret;
295 }
296
297 return HandleResponse(response, info);
298}
299
300RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
301 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700302 prolog_("Uploading '" + outfile + "'");
303 auto result = UploadInner(outfile, response, info);
304 epilog_(result);
305 return result;
306}
307
Yifan Hongbbf374d2021-02-17 11:16:39 -0800308// This function executes cmd, then expect a "DATA" response with a number N, followed
309// by N bytes, and another response.
310// This is the common way for the device to send data to the driver used by upload and fetch.
311RetCode FastBootDriver::RunAndReadBuffer(
312 const std::string& cmd, std::string* response, std::vector<std::string>* info,
313 const std::function<RetCode(const char* data, uint64_t size)>& write_fn) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500314 RetCode ret;
qiwu chen325ba6f2019-08-29 14:50:51 +0800315 int dsize = 0;
Yifan Hongbbf374d2021-02-17 11:16:39 -0800316 if ((ret = RawCommand(cmd, response, info, &dsize))) {
317 error_ = android::base::StringPrintf("%s request failed: %s", cmd.c_str(), error_.c_str());
Aaron Wisnerdb511202018-06-26 15:38:35 -0500318 return ret;
319 }
320
Yifan Hongbbf374d2021-02-17 11:16:39 -0800321 if (dsize <= 0) {
322 error_ = android::base::StringPrintf("%s request failed, device reports %d bytes available",
323 cmd.c_str(), dsize);
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500324 return BAD_DEV_RESP;
325 }
326
Yifan Hong17d469b2021-02-18 15:15:46 -0800327 const uint64_t total_size = dsize;
328 const uint64_t buf_size = std::min<uint64_t>(total_size, 1_MiB);
329 std::vector<char> data(buf_size);
330 uint64_t current_offset = 0;
331 while (current_offset < total_size) {
332 uint64_t remaining = total_size - current_offset;
333 uint64_t chunk_size = std::min(buf_size, remaining);
334 if ((ret = ReadBuffer(data.data(), chunk_size)) != SUCCESS) {
335 return ret;
336 }
337 if ((ret = write_fn(data.data(), chunk_size)) != SUCCESS) {
338 return ret;
339 }
340 current_offset += chunk_size;
Yifan Hongbbf374d2021-02-17 11:16:39 -0800341 }
342 return HandleResponse(response, info);
343}
Aaron Wisnerdb511202018-06-26 15:38:35 -0500344
Yifan Hongbbf374d2021-02-17 11:16:39 -0800345RetCode FastBootDriver::UploadInner(const std::string& outfile, std::string* response,
346 std::vector<std::string>* info) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500347 std::ofstream ofs;
348 ofs.open(outfile, std::ofstream::out | std::ofstream::binary);
349 if (ofs.fail()) {
350 error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str());
351 return IO_ERROR;
352 }
Yifan Hongbbf374d2021-02-17 11:16:39 -0800353 auto write_fn = [&](const char* data, uint64_t size) {
354 ofs.write(data, size);
355 if (ofs.fail() || ofs.bad()) {
356 error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str());
357 return IO_ERROR;
358 }
359 return SUCCESS;
360 };
361 RetCode ret = RunAndReadBuffer(FB_CMD_UPLOAD, response, info, write_fn);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500362 ofs.close();
Yifan Hongbbf374d2021-02-17 11:16:39 -0800363 return ret;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500364}
365
Yifan Hongbcd27702021-02-16 19:37:32 -0800366RetCode FastBootDriver::FetchToFd(const std::string& partition, android::base::borrowed_fd fd,
367 int64_t offset, int64_t size, std::string* response,
368 std::vector<std::string>* info) {
369 prolog_(android::base::StringPrintf("Fetching %s (offset=%" PRIx64 ", size=%" PRIx64 ")",
370 partition.c_str(), offset, size));
371 std::string cmd = FB_CMD_FETCH ":" + partition;
372 if (offset >= 0) {
373 cmd += android::base::StringPrintf(":0x%08" PRIx64, offset);
374 if (size >= 0) {
375 cmd += android::base::StringPrintf(":0x%08" PRIx64, size);
376 }
377 }
378 RetCode ret = RunAndReadBuffer(cmd, response, info, [&](const char* data, uint64_t size) {
379 if (!android::base::WriteFully(fd, data, size)) {
380 error_ = android::base::StringPrintf("Cannot write: %s", strerror(errno));
381 return IO_ERROR;
382 }
383 return SUCCESS;
384 });
385 epilog_(ret);
386 return ret;
387}
388
Aaron Wisnerdb511202018-06-26 15:38:35 -0500389// Helpers
Tom Cherry9027af02018-09-24 15:48:09 -0700390void FastBootDriver::SetInfoCallback(std::function<void(const std::string&)> info) {
391 info_ = info;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500392}
393
394const std::string FastBootDriver::RCString(RetCode rc) {
395 switch (rc) {
396 case SUCCESS:
397 return std::string("Success");
398
399 case BAD_ARG:
400 return std::string("Invalid Argument");
401
402 case IO_ERROR:
403 return std::string("I/O Error");
404
405 case BAD_DEV_RESP:
406 return std::string("Invalid Device Response");
407
408 case DEVICE_FAIL:
409 return std::string("Device Error");
410
411 case TIMEOUT:
412 return std::string("Timeout");
413
414 default:
415 return std::string("Unknown Error");
416 }
417}
418
419std::string FastBootDriver::Error() {
420 return error_;
421}
422
423RetCode FastBootDriver::WaitForDisconnect() {
David Anderson1d887432018-08-27 16:47:32 -0700424 return transport_->WaitForDisconnect() ? IO_ERROR : SUCCESS;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500425}
426
427/****************************** PROTECTED *************************************/
Tom Cherry9027af02018-09-24 15:48:09 -0700428RetCode FastBootDriver::RawCommand(const std::string& cmd, const std::string& message,
429 std::string* response, std::vector<std::string>* info,
430 int* dsize) {
431 prolog_(message);
432 auto result = RawCommand(cmd, response, info, dsize);
433 epilog_(result);
434 return result;
435}
436
Aaron Wisnerdb511202018-06-26 15:38:35 -0500437RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
438 std::vector<std::string>* info, int* dsize) {
439 error_ = ""; // Clear any pending error
440 if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) {
441 error_ = "Command length to RawCommand() is too long";
442 return BAD_ARG;
443 }
444
David Anderson1d887432018-08-27 16:47:32 -0700445 if (transport_->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500446 error_ = ErrnoStr("Write to device failed");
447 return IO_ERROR;
448 }
449
450 // Read the response
451 return HandleResponse(response, info, dsize);
452}
453
454RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
455 std::vector<std::string>* info) {
Tom Cherry9027af02018-09-24 15:48:09 -0700456 std::string cmd(android::base::StringPrintf("%s:%08" PRIx32, FB_CMD_DOWNLOAD, size));
Aaron Wisnerdb511202018-06-26 15:38:35 -0500457 RetCode ret;
458 if ((ret = RawCommand(cmd, response, info))) {
459 return ret;
460 }
461 return SUCCESS;
462}
463
464RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
465 int* dsize) {
466 char status[FB_RESPONSE_SZ + 1];
Dima Zavina5b85a42019-02-28 14:50:25 -0800467 auto start = std::chrono::steady_clock::now();
Aaron Wisnerdb511202018-06-26 15:38:35 -0500468
469 auto set_response = [response](std::string s) {
470 if (response) *response = std::move(s);
471 };
472 auto add_info = [info](std::string s) {
473 if (info) info->push_back(std::move(s));
474 };
475
476 // erase response
477 set_response("");
Dima Zavina5b85a42019-02-28 14:50:25 -0800478 while ((std::chrono::steady_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
David Anderson1d887432018-08-27 16:47:32 -0700479 int r = transport_->Read(status, FB_RESPONSE_SZ);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500480 if (r < 0) {
481 error_ = ErrnoStr("Status read failed");
482 return IO_ERROR;
483 }
484
485 status[r] = '\0'; // Need the null terminator
486 std::string input(status);
487 if (android::base::StartsWith(input, "INFO")) {
488 std::string tmp = input.substr(strlen("INFO"));
Tom Cherry9027af02018-09-24 15:48:09 -0700489 info_(tmp);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500490 add_info(std::move(tmp));
Dima Zavin6d46a492019-02-23 21:14:38 -0800491 // We may receive one or more INFO packets during long operations,
492 // e.g. flash/erase if they are back by slow media like NAND/NOR
493 // flash. In that case, reset the timer since it's not a real
494 // timeout.
495 start = std::chrono::steady_clock::now();
Aaron Wisnerdb511202018-06-26 15:38:35 -0500496 } else if (android::base::StartsWith(input, "OKAY")) {
497 set_response(input.substr(strlen("OKAY")));
498 return SUCCESS;
499 } else if (android::base::StartsWith(input, "FAIL")) {
500 error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
501 set_response(input.substr(strlen("FAIL")));
502 return DEVICE_FAIL;
Raphael Herouart99097cc2022-12-30 11:51:54 +0000503 } else if (android::base::StartsWith(input, "TEXT")) {
504 text_(input.substr(strlen("TEXT")));
505 // Reset timeout as many more TEXT may come
506 start = std::chrono::steady_clock::now();
Aaron Wisnerdb511202018-06-26 15:38:35 -0500507 } else if (android::base::StartsWith(input, "DATA")) {
508 std::string tmp = input.substr(strlen("DATA"));
509 uint32_t num = strtol(tmp.c_str(), 0, 16);
510 if (num > MAX_DOWNLOAD_SIZE) {
511 error_ = android::base::StringPrintf("Data size too large (%d)", num);
512 return BAD_DEV_RESP;
513 }
514 if (dsize) *dsize = num;
515 set_response(std::move(tmp));
516 return SUCCESS;
517 } else {
518 error_ = android::base::StringPrintf("Device sent unknown status code: %s", status);
519 return BAD_DEV_RESP;
520 }
521
522 } // End of while loop
523
524 return TIMEOUT;
525}
526
527std::string FastBootDriver::ErrnoStr(const std::string& msg) {
528 return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
529}
530
Aaron Wisnerdb511202018-06-26 15:38:35 -0500531/******************************* PRIVATE **************************************/
Yifan Hong58532df2021-03-22 16:39:13 -0700532RetCode FastBootDriver::SendBuffer(android::base::borrowed_fd fd, size_t size) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500533 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
534 off64_t offset = 0;
535 uint32_t remaining = size;
536 RetCode ret;
537
538 while (remaining) {
539 // Memory map the file
Aaron Wisnerdb511202018-06-26 15:38:35 -0500540 size_t len = std::min(remaining, MAX_MAP_SIZE);
Elliott Hughese8f4b142018-10-19 16:09:39 -0700541 auto mapping{android::base::MappedFile::FromFd(fd, offset, len, PROT_READ)};
542 if (!mapping) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500543 error_ = "Creating filemap failed";
544 return IO_ERROR;
545 }
546
Elliott Hughese8f4b142018-10-19 16:09:39 -0700547 if ((ret = SendBuffer(mapping->data(), mapping->size()))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500548 return ret;
549 }
550
551 remaining -= len;
552 offset += len;
553 }
554
555 return SUCCESS;
556}
557
558RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) {
559 // Write the buffer
560 return SendBuffer(buf.data(), buf.size());
561}
562
563RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500564 // ioctl on 0-length buffer causes freezing
David Anderson0c7bde82018-07-30 12:54:53 -0700565 if (!size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500566 return BAD_ARG;
David Anderson0c7bde82018-07-30 12:54:53 -0700567 }
Aaron Wisnerdb511202018-06-26 15:38:35 -0500568 // Write the buffer
David Anderson1d887432018-08-27 16:47:32 -0700569 ssize_t tmp = transport_->Write(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500570
571 if (tmp < 0) {
572 error_ = ErrnoStr("Write to device failed in SendBuffer()");
573 return IO_ERROR;
574 } else if (static_cast<size_t>(tmp) != size) {
575 error_ = android::base::StringPrintf("Failed to write all %zu bytes", size);
576
577 return IO_ERROR;
578 }
579
580 return SUCCESS;
581}
582
Aaron Wisnerdb511202018-06-26 15:38:35 -0500583RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
584 // Read the buffer
David Anderson1d887432018-08-27 16:47:32 -0700585 ssize_t tmp = transport_->Read(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500586
587 if (tmp < 0) {
588 error_ = ErrnoStr("Read from device failed in ReadBuffer()");
589 return IO_ERROR;
590 } else if (static_cast<size_t>(tmp) != size) {
591 error_ = android::base::StringPrintf("Failed to read all %zu bytes", size);
592 return IO_ERROR;
593 }
594
595 return SUCCESS;
596}
597
598int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) {
599 size_t total = 0;
600 size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len);
601
602 // Handle the residual
603 tpbuf.insert(tpbuf.end(), data, data + to_write);
604 if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) { // Nothing enough to send rn
605 return 0;
606 }
607
608 if (SendBuffer(tpbuf)) {
609 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
610 return -1;
611 }
612 tpbuf.clear();
613 total += to_write;
614
615 // Now we need to send a multiple of chunk size
616 size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
617 size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500618 if (nbytes && SendBuffer(data + total, nbytes)) { // Don't send a ZLP
Aaron Wisnerdb511202018-06-26 15:38:35 -0500619 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
620 return -1;
621 }
622 total += nbytes;
623
624 if (len - total > 0) { // We have residual data to save for next time
625 tpbuf.assign(data + total, data + len);
626 }
627
628 return 0;
629}
630
Dmitrii Merkurev0b627d92023-09-03 17:30:46 +0100631void FastBootDriver::set_transport(std::unique_ptr<Transport> transport) {
632 transport_ = std::move(transport);
David Anderson1d887432018-08-27 16:47:32 -0700633}
634
Aaron Wisnerdb511202018-06-26 15:38:35 -0500635} // End namespace fastboot