blob: e8587c7be5ff82ff9fe6d85196784f458b65b91c [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() {
61 set_transport(nullptr);
62}
63
Aaron Wisnerdb511202018-06-26 15:38:35 -050064RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
65 return RawCommand(Commands::BOOT, response, info);
66}
67
68RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
69 return RawCommand(Commands::CONTINUE, response, info);
70}
71
72RetCode FastBootDriver::Erase(const std::string& part, std::string* response,
73 std::vector<std::string>* info) {
74 return RawCommand(Commands::ERASE + part, response, info);
75}
76
77RetCode FastBootDriver::Flash(const std::string& part, std::string* response,
78 std::vector<std::string>* info) {
79 return RawCommand(Commands::FLASH + part, response, info);
80}
81
82RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
83 std::vector<std::string>* info) {
84 return RawCommand(Commands::GET_VAR + key, val, info);
85}
86
87RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
88 std::string tmp;
89 return GetVar("all", &tmp, response);
90}
91
92RetCode FastBootDriver::Powerdown(std::string* response, std::vector<std::string>* info) {
93 return RawCommand(Commands::POWERDOWN, response, info);
94}
95
96RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
97 return RawCommand(Commands::REBOOT, response, info);
98}
99
David Anderson1d887432018-08-27 16:47:32 -0700100RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
101 std::vector<std::string>* info) {
102 return RawCommand("reboot-" + target, response, info);
103}
104
Aaron Wisnerdb511202018-06-26 15:38:35 -0500105RetCode FastBootDriver::SetActive(const std::string& part, std::string* response,
106 std::vector<std::string>* info) {
107 return RawCommand(Commands::SET_ACTIVE + part, response, info);
108}
109
110RetCode FastBootDriver::Verify(uint32_t num, std::string* response, std::vector<std::string>* info) {
111 std::string cmd = android::base::StringPrintf("%s%08" PRIx32, Commands::VERIFY.c_str(), num);
112 return RawCommand(cmd, response, info);
113}
114
115RetCode FastBootDriver::FlashPartition(const std::string& part, const std::vector<char>& data) {
116 RetCode ret;
117 if ((ret = Download(data))) {
118 return ret;
119 }
120 return RawCommand(Commands::FLASH + part);
121}
122
123RetCode FastBootDriver::FlashPartition(const std::string& part, int fd, uint32_t sz) {
124 RetCode ret;
125 if ((ret = Download(fd, sz))) {
126 return ret;
127 }
128 return RawCommand(Commands::FLASH + part);
129}
130
131RetCode FastBootDriver::FlashPartition(const std::string& part, sparse_file* s) {
132 RetCode ret;
133 if ((ret = Download(s))) {
134 return ret;
135 }
136 return RawCommand(Commands::FLASH + part);
137}
138
139RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint32_t>>* parts) {
140 std::vector<std::string> all;
141 RetCode ret;
142 if ((ret = GetVarAll(&all))) {
143 return ret;
144 }
145
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500146 std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:xdigit:]]+)");
Aaron Wisnerdb511202018-06-26 15:38:35 -0500147 std::smatch sm;
148
149 for (auto& s : all) {
150 if (std::regex_match(s, sm, reg)) {
151 std::string m1(sm[1]);
152 std::string m2(sm[2]);
153 uint32_t tmp = strtol(m2.c_str(), 0, 16);
154 parts->push_back(std::make_tuple(m1, tmp));
155 }
156 }
157 return SUCCESS;
158}
159
160RetCode FastBootDriver::Require(const std::string& var, const std::vector<std::string>& allowed,
161 bool* reqmet, bool invert) {
162 *reqmet = invert;
163 RetCode ret;
164 std::string response;
165 if ((ret = GetVar(var, &response))) {
166 return ret;
167 }
168
169 // Now check if we have a match
170 for (const auto s : allowed) {
171 // If it ends in *, and starting substring match
172 if (response == s || (s.length() && s.back() == '*' &&
173 !response.compare(0, s.length() - 1, s, 0, s.length() - 1))) {
174 *reqmet = !invert;
175 break;
176 }
177 }
178
179 return SUCCESS;
180}
181
182RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
183 std::vector<std::string>* info) {
184 RetCode ret;
185
186 if ((size <= 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
187 error_ = "File is too large to download";
188 return BAD_ARG;
189 }
190
191 uint32_t u32size = static_cast<uint32_t>(size);
192 if ((ret = DownloadCommand(u32size, response, info))) {
193 return ret;
194 }
195
196 // Write the buffer
197 if ((ret = SendBuffer(fd, size))) {
198 return ret;
199 }
200
201 // Wait for response
202 return HandleResponse(response, info);
203}
204
205RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
206 std::vector<std::string>* info) {
207 return Download(buf.data(), buf.size(), response, info);
208}
209
210RetCode FastBootDriver::Download(const char* buf, uint32_t size, std::string* response,
211 std::vector<std::string>* info) {
212 RetCode ret;
213 error_ = "";
214 if ((size == 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
215 error_ = "Buffer is too large or 0 bytes";
216 return BAD_ARG;
217 }
218
219 if ((ret = DownloadCommand(size, response, info))) {
220 return ret;
221 }
222
223 // Write the buffer
224 if ((ret = SendBuffer(buf, size))) {
225 return ret;
226 }
227
228 // Wait for response
229 return HandleResponse(response, info);
230}
231
Aaron Wisner9812b582018-08-22 11:01:04 -0500232RetCode FastBootDriver::Download(sparse_file* s, bool use_crc, std::string* response,
Aaron Wisnerdb511202018-06-26 15:38:35 -0500233 std::vector<std::string>* info) {
234 error_ = "";
Aaron Wisner9812b582018-08-22 11:01:04 -0500235 int64_t size = sparse_file_len(s, true, use_crc);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500236 if (size <= 0 || size > MAX_DOWNLOAD_SIZE) {
237 error_ = "Sparse file is too large or invalid";
238 return BAD_ARG;
239 }
240
241 RetCode ret;
242 uint32_t u32size = static_cast<uint32_t>(size);
243 if ((ret = DownloadCommand(u32size, response, info))) {
244 return ret;
245 }
246
247 struct SparseCBPrivate {
248 FastBootDriver* self;
249 std::vector<char> tpbuf;
250 } cb_priv;
251 cb_priv.self = this;
252
253 auto cb = [](void* priv, const void* buf, size_t len) -> int {
254 SparseCBPrivate* data = static_cast<SparseCBPrivate*>(priv);
255 const char* cbuf = static_cast<const char*>(buf);
256 return data->self->SparseWriteCallback(data->tpbuf, cbuf, len);
257 };
258
Aaron Wisner9812b582018-08-22 11:01:04 -0500259 if (sparse_file_callback(s, true, use_crc, cb, &cb_priv) < 0) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500260 error_ = "Error reading sparse file";
261 return IO_ERROR;
262 }
263
264 // Now flush
265 if (cb_priv.tpbuf.size() && (ret = SendBuffer(cb_priv.tpbuf))) {
266 return ret;
267 }
268
269 return HandleResponse(response, info);
270}
271
272RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
273 std::vector<std::string>* info) {
274 RetCode ret;
275 int dsize;
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500276 if ((ret = RawCommand(Commands::UPLOAD, response, info, &dsize))) {
277 error_ = "Upload request failed: " + error_;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500278 return ret;
279 }
280
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500281 if (!dsize) {
282 error_ = "Upload request failed, device reports 0 bytes available";
283 return BAD_DEV_RESP;
284 }
285
Aaron Wisnerdb511202018-06-26 15:38:35 -0500286 std::vector<char> data;
287 data.resize(dsize);
288
289 if ((ret = ReadBuffer(data))) {
290 return ret;
291 }
292
293 std::ofstream ofs;
294 ofs.open(outfile, std::ofstream::out | std::ofstream::binary);
295 if (ofs.fail()) {
296 error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str());
297 return IO_ERROR;
298 }
299 ofs.write(data.data(), data.size());
300 if (ofs.fail() || ofs.bad()) {
301 error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str());
302 return IO_ERROR;
303 }
304 ofs.close();
305
306 return HandleResponse(response, info);
307}
308
309// Helpers
310void FastBootDriver::SetInfoCallback(std::function<void(std::string&)> info) {
311 info_cb_ = info;
312}
313
314const std::string FastBootDriver::RCString(RetCode rc) {
315 switch (rc) {
316 case SUCCESS:
317 return std::string("Success");
318
319 case BAD_ARG:
320 return std::string("Invalid Argument");
321
322 case IO_ERROR:
323 return std::string("I/O Error");
324
325 case BAD_DEV_RESP:
326 return std::string("Invalid Device Response");
327
328 case DEVICE_FAIL:
329 return std::string("Device Error");
330
331 case TIMEOUT:
332 return std::string("Timeout");
333
334 default:
335 return std::string("Unknown Error");
336 }
337}
338
339std::string FastBootDriver::Error() {
340 return error_;
341}
342
343RetCode FastBootDriver::WaitForDisconnect() {
David Anderson1d887432018-08-27 16:47:32 -0700344 return transport_->WaitForDisconnect() ? IO_ERROR : SUCCESS;
Aaron Wisnerdb511202018-06-26 15:38:35 -0500345}
346
347/****************************** PROTECTED *************************************/
348RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
349 std::vector<std::string>* info, int* dsize) {
350 error_ = ""; // Clear any pending error
351 if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) {
352 error_ = "Command length to RawCommand() is too long";
353 return BAD_ARG;
354 }
355
David Anderson1d887432018-08-27 16:47:32 -0700356 if (transport_->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
Aaron Wisnerdb511202018-06-26 15:38:35 -0500357 error_ = ErrnoStr("Write to device failed");
358 return IO_ERROR;
359 }
360
361 // Read the response
362 return HandleResponse(response, info, dsize);
363}
364
365RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
366 std::vector<std::string>* info) {
367 std::string cmd(android::base::StringPrintf("%s%08" PRIx32, Commands::DOWNLOAD.c_str(), size));
368 RetCode ret;
369 if ((ret = RawCommand(cmd, response, info))) {
370 return ret;
371 }
372 return SUCCESS;
373}
374
375RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
376 int* dsize) {
377 char status[FB_RESPONSE_SZ + 1];
378 auto start = std::chrono::system_clock::now();
379
380 auto set_response = [response](std::string s) {
381 if (response) *response = std::move(s);
382 };
383 auto add_info = [info](std::string s) {
384 if (info) info->push_back(std::move(s));
385 };
386
387 // erase response
388 set_response("");
389 while ((std::chrono::system_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
David Anderson1d887432018-08-27 16:47:32 -0700390 int r = transport_->Read(status, FB_RESPONSE_SZ);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500391 if (r < 0) {
392 error_ = ErrnoStr("Status read failed");
393 return IO_ERROR;
394 }
395
396 status[r] = '\0'; // Need the null terminator
397 std::string input(status);
398 if (android::base::StartsWith(input, "INFO")) {
399 std::string tmp = input.substr(strlen("INFO"));
400 info_cb_(tmp);
401 add_info(std::move(tmp));
402 } else if (android::base::StartsWith(input, "OKAY")) {
403 set_response(input.substr(strlen("OKAY")));
404 return SUCCESS;
405 } else if (android::base::StartsWith(input, "FAIL")) {
406 error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
407 set_response(input.substr(strlen("FAIL")));
408 return DEVICE_FAIL;
409 } else if (android::base::StartsWith(input, "DATA")) {
410 std::string tmp = input.substr(strlen("DATA"));
411 uint32_t num = strtol(tmp.c_str(), 0, 16);
412 if (num > MAX_DOWNLOAD_SIZE) {
413 error_ = android::base::StringPrintf("Data size too large (%d)", num);
414 return BAD_DEV_RESP;
415 }
416 if (dsize) *dsize = num;
417 set_response(std::move(tmp));
418 return SUCCESS;
419 } else {
420 error_ = android::base::StringPrintf("Device sent unknown status code: %s", status);
421 return BAD_DEV_RESP;
422 }
423
424 } // End of while loop
425
426 return TIMEOUT;
427}
428
429std::string FastBootDriver::ErrnoStr(const std::string& msg) {
430 return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
431}
432
433const std::string FastBootDriver::Commands::BOOT = "boot";
434const std::string FastBootDriver::Commands::CONTINUE = "continue";
435const std::string FastBootDriver::Commands::DOWNLOAD = "download:";
436const std::string FastBootDriver::Commands::ERASE = "erase:";
437const std::string FastBootDriver::Commands::FLASH = "flash:";
438const std::string FastBootDriver::Commands::GET_VAR = "getvar:";
439const std::string FastBootDriver::Commands::POWERDOWN = "powerdown";
440const std::string FastBootDriver::Commands::REBOOT = "reboot";
441const std::string FastBootDriver::Commands::SET_ACTIVE = "set_active:";
442const std::string FastBootDriver::Commands::UPLOAD = "upload";
443const std::string FastBootDriver::Commands::VERIFY = "verify:";
444
445/******************************* PRIVATE **************************************/
446RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
447 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
448 off64_t offset = 0;
449 uint32_t remaining = size;
450 RetCode ret;
451
452 while (remaining) {
453 // Memory map the file
454 android::FileMap filemap;
455 size_t len = std::min(remaining, MAX_MAP_SIZE);
456
457 if (!filemap.create(NULL, fd, offset, len, true)) {
458 error_ = "Creating filemap failed";
459 return IO_ERROR;
460 }
461
462 if ((ret = SendBuffer(filemap.getDataPtr(), len))) {
463 return ret;
464 }
465
466 remaining -= len;
467 offset += len;
468 }
469
470 return SUCCESS;
471}
472
473RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) {
474 // Write the buffer
475 return SendBuffer(buf.data(), buf.size());
476}
477
478RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500479 // ioctl on 0-length buffer causes freezing
David Anderson0c7bde82018-07-30 12:54:53 -0700480 if (!size) {
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500481 return BAD_ARG;
David Anderson0c7bde82018-07-30 12:54:53 -0700482 }
Aaron Wisnerdb511202018-06-26 15:38:35 -0500483 // Write the buffer
David Anderson1d887432018-08-27 16:47:32 -0700484 ssize_t tmp = transport_->Write(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500485
486 if (tmp < 0) {
487 error_ = ErrnoStr("Write to device failed in SendBuffer()");
488 return IO_ERROR;
489 } else if (static_cast<size_t>(tmp) != size) {
490 error_ = android::base::StringPrintf("Failed to write all %zu bytes", size);
491
492 return IO_ERROR;
493 }
494
495 return SUCCESS;
496}
497
498RetCode FastBootDriver::ReadBuffer(std::vector<char>& buf) {
499 // Read the buffer
500 return ReadBuffer(buf.data(), buf.size());
501}
502
503RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
504 // Read the buffer
David Anderson1d887432018-08-27 16:47:32 -0700505 ssize_t tmp = transport_->Read(buf, size);
Aaron Wisnerdb511202018-06-26 15:38:35 -0500506
507 if (tmp < 0) {
508 error_ = ErrnoStr("Read from device failed in ReadBuffer()");
509 return IO_ERROR;
510 } else if (static_cast<size_t>(tmp) != size) {
511 error_ = android::base::StringPrintf("Failed to read all %zu bytes", size);
512 return IO_ERROR;
513 }
514
515 return SUCCESS;
516}
517
518int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) {
519 size_t total = 0;
520 size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len);
521
522 // Handle the residual
523 tpbuf.insert(tpbuf.end(), data, data + to_write);
524 if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) { // Nothing enough to send rn
525 return 0;
526 }
527
528 if (SendBuffer(tpbuf)) {
529 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
530 return -1;
531 }
532 tpbuf.clear();
533 total += to_write;
534
535 // Now we need to send a multiple of chunk size
536 size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
537 size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
Aaron Wisnerc771ae02018-08-01 12:57:20 -0500538 if (nbytes && SendBuffer(data + total, nbytes)) { // Don't send a ZLP
Aaron Wisnerdb511202018-06-26 15:38:35 -0500539 error_ = ErrnoStr("Send failed in SparseWriteCallback()");
540 return -1;
541 }
542 total += nbytes;
543
544 if (len - total > 0) { // We have residual data to save for next time
545 tpbuf.assign(data + total, data + len);
546 }
547
548 return 0;
549}
550
David Anderson1d887432018-08-27 16:47:32 -0700551void FastBootDriver::set_transport(Transport* transport) {
552 if (transport_) {
553 transport_->Close();
554 delete transport_;
555 }
556 transport_ = transport;
557}
558
Aaron Wisnerdb511202018-06-26 15:38:35 -0500559} // End namespace fastboot