1 /*
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 */
28
29 #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>
44 #include <android-base/mapped_file.h>
45 #include <android-base/stringprintf.h>
46 #include <android-base/strings.h>
47 #include <android-base/unique_fd.h>
48
49 #include "constants.h"
50 #include "transport.h"
51
52 using android::base::StringPrintf;
53
54 namespace fastboot {
55
56 /*************************** PUBLIC *******************************/
FastBootDriver(Transport * transport,DriverCallbacks driver_callbacks,bool no_checks)57 FastBootDriver::FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks,
58 bool no_checks)
59 : 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) {}
64
~FastBootDriver()65 FastBootDriver::~FastBootDriver() {
66 }
67
Boot(std::string * response,std::vector<std::string> * info)68 RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
69 return RawCommand(FB_CMD_BOOT, "Booting", response, info);
70 }
71
Continue(std::string * response,std::vector<std::string> * info)72 RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
73 return RawCommand(FB_CMD_CONTINUE, "Resuming boot", response, info);
74 }
75
CreatePartition(const std::string & partition,const std::string & size)76 RetCode FastBootDriver::CreatePartition(const std::string& partition, const std::string& size) {
77 return RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size,
78 "Creating '" + partition + "'");
79 }
80
DeletePartition(const std::string & partition)81 RetCode FastBootDriver::DeletePartition(const std::string& partition) {
82 return RawCommand(FB_CMD_DELETE_PARTITION ":" + partition, "Deleting '" + partition + "'");
83 }
84
Erase(const std::string & partition,std::string * response,std::vector<std::string> * info)85 RetCode FastBootDriver::Erase(const std::string& partition, std::string* response,
86 std::vector<std::string>* info) {
87 return RawCommand(FB_CMD_ERASE ":" + partition, "Erasing '" + partition + "'", response, info);
88 }
89
Flash(const std::string & partition,std::string * response,std::vector<std::string> * info)90 RetCode 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);
93 }
94
GetVar(const std::string & key,std::string * val,std::vector<std::string> * info)95 RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
96 std::vector<std::string>* info) {
97 return RawCommand(FB_CMD_GETVAR ":" + key, val, info);
98 }
99
GetVarAll(std::vector<std::string> * response)100 RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
101 std::string tmp;
102 return GetVar("all", &tmp, response);
103 }
104
Reboot(std::string * response,std::vector<std::string> * info)105 RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
106 return RawCommand(FB_CMD_REBOOT, "Rebooting", response, info);
107 }
108
RebootTo(std::string target,std::string * response,std::vector<std::string> * info)109 RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
110 std::vector<std::string>* info) {
111 return RawCommand("reboot-" + target, "Rebooting into " + target, response, info);
112 }
113
ResizePartition(const std::string & partition,const std::string & size)114 RetCode FastBootDriver::ResizePartition(const std::string& partition, const std::string& size) {
115 return RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size,
116 "Resizing '" + partition + "'");
117 }
118
SetActive(const std::string & slot,std::string * response,std::vector<std::string> * info)119 RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response,
120 std::vector<std::string>* info) {
121 return RawCommand(FB_CMD_SET_ACTIVE ":" + slot, "Setting current slot to '" + slot + "'",
122 response, info);
123 }
124
SnapshotUpdateCommand(const std::string & command,std::string * response,std::vector<std::string> * info)125 RetCode FastBootDriver::SnapshotUpdateCommand(const std::string& command, std::string* response,
126 std::vector<std::string>* info) {
127 prolog_(StringPrintf("Snapshot %s", command.c_str()));
128 std::string raw = FB_CMD_SNAPSHOT_UPDATE ":" + command;
129 auto result = RawCommand(raw, response, info);
130 epilog_(result);
131 return result;
132 }
133
FlashPartition(const std::string & partition,const std::vector<char> & data)134 RetCode FastBootDriver::FlashPartition(const std::string& partition,
135 const std::vector<char>& data) {
136 RetCode ret;
137 if ((ret = Download(partition, data))) {
138 return ret;
139 }
140 return Flash(partition);
141 }
142
FlashPartition(const std::string & partition,int fd,uint32_t size)143 RetCode FastBootDriver::FlashPartition(const std::string& partition, int fd, uint32_t size) {
144 RetCode ret;
145 if ((ret = Download(partition, fd, size))) {
146 return ret;
147 }
148 return Flash(partition);
149 }
150
FlashPartition(const std::string & partition,sparse_file * s,uint32_t size,size_t current,size_t total)151 RetCode FastBootDriver::FlashPartition(const std::string& partition, sparse_file* s, uint32_t size,
152 size_t current, size_t total) {
153 RetCode ret;
154 if ((ret = Download(partition, s, size, current, total, false))) {
155 return ret;
156 }
157 return Flash(partition);
158 }
159
Partitions(std::vector<std::tuple<std::string,uint64_t>> * partitions)160 RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions) {
161 std::vector<std::string> all;
162 RetCode ret;
163 if ((ret = GetVarAll(&all))) {
164 return ret;
165 }
166
167 std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)");
168 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]);
174 uint64_t tmp = strtoll(m2.c_str(), 0, 16);
175 partitions->push_back(std::make_tuple(m1, tmp));
176 }
177 }
178 return SUCCESS;
179 }
180
Download(const std::string & name,int fd,size_t size,std::string * response,std::vector<std::string> * info)181 RetCode 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
Download(int fd,size_t size,std::string * response,std::vector<std::string> * info)189 RetCode 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
Download(const std::string & name,const std::vector<char> & buf,std::string * response,std::vector<std::string> * info)212 RetCode 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
Download(const std::vector<char> & buf,std::string * response,std::vector<std::string> * info)220 RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
221 std::vector<std::string>* info) {
222 RetCode ret;
223 error_ = "";
224 if ((buf.size() == 0 || buf.size() > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
225 error_ = "Buffer is too large or 0 bytes";
226 return BAD_ARG;
227 }
228
229 if ((ret = DownloadCommand(buf.size(), response, info))) {
230 return ret;
231 }
232
233 // Write the buffer
234 if ((ret = SendBuffer(buf))) {
235 return ret;
236 }
237
238 // Wait for response
239 return HandleResponse(response, info);
240 }
241
Download(const std::string & partition,struct sparse_file * s,uint32_t size,size_t current,size_t total,bool use_crc,std::string * response,std::vector<std::string> * info)242 RetCode 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
Download(sparse_file * s,bool use_crc,std::string * response,std::vector<std::string> * info)252 RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response,
253 std::vector<std::string>* info) {
254 error_ = "";
255 int64_t size = sparse_file_len(s, true, use_crc);
256 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
279 if (sparse_file_callback(s, true, use_crc, cb, &cb_priv) < 0) {
280 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
Upload(const std::string & outfile,std::string * response,std::vector<std::string> * info)292 RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
293 std::vector<std::string>* info) {
294 prolog_("Uploading '" + outfile + "'");
295 auto result = UploadInner(outfile, response, info);
296 epilog_(result);
297 return result;
298 }
299
UploadInner(const std::string & outfile,std::string * response,std::vector<std::string> * info)300 RetCode FastBootDriver::UploadInner(const std::string& outfile, std::string* response,
301 std::vector<std::string>* info) {
302 RetCode ret;
303 int dsize = 0;
304 if ((ret = RawCommand(FB_CMD_UPLOAD, response, info, &dsize))) {
305 error_ = "Upload request failed: " + error_;
306 return ret;
307 }
308
309 if (!dsize) {
310 error_ = "Upload request failed, device reports 0 bytes available";
311 return BAD_DEV_RESP;
312 }
313
314 std::vector<char> data;
315 data.resize(dsize);
316
317 if ((ret = ReadBuffer(data))) {
318 return ret;
319 }
320
321 std::ofstream ofs;
322 ofs.open(outfile, std::ofstream::out | std::ofstream::binary);
323 if (ofs.fail()) {
324 error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str());
325 return IO_ERROR;
326 }
327 ofs.write(data.data(), data.size());
328 if (ofs.fail() || ofs.bad()) {
329 error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str());
330 return IO_ERROR;
331 }
332 ofs.close();
333
334 return HandleResponse(response, info);
335 }
336
337 // Helpers
SetInfoCallback(std::function<void (const std::string &)> info)338 void FastBootDriver::SetInfoCallback(std::function<void(const std::string&)> info) {
339 info_ = info;
340 }
341
RCString(RetCode rc)342 const std::string FastBootDriver::RCString(RetCode rc) {
343 switch (rc) {
344 case SUCCESS:
345 return std::string("Success");
346
347 case BAD_ARG:
348 return std::string("Invalid Argument");
349
350 case IO_ERROR:
351 return std::string("I/O Error");
352
353 case BAD_DEV_RESP:
354 return std::string("Invalid Device Response");
355
356 case DEVICE_FAIL:
357 return std::string("Device Error");
358
359 case TIMEOUT:
360 return std::string("Timeout");
361
362 default:
363 return std::string("Unknown Error");
364 }
365 }
366
Error()367 std::string FastBootDriver::Error() {
368 return error_;
369 }
370
WaitForDisconnect()371 RetCode FastBootDriver::WaitForDisconnect() {
372 return transport_->WaitForDisconnect() ? IO_ERROR : SUCCESS;
373 }
374
375 /****************************** PROTECTED *************************************/
RawCommand(const std::string & cmd,const std::string & message,std::string * response,std::vector<std::string> * info,int * dsize)376 RetCode FastBootDriver::RawCommand(const std::string& cmd, const std::string& message,
377 std::string* response, std::vector<std::string>* info,
378 int* dsize) {
379 prolog_(message);
380 auto result = RawCommand(cmd, response, info, dsize);
381 epilog_(result);
382 return result;
383 }
384
RawCommand(const std::string & cmd,std::string * response,std::vector<std::string> * info,int * dsize)385 RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
386 std::vector<std::string>* info, int* dsize) {
387 error_ = ""; // Clear any pending error
388 if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) {
389 error_ = "Command length to RawCommand() is too long";
390 return BAD_ARG;
391 }
392
393 if (transport_->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
394 error_ = ErrnoStr("Write to device failed");
395 return IO_ERROR;
396 }
397
398 // Read the response
399 return HandleResponse(response, info, dsize);
400 }
401
DownloadCommand(uint32_t size,std::string * response,std::vector<std::string> * info)402 RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
403 std::vector<std::string>* info) {
404 std::string cmd(android::base::StringPrintf("%s:%08" PRIx32, FB_CMD_DOWNLOAD, size));
405 RetCode ret;
406 if ((ret = RawCommand(cmd, response, info))) {
407 return ret;
408 }
409 return SUCCESS;
410 }
411
HandleResponse(std::string * response,std::vector<std::string> * info,int * dsize)412 RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
413 int* dsize) {
414 char status[FB_RESPONSE_SZ + 1];
415 auto start = std::chrono::steady_clock::now();
416
417 auto set_response = [response](std::string s) {
418 if (response) *response = std::move(s);
419 };
420 auto add_info = [info](std::string s) {
421 if (info) info->push_back(std::move(s));
422 };
423
424 // erase response
425 set_response("");
426 while ((std::chrono::steady_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
427 int r = transport_->Read(status, FB_RESPONSE_SZ);
428 if (r < 0) {
429 error_ = ErrnoStr("Status read failed");
430 return IO_ERROR;
431 }
432
433 status[r] = '\0'; // Need the null terminator
434 std::string input(status);
435 if (android::base::StartsWith(input, "INFO")) {
436 std::string tmp = input.substr(strlen("INFO"));
437 info_(tmp);
438 add_info(std::move(tmp));
439 // We may receive one or more INFO packets during long operations,
440 // e.g. flash/erase if they are back by slow media like NAND/NOR
441 // flash. In that case, reset the timer since it's not a real
442 // timeout.
443 start = std::chrono::steady_clock::now();
444 } else if (android::base::StartsWith(input, "OKAY")) {
445 set_response(input.substr(strlen("OKAY")));
446 return SUCCESS;
447 } else if (android::base::StartsWith(input, "FAIL")) {
448 error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
449 set_response(input.substr(strlen("FAIL")));
450 return DEVICE_FAIL;
451 } else if (android::base::StartsWith(input, "DATA")) {
452 std::string tmp = input.substr(strlen("DATA"));
453 uint32_t num = strtol(tmp.c_str(), 0, 16);
454 if (num > MAX_DOWNLOAD_SIZE) {
455 error_ = android::base::StringPrintf("Data size too large (%d)", num);
456 return BAD_DEV_RESP;
457 }
458 if (dsize) *dsize = num;
459 set_response(std::move(tmp));
460 return SUCCESS;
461 } else {
462 error_ = android::base::StringPrintf("Device sent unknown status code: %s", status);
463 return BAD_DEV_RESP;
464 }
465
466 } // End of while loop
467
468 return TIMEOUT;
469 }
470
ErrnoStr(const std::string & msg)471 std::string FastBootDriver::ErrnoStr(const std::string& msg) {
472 return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
473 }
474
475 /******************************* PRIVATE **************************************/
SendBuffer(int fd,size_t size)476 RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
477 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
478 off64_t offset = 0;
479 uint32_t remaining = size;
480 RetCode ret;
481
482 while (remaining) {
483 // Memory map the file
484 size_t len = std::min(remaining, MAX_MAP_SIZE);
485 auto mapping{android::base::MappedFile::FromFd(fd, offset, len, PROT_READ)};
486 if (!mapping) {
487 error_ = "Creating filemap failed";
488 return IO_ERROR;
489 }
490
491 if ((ret = SendBuffer(mapping->data(), mapping->size()))) {
492 return ret;
493 }
494
495 remaining -= len;
496 offset += len;
497 }
498
499 return SUCCESS;
500 }
501
SendBuffer(const std::vector<char> & buf)502 RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) {
503 // Write the buffer
504 return SendBuffer(buf.data(), buf.size());
505 }
506
SendBuffer(const void * buf,size_t size)507 RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
508 // ioctl on 0-length buffer causes freezing
509 if (!size) {
510 return BAD_ARG;
511 }
512 // Write the buffer
513 ssize_t tmp = transport_->Write(buf, size);
514
515 if (tmp < 0) {
516 error_ = ErrnoStr("Write to device failed in SendBuffer()");
517 return IO_ERROR;
518 } else if (static_cast<size_t>(tmp) != size) {
519 error_ = android::base::StringPrintf("Failed to write all %zu bytes", size);
520
521 return IO_ERROR;
522 }
523
524 return SUCCESS;
525 }
526
ReadBuffer(std::vector<char> & buf)527 RetCode FastBootDriver::ReadBuffer(std::vector<char>& buf) {
528 // Read the buffer
529 return ReadBuffer(buf.data(), buf.size());
530 }
531
ReadBuffer(void * buf,size_t size)532 RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
533 // Read the buffer
534 ssize_t tmp = transport_->Read(buf, size);
535
536 if (tmp < 0) {
537 error_ = ErrnoStr("Read from device failed in ReadBuffer()");
538 return IO_ERROR;
539 } else if (static_cast<size_t>(tmp) != size) {
540 error_ = android::base::StringPrintf("Failed to read all %zu bytes", size);
541 return IO_ERROR;
542 }
543
544 return SUCCESS;
545 }
546
SparseWriteCallback(std::vector<char> & tpbuf,const char * data,size_t len)547 int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) {
548 size_t total = 0;
549 size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len);
550
551 // Handle the residual
552 tpbuf.insert(tpbuf.end(), data, data + to_write);
553 if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) { // Nothing enough to send rn
554 return 0;
555 }
556
557 if (SendBuffer(tpbuf)) {
558 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
559 return -1;
560 }
561 tpbuf.clear();
562 total += to_write;
563
564 // Now we need to send a multiple of chunk size
565 size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
566 size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
567 if (nbytes && SendBuffer(data + total, nbytes)) { // Don't send a ZLP
568 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
569 return -1;
570 }
571 total += nbytes;
572
573 if (len - total > 0) { // We have residual data to save for next time
574 tpbuf.assign(data + total, data + len);
575 }
576
577 return 0;
578 }
579
set_transport(Transport * transport)580 Transport* FastBootDriver::set_transport(Transport* transport) {
581 std::swap(transport_, transport);
582 return transport;
583 }
584
585 } // End namespace fastboot
586