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