blob: 97857d95c28ce287b7be460a43e4a0a2c974ac53 [file] [log] [blame]
Aaron Wisnerdb511202018-06-26 15:38:35 -05001/*
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#include "fastboot_driver.h"
29
30#include <errno.h>
31#include <fcntl.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <algorithm>
36#include <chrono>
37#include <fstream>
38#include <memory>
39#include <regex>
40#include <vector>
41
42#include <android-base/file.h>
43#include <android-base/stringprintf.h>
44#include <android-base/strings.h>
45#include <android-base/unique_fd.h>
46#include <utils/FileMap.h>
47#include "fastboot_driver.h"
48#include "transport.h"
49
50namespace fastboot {
51
52/*************************** PUBLIC *******************************/
53FastBootDriver::FastBootDriver(Transport* transport, std::function<void(std::string&)> info,
54 bool no_checks)
David Anderson1d887432018-08-27 16:47:32 -070055 : transport_(transport) {
Aaron Wisnerdb511202018-06-26 15:38:35 -050056 info_cb_ = info;
57 disable_checks_ = no_checks;
58}
59
David Anderson1d887432018-08-27 16:47:32 -070060FastBootDriver::~FastBootDriver() {
David Anderson1d887432018-08-27 16:47:32 -070061}
62
Aaron Wisnerdb511202018-06-26 15:38:35 -050063RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
64 return RawCommand(Commands::BOOT, response, info);
65}
66
67RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
68 return RawCommand(Commands::CONTINUE, response, info);
69}
70
71RetCode FastBootDriver::Erase(const std::string& part, std::string* response,
72 std::vector<std::string>* info) {
73 return RawCommand(Commands::ERASE + part, response, info);
74}
75
76RetCode FastBootDriver::Flash(const std::string& part, std::string* response,
77 std::vector<std::string>* info) {
78 return RawCommand(Commands::FLASH + part, response, info);
79}
80
81RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
82 std::vector<std::string>* info) {
83 return RawCommand(Commands::GET_VAR + key, val, info);
84}
85
86RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
87 std::string tmp;
88 return GetVar("all", &tmp, response);
89}
90
Aaron Wisnerdb511202018-06-26 15:38:35 -050091RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
92 return RawCommand(Commands::REBOOT, response, info);
93}
94
David Anderson1d887432018-08-27 16:47:32 -070095RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
96 std::vector<std::string>* info) {
97 return RawCommand("reboot-" + target, response, info);
98}
99
Tom Cherry11f12092018-08-29 21:36:28 -0700100RetCode FastBootDriver::SetActive(const std::string& slot, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500101 std::vector<std::string>* info) {
Tom Cherry11f12092018-08-29 21:36:28 -0700102 return RawCommand(Commands::SET_ACTIVE + slot, response, info);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500103}
104
Aaron Wisnerdb511202018-06-26 15:38:35 -0500105RetCode FastBootDriver::FlashPartition(const std::string& part, const std::vector<char>& data) {
106 RetCode ret;
107 if ((ret = Download(data))) {
108 return ret;
109 }
110 return RawCommand(Commands::FLASH + part);
111}
112
113RetCode FastBootDriver::FlashPartition(const std::string& part, int fd, uint32_t sz) {
114 RetCode ret;
115 if ((ret = Download(fd, sz))) {
116 return ret;
117 }
118 return RawCommand(Commands::FLASH + part);
119}
120
121RetCode FastBootDriver::FlashPartition(const std::string& part, sparse_file* s) {
122 RetCode ret;
123 if ((ret = Download(s))) {
124 return ret;
125 }
126 return RawCommand(Commands::FLASH + part);
127}
128
David Anderson6c30f6e2018-09-04 15:57:39 -0700129RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* parts) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500130 std::vector<std::string> all;
131 RetCode ret;
132 if ((ret = GetVarAll(&all))) {
133 return ret;
134 }
135
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500136 std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)");
Aaron Wisnerdb511202018-06-26 15:38:35 -0500137 std::smatch sm;
138
139 for (auto& s : all) {
140 if (std::regex_match(s, sm, reg)) {
141 std::string m1(sm[1]);
142 std::string m2(sm[2]);
David Anderson6c30f6e2018-09-04 15:57:39 -0700143 uint64_t tmp = strtoll(m2.c_str(), 0, 16);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500144 parts->push_back(std::make_tuple(m1, tmp));
145 }
146 }
147 return SUCCESS;
148}
149
150RetCode FastBootDriver::Require(const std::string& var, const std::vector<std::string>& allowed,
151 bool* reqmet, bool invert) {
152 *reqmet = invert;
153 RetCode ret;
154 std::string response;
155 if ((ret = GetVar(var, &response))) {
156 return ret;
157 }
158
159 // Now check if we have a match
160 for (const auto s : allowed) {
161 // If it ends in *, and starting substring match
162 if (response == s || (s.length() && s.back() == '*' &&
163 !response.compare(0, s.length() - 1, s, 0, s.length() - 1))) {
164 *reqmet = !invert;
165 break;
166 }
167 }
168
169 return SUCCESS;
170}
171
172RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
173 std::vector<std::string>* info) {
174 RetCode ret;
175
176 if ((size <= 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
177 error_ = "File is too large to download";
178 return BAD_ARG;
179 }
180
181 uint32_t u32size = static_cast<uint32_t>(size);
182 if ((ret = DownloadCommand(u32size, response, info))) {
183 return ret;
184 }
185
186 // Write the buffer
187 if ((ret = SendBuffer(fd, size))) {
188 return ret;
189 }
190
191 // Wait for response
192 return HandleResponse(response, info);
193}
194
195RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
196 std::vector<std::string>* info) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500197 RetCode ret;
198 error_ = "";
Tom Cherrydfd85df2018-09-20 14:45:05 -0700199 if ((buf.size() == 0 || buf.size() > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500200 error_ = "Buffer is too large or 0 bytes";
201 return BAD_ARG;
202 }
203
Tom Cherrydfd85df2018-09-20 14:45:05 -0700204 if ((ret = DownloadCommand(buf.size(), response, info))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500205 return ret;
206 }
207
208 // Write the buffer
Tom Cherrydfd85df2018-09-20 14:45:05 -0700209 if ((ret = SendBuffer(buf))) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500210 return ret;
211 }
212
213 // Wait for response
214 return HandleResponse(response, info);
215}
216
Aaron Wisner9812b582018-08-22 11:01:04 -0500217RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500218 std::vector<std::string>* info) {
219 error_ = "";
Aaron Wisner9812b582018-08-22 11:01:04 -0500220 int64_t size = sparse_file_len(s, true, use_crc);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500221 if (size <= 0 || size > MAX_DOWNLOAD_SIZE) {
222 error_ = "Sparse file is too large or invalid";
223 return BAD_ARG;
224 }
225
226 RetCode ret;
227 uint32_t u32size = static_cast<uint32_t>(size);
228 if ((ret = DownloadCommand(u32size, response, info))) {
229 return ret;
230 }
231
232 struct SparseCBPrivate {
233 FastBootDriver* self;
234 std::vector<char> tpbuf;
235 } cb_priv;
236 cb_priv.self = this;
237
238 auto cb = [](void* priv, const void* buf, size_t len) -> int {
239 SparseCBPrivate* data = static_cast<SparseCBPrivate*>(priv);
240 const char* cbuf = static_cast<const char*>(buf);
241 return data->self->SparseWriteCallback(data->tpbuf, cbuf, len);
242 };
243
Aaron Wisner9812b582018-08-22 11:01:04 -0500244 if (sparse_file_callback(s, true, use_crc, cb, &cb_priv) < 0) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500245 error_ = "Error reading sparse file";
246 return IO_ERROR;
247 }
248
249 // Now flush
250 if (cb_priv.tpbuf.size() && (ret = SendBuffer(cb_priv.tpbuf))) {
251 return ret;
252 }
253
254 return HandleResponse(response, info);
255}
256
257RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
258 std::vector<std::string>* info) {
259 RetCode ret;
260 int dsize;
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500261 if ((ret = RawCommand(Commands::UPLOAD, response, info, &dsize))) {
262 error_ = "Upload request failed: " + error_;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500263 return ret;
264 }
265
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500266 if (!dsize) {
267 error_ = "Upload request failed, device reports 0 bytes available";
268 return BAD_DEV_RESP;
269 }
270
Aaron Wisnerdb511202018-06-26 15:38:35 -0500271 std::vector<char> data;
272 data.resize(dsize);
273
274 if ((ret = ReadBuffer(data))) {
275 return ret;
276 }
277
278 std::ofstream ofs;
279 ofs.open(outfile, std::ofstream::out | std::ofstream::binary);
280 if (ofs.fail()) {
281 error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str());
282 return IO_ERROR;
283 }
284 ofs.write(data.data(), data.size());
285 if (ofs.fail() || ofs.bad()) {
286 error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str());
287 return IO_ERROR;
288 }
289 ofs.close();
290
291 return HandleResponse(response, info);
292}
293
294// Helpers
295void FastBootDriver::SetInfoCallback(std::function<void(std::string&)> info) {
296 info_cb_ = info;
297}
298
299const std::string FastBootDriver::RCString(RetCode rc) {
300 switch (rc) {
301 case SUCCESS:
302 return std::string("Success");
303
304 case BAD_ARG:
305 return std::string("Invalid Argument");
306
307 case IO_ERROR:
308 return std::string("I/O Error");
309
310 case BAD_DEV_RESP:
311 return std::string("Invalid Device Response");
312
313 case DEVICE_FAIL:
314 return std::string("Device Error");
315
316 case TIMEOUT:
317 return std::string("Timeout");
318
319 default:
320 return std::string("Unknown Error");
321 }
322}
323
324std::string FastBootDriver::Error() {
325 return error_;
326}
327
328RetCode FastBootDriver::WaitForDisconnect() {
David Anderson1d887432018-08-27 16:47:32 -0700329 return transport_->WaitForDisconnect() ? IO_ERROR : SUCCESS;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500330}
331
332/****************************** PROTECTED *************************************/
333RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
334 std::vector<std::string>* info, int* dsize) {
335 error_ = ""; // Clear any pending error
336 if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) {
337 error_ = "Command length to RawCommand() is too long";
338 return BAD_ARG;
339 }
340
David Anderson1d887432018-08-27 16:47:32 -0700341 if (transport_->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500342 error_ = ErrnoStr("Write to device failed");
343 return IO_ERROR;
344 }
345
346 // Read the response
347 return HandleResponse(response, info, dsize);
348}
349
350RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
351 std::vector<std::string>* info) {
352 std::string cmd(android::base::StringPrintf("%s%08" PRIx32, Commands::DOWNLOAD.c_str(), size));
353 RetCode ret;
354 if ((ret = RawCommand(cmd, response, info))) {
355 return ret;
356 }
357 return SUCCESS;
358}
359
360RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
361 int* dsize) {
362 char status[FB_RESPONSE_SZ + 1];
363 auto start = std::chrono::system_clock::now();
364
365 auto set_response = [response](std::string s) {
366 if (response) *response = std::move(s);
367 };
368 auto add_info = [info](std::string s) {
369 if (info) info->push_back(std::move(s));
370 };
371
372 // erase response
373 set_response("");
374 while ((std::chrono::system_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
David Anderson1d887432018-08-27 16:47:32 -0700375 int r = transport_->Read(status, FB_RESPONSE_SZ);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500376 if (r < 0) {
377 error_ = ErrnoStr("Status read failed");
378 return IO_ERROR;
379 }
380
381 status[r] = '\0'; // Need the null terminator
382 std::string input(status);
383 if (android::base::StartsWith(input, "INFO")) {
384 std::string tmp = input.substr(strlen("INFO"));
385 info_cb_(tmp);
386 add_info(std::move(tmp));
387 } else if (android::base::StartsWith(input, "OKAY")) {
388 set_response(input.substr(strlen("OKAY")));
389 return SUCCESS;
390 } else if (android::base::StartsWith(input, "FAIL")) {
391 error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
392 set_response(input.substr(strlen("FAIL")));
393 return DEVICE_FAIL;
394 } else if (android::base::StartsWith(input, "DATA")) {
395 std::string tmp = input.substr(strlen("DATA"));
396 uint32_t num = strtol(tmp.c_str(), 0, 16);
397 if (num > MAX_DOWNLOAD_SIZE) {
398 error_ = android::base::StringPrintf("Data size too large (%d)", num);
399 return BAD_DEV_RESP;
400 }
401 if (dsize) *dsize = num;
402 set_response(std::move(tmp));
403 return SUCCESS;
404 } else {
405 error_ = android::base::StringPrintf("Device sent unknown status code: %s", status);
406 return BAD_DEV_RESP;
407 }
408
409 } // End of while loop
410
411 return TIMEOUT;
412}
413
414std::string FastBootDriver::ErrnoStr(const std::string& msg) {
415 return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
416}
417
418const std::string FastBootDriver::Commands::BOOT = "boot";
419const std::string FastBootDriver::Commands::CONTINUE = "continue";
420const std::string FastBootDriver::Commands::DOWNLOAD = "download:";
421const std::string FastBootDriver::Commands::ERASE = "erase:";
422const std::string FastBootDriver::Commands::FLASH = "flash:";
423const std::string FastBootDriver::Commands::GET_VAR = "getvar:";
Aaron Wisnerdb511202018-06-26 15:38:35 -0500424const std::string FastBootDriver::Commands::REBOOT = "reboot";
425const std::string FastBootDriver::Commands::SET_ACTIVE = "set_active:";
426const std::string FastBootDriver::Commands::UPLOAD = "upload";
Aaron Wisnerdb511202018-06-26 15:38:35 -0500427
428/******************************* PRIVATE **************************************/
429RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
430 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
431 off64_t offset = 0;
432 uint32_t remaining = size;
433 RetCode ret;
434
435 while (remaining) {
436 // Memory map the file
437 android::FileMap filemap;
438 size_t len = std::min(remaining, MAX_MAP_SIZE);
439
440 if (!filemap.create(NULL, fd, offset, len, true)) {
441 error_ = "Creating filemap failed";
442 return IO_ERROR;
443 }
444
445 if ((ret = SendBuffer(filemap.getDataPtr(), len))) {
446 return ret;
447 }
448
449 remaining -= len;
450 offset += len;
451 }
452
453 return SUCCESS;
454}
455
456RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) {
457 // Write the buffer
458 return SendBuffer(buf.data(), buf.size());
459}
460
461RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500462 // ioctl on 0-length buffer causes freezing
David Anderson0c7bde82018-07-30 12:54:53 -0700463 if (!size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500464 return BAD_ARG;
David Anderson0c7bde82018-07-30 12:54:53 -0700465 }
Aaron Wisnerdb511202018-06-26 15:38:35 -0500466 // Write the buffer
David Anderson1d887432018-08-27 16:47:32 -0700467 ssize_t tmp = transport_->Write(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500468
469 if (tmp < 0) {
470 error_ = ErrnoStr("Write to device failed in SendBuffer()");
471 return IO_ERROR;
472 } else if (static_cast<size_t>(tmp) != size) {
473 error_ = android::base::StringPrintf("Failed to write all %zu bytes", size);
474
475 return IO_ERROR;
476 }
477
478 return SUCCESS;
479}
480
481RetCode FastBootDriver::ReadBuffer(std::vector<char>& buf) {
482 // Read the buffer
483 return ReadBuffer(buf.data(), buf.size());
484}
485
486RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
487 // Read the buffer
David Anderson1d887432018-08-27 16:47:32 -0700488 ssize_t tmp = transport_->Read(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500489
490 if (tmp < 0) {
491 error_ = ErrnoStr("Read from device failed in ReadBuffer()");
492 return IO_ERROR;
493 } else if (static_cast<size_t>(tmp) != size) {
494 error_ = android::base::StringPrintf("Failed to read all %zu bytes", size);
495 return IO_ERROR;
496 }
497
498 return SUCCESS;
499}
500
501int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) {
502 size_t total = 0;
503 size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len);
504
505 // Handle the residual
506 tpbuf.insert(tpbuf.end(), data, data + to_write);
507 if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) { // Nothing enough to send rn
508 return 0;
509 }
510
511 if (SendBuffer(tpbuf)) {
512 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
513 return -1;
514 }
515 tpbuf.clear();
516 total += to_write;
517
518 // Now we need to send a multiple of chunk size
519 size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
520 size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500521 if (nbytes && SendBuffer(data + total, nbytes)) { // Don't send a ZLP
Aaron Wisnerdb511202018-06-26 15:38:35 -0500522 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
523 return -1;
524 }
525 total += nbytes;
526
527 if (len - total > 0) { // We have residual data to save for next time
528 tpbuf.assign(data + total, data + len);
529 }
530
531 return 0;
532}
533
David Anderson03de6452018-09-04 14:32:54 -0700534Transport* FastBootDriver::set_transport(Transport* transport) {
535 std::swap(transport_, transport);
536 return transport;
David Anderson1d887432018-08-27 16:47:32 -0700537}
538
Aaron Wisnerdb511202018-06-26 15:38:35 -0500539} // End namespace fastboot