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