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