blob: 60b71247eb02e398bc2259538d2f33e51ddb79de [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2008 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
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080012 * the documentation and/or other materials provided with the
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080013 * 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
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080022 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080023 * 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
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080029#include "fastboot.h"
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080030
Colin Cross81c632e2013-01-23 19:13:43 -080031#include <errno.h>
Elliott Hughes3ab8b852015-08-25 19:34:13 -070032#include <stdarg.h>
Mark Salyzyn5957c1f2014-04-30 14:05:28 -070033#include <stdio.h>
34#include <stdlib.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080035#include <string.h>
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080036#include <sys/stat.h>
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080037#include <sys/types.h>
38#include <unistd.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080039
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -070040#include <memory>
41#include <vector>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080042
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -070043#include <android-base/stringprintf.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080044
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -070045enum Op {
46 OP_DOWNLOAD,
47 OP_COMMAND,
48 OP_QUERY,
49 OP_NOTICE,
50 OP_DOWNLOAD_SPARSE,
51 OP_WAIT_FOR_DISCONNECT,
52 OP_DOWNLOAD_FD,
53 OP_UPLOAD,
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080054};
55
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -070056struct Action {
57 Action(Op op, const std::string& cmd) : op(op), cmd(cmd) {}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080058
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -070059 Op op;
60 std::string cmd;
61 std::string msg;
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080062
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -070063 std::string product;
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080064
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -070065 void* data = nullptr;
66 // The protocol only supports 32-bit sizes, so you'll have to break
67 // anything larger into multiple chunks.
68 uint32_t size = 0;
69
70 int fd = -1;
71
72 int (*func)(Action& a, int status, const char* resp) = nullptr;
73
74 double start = -1;
75};
76
77static std::vector<std::unique_ptr<Action>> action_list;
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080078
David Pursell0b156632015-10-30 11:22:01 -070079bool fb_getvar(Transport* transport, const std::string& key, std::string* value) {
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -070080 std::string cmd = "getvar:" + key;
Colin Cross80f2d032012-05-24 18:24:53 -070081
Elliott Hughes2fd45a92015-10-30 11:49:47 -070082 char buf[FB_RESPONSE_SZ + 1];
83 memset(buf, 0, sizeof(buf));
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -070084 if (fb_command_response(transport, cmd, buf)) {
85 return false;
Elliott Hughes2fd45a92015-10-30 11:49:47 -070086 }
87 *value = buf;
88 return true;
Colin Cross80f2d032012-05-24 18:24:53 -070089}
90
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -070091static int cb_default(Action& a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080092 if (status) {
93 fprintf(stderr,"FAILED (%s)\n", resp);
94 } else {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -050095 double split = now();
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -070096 fprintf(stderr, "OKAY [%7.3fs]\n", (split - a.start));
97 a.start = split;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080098 }
99 return status;
100}
101
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700102static Action& queue_action(Op op, const std::string& cmd) {
103 std::unique_ptr<Action> a{new Action(op, cmd)};
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800104 a->func = cb_default;
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500105
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700106 action_list.push_back(std::move(a));
107 return *action_list.back();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800108}
109
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700110void fb_set_active(const std::string& slot) {
111 Action& a = queue_action(OP_COMMAND, "set_active:" + slot);
112 a.msg = "Setting current slot to '" + slot + "'...";
Daniel Rosenbergb7bd4ae2015-09-14 21:05:41 -0700113}
114
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700115void fb_queue_erase(const std::string& partition) {
116 Action& a = queue_action(OP_COMMAND, "erase:" + partition);
117 a.msg = "Erasing '" + partition + "'...";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800118}
119
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700120void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz) {
121 Action& a = queue_action(OP_DOWNLOAD_FD, "");
122 a.fd = fd;
123 a.size = sz;
124 a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);
Chris Fries0ea946c2017-04-12 10:25:57 -0500125
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700126 Action& b = queue_action(OP_COMMAND, "flash:" + partition);
127 b.msg = "Writing '" + partition + "'...";
Chris Fries0ea946c2017-04-12 10:25:57 -0500128}
129
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700130void fb_queue_flash(const std::string& partition, void* data, uint32_t sz) {
131 Action& a = queue_action(OP_DOWNLOAD, "");
132 a.data = data;
133 a.size = sz;
134 a.msg = android::base::StringPrintf("Sending '%s' (%d KB)...", partition.c_str(), sz / 1024);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800135
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700136 Action& b = queue_action(OP_COMMAND, "flash:" + partition);
137 b.msg = "Writing '" + partition + "'...";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800138}
139
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700140void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
141 size_t current, size_t total) {
142 Action& a = queue_action(OP_DOWNLOAD_SPARSE, "");
143 a.data = s;
144 a.size = 0;
145 a.msg = android::base::StringPrintf("Sending sparse '%s' %zu/%zu (%d KB)...", partition.c_str(),
146 current, total, sz / 1024);
Colin Crossf8387882012-05-24 17:18:41 -0700147
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700148 Action& b = queue_action(OP_COMMAND, "flash:" + partition);
149 b.msg =
150 android::base::StringPrintf("Writing '%s' %zu/%zu...", partition.c_str(), current, total);
Colin Crossf8387882012-05-24 17:18:41 -0700151}
152
Elliott Hughesb3748de2015-06-23 20:27:58 -0700153static int match(const char* str, const char** value, unsigned count) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800154 unsigned n;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800155
156 for (n = 0; n < count; n++) {
157 const char *val = value[n];
158 int len = strlen(val);
159 int match;
160
161 if ((len > 1) && (val[len-1] == '*')) {
162 len--;
163 match = !strncmp(val, str, len);
164 } else {
165 match = !strcmp(val, str);
166 }
167
168 if (match) return 1;
169 }
170
171 return 0;
172}
173
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700174static int cb_check(Action& a, int status, const char* resp, int invert) {
175 const char** value = reinterpret_cast<const char**>(a.data);
176 unsigned count = a.size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800177 unsigned n;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800178
179 if (status) {
180 fprintf(stderr,"FAILED (%s)\n", resp);
181 return status;
182 }
183
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700184 if (!a.product.empty()) {
185 if (a.product != cur_product) {
Wink Savilleb98762f2011-04-04 17:54:59 -0700186 double split = now();
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700187 fprintf(stderr, "IGNORE, product is %s required only for %s [%7.3fs]\n", cur_product,
188 a.product.c_str(), (split - a.start));
189 a.start = split;
Wink Savilleb98762f2011-04-04 17:54:59 -0700190 return 0;
191 }
192 }
193
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700194 int yes = match(resp, value, count);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800195 if (invert) yes = !yes;
196
197 if (yes) {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500198 double split = now();
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700199 fprintf(stderr, "OKAY [%7.3fs]\n", (split - a.start));
200 a.start = split;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800201 return 0;
202 }
203
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700204 fprintf(stderr, "FAILED\n\n");
205 fprintf(stderr, "Device %s is '%s'.\n", a.cmd.c_str() + 7, resp);
206 fprintf(stderr, "Update %s '%s'", invert ? "rejects" : "requires", value[0]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800207 for (n = 1; n < count; n++) {
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700208 fprintf(stderr, " or '%s'", value[n]);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800209 }
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700210 fprintf(stderr, ".\n\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800211 return -1;
212}
213
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700214static int cb_require(Action& a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800215 return cb_check(a, status, resp, 0);
216}
217
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700218static int cb_reject(Action& a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800219 return cb_check(a, status, resp, 1);
220}
221
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700222void fb_queue_require(const std::string& product, const std::string& var, bool invert,
223 size_t nvalues, const char** values) {
224 Action& a = queue_action(OP_QUERY, "getvar:" + var);
225 a.product = product;
226 a.data = values;
227 a.size = nvalues;
228 a.msg = "Checking " + var;
229 a.func = invert ? cb_reject : cb_require;
230 if (a.data == nullptr) die("out of memory");
Elliott Hughesd6365a72017-05-08 18:04:49 -0700231}
232
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700233static int cb_display(Action& a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800234 if (status) {
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700235 fprintf(stderr, "%s FAILED (%s)\n", a.cmd.c_str(), resp);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800236 return status;
237 }
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700238 fprintf(stderr, "%s: %s\n", static_cast<const char*>(a.data), resp);
239 free(static_cast<char*>(a.data));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800240 return 0;
241}
242
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700243void fb_queue_display(const std::string& label, const std::string& var) {
244 Action& a = queue_action(OP_QUERY, "getvar:" + var);
245 a.data = xstrdup(label.c_str());
246 a.func = cb_display;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800247}
248
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700249static int cb_save(Action& a, int status, const char* resp) {
Wink Savilleb98762f2011-04-04 17:54:59 -0700250 if (status) {
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700251 fprintf(stderr, "%s FAILED (%s)\n", a.cmd.c_str(), resp);
Wink Savilleb98762f2011-04-04 17:54:59 -0700252 return status;
253 }
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700254 strncpy(reinterpret_cast<char*>(a.data), resp, a.size);
Wink Savilleb98762f2011-04-04 17:54:59 -0700255 return 0;
256}
257
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700258void fb_queue_query_save(const std::string& var, char* dest, uint32_t dest_size) {
259 Action& a = queue_action(OP_QUERY, "getvar:" + var);
260 a.data = dest;
261 a.size = dest_size;
262 a.func = cb_save;
Wink Savilleb98762f2011-04-04 17:54:59 -0700263}
264
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700265static int cb_do_nothing(Action&, int, const char*) {
266 fprintf(stderr, "\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800267 return 0;
268}
269
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700270void fb_queue_reboot() {
271 Action& a = queue_action(OP_COMMAND, "reboot");
272 a.func = cb_do_nothing;
273 a.msg = "Rebooting...";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800274}
275
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700276void fb_queue_command(const std::string& cmd, const std::string& msg) {
277 Action& a = queue_action(OP_COMMAND, cmd);
278 a.msg = msg;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800279}
280
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700281void fb_queue_download(const std::string& name, void* data, uint32_t size) {
282 Action& a = queue_action(OP_DOWNLOAD, "");
283 a.data = data;
284 a.size = size;
285 a.msg = "Downloading '" + name + "'";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800286}
287
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700288void fb_queue_download_fd(const std::string& name, int fd, uint32_t sz) {
289 Action& a = queue_action(OP_DOWNLOAD_FD, "");
290 a.fd = fd;
291 a.size = sz;
292 a.msg = android::base::StringPrintf("Sending '%s' (%d KB)", name.c_str(), sz / 1024);
Jocelyn Bohr98cc2832017-01-26 19:20:53 -0800293}
294
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700295void fb_queue_upload(const std::string& outfile) {
296 Action& a = queue_action(OP_UPLOAD, "");
297 a.data = xstrdup(outfile.c_str());
298 a.msg = "Uploading '" + outfile + "'";
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800299}
300
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700301void fb_queue_notice(const std::string& notice) {
302 Action& a = queue_action(OP_NOTICE, "");
303 a.msg = notice;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800304}
305
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700306void fb_queue_wait_for_disconnect() {
Mark Wachsler157b0012013-10-02 09:35:38 -0400307 queue_action(OP_WAIT_FOR_DISCONNECT, "");
308}
309
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700310int64_t fb_execute_queue(Transport* transport) {
Chris Fries6a999712017-04-04 09:52:47 -0500311 int64_t status = 0;
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700312 for (auto& a : action_list) {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500313 a->start = now();
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700314 if (!a->msg.empty()) {
315 fprintf(stderr, "%s\n", a->msg.c_str());
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800316 }
317 if (a->op == OP_DOWNLOAD) {
David Pursell0b156632015-10-30 11:22:01 -0700318 status = fb_download_data(transport, a->data, a->size);
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700319 status = a->func(*a, status, status ? fb_get_error().c_str() : "");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800320 if (status) break;
Chris Fries0ea946c2017-04-12 10:25:57 -0500321 } else if (a->op == OP_DOWNLOAD_FD) {
322 status = fb_download_data_fd(transport, a->fd, a->size);
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700323 status = a->func(*a, status, status ? fb_get_error().c_str() : "");
Chris Fries0ea946c2017-04-12 10:25:57 -0500324 if (status) break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800325 } else if (a->op == OP_COMMAND) {
David Pursell0b156632015-10-30 11:22:01 -0700326 status = fb_command(transport, a->cmd);
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700327 status = a->func(*a, status, status ? fb_get_error().c_str() : "");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800328 if (status) break;
329 } else if (a->op == OP_QUERY) {
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700330 char resp[FB_RESPONSE_SZ + 1] = {};
David Pursell0b156632015-10-30 11:22:01 -0700331 status = fb_command_response(transport, a->cmd, resp);
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700332 status = a->func(*a, status, status ? fb_get_error().c_str() : resp);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800333 if (status) break;
334 } else if (a->op == OP_NOTICE) {
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700335 // We already showed the notice because it's in `Action::msg`.
Colin Crossf8387882012-05-24 17:18:41 -0700336 } else if (a->op == OP_DOWNLOAD_SPARSE) {
David Pursell0b156632015-10-30 11:22:01 -0700337 status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700338 status = a->func(*a, status, status ? fb_get_error().c_str() : "");
Colin Crossf8387882012-05-24 17:18:41 -0700339 if (status) break;
Mark Wachsler157b0012013-10-02 09:35:38 -0400340 } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
David Pursell0b156632015-10-30 11:22:01 -0700341 transport->WaitForDisconnect();
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800342 } else if (a->op == OP_UPLOAD) {
343 status = fb_upload_data(transport, reinterpret_cast<char*>(a->data));
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700344 status = a->func(*a, status, status ? fb_get_error().c_str() : "");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800345 } else {
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700346 die("unknown action: %d", a->op);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800347 }
348 }
Elliott Hughes9b7cd9a2018-03-28 08:20:00 -0700349 action_list.clear();
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700350 return status;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800351}