blob: 7e10cc9bf427d5e853bce0552be0f8a2ececdcf4 [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"
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -070030#include "fs.h"
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080031
Colin Cross81c632e2013-01-23 19:13:43 -080032#include <errno.h>
Elliott Hughes3ab8b852015-08-25 19:34:13 -070033#include <stdarg.h>
Mark Salyzyn5957c1f2014-04-30 14:05:28 -070034#include <stdio.h>
35#include <stdlib.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080036#include <string.h>
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080037#include <sys/stat.h>
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080038#include <sys/types.h>
39#include <unistd.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080040
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080041#define OP_DOWNLOAD 1
42#define OP_COMMAND 2
43#define OP_QUERY 3
44#define OP_NOTICE 4
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -070045#define OP_DOWNLOAD_SPARSE 5
46#define OP_WAIT_FOR_DISCONNECT 6
Chris Fries0ea946c2017-04-12 10:25:57 -050047#define OP_DOWNLOAD_FD 7
Jocelyn Bohr91fefad2017-01-27 14:17:56 -080048#define OP_UPLOAD 8
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080049
50typedef struct Action Action;
51
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080052#define CMD_SIZE 64
53
Elliott Hughesfc797672015-04-07 20:12:50 -070054struct Action {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080055 unsigned op;
Elliott Hughesfc797672015-04-07 20:12:50 -070056 Action* next;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080057
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080058 char cmd[CMD_SIZE];
Elliott Hughesfc797672015-04-07 20:12:50 -070059 const char* prod;
60 void* data;
Chris Fries0ea946c2017-04-12 10:25:57 -050061 int fd;
Elliott Hughesfc797672015-04-07 20:12:50 -070062
63 // The protocol only supports 32-bit sizes, so you'll have to break
64 // anything larger into chunks.
65 uint32_t size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080066
67 const char *msg;
Elliott Hughesb3748de2015-06-23 20:27:58 -070068 int (*func)(Action* a, int status, const char* resp);
Daniel Sandlercb6e22b2010-02-25 14:05:33 -050069
70 double start;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080071};
72
73static Action *action_list = 0;
74static Action *action_last = 0;
75
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080076
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080077
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 Hughes2fd45a92015-10-30 11:49:47 -070080 std::string cmd = "getvar:";
81 cmd += key;
Colin Cross80f2d032012-05-24 18:24:53 -070082
Elliott Hughes2fd45a92015-10-30 11:49:47 -070083 char buf[FB_RESPONSE_SZ + 1];
84 memset(buf, 0, sizeof(buf));
David Pursell0b156632015-10-30 11:22:01 -070085 if (fb_command_response(transport, cmd.c_str(), buf)) {
Elliott Hughes2fd45a92015-10-30 11:49:47 -070086 return false;
87 }
88 *value = buf;
89 return true;
Colin Cross80f2d032012-05-24 18:24:53 -070090}
91
Elliott Hughesb3748de2015-06-23 20:27:58 -070092static int cb_default(Action* a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080093 if (status) {
94 fprintf(stderr,"FAILED (%s)\n", resp);
95 } else {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -050096 double split = now();
97 fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
98 a->start = split;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080099 }
100 return status;
101}
102
103static Action *queue_action(unsigned op, const char *fmt, ...)
104{
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800105 va_list ap;
Bruce Beare50b39952010-07-15 08:52:01 -0700106 size_t cmdsize;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800107
Elliott Hughesb3748de2015-06-23 20:27:58 -0700108 Action* a = reinterpret_cast<Action*>(calloc(1, sizeof(Action)));
109 if (a == nullptr) die("out of memory");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800110
111 va_start(ap, fmt);
Bruce Beare50b39952010-07-15 08:52:01 -0700112 cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800113 va_end(ap);
114
Bruce Beare50b39952010-07-15 08:52:01 -0700115 if (cmdsize >= sizeof(a->cmd)) {
116 free(a);
117 die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd));
118 }
119
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800120 if (action_last) {
121 action_last->next = a;
122 } else {
123 action_list = a;
124 }
125 action_last = a;
126 a->op = op;
127 a->func = cb_default;
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500128
129 a->start = -1;
130
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800131 return a;
132}
133
Daniel Rosenbergb7bd4ae2015-09-14 21:05:41 -0700134void fb_set_active(const char *slot)
135{
136 Action *a;
137 a = queue_action(OP_COMMAND, "set_active:%s", slot);
138 a->msg = mkmsg("Setting current slot to '%s'", slot);
139}
140
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800141void fb_queue_erase(const char *ptn)
142{
143 Action *a;
144 a = queue_action(OP_COMMAND, "erase:%s", ptn);
145 a->msg = mkmsg("erasing '%s'", ptn);
146}
147
Chris Fries0ea946c2017-04-12 10:25:57 -0500148void fb_queue_flash_fd(const char *ptn, int fd, uint32_t sz)
149{
150 Action *a;
151
152 a = queue_action(OP_DOWNLOAD_FD, "");
153 a->fd = fd;
154 a->size = sz;
155 a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
156
157 a = queue_action(OP_COMMAND, "flash:%s", ptn);
158 a->msg = mkmsg("writing '%s'", ptn);
159}
160
161void fb_queue_flash(const char *ptn, void *data, uint32_t sz)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800162{
163 Action *a;
164
165 a = queue_action(OP_DOWNLOAD, "");
166 a->data = data;
167 a->size = sz;
168 a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
169
170 a = queue_action(OP_COMMAND, "flash:%s", ptn);
171 a->msg = mkmsg("writing '%s'", ptn);
172}
173
Chris Fries0ea946c2017-04-12 10:25:57 -0500174void fb_queue_flash_sparse(const char* ptn, struct sparse_file* s, uint32_t sz, size_t current,
Josh Gao9da9ac52016-01-19 14:50:18 -0800175 size_t total) {
Colin Crossf8387882012-05-24 17:18:41 -0700176 Action *a;
177
178 a = queue_action(OP_DOWNLOAD_SPARSE, "");
179 a->data = s;
180 a->size = 0;
Josh Gao9da9ac52016-01-19 14:50:18 -0800181 a->msg = mkmsg("sending sparse '%s' %zu/%zu (%d KB)", ptn, current, total, sz / 1024);
Colin Crossf8387882012-05-24 17:18:41 -0700182
183 a = queue_action(OP_COMMAND, "flash:%s", ptn);
Josh Gao9da9ac52016-01-19 14:50:18 -0800184 a->msg = mkmsg("writing '%s' %zu/%zu", ptn, current, total);
Colin Crossf8387882012-05-24 17:18:41 -0700185}
186
Elliott Hughesb3748de2015-06-23 20:27:58 -0700187static int match(const char* str, const char** value, unsigned count) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800188 unsigned n;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800189
190 for (n = 0; n < count; n++) {
191 const char *val = value[n];
192 int len = strlen(val);
193 int match;
194
195 if ((len > 1) && (val[len-1] == '*')) {
196 len--;
197 match = !strncmp(val, str, len);
198 } else {
199 match = !strcmp(val, str);
200 }
201
202 if (match) return 1;
203 }
204
205 return 0;
206}
207
208
209
Elliott Hughesb3748de2015-06-23 20:27:58 -0700210static int cb_check(Action* a, int status, const char* resp, int invert)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800211{
Elliott Hughesb3748de2015-06-23 20:27:58 -0700212 const char** value = reinterpret_cast<const char**>(a->data);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800213 unsigned count = a->size;
214 unsigned n;
215 int yes;
216
217 if (status) {
218 fprintf(stderr,"FAILED (%s)\n", resp);
219 return status;
220 }
221
Wink Savilleb98762f2011-04-04 17:54:59 -0700222 if (a->prod) {
223 if (strcmp(a->prod, cur_product) != 0) {
224 double split = now();
225 fprintf(stderr,"IGNORE, product is %s required only for %s [%7.3fs]\n",
226 cur_product, a->prod, (split - a->start));
227 a->start = split;
228 return 0;
229 }
230 }
231
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800232 yes = match(resp, value, count);
233 if (invert) yes = !yes;
234
235 if (yes) {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500236 double split = now();
237 fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
238 a->start = split;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800239 return 0;
240 }
241
242 fprintf(stderr,"FAILED\n\n");
243 fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp);
244 fprintf(stderr,"Update %s '%s'",
245 invert ? "rejects" : "requires", value[0]);
246 for (n = 1; n < count; n++) {
247 fprintf(stderr," or '%s'", value[n]);
248 }
249 fprintf(stderr,".\n\n");
250 return -1;
251}
252
Elliott Hughesb3748de2015-06-23 20:27:58 -0700253static int cb_require(Action*a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800254 return cb_check(a, status, resp, 0);
255}
256
Elliott Hughesb3748de2015-06-23 20:27:58 -0700257static int cb_reject(Action* a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800258 return cb_check(a, status, resp, 1);
259}
260
Elliott Hughesd6365a72017-05-08 18:04:49 -0700261static char* xstrdup(const char* s) {
262 char* result = strdup(s);
263 if (!result) die("out of memory");
264 return result;
265}
266
Wink Savilleb98762f2011-04-04 17:54:59 -0700267void fb_queue_require(const char *prod, const char *var,
Elliott Hughesfc797672015-04-07 20:12:50 -0700268 bool invert, size_t nvalues, const char **value)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800269{
270 Action *a;
271 a = queue_action(OP_QUERY, "getvar:%s", var);
Wink Savilleb98762f2011-04-04 17:54:59 -0700272 a->prod = prod;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800273 a->data = value;
274 a->size = nvalues;
275 a->msg = mkmsg("checking %s", var);
276 a->func = invert ? cb_reject : cb_require;
Elliott Hughesb3748de2015-06-23 20:27:58 -0700277 if (a->data == nullptr) die("out of memory");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800278}
279
Elliott Hughesb3748de2015-06-23 20:27:58 -0700280static int cb_display(Action* a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800281 if (status) {
282 fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
283 return status;
284 }
Elliott Hughesd6365a72017-05-08 18:04:49 -0700285 fprintf(stderr, "%s: %s\n", static_cast<const char*>(a->data), resp);
286 free(static_cast<char*>(a->data));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800287 return 0;
288}
289
Elliott Hughesd6365a72017-05-08 18:04:49 -0700290void fb_queue_display(const char* var, const char* prettyname) {
291 Action* a = queue_action(OP_QUERY, "getvar:%s", var);
292 a->data = xstrdup(prettyname);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800293 a->func = cb_display;
294}
295
Elliott Hughesb3748de2015-06-23 20:27:58 -0700296static int cb_save(Action* a, int status, const char* resp) {
Wink Savilleb98762f2011-04-04 17:54:59 -0700297 if (status) {
298 fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
299 return status;
300 }
Elliott Hughesb3748de2015-06-23 20:27:58 -0700301 strncpy(reinterpret_cast<char*>(a->data), resp, a->size);
Wink Savilleb98762f2011-04-04 17:54:59 -0700302 return 0;
303}
304
Elliott Hughesd6365a72017-05-08 18:04:49 -0700305void fb_queue_query_save(const char* var, char* dest, uint32_t dest_size) {
306 Action* a = queue_action(OP_QUERY, "getvar:%s", var);
307 a->data = dest;
Wink Savilleb98762f2011-04-04 17:54:59 -0700308 a->size = dest_size;
309 a->func = cb_save;
310}
311
Elliott Hughesb3748de2015-06-23 20:27:58 -0700312static int cb_do_nothing(Action*, int , const char*) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800313 fprintf(stderr,"\n");
314 return 0;
315}
316
317void fb_queue_reboot(void)
318{
319 Action *a = queue_action(OP_COMMAND, "reboot");
320 a->func = cb_do_nothing;
321 a->msg = "rebooting";
322}
323
324void fb_queue_command(const char *cmd, const char *msg)
325{
326 Action *a = queue_action(OP_COMMAND, cmd);
327 a->msg = msg;
328}
329
Chris Fries0ea946c2017-04-12 10:25:57 -0500330void fb_queue_download(const char *name, void *data, uint32_t size)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800331{
332 Action *a = queue_action(OP_DOWNLOAD, "");
333 a->data = data;
334 a->size = size;
335 a->msg = mkmsg("downloading '%s'", name);
336}
337
Jocelyn Bohr98cc2832017-01-26 19:20:53 -0800338void fb_queue_download_fd(const char *name, int fd, uint32_t sz)
339{
340 Action *a;
341 a = queue_action(OP_DOWNLOAD_FD, "");
342 a->fd = fd;
343 a->size = sz;
344 a->msg = mkmsg("sending '%s' (%d KB)", name, sz / 1024);
345}
346
Elliott Hughesd6365a72017-05-08 18:04:49 -0700347void fb_queue_upload(const char* outfile) {
348 Action* a = queue_action(OP_UPLOAD, "");
349 a->data = xstrdup(outfile);
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800350 a->msg = mkmsg("uploading '%s'", outfile);
351}
352
Elliott Hughesd6365a72017-05-08 18:04:49 -0700353void fb_queue_notice(const char* notice) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800354 Action *a = queue_action(OP_NOTICE, "");
355 a->data = (void*) notice;
356}
357
Mark Wachsler157b0012013-10-02 09:35:38 -0400358void fb_queue_wait_for_disconnect(void)
359{
360 queue_action(OP_WAIT_FOR_DISCONNECT, "");
361}
362
Chris Fries6a999712017-04-04 09:52:47 -0500363int64_t fb_execute_queue(Transport* transport)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800364{
365 Action *a;
366 char resp[FB_RESPONSE_SZ+1];
Chris Fries6a999712017-04-04 09:52:47 -0500367 int64_t status = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800368
369 a = action_list;
Scott Anderson13081c62012-04-06 12:39:30 -0700370 if (!a)
371 return status;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800372 resp[FB_RESPONSE_SZ] = 0;
373
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500374 double start = -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800375 for (a = action_list; a; a = a->next) {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500376 a->start = now();
377 if (start < 0) start = a->start;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800378 if (a->msg) {
Brian Swetland63e52052010-06-28 11:14:26 -0700379 // fprintf(stderr,"%30s... ",a->msg);
380 fprintf(stderr,"%s...\n",a->msg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800381 }
382 if (a->op == OP_DOWNLOAD) {
David Pursell0b156632015-10-30 11:22:01 -0700383 status = fb_download_data(transport, a->data, a->size);
Elliott Hughes2810d002016-04-25 14:31:18 -0700384 status = a->func(a, status, status ? fb_get_error().c_str() : "");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800385 if (status) break;
Chris Fries0ea946c2017-04-12 10:25:57 -0500386 } else if (a->op == OP_DOWNLOAD_FD) {
387 status = fb_download_data_fd(transport, a->fd, a->size);
388 status = a->func(a, status, status ? fb_get_error().c_str() : "");
389 if (status) break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800390 } else if (a->op == OP_COMMAND) {
David Pursell0b156632015-10-30 11:22:01 -0700391 status = fb_command(transport, a->cmd);
Elliott Hughes2810d002016-04-25 14:31:18 -0700392 status = a->func(a, status, status ? fb_get_error().c_str() : "");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800393 if (status) break;
394 } else if (a->op == OP_QUERY) {
David Pursell0b156632015-10-30 11:22:01 -0700395 status = fb_command_response(transport, a->cmd, resp);
Elliott Hughes2810d002016-04-25 14:31:18 -0700396 status = a->func(a, status, status ? fb_get_error().c_str() : resp);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800397 if (status) break;
398 } else if (a->op == OP_NOTICE) {
399 fprintf(stderr,"%s\n",(char*)a->data);
Colin Crossf8387882012-05-24 17:18:41 -0700400 } else if (a->op == OP_DOWNLOAD_SPARSE) {
David Pursell0b156632015-10-30 11:22:01 -0700401 status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
Elliott Hughes2810d002016-04-25 14:31:18 -0700402 status = a->func(a, status, status ? fb_get_error().c_str() : "");
Colin Crossf8387882012-05-24 17:18:41 -0700403 if (status) break;
Mark Wachsler157b0012013-10-02 09:35:38 -0400404 } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
David Pursell0b156632015-10-30 11:22:01 -0700405 transport->WaitForDisconnect();
Jocelyn Bohr91fefad2017-01-27 14:17:56 -0800406 } else if (a->op == OP_UPLOAD) {
407 status = fb_upload_data(transport, reinterpret_cast<char*>(a->data));
408 status = a->func(a, status, status ? fb_get_error().c_str() : "");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800409 } else {
410 die("bogus action");
411 }
412 }
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500413
414 fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700415 return status;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800416}