From 157b00171a06f9ac2fd25ee3a86e801e896713d6 Mon Sep 17 00:00:00 2001 From: Mark Wachsler Date: Wed, 2 Oct 2013 09:35:38 -0400 Subject: [PATCH] Wait for device to disappear after reboot-bootloader. (Linux only for now) With fastboot reading serial numbers from sysfs, it had become possible for a fastboot command issued immediately after rebooting the bootloader to fail, because sysfs still thought the device was online. To prevent this, after reboot-bootloader we wait for the device to disconnect. Also made usb_read and usb_write fail immediately if the descriptor has been closed; this prevents an incorrect error message ("Bad file descriptor") when errors from fb_getvar are ignored (e.g., by fb_format_supported). Also removed unused fd param from filter_usb_device, and simplified logic in usb_write by using do/while instead of a special case for len == 0. Change-Id: I799b857eab411fd8ad25f5777fc61c685152ea86 --- fastboot/Android.mk | 4 +-- fastboot/engine.c | 31 +++++-------------- fastboot/fastboot.c | 13 +------- fastboot/fastboot.h | 3 ++ fastboot/usb.h | 2 +- fastboot/usb_linux.c | 49 +++++++++++++++++------------- fastboot/usb_osx.c | 5 +++ fastboot/usb_windows.c | 5 +++ fastboot/util.c | 69 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 122 insertions(+), 59 deletions(-) create mode 100644 fastboot/util.c diff --git a/fastboot/Android.mk b/fastboot/Android.mk index 1189e1f4c..f33998876 100644 --- a/fastboot/Android.mk +++ b/fastboot/Android.mk @@ -18,7 +18,7 @@ include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \ $(LOCAL_PATH)/../../extras/ext4_utils -LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c +LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c LOCAL_MODULE := fastboot LOCAL_MODULE_TAGS := debug @@ -69,7 +69,7 @@ $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE)) ifeq ($(HOST_OS),linux) include $(CLEAR_VARS) -LOCAL_SRC_FILES := usbtest.c usb_linux.c +LOCAL_SRC_FILES := usbtest.c usb_linux.c util.c LOCAL_MODULE := usbtest include $(BUILD_HOST_EXECUTABLE) endif diff --git a/fastboot/engine.c b/fastboot/engine.c index 8d469911a..84ea98406 100644 --- a/fastboot/engine.c +++ b/fastboot/engine.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include @@ -48,34 +47,13 @@ #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -double now() -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (double)tv.tv_sec + (double)tv.tv_usec / 1000000; -} - -char *mkmsg(const char *fmt, ...) -{ - char buf[256]; - char *s; - va_list ap; - - va_start(ap, fmt); - vsprintf(buf, fmt, ap); - va_end(ap); - - s = strdup(buf); - if (s == 0) die("out of memory"); - return s; -} - #define OP_DOWNLOAD 1 #define OP_COMMAND 2 #define OP_QUERY 3 #define OP_NOTICE 4 #define OP_FORMAT 5 #define OP_DOWNLOAD_SPARSE 6 +#define OP_WAIT_FOR_DISCONNECT 7 typedef struct Action Action; @@ -587,6 +565,11 @@ void fb_queue_notice(const char *notice) a->data = (void*) notice; } +void fb_queue_wait_for_disconnect(void) +{ + queue_action(OP_WAIT_FOR_DISCONNECT, ""); +} + int fb_execute_queue(usb_handle *usb) { Action *a; @@ -628,6 +611,8 @@ int fb_execute_queue(usb_handle *usb) status = fb_download_data_sparse(usb, a->data); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; + } else if (a->op == OP_WAIT_FOR_DISCONNECT) { + usb_wait_for_disconnect(usb); } else { die("bogus action"); } diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index 447b2572b..70b838f03 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -82,17 +81,6 @@ unsigned second_offset = 0x00f00000; unsigned tags_offset = 0x00000100; -void die(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr,"error: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr,"\n"); - va_end(ap); - exit(1); -} - void get_my_path(char *path); char *find_item(const char *item, const char *product) @@ -1031,6 +1019,7 @@ int main(int argc, char **argv) fb_queue_reboot(); } else if (wants_reboot_bootloader) { fb_queue_command("reboot-bootloader", "rebooting into bootloader"); + fb_queue_wait_for_disconnect(); } if (fb_queue_is_empty()) diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h index c1b29646e..976c397ee 100644 --- a/fastboot/fastboot.h +++ b/fastboot/fastboot.h @@ -58,10 +58,13 @@ void fb_queue_reboot(void); void fb_queue_command(const char *cmd, const char *msg); void fb_queue_download(const char *name, void *data, unsigned size); void fb_queue_notice(const char *notice); +void fb_queue_wait_for_disconnect(void); int fb_execute_queue(usb_handle *usb); int fb_queue_is_empty(void); /* util stuff */ +double now(); +char *mkmsg(const char *fmt, ...); void die(const char *fmt, ...); /* Current product */ diff --git a/fastboot/usb.h b/fastboot/usb.h index d504ee26a..17cf0a978 100644 --- a/fastboot/usb.h +++ b/fastboot/usb.h @@ -62,6 +62,6 @@ usb_handle *usb_open(ifc_match_func callback); int usb_close(usb_handle *h); int usb_read(usb_handle *h, void *_data, int len); int usb_write(usb_handle *h, const void *_data, int len); - +int usb_wait_for_disconnect(usb_handle *h); #endif diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c index 9153c8d6c..f2ce2267d 100644 --- a/fastboot/usb_linux.c +++ b/fastboot/usb_linux.c @@ -50,10 +50,17 @@ #endif #include +#include "fastboot.h" #include "usb.h" #define MAX_RETRIES 5 +/* Timeout in seconds for usb_wait_for_disconnect. + * It doesn't usually take long for a device to disconnect (almost always + * under 2 seconds) but we'll time out after 3 seconds just in case. + */ +#define WAIT_FOR_DISCONNECT_TIMEOUT 3 + #ifdef TRACE_USB #define DBG1(x...) fprintf(stderr, x) #define DBG(x...) fprintf(stderr, x) @@ -103,7 +110,7 @@ static int check(void *_desc, int len, unsigned type, int size) return 0; } -static int filter_usb_device(int fd, char* sysfs_name, +static int filter_usb_device(char* sysfs_name, char *ptr, int len, int writable, ifc_match_func callback, int *ept_in_id, int *ept_out_id, int *ifc_id) @@ -308,7 +315,7 @@ static usb_handle *find_usb_device(const char *base, ifc_match_func callback) n = read(fd, desc, sizeof(desc)); - if(filter_usb_device(fd, de->d_name, desc, n, writable, callback, + if(filter_usb_device(de->d_name, desc, n, writable, callback, &in, &out, &ifc) == 0) { usb = calloc(1, sizeof(usb_handle)); strcpy(usb->fname, devname); @@ -340,26 +347,11 @@ int usb_write(usb_handle *h, const void *_data, int len) struct usbdevfs_bulktransfer bulk; int n; - if(h->ep_out == 0) { + if(h->ep_out == 0 || h->desc == -1) { return -1; } - if(len == 0) { - bulk.ep = h->ep_out; - bulk.len = 0; - bulk.data = data; - bulk.timeout = 0; - - n = ioctl(h->desc, USBDEVFS_BULK, &bulk); - if(n != 0) { - fprintf(stderr,"ERROR: n = %d, errno = %d (%s)\n", - n, errno, strerror(errno)); - return -1; - } - return 0; - } - - while(len > 0) { + do { int xfer; xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len; @@ -378,7 +370,7 @@ int usb_write(usb_handle *h, const void *_data, int len) count += xfer; len -= xfer; data += xfer; - } + } while(len > 0); return count; } @@ -390,7 +382,7 @@ int usb_read(usb_handle *h, void *_data, int len) struct usbdevfs_bulktransfer bulk; int n, retry; - if(h->ep_in == 0) { + if(h->ep_in == 0 || h->desc == -1) { return -1; } @@ -458,3 +450,18 @@ usb_handle *usb_open(ifc_match_func callback) { return find_usb_device("/sys/bus/usb/devices", callback); } + +/* Wait for the system to notice the device is gone, so that a subsequent + * fastboot command won't try to access the device before it's rebooted. + * Returns 0 for success, -1 for timeout. + */ +int usb_wait_for_disconnect(usb_handle *usb) +{ + double deadline = now() + WAIT_FOR_DISCONNECT_TIMEOUT; + while (now() < deadline) { + if (access(usb->fname, F_OK)) + return 0; + usleep(50000); + } + return -1; +} diff --git a/fastboot/usb_osx.c b/fastboot/usb_osx.c index 1548ba8dd..0f55e0d82 100644 --- a/fastboot/usb_osx.c +++ b/fastboot/usb_osx.c @@ -467,6 +467,11 @@ int usb_close(usb_handle *h) { return 0; } +int usb_wait_for_disconnect(usb_handle *usb) { + /* TODO: Punt for now */ + return 0; +} + int usb_read(usb_handle *h, void *data, int len) { IOReturn result; UInt32 numBytes = len; diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c index 7aa36b2f0..07f7be258 100644 --- a/fastboot/usb_windows.c +++ b/fastboot/usb_windows.c @@ -269,6 +269,11 @@ int usb_close(usb_handle* handle) { return 0; } +int usb_wait_for_disconnect(usb_handle *usb) { + /* TODO: Punt for now */ + return 0; +} + int recognized_device(usb_handle* handle, ifc_match_func callback) { struct usb_ifc_info info; USB_DEVICE_DESCRIPTOR device_desc; diff --git a/fastboot/util.c b/fastboot/util.c new file mode 100644 index 000000000..f2bbd3472 --- /dev/null +++ b/fastboot/util.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#include "fastboot.h" + +double now() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000; +} + +char *mkmsg(const char *fmt, ...) +{ + char buf[256]; + char *s; + va_list ap; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + + s = strdup(buf); + if (s == 0) die("out of memory"); + return s; +} + +void die(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr,"error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr,"\n"); + va_end(ap); + exit(1); +}