• 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 <inttypes.h>
34 #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>
45 #include <android-base/mapped_file.h>
46 #include <android-base/parseint.h>
47 #include <android-base/stringprintf.h>
48 #include <android-base/strings.h>
49 #include <android-base/unique_fd.h>
50 #include <storage_literals/storage_literals.h>
51 
52 #include "constants.h"
53 #include "transport.h"
54 
55 using android::base::StringPrintf;
56 using namespace android::storage_literals;
57 
58 namespace fastboot {
59 
60 /*************************** PUBLIC *******************************/
FastBootDriver(Transport * transport,DriverCallbacks driver_callbacks,bool no_checks)61 FastBootDriver::FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks,
62                                bool no_checks)
63     : transport_(transport),
64       prolog_(std::move(driver_callbacks.prolog)),
65       epilog_(std::move(driver_callbacks.epilog)),
66       info_(std::move(driver_callbacks.info)),
67       text_(std::move(driver_callbacks.text)),
68       disable_checks_(no_checks) {}
69 
~FastBootDriver()70 FastBootDriver::~FastBootDriver() {
71 }
72 
Boot(std::string * response,std::vector<std::string> * info)73 RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
74     return RawCommand(FB_CMD_BOOT, "Booting", response, info);
75 }
76 
Continue(std::string * response,std::vector<std::string> * info)77 RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
78     return RawCommand(FB_CMD_CONTINUE, "Resuming boot", response, info);
79 }
80 
CreatePartition(const std::string & partition,const std::string & size)81 RetCode FastBootDriver::CreatePartition(const std::string& partition, const std::string& size) {
82     return RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size,
83                       "Creating '" + partition + "'");
84 }
85 
DeletePartition(const std::string & partition)86 RetCode FastBootDriver::DeletePartition(const std::string& partition) {
87     return RawCommand(FB_CMD_DELETE_PARTITION ":" + partition, "Deleting '" + partition + "'");
88 }
89 
Erase(const std::string & partition,std::string * response,std::vector<std::string> * info)90 RetCode FastBootDriver::Erase(const std::string& partition, std::string* response,
91                               std::vector<std::string>* info) {
92     return RawCommand(FB_CMD_ERASE ":" + partition, "Erasing '" + partition + "'", response, info);
93 }
94 
Flash(const std::string & partition,std::string * response,std::vector<std::string> * info)95 RetCode FastBootDriver::Flash(const std::string& partition, std::string* response,
96                               std::vector<std::string>* info) {
97     return RawCommand(FB_CMD_FLASH ":" + partition, "Writing '" + partition + "'", response, info);
98 }
99 
GetVar(const std::string & key,std::string * val,std::vector<std::string> * info)100 RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
101                                std::vector<std::string>* info) {
102     return RawCommand(FB_CMD_GETVAR ":" + key, val, info);
103 }
104 
GetVarAll(std::vector<std::string> * response)105 RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
106     std::string tmp;
107     return GetVar("all", &tmp, response);
108 }
109 
Reboot(std::string * response,std::vector<std::string> * info)110 RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
111     return RawCommand(FB_CMD_REBOOT, "Rebooting", response, info);
112 }
113 
RebootTo(std::string target,std::string * response,std::vector<std::string> * info)114 RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
115                                  std::vector<std::string>* info) {
116     return RawCommand("reboot-" + target, "Rebooting into " + target, response, info);
117 }
118 
ResizePartition(const std::string & partition,const std::string & size)119 RetCode FastBootDriver::ResizePartition(const std::string& partition, const std::string& size) {
120     return RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size,
121                       "Resizing '" + partition + "'");
122 }
123 
SetActive(const std::string & slot,std::string * response,std::vector<std::string> * info)124 RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response,
125                                   std::vector<std::string>* info) {
126     return RawCommand(FB_CMD_SET_ACTIVE ":" + slot, "Setting current slot to '" + slot + "'",
127                       response, info);
128 }
129 
SnapshotUpdateCommand(const std::string & command,std::string * response,std::vector<std::string> * info)130 RetCode FastBootDriver::SnapshotUpdateCommand(const std::string& command, std::string* response,
131                                               std::vector<std::string>* info) {
132     prolog_(StringPrintf("Snapshot %s", command.c_str()));
133     std::string raw = FB_CMD_SNAPSHOT_UPDATE ":" + command;
134     auto result = RawCommand(raw, response, info);
135     epilog_(result);
136     return result;
137 }
138 
FlashPartition(const std::string & partition,const std::vector<char> & data)139 RetCode FastBootDriver::FlashPartition(const std::string& partition,
140                                        const std::vector<char>& data) {
141     RetCode ret;
142     if ((ret = Download(partition, data))) {
143         return ret;
144     }
145     return Flash(partition);
146 }
147 
FlashPartition(const std::string & partition,android::base::borrowed_fd fd,uint32_t size)148 RetCode FastBootDriver::FlashPartition(const std::string& partition, android::base::borrowed_fd fd,
149                                        uint32_t size) {
150     RetCode ret;
151     if ((ret = Download(partition, fd, size))) {
152         return ret;
153     }
154     return Flash(partition);
155 }
156 
FlashPartition(const std::string & partition,sparse_file * s,uint32_t size,size_t current,size_t total)157 RetCode FastBootDriver::FlashPartition(const std::string& partition, sparse_file* s, uint32_t size,
158                                        size_t current, size_t total) {
159     RetCode ret;
160     if ((ret = Download(partition, s, size, current, total, false))) {
161         return ret;
162     }
163     return Flash(partition);
164 }
165 
Partitions(std::vector<std::tuple<std::string,uint64_t>> * partitions)166 RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions) {
167     std::vector<std::string> all;
168     RetCode ret;
169     if ((ret = GetVarAll(&all))) {
170         return ret;
171     }
172 
173     std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)");
174     std::smatch sm;
175 
176     for (auto& s : all) {
177         if (std::regex_match(s, sm, reg)) {
178             std::string m1(sm[1]);
179             std::string m2(sm[2]);
180             uint64_t tmp = strtoll(m2.c_str(), 0, 16);
181             partitions->push_back(std::make_tuple(m1, tmp));
182         }
183     }
184     return SUCCESS;
185 }
186 
Download(const std::string & name,android::base::borrowed_fd fd,size_t size,std::string * response,std::vector<std::string> * info)187 RetCode FastBootDriver::Download(const std::string& name, android::base::borrowed_fd fd,
188                                  size_t size, std::string* response,
189                                  std::vector<std::string>* info) {
190     prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), size / 1024));
191     auto result = Download(fd, size, response, info);
192     epilog_(result);
193     return result;
194 }
195 
Download(android::base::borrowed_fd fd,size_t size,std::string * response,std::vector<std::string> * info)196 RetCode FastBootDriver::Download(android::base::borrowed_fd fd, size_t size, std::string* response,
197                                  std::vector<std::string>* info) {
198     RetCode ret;
199 
200     if ((size <= 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
201         error_ = "File is too large to download";
202         return BAD_ARG;
203     }
204 
205     uint32_t u32size = static_cast<uint32_t>(size);
206     if ((ret = DownloadCommand(u32size, response, info))) {
207         return ret;
208     }
209 
210     // Write the buffer
211     if ((ret = SendBuffer(fd, size))) {
212         return ret;
213     }
214 
215     // Wait for response
216     return HandleResponse(response, info);
217 }
218 
Download(const std::string & name,const std::vector<char> & buf,std::string * response,std::vector<std::string> * info)219 RetCode FastBootDriver::Download(const std::string& name, const std::vector<char>& buf,
220                                  std::string* response, std::vector<std::string>* info) {
221     prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), buf.size() / 1024));
222     auto result = Download(buf, response, info);
223     epilog_(result);
224     return result;
225 }
226 
Download(const std::vector<char> & buf,std::string * response,std::vector<std::string> * info)227 RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
228                                  std::vector<std::string>* info) {
229     RetCode ret;
230     error_ = "";
231     if ((buf.size() == 0 || buf.size() > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
232         error_ = "Buffer is too large or 0 bytes";
233         return BAD_ARG;
234     }
235 
236     if ((ret = DownloadCommand(buf.size(), response, info))) {
237         return ret;
238     }
239 
240     // Write the buffer
241     if ((ret = SendBuffer(buf))) {
242         return ret;
243     }
244 
245     // Wait for response
246     return HandleResponse(response, info);
247 }
248 
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)249 RetCode FastBootDriver::Download(const std::string& partition, struct sparse_file* s, uint32_t size,
250                                  size_t current, size_t total, bool use_crc, std::string* response,
251                                  std::vector<std::string>* info) {
252     prolog_(StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(), current, total,
253                          size / 1024));
254     auto result = Download(s, use_crc, response, info);
255     epilog_(result);
256     return result;
257 }
258 
Download(sparse_file * s,bool use_crc,std::string * response,std::vector<std::string> * info)259 RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response,
260                                  std::vector<std::string>* info) {
261     error_ = "";
262     int64_t size = sparse_file_len(s, true, use_crc);
263     if (size <= 0 || size > MAX_DOWNLOAD_SIZE) {
264         error_ = "Sparse file is too large or invalid";
265         return BAD_ARG;
266     }
267 
268     RetCode ret;
269     uint32_t u32size = static_cast<uint32_t>(size);
270     if ((ret = DownloadCommand(u32size, response, info))) {
271         return ret;
272     }
273 
274     struct SparseCBPrivate {
275         FastBootDriver* self;
276         std::vector<char> tpbuf;
277     } cb_priv;
278     cb_priv.self = this;
279 
280     auto cb = [](void* priv, const void* buf, size_t len) -> int {
281         SparseCBPrivate* data = static_cast<SparseCBPrivate*>(priv);
282         const char* cbuf = static_cast<const char*>(buf);
283         return data->self->SparseWriteCallback(data->tpbuf, cbuf, len);
284     };
285 
286     if (sparse_file_callback(s, true, use_crc, cb, &cb_priv) < 0) {
287         error_ = "Error reading sparse file";
288         return IO_ERROR;
289     }
290 
291     // Now flush
292     if (cb_priv.tpbuf.size() && (ret = SendBuffer(cb_priv.tpbuf))) {
293         return ret;
294     }
295 
296     return HandleResponse(response, info);
297 }
298 
Upload(const std::string & outfile,std::string * response,std::vector<std::string> * info)299 RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
300                                std::vector<std::string>* info) {
301     prolog_("Uploading '" + outfile + "'");
302     auto result = UploadInner(outfile, response, info);
303     epilog_(result);
304     return result;
305 }
306 
307 // This function executes cmd, then expect a "DATA" response with a number N, followed
308 // by N bytes, and another response.
309 // This is the common way for the device to send data to the driver used by upload and fetch.
RunAndReadBuffer(const std::string & cmd,std::string * response,std::vector<std::string> * info,const std::function<RetCode (const char * data,uint64_t size)> & write_fn)310 RetCode FastBootDriver::RunAndReadBuffer(
311         const std::string& cmd, std::string* response, std::vector<std::string>* info,
312         const std::function<RetCode(const char* data, uint64_t size)>& write_fn) {
313     RetCode ret;
314     int dsize = 0;
315     if ((ret = RawCommand(cmd, response, info, &dsize))) {
316         error_ = android::base::StringPrintf("%s request failed: %s", cmd.c_str(), error_.c_str());
317         return ret;
318     }
319 
320     if (dsize <= 0) {
321         error_ = android::base::StringPrintf("%s request failed, device reports %d bytes available",
322                                              cmd.c_str(), dsize);
323         return BAD_DEV_RESP;
324     }
325 
326     const uint64_t total_size = dsize;
327     const uint64_t buf_size = std::min<uint64_t>(total_size, 1_MiB);
328     std::vector<char> data(buf_size);
329     uint64_t current_offset = 0;
330     while (current_offset < total_size) {
331         uint64_t remaining = total_size - current_offset;
332         uint64_t chunk_size = std::min(buf_size, remaining);
333         if ((ret = ReadBuffer(data.data(), chunk_size)) != SUCCESS) {
334             return ret;
335         }
336         if ((ret = write_fn(data.data(), chunk_size)) != SUCCESS) {
337             return ret;
338         }
339         current_offset += chunk_size;
340     }
341     return HandleResponse(response, info);
342 }
343 
UploadInner(const std::string & outfile,std::string * response,std::vector<std::string> * info)344 RetCode FastBootDriver::UploadInner(const std::string& outfile, std::string* response,
345                                     std::vector<std::string>* info) {
346     std::ofstream ofs;
347     ofs.open(outfile, std::ofstream::out | std::ofstream::binary);
348     if (ofs.fail()) {
349         error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str());
350         return IO_ERROR;
351     }
352     auto write_fn = [&](const char* data, uint64_t size) {
353         ofs.write(data, size);
354         if (ofs.fail() || ofs.bad()) {
355             error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str());
356             return IO_ERROR;
357         }
358         return SUCCESS;
359     };
360     RetCode ret = RunAndReadBuffer(FB_CMD_UPLOAD, response, info, write_fn);
361     ofs.close();
362     return ret;
363 }
364 
FetchToFd(const std::string & partition,android::base::borrowed_fd fd,int64_t offset,int64_t size,std::string * response,std::vector<std::string> * info)365 RetCode FastBootDriver::FetchToFd(const std::string& partition, android::base::borrowed_fd fd,
366                                   int64_t offset, int64_t size, std::string* response,
367                                   std::vector<std::string>* info) {
368     prolog_(android::base::StringPrintf("Fetching %s (offset=%" PRIx64 ", size=%" PRIx64 ")",
369                                         partition.c_str(), offset, size));
370     std::string cmd = FB_CMD_FETCH ":" + partition;
371     if (offset >= 0) {
372         cmd += android::base::StringPrintf(":0x%08" PRIx64, offset);
373         if (size >= 0) {
374             cmd += android::base::StringPrintf(":0x%08" PRIx64, size);
375         }
376     }
377     RetCode ret = RunAndReadBuffer(cmd, response, info, [&](const char* data, uint64_t size) {
378         if (!android::base::WriteFully(fd, data, size)) {
379             error_ = android::base::StringPrintf("Cannot write: %s", strerror(errno));
380             return IO_ERROR;
381         }
382         return SUCCESS;
383     });
384     epilog_(ret);
385     return ret;
386 }
387 
388 // Helpers
SetInfoCallback(std::function<void (const std::string &)> info)389 void FastBootDriver::SetInfoCallback(std::function<void(const std::string&)> info) {
390     info_ = info;
391 }
392 
RCString(RetCode rc)393 const std::string FastBootDriver::RCString(RetCode rc) {
394     switch (rc) {
395         case SUCCESS:
396             return std::string("Success");
397 
398         case BAD_ARG:
399             return std::string("Invalid Argument");
400 
401         case IO_ERROR:
402             return std::string("I/O Error");
403 
404         case BAD_DEV_RESP:
405             return std::string("Invalid Device Response");
406 
407         case DEVICE_FAIL:
408             return std::string("Device Error");
409 
410         case TIMEOUT:
411             return std::string("Timeout");
412 
413         default:
414             return std::string("Unknown Error");
415     }
416 }
417 
Error()418 std::string FastBootDriver::Error() {
419     return error_;
420 }
421 
WaitForDisconnect()422 RetCode FastBootDriver::WaitForDisconnect() {
423     return transport_->WaitForDisconnect() ? IO_ERROR : SUCCESS;
424 }
425 
426 /****************************** PROTECTED *************************************/
RawCommand(const std::string & cmd,const std::string & message,std::string * response,std::vector<std::string> * info,int * dsize)427 RetCode FastBootDriver::RawCommand(const std::string& cmd, const std::string& message,
428                                    std::string* response, std::vector<std::string>* info,
429                                    int* dsize) {
430     prolog_(message);
431     auto result = RawCommand(cmd, response, info, dsize);
432     epilog_(result);
433     return result;
434 }
435 
RawCommand(const std::string & cmd,std::string * response,std::vector<std::string> * info,int * dsize)436 RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
437                                    std::vector<std::string>* info, int* dsize) {
438     error_ = "";  // Clear any pending error
439     if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) {
440         error_ = "Command length to RawCommand() is too long";
441         return BAD_ARG;
442     }
443 
444     if (transport_->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
445         error_ = ErrnoStr("Write to device failed");
446         return IO_ERROR;
447     }
448 
449     // Read the response
450     return HandleResponse(response, info, dsize);
451 }
452 
DownloadCommand(uint32_t size,std::string * response,std::vector<std::string> * info)453 RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
454                                         std::vector<std::string>* info) {
455     std::string cmd(android::base::StringPrintf("%s:%08" PRIx32, FB_CMD_DOWNLOAD, size));
456     RetCode ret;
457     if ((ret = RawCommand(cmd, response, info))) {
458         return ret;
459     }
460     return SUCCESS;
461 }
462 
HandleResponse(std::string * response,std::vector<std::string> * info,int * dsize)463 RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
464                                        int* dsize) {
465     char status[FB_RESPONSE_SZ + 1];
466     auto start = std::chrono::steady_clock::now();
467 
468     auto set_response = [response](std::string s) {
469         if (response) *response = std::move(s);
470     };
471     auto add_info = [info](std::string s) {
472         if (info) info->push_back(std::move(s));
473     };
474 
475     // erase response
476     set_response("");
477     while ((std::chrono::steady_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
478         int r = transport_->Read(status, FB_RESPONSE_SZ);
479         if (r < 0) {
480             error_ = ErrnoStr("Status read failed");
481             return IO_ERROR;
482         }
483 
484         status[r] = '\0';  // Need the null terminator
485         std::string input(status);
486         if (android::base::StartsWith(input, "INFO")) {
487             std::string tmp = input.substr(strlen("INFO"));
488             info_(tmp);
489             add_info(std::move(tmp));
490             // We may receive one or more INFO packets during long operations,
491             // e.g. flash/erase if they are back by slow media like NAND/NOR
492             // flash. In that case, reset the timer since it's not a real
493             // timeout.
494             start = std::chrono::steady_clock::now();
495         } else if (android::base::StartsWith(input, "OKAY")) {
496             set_response(input.substr(strlen("OKAY")));
497             return SUCCESS;
498         } else if (android::base::StartsWith(input, "FAIL")) {
499             error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
500             set_response(input.substr(strlen("FAIL")));
501             return DEVICE_FAIL;
502         } else if (android::base::StartsWith(input, "TEXT")) {
503             text_(input.substr(strlen("TEXT")));
504             // Reset timeout as many more TEXT may come
505             start = std::chrono::steady_clock::now();
506         } else if (android::base::StartsWith(input, "DATA")) {
507             std::string tmp = input.substr(strlen("DATA"));
508             uint32_t num = strtol(tmp.c_str(), 0, 16);
509             if (num > MAX_DOWNLOAD_SIZE) {
510                 error_ = android::base::StringPrintf("Data size too large (%d)", num);
511                 return BAD_DEV_RESP;
512             }
513             if (dsize) *dsize = num;
514             set_response(std::move(tmp));
515             return SUCCESS;
516         } else {
517             error_ = android::base::StringPrintf("Device sent unknown status code: %s", status);
518             return BAD_DEV_RESP;
519         }
520 
521     }  // End of while loop
522 
523     return TIMEOUT;
524 }
525 
ErrnoStr(const std::string & msg)526 std::string FastBootDriver::ErrnoStr(const std::string& msg) {
527     return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
528 }
529 
530 /******************************* PRIVATE **************************************/
SendBuffer(android::base::borrowed_fd fd,size_t size)531 RetCode FastBootDriver::SendBuffer(android::base::borrowed_fd fd, size_t size) {
532     static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
533     off64_t offset = 0;
534     uint32_t remaining = size;
535     RetCode ret;
536 
537     while (remaining) {
538         // Memory map the file
539         size_t len = std::min(remaining, MAX_MAP_SIZE);
540         auto mapping{android::base::MappedFile::FromFd(fd, offset, len, PROT_READ)};
541         if (!mapping) {
542             error_ = "Creating filemap failed";
543             return IO_ERROR;
544         }
545 
546         if ((ret = SendBuffer(mapping->data(), mapping->size()))) {
547             return ret;
548         }
549 
550         remaining -= len;
551         offset += len;
552     }
553 
554     return SUCCESS;
555 }
556 
SendBuffer(const std::vector<char> & buf)557 RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) {
558     // Write the buffer
559     return SendBuffer(buf.data(), buf.size());
560 }
561 
SendBuffer(const void * buf,size_t size)562 RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
563     // ioctl on 0-length buffer causes freezing
564     if (!size) {
565         return BAD_ARG;
566     }
567     // Write the buffer
568     ssize_t tmp = transport_->Write(buf, size);
569 
570     if (tmp < 0) {
571         error_ = ErrnoStr("Write to device failed in SendBuffer()");
572         return IO_ERROR;
573     } else if (static_cast<size_t>(tmp) != size) {
574         error_ = android::base::StringPrintf("Failed to write all %zu bytes", size);
575 
576         return IO_ERROR;
577     }
578 
579     return SUCCESS;
580 }
581 
ReadBuffer(void * buf,size_t size)582 RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
583     // Read the buffer
584     ssize_t tmp = transport_->Read(buf, size);
585 
586     if (tmp < 0) {
587         error_ = ErrnoStr("Read from device failed in ReadBuffer()");
588         return IO_ERROR;
589     } else if (static_cast<size_t>(tmp) != size) {
590         error_ = android::base::StringPrintf("Failed to read all %zu bytes", size);
591         return IO_ERROR;
592     }
593 
594     return SUCCESS;
595 }
596 
SparseWriteCallback(std::vector<char> & tpbuf,const char * data,size_t len)597 int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) {
598     size_t total = 0;
599     size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len);
600 
601     // Handle the residual
602     tpbuf.insert(tpbuf.end(), data, data + to_write);
603     if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) {  // Nothing enough to send rn
604         return 0;
605     }
606 
607     if (SendBuffer(tpbuf)) {
608         error_ = ErrnoStr("Send failed in SparseWriteCallback()");
609         return -1;
610     }
611     tpbuf.clear();
612     total += to_write;
613 
614     // Now we need to send a multiple of chunk size
615     size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
616     size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
617     if (nbytes && SendBuffer(data + total, nbytes)) {  // Don't send a ZLP
618         error_ = ErrnoStr("Send failed in SparseWriteCallback()");
619         return -1;
620     }
621     total += nbytes;
622 
623     if (len - total > 0) {  // We have residual data to save for next time
624         tpbuf.assign(data + total, data + len);
625     }
626 
627     return 0;
628 }
629 
set_transport(Transport * transport)630 Transport* FastBootDriver::set_transport(Transport* transport) {
631     std::swap(transport_, transport);
632     return transport;
633 }
634 
635 }  // End namespace fastboot
636