• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
FlashPartition(const std::string & partition,const std::vector<char> & data)125 RetCode FastBootDriver::FlashPartition(const std::string& partition,
126                                        const std::vector<char>& data) {
127     RetCode ret;
128     if ((ret = Download(partition, data))) {
129         return ret;
130     }
131     return Flash(partition);
132 }
133 
FlashPartition(const std::string & partition,int fd,uint32_t size)134 RetCode FastBootDriver::FlashPartition(const std::string& partition, int fd, uint32_t size) {
135     RetCode ret;
136     if ((ret = Download(partition, fd, size))) {
137         return ret;
138     }
139     return Flash(partition);
140 }
141 
FlashPartition(const std::string & partition,sparse_file * s,uint32_t size,size_t current,size_t total)142 RetCode FastBootDriver::FlashPartition(const std::string& partition, sparse_file* s, uint32_t size,
143                                        size_t current, size_t total) {
144     RetCode ret;
145     if ((ret = Download(partition, s, size, current, total, false))) {
146         return ret;
147     }
148     return Flash(partition);
149 }
150 
Partitions(std::vector<std::tuple<std::string,uint64_t>> * partitions)151 RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions) {
152     std::vector<std::string> all;
153     RetCode ret;
154     if ((ret = GetVarAll(&all))) {
155         return ret;
156     }
157 
158     std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)");
159     std::smatch sm;
160 
161     for (auto& s : all) {
162         if (std::regex_match(s, sm, reg)) {
163             std::string m1(sm[1]);
164             std::string m2(sm[2]);
165             uint64_t tmp = strtoll(m2.c_str(), 0, 16);
166             partitions->push_back(std::make_tuple(m1, tmp));
167         }
168     }
169     return SUCCESS;
170 }
171 
Download(const std::string & name,int fd,size_t size,std::string * response,std::vector<std::string> * info)172 RetCode FastBootDriver::Download(const std::string& name, int fd, size_t size,
173                                  std::string* response, std::vector<std::string>* info) {
174     prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), size / 1024));
175     auto result = Download(fd, size, response, info);
176     epilog_(result);
177     return result;
178 }
179 
Download(int fd,size_t size,std::string * response,std::vector<std::string> * info)180 RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
181                                  std::vector<std::string>* info) {
182     RetCode ret;
183 
184     if ((size <= 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
185         error_ = "File is too large to download";
186         return BAD_ARG;
187     }
188 
189     uint32_t u32size = static_cast<uint32_t>(size);
190     if ((ret = DownloadCommand(u32size, response, info))) {
191         return ret;
192     }
193 
194     // Write the buffer
195     if ((ret = SendBuffer(fd, size))) {
196         return ret;
197     }
198 
199     // Wait for response
200     return HandleResponse(response, info);
201 }
202 
Download(const std::string & name,const std::vector<char> & buf,std::string * response,std::vector<std::string> * info)203 RetCode FastBootDriver::Download(const std::string& name, const std::vector<char>& buf,
204                                  std::string* response, std::vector<std::string>* info) {
205     prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), buf.size() / 1024));
206     auto result = Download(buf, response, info);
207     epilog_(result);
208     return result;
209 }
210 
Download(const std::vector<char> & buf,std::string * response,std::vector<std::string> * info)211 RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
212                                  std::vector<std::string>* info) {
213     RetCode ret;
214     error_ = "";
215     if ((buf.size() == 0 || buf.size() > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
216         error_ = "Buffer is too large or 0 bytes";
217         return BAD_ARG;
218     }
219 
220     if ((ret = DownloadCommand(buf.size(), response, info))) {
221         return ret;
222     }
223 
224     // Write the buffer
225     if ((ret = SendBuffer(buf))) {
226         return ret;
227     }
228 
229     // Wait for response
230     return HandleResponse(response, info);
231 }
232 
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)233 RetCode FastBootDriver::Download(const std::string& partition, struct sparse_file* s, uint32_t size,
234                                  size_t current, size_t total, bool use_crc, std::string* response,
235                                  std::vector<std::string>* info) {
236     prolog_(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
237                          size / 1024));
238     auto result = Download(s, use_crc, response, info);
239     epilog_(result);
240     return result;
241 }
242 
Download(sparse_file * s,bool use_crc,std::string * response,std::vector<std::string> * info)243 RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response,
244                                  std::vector<std::string>* info) {
245     error_ = "";
246     int64_t size = sparse_file_len(s, true, use_crc);
247     if (size <= 0 || size > MAX_DOWNLOAD_SIZE) {
248         error_ = "Sparse file is too large or invalid";
249         return BAD_ARG;
250     }
251 
252     RetCode ret;
253     uint32_t u32size = static_cast<uint32_t>(size);
254     if ((ret = DownloadCommand(u32size, response, info))) {
255         return ret;
256     }
257 
258     struct SparseCBPrivate {
259         FastBootDriver* self;
260         std::vector<char> tpbuf;
261     } cb_priv;
262     cb_priv.self = this;
263 
264     auto cb = [](void* priv, const void* buf, size_t len) -> int {
265         SparseCBPrivate* data = static_cast<SparseCBPrivate*>(priv);
266         const char* cbuf = static_cast<const char*>(buf);
267         return data->self->SparseWriteCallback(data->tpbuf, cbuf, len);
268     };
269 
270     if (sparse_file_callback(s, true, use_crc, cb, &cb_priv) < 0) {
271         error_ = "Error reading sparse file";
272         return IO_ERROR;
273     }
274 
275     // Now flush
276     if (cb_priv.tpbuf.size() && (ret = SendBuffer(cb_priv.tpbuf))) {
277         return ret;
278     }
279 
280     return HandleResponse(response, info);
281 }
282 
Upload(const std::string & outfile,std::string * response,std::vector<std::string> * info)283 RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
284                                std::vector<std::string>* info) {
285     prolog_("Uploading '" + outfile + "'");
286     auto result = UploadInner(outfile, response, info);
287     epilog_(result);
288     return result;
289 }
290 
UploadInner(const std::string & outfile,std::string * response,std::vector<std::string> * info)291 RetCode FastBootDriver::UploadInner(const std::string& outfile, std::string* response,
292                                     std::vector<std::string>* info) {
293     RetCode ret;
294     int dsize;
295     if ((ret = RawCommand(FB_CMD_UPLOAD, response, info, &dsize))) {
296         error_ = "Upload request failed: " + error_;
297         return ret;
298     }
299 
300     if (!dsize) {
301         error_ = "Upload request failed, device reports 0 bytes available";
302         return BAD_DEV_RESP;
303     }
304 
305     std::vector<char> data;
306     data.resize(dsize);
307 
308     if ((ret = ReadBuffer(data))) {
309         return ret;
310     }
311 
312     std::ofstream ofs;
313     ofs.open(outfile, std::ofstream::out | std::ofstream::binary);
314     if (ofs.fail()) {
315         error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str());
316         return IO_ERROR;
317     }
318     ofs.write(data.data(), data.size());
319     if (ofs.fail() || ofs.bad()) {
320         error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str());
321         return IO_ERROR;
322     }
323     ofs.close();
324 
325     return HandleResponse(response, info);
326 }
327 
328 // Helpers
SetInfoCallback(std::function<void (const std::string &)> info)329 void FastBootDriver::SetInfoCallback(std::function<void(const std::string&)> info) {
330     info_ = info;
331 }
332 
RCString(RetCode rc)333 const std::string FastBootDriver::RCString(RetCode rc) {
334     switch (rc) {
335         case SUCCESS:
336             return std::string("Success");
337 
338         case BAD_ARG:
339             return std::string("Invalid Argument");
340 
341         case IO_ERROR:
342             return std::string("I/O Error");
343 
344         case BAD_DEV_RESP:
345             return std::string("Invalid Device Response");
346 
347         case DEVICE_FAIL:
348             return std::string("Device Error");
349 
350         case TIMEOUT:
351             return std::string("Timeout");
352 
353         default:
354             return std::string("Unknown Error");
355     }
356 }
357 
Error()358 std::string FastBootDriver::Error() {
359     return error_;
360 }
361 
WaitForDisconnect()362 RetCode FastBootDriver::WaitForDisconnect() {
363     return transport_->WaitForDisconnect() ? IO_ERROR : SUCCESS;
364 }
365 
366 /****************************** PROTECTED *************************************/
RawCommand(const std::string & cmd,const std::string & message,std::string * response,std::vector<std::string> * info,int * dsize)367 RetCode FastBootDriver::RawCommand(const std::string& cmd, const std::string& message,
368                                    std::string* response, std::vector<std::string>* info,
369                                    int* dsize) {
370     prolog_(message);
371     auto result = RawCommand(cmd, response, info, dsize);
372     epilog_(result);
373     return result;
374 }
375 
RawCommand(const std::string & cmd,std::string * response,std::vector<std::string> * info,int * dsize)376 RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
377                                    std::vector<std::string>* info, int* dsize) {
378     error_ = "";  // Clear any pending error
379     if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) {
380         error_ = "Command length to RawCommand() is too long";
381         return BAD_ARG;
382     }
383 
384     if (transport_->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
385         error_ = ErrnoStr("Write to device failed");
386         return IO_ERROR;
387     }
388 
389     // Read the response
390     return HandleResponse(response, info, dsize);
391 }
392 
DownloadCommand(uint32_t size,std::string * response,std::vector<std::string> * info)393 RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
394                                         std::vector<std::string>* info) {
395     std::string cmd(android::base::StringPrintf("%s:%08" PRIx32, FB_CMD_DOWNLOAD, size));
396     RetCode ret;
397     if ((ret = RawCommand(cmd, response, info))) {
398         return ret;
399     }
400     return SUCCESS;
401 }
402 
HandleResponse(std::string * response,std::vector<std::string> * info,int * dsize)403 RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
404                                        int* dsize) {
405     char status[FB_RESPONSE_SZ + 1];
406     auto start = std::chrono::steady_clock::now();
407 
408     auto set_response = [response](std::string s) {
409         if (response) *response = std::move(s);
410     };
411     auto add_info = [info](std::string s) {
412         if (info) info->push_back(std::move(s));
413     };
414 
415     // erase response
416     set_response("");
417     while ((std::chrono::steady_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
418         int r = transport_->Read(status, FB_RESPONSE_SZ);
419         if (r < 0) {
420             error_ = ErrnoStr("Status read failed");
421             return IO_ERROR;
422         }
423 
424         status[r] = '\0';  // Need the null terminator
425         std::string input(status);
426         if (android::base::StartsWith(input, "INFO")) {
427             std::string tmp = input.substr(strlen("INFO"));
428             info_(tmp);
429             add_info(std::move(tmp));
430             // We may receive one or more INFO packets during long operations,
431             // e.g. flash/erase if they are back by slow media like NAND/NOR
432             // flash. In that case, reset the timer since it's not a real
433             // timeout.
434             start = std::chrono::steady_clock::now();
435         } else if (android::base::StartsWith(input, "OKAY")) {
436             set_response(input.substr(strlen("OKAY")));
437             return SUCCESS;
438         } else if (android::base::StartsWith(input, "FAIL")) {
439             error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
440             set_response(input.substr(strlen("FAIL")));
441             return DEVICE_FAIL;
442         } else if (android::base::StartsWith(input, "DATA")) {
443             std::string tmp = input.substr(strlen("DATA"));
444             uint32_t num = strtol(tmp.c_str(), 0, 16);
445             if (num > MAX_DOWNLOAD_SIZE) {
446                 error_ = android::base::StringPrintf("Data size too large (%d)", num);
447                 return BAD_DEV_RESP;
448             }
449             if (dsize) *dsize = num;
450             set_response(std::move(tmp));
451             return SUCCESS;
452         } else {
453             error_ = android::base::StringPrintf("Device sent unknown status code: %s", status);
454             return BAD_DEV_RESP;
455         }
456 
457     }  // End of while loop
458 
459     return TIMEOUT;
460 }
461 
ErrnoStr(const std::string & msg)462 std::string FastBootDriver::ErrnoStr(const std::string& msg) {
463     return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
464 }
465 
466 /******************************* PRIVATE **************************************/
SendBuffer(int fd,size_t size)467 RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
468     static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
469     off64_t offset = 0;
470     uint32_t remaining = size;
471     RetCode ret;
472 
473     while (remaining) {
474         // Memory map the file
475         size_t len = std::min(remaining, MAX_MAP_SIZE);
476         auto mapping{android::base::MappedFile::FromFd(fd, offset, len, PROT_READ)};
477         if (!mapping) {
478             error_ = "Creating filemap failed";
479             return IO_ERROR;
480         }
481 
482         if ((ret = SendBuffer(mapping->data(), mapping->size()))) {
483             return ret;
484         }
485 
486         remaining -= len;
487         offset += len;
488     }
489 
490     return SUCCESS;
491 }
492 
SendBuffer(const std::vector<char> & buf)493 RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) {
494     // Write the buffer
495     return SendBuffer(buf.data(), buf.size());
496 }
497 
SendBuffer(const void * buf,size_t size)498 RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
499     // ioctl on 0-length buffer causes freezing
500     if (!size) {
501         return BAD_ARG;
502     }
503     // Write the buffer
504     ssize_t tmp = transport_->Write(buf, size);
505 
506     if (tmp < 0) {
507         error_ = ErrnoStr("Write to device failed in SendBuffer()");
508         return IO_ERROR;
509     } else if (static_cast<size_t>(tmp) != size) {
510         error_ = android::base::StringPrintf("Failed to write all %zu bytes", size);
511 
512         return IO_ERROR;
513     }
514 
515     return SUCCESS;
516 }
517 
ReadBuffer(std::vector<char> & buf)518 RetCode FastBootDriver::ReadBuffer(std::vector<char>& buf) {
519     // Read the buffer
520     return ReadBuffer(buf.data(), buf.size());
521 }
522 
ReadBuffer(void * buf,size_t size)523 RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
524     // Read the buffer
525     ssize_t tmp = transport_->Read(buf, size);
526 
527     if (tmp < 0) {
528         error_ = ErrnoStr("Read from device failed in ReadBuffer()");
529         return IO_ERROR;
530     } else if (static_cast<size_t>(tmp) != size) {
531         error_ = android::base::StringPrintf("Failed to read all %zu bytes", size);
532         return IO_ERROR;
533     }
534 
535     return SUCCESS;
536 }
537 
SparseWriteCallback(std::vector<char> & tpbuf,const char * data,size_t len)538 int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) {
539     size_t total = 0;
540     size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len);
541 
542     // Handle the residual
543     tpbuf.insert(tpbuf.end(), data, data + to_write);
544     if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) {  // Nothing enough to send rn
545         return 0;
546     }
547 
548     if (SendBuffer(tpbuf)) {
549         error_ = ErrnoStr("Send failed in SparseWriteCallback()");
550         return -1;
551     }
552     tpbuf.clear();
553     total += to_write;
554 
555     // Now we need to send a multiple of chunk size
556     size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
557     size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
558     if (nbytes && SendBuffer(data + total, nbytes)) {  // Don't send a ZLP
559         error_ = ErrnoStr("Send failed in SparseWriteCallback()");
560         return -1;
561     }
562     total += nbytes;
563 
564     if (len - total > 0) {  // We have residual data to save for next time
565         tpbuf.assign(data + total, data + len);
566     }
567 
568     return 0;
569 }
570 
set_transport(Transport * transport)571 Transport* FastBootDriver::set_transport(Transport* transport) {
572     std::swap(transport_, transport);
573     return transport;
574 }
575 
576 }  // End namespace fastboot
577