| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 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 |  */ | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 28 |  | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 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/stringprintf.h> | 
 | 45 | #include <android-base/strings.h> | 
 | 46 | #include <android-base/unique_fd.h> | 
 | 47 | #include <utils/FileMap.h> | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 48 |  | 
 | 49 | #include "constants.h" | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 50 | #include "transport.h" | 
 | 51 |  | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 52 | using android::base::StringPrintf; | 
 | 53 |  | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 54 | namespace fastboot { | 
 | 55 |  | 
 | 56 | /*************************** PUBLIC *******************************/ | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 57 | FastBootDriver::FastBootDriver(Transport* transport, DriverCallbacks driver_callbacks, | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 58 |                                bool no_checks) | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 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) {} | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 64 |  | 
| David Anderson | 1d88743 | 2018-08-27 16:47:32 -0700 | [diff] [blame] | 65 | FastBootDriver::~FastBootDriver() { | 
| David Anderson | 1d88743 | 2018-08-27 16:47:32 -0700 | [diff] [blame] | 66 | } | 
 | 67 |  | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 68 | RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) { | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 69 |     return RawCommand(FB_CMD_BOOT, "Booting", response, info); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 70 | } | 
 | 71 |  | 
 | 72 | RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) { | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 73 |     return RawCommand(FB_CMD_CONTINUE, "Resuming boot", response, info); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 74 | } | 
 | 75 |  | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 76 | RetCode FastBootDriver::CreatePartition(const std::string& partition, const std::string& size) { | 
 | 77 |     return RawCommand(FB_CMD_CREATE_PARTITION ":" + partition + ":" + size, | 
 | 78 |                       "Creating '" + partition + "'"); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 79 | } | 
 | 80 |  | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 81 | RetCode FastBootDriver::DeletePartition(const std::string& partition) { | 
 | 82 |     return RawCommand(FB_CMD_DELETE_PARTITION ":" + partition, "Deleting '" + partition + "'"); | 
 | 83 | } | 
 | 84 |  | 
 | 85 | RetCode FastBootDriver::Erase(const std::string& partition, std::string* response, | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 86 |                               std::vector<std::string>* info) { | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 87 |     return RawCommand(FB_CMD_ERASE ":" + partition, "Erasing '" + partition + "'", response, info); | 
 | 88 | } | 
 | 89 |  | 
 | 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); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 93 | } | 
 | 94 |  | 
 | 95 | RetCode FastBootDriver::GetVar(const std::string& key, std::string* val, | 
 | 96 |                                std::vector<std::string>* info) { | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 97 |     return RawCommand(FB_CMD_GETVAR ":" + key, val, info); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 98 | } | 
 | 99 |  | 
 | 100 | RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) { | 
 | 101 |     std::string tmp; | 
 | 102 |     return GetVar("all", &tmp, response); | 
 | 103 | } | 
 | 104 |  | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 105 | RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) { | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 106 |     return RawCommand(FB_CMD_REBOOT, "Rebooting", response, info); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 107 | } | 
 | 108 |  | 
| David Anderson | 1d88743 | 2018-08-27 16:47:32 -0700 | [diff] [blame] | 109 | RetCode FastBootDriver::RebootTo(std::string target, std::string* response, | 
 | 110 |                                  std::vector<std::string>* info) { | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 111 |     return RawCommand("reboot-" + target, "Rebooting into " + target, response, info); | 
 | 112 | } | 
 | 113 |  | 
 | 114 | RetCode FastBootDriver::ResizePartition(const std::string& partition, const std::string& size) { | 
 | 115 |     return RawCommand(FB_CMD_RESIZE_PARTITION ":" + partition + ":" + size, | 
 | 116 |                       "Resizing '" + partition + "'"); | 
| David Anderson | 1d88743 | 2018-08-27 16:47:32 -0700 | [diff] [blame] | 117 | } | 
 | 118 |  | 
| Tom Cherry | 11f1209 | 2018-08-29 21:36:28 -0700 | [diff] [blame] | 119 | RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response, | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 120 |                                   std::vector<std::string>* info) { | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 121 |     return RawCommand(FB_CMD_SET_ACTIVE ":" + slot, "Setting current slot to '" + slot + "'", | 
 | 122 |                       response, info); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 123 | } | 
 | 124 |  | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 125 | RetCode FastBootDriver::FlashPartition(const std::string& partition, | 
 | 126 |                                        const std::vector<char>& data) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 127 |     RetCode ret; | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 128 |     if ((ret = Download(partition, data))) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 129 |         return ret; | 
 | 130 |     } | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 131 |     return Flash(partition); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 132 | } | 
 | 133 |  | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 134 | RetCode FastBootDriver::FlashPartition(const std::string& partition, int fd, uint32_t size) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 135 |     RetCode ret; | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 136 |     if ((ret = Download(partition, fd, size))) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 137 |         return ret; | 
 | 138 |     } | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 139 |     return Flash(partition); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 140 | } | 
 | 141 |  | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 142 | RetCode FastBootDriver::FlashPartition(const std::string& partition, sparse_file* s, uint32_t size, | 
 | 143 |                                        size_t current, size_t total) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 144 |     RetCode ret; | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 145 |     if ((ret = Download(partition, s, size, current, total, false))) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 146 |         return ret; | 
 | 147 |     } | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 148 |     return Flash(partition); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 149 | } | 
 | 150 |  | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 151 | RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* partitions) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 152 |     std::vector<std::string> all; | 
 | 153 |     RetCode ret; | 
 | 154 |     if ((ret = GetVarAll(&all))) { | 
 | 155 |         return ret; | 
 | 156 |     } | 
 | 157 |  | 
| Aaron Wisner | c771ae0 | 2018-08-01 12:57:20 -0500 | [diff] [blame] | 158 |     std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)"); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 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]); | 
| David Anderson | 6c30f6e | 2018-09-04 15:57:39 -0700 | [diff] [blame] | 165 |             uint64_t tmp = strtoll(m2.c_str(), 0, 16); | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 166 |             partitions->push_back(std::make_tuple(m1, tmp)); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 167 |         } | 
 | 168 |     } | 
 | 169 |     return SUCCESS; | 
 | 170 | } | 
 | 171 |  | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 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 |  | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 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 |  | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 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 |  | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 211 | RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response, | 
 | 212 |                                  std::vector<std::string>* info) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 213 |     RetCode ret; | 
 | 214 |     error_ = ""; | 
| Tom Cherry | dfd85df | 2018-09-20 14:45:05 -0700 | [diff] [blame] | 215 |     if ((buf.size() == 0 || buf.size() > MAX_DOWNLOAD_SIZE) && !disable_checks_) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 216 |         error_ = "Buffer is too large or 0 bytes"; | 
 | 217 |         return BAD_ARG; | 
 | 218 |     } | 
 | 219 |  | 
| Tom Cherry | dfd85df | 2018-09-20 14:45:05 -0700 | [diff] [blame] | 220 |     if ((ret = DownloadCommand(buf.size(), response, info))) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 221 |         return ret; | 
 | 222 |     } | 
 | 223 |  | 
 | 224 |     // Write the buffer | 
| Tom Cherry | dfd85df | 2018-09-20 14:45:05 -0700 | [diff] [blame] | 225 |     if ((ret = SendBuffer(buf))) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 226 |         return ret; | 
 | 227 |     } | 
 | 228 |  | 
 | 229 |     // Wait for response | 
 | 230 |     return HandleResponse(response, info); | 
 | 231 | } | 
 | 232 |  | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 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 |  | 
| Aaron Wisner | 9812b58 | 2018-08-22 11:01:04 -0500 | [diff] [blame] | 243 | RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response, | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 244 |                                  std::vector<std::string>* info) { | 
 | 245 |     error_ = ""; | 
| Aaron Wisner | 9812b58 | 2018-08-22 11:01:04 -0500 | [diff] [blame] | 246 |     int64_t size = sparse_file_len(s, true, use_crc); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 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 |  | 
| Aaron Wisner | 9812b58 | 2018-08-22 11:01:04 -0500 | [diff] [blame] | 270 |     if (sparse_file_callback(s, true, use_crc, cb, &cb_priv) < 0) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 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 |  | 
 | 283 | RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response, | 
 | 284 |                                std::vector<std::string>* info) { | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 285 |     prolog_("Uploading '" + outfile + "'"); | 
 | 286 |     auto result = UploadInner(outfile, response, info); | 
 | 287 |     epilog_(result); | 
 | 288 |     return result; | 
 | 289 | } | 
 | 290 |  | 
 | 291 | RetCode FastBootDriver::UploadInner(const std::string& outfile, std::string* response, | 
 | 292 |                                     std::vector<std::string>* info) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 293 |     RetCode ret; | 
 | 294 |     int dsize; | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 295 |     if ((ret = RawCommand(FB_CMD_UPLOAD, response, info, &dsize))) { | 
| Aaron Wisner | c771ae0 | 2018-08-01 12:57:20 -0500 | [diff] [blame] | 296 |         error_ = "Upload request failed: " + error_; | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 297 |         return ret; | 
 | 298 |     } | 
 | 299 |  | 
| Aaron Wisner | c771ae0 | 2018-08-01 12:57:20 -0500 | [diff] [blame] | 300 |     if (!dsize) { | 
 | 301 |         error_ = "Upload request failed, device reports 0 bytes available"; | 
 | 302 |         return BAD_DEV_RESP; | 
 | 303 |     } | 
 | 304 |  | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 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 | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 329 | void FastBootDriver::SetInfoCallback(std::function<void(const std::string&)> info) { | 
 | 330 |     info_ = info; | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 331 | } | 
 | 332 |  | 
 | 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 |  | 
 | 358 | std::string FastBootDriver::Error() { | 
 | 359 |     return error_; | 
 | 360 | } | 
 | 361 |  | 
 | 362 | RetCode FastBootDriver::WaitForDisconnect() { | 
| David Anderson | 1d88743 | 2018-08-27 16:47:32 -0700 | [diff] [blame] | 363 |     return transport_->WaitForDisconnect() ? IO_ERROR : SUCCESS; | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 364 | } | 
 | 365 |  | 
 | 366 | /****************************** PROTECTED *************************************/ | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 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 |  | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 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 |  | 
| David Anderson | 1d88743 | 2018-08-27 16:47:32 -0700 | [diff] [blame] | 384 |     if (transport_->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) { | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 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 |  | 
 | 393 | RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response, | 
 | 394 |                                         std::vector<std::string>* info) { | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 395 |     std::string cmd(android::base::StringPrintf("%s:%08" PRIx32, FB_CMD_DOWNLOAD, size)); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 396 |     RetCode ret; | 
 | 397 |     if ((ret = RawCommand(cmd, response, info))) { | 
 | 398 |         return ret; | 
 | 399 |     } | 
 | 400 |     return SUCCESS; | 
 | 401 | } | 
 | 402 |  | 
 | 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::system_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::system_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) { | 
| David Anderson | 1d88743 | 2018-08-27 16:47:32 -0700 | [diff] [blame] | 418 |         int r = transport_->Read(status, FB_RESPONSE_SZ); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 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")); | 
| Tom Cherry | 9027af0 | 2018-09-24 15:48:09 -0700 | [diff] [blame] | 428 |             info_(tmp); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 429 |             add_info(std::move(tmp)); | 
 | 430 |         } else if (android::base::StartsWith(input, "OKAY")) { | 
 | 431 |             set_response(input.substr(strlen("OKAY"))); | 
 | 432 |             return SUCCESS; | 
 | 433 |         } else if (android::base::StartsWith(input, "FAIL")) { | 
 | 434 |             error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL")); | 
 | 435 |             set_response(input.substr(strlen("FAIL"))); | 
 | 436 |             return DEVICE_FAIL; | 
 | 437 |         } else if (android::base::StartsWith(input, "DATA")) { | 
 | 438 |             std::string tmp = input.substr(strlen("DATA")); | 
 | 439 |             uint32_t num = strtol(tmp.c_str(), 0, 16); | 
 | 440 |             if (num > MAX_DOWNLOAD_SIZE) { | 
 | 441 |                 error_ = android::base::StringPrintf("Data size too large (%d)", num); | 
 | 442 |                 return BAD_DEV_RESP; | 
 | 443 |             } | 
 | 444 |             if (dsize) *dsize = num; | 
 | 445 |             set_response(std::move(tmp)); | 
 | 446 |             return SUCCESS; | 
 | 447 |         } else { | 
 | 448 |             error_ = android::base::StringPrintf("Device sent unknown status code: %s", status); | 
 | 449 |             return BAD_DEV_RESP; | 
 | 450 |         } | 
 | 451 |  | 
 | 452 |     }  // End of while loop | 
 | 453 |  | 
 | 454 |     return TIMEOUT; | 
 | 455 | } | 
 | 456 |  | 
 | 457 | std::string FastBootDriver::ErrnoStr(const std::string& msg) { | 
 | 458 |     return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno)); | 
 | 459 | } | 
 | 460 |  | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 461 | /******************************* PRIVATE **************************************/ | 
 | 462 | RetCode FastBootDriver::SendBuffer(int fd, size_t size) { | 
 | 463 |     static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024; | 
 | 464 |     off64_t offset = 0; | 
 | 465 |     uint32_t remaining = size; | 
 | 466 |     RetCode ret; | 
 | 467 |  | 
 | 468 |     while (remaining) { | 
 | 469 |         // Memory map the file | 
 | 470 |         android::FileMap filemap; | 
 | 471 |         size_t len = std::min(remaining, MAX_MAP_SIZE); | 
 | 472 |  | 
 | 473 |         if (!filemap.create(NULL, fd, offset, len, true)) { | 
 | 474 |             error_ = "Creating filemap failed"; | 
 | 475 |             return IO_ERROR; | 
 | 476 |         } | 
 | 477 |  | 
 | 478 |         if ((ret = SendBuffer(filemap.getDataPtr(), len))) { | 
 | 479 |             return ret; | 
 | 480 |         } | 
 | 481 |  | 
 | 482 |         remaining -= len; | 
 | 483 |         offset += len; | 
 | 484 |     } | 
 | 485 |  | 
 | 486 |     return SUCCESS; | 
 | 487 | } | 
 | 488 |  | 
 | 489 | RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) { | 
 | 490 |     // Write the buffer | 
 | 491 |     return SendBuffer(buf.data(), buf.size()); | 
 | 492 | } | 
 | 493 |  | 
 | 494 | RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) { | 
| Aaron Wisner | c771ae0 | 2018-08-01 12:57:20 -0500 | [diff] [blame] | 495 |     // ioctl on 0-length buffer causes freezing | 
| David Anderson | 0c7bde8 | 2018-07-30 12:54:53 -0700 | [diff] [blame] | 496 |     if (!size) { | 
| Aaron Wisner | c771ae0 | 2018-08-01 12:57:20 -0500 | [diff] [blame] | 497 |         return BAD_ARG; | 
| David Anderson | 0c7bde8 | 2018-07-30 12:54:53 -0700 | [diff] [blame] | 498 |     } | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 499 |     // Write the buffer | 
| David Anderson | 1d88743 | 2018-08-27 16:47:32 -0700 | [diff] [blame] | 500 |     ssize_t tmp = transport_->Write(buf, size); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 501 |  | 
 | 502 |     if (tmp < 0) { | 
 | 503 |         error_ = ErrnoStr("Write to device failed in SendBuffer()"); | 
 | 504 |         return IO_ERROR; | 
 | 505 |     } else if (static_cast<size_t>(tmp) != size) { | 
 | 506 |         error_ = android::base::StringPrintf("Failed to write all %zu bytes", size); | 
 | 507 |  | 
 | 508 |         return IO_ERROR; | 
 | 509 |     } | 
 | 510 |  | 
 | 511 |     return SUCCESS; | 
 | 512 | } | 
 | 513 |  | 
 | 514 | RetCode FastBootDriver::ReadBuffer(std::vector<char>& buf) { | 
 | 515 |     // Read the buffer | 
 | 516 |     return ReadBuffer(buf.data(), buf.size()); | 
 | 517 | } | 
 | 518 |  | 
 | 519 | RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) { | 
 | 520 |     // Read the buffer | 
| David Anderson | 1d88743 | 2018-08-27 16:47:32 -0700 | [diff] [blame] | 521 |     ssize_t tmp = transport_->Read(buf, size); | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 522 |  | 
 | 523 |     if (tmp < 0) { | 
 | 524 |         error_ = ErrnoStr("Read from device failed in ReadBuffer()"); | 
 | 525 |         return IO_ERROR; | 
 | 526 |     } else if (static_cast<size_t>(tmp) != size) { | 
 | 527 |         error_ = android::base::StringPrintf("Failed to read all %zu bytes", size); | 
 | 528 |         return IO_ERROR; | 
 | 529 |     } | 
 | 530 |  | 
 | 531 |     return SUCCESS; | 
 | 532 | } | 
 | 533 |  | 
 | 534 | int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) { | 
 | 535 |     size_t total = 0; | 
 | 536 |     size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len); | 
 | 537 |  | 
 | 538 |     // Handle the residual | 
 | 539 |     tpbuf.insert(tpbuf.end(), data, data + to_write); | 
 | 540 |     if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) {  // Nothing enough to send rn | 
 | 541 |         return 0; | 
 | 542 |     } | 
 | 543 |  | 
 | 544 |     if (SendBuffer(tpbuf)) { | 
 | 545 |         error_ = ErrnoStr("Send failed in SparseWriteCallback()"); | 
 | 546 |         return -1; | 
 | 547 |     } | 
 | 548 |     tpbuf.clear(); | 
 | 549 |     total += to_write; | 
 | 550 |  | 
 | 551 |     // Now we need to send a multiple of chunk size | 
 | 552 |     size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE; | 
 | 553 |     size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks; | 
| Aaron Wisner | c771ae0 | 2018-08-01 12:57:20 -0500 | [diff] [blame] | 554 |     if (nbytes && SendBuffer(data + total, nbytes)) {  // Don't send a ZLP | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 555 |         error_ = ErrnoStr("Send failed in SparseWriteCallback()"); | 
 | 556 |         return -1; | 
 | 557 |     } | 
 | 558 |     total += nbytes; | 
 | 559 |  | 
 | 560 |     if (len - total > 0) {  // We have residual data to save for next time | 
 | 561 |         tpbuf.assign(data + total, data + len); | 
 | 562 |     } | 
 | 563 |  | 
 | 564 |     return 0; | 
 | 565 | } | 
 | 566 |  | 
| David Anderson | 03de645 | 2018-09-04 14:32:54 -0700 | [diff] [blame] | 567 | Transport* FastBootDriver::set_transport(Transport* transport) { | 
 | 568 |     std::swap(transport_, transport); | 
 | 569 |     return transport; | 
| David Anderson | 1d88743 | 2018-08-27 16:47:32 -0700 | [diff] [blame] | 570 | } | 
 | 571 |  | 
| Aaron Wisner | db51120 | 2018-06-26 15:38:35 -0500 | [diff] [blame] | 572 | }  // End namespace fastboot |