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
This commit is contained in:
Mark Wachsler 2013-10-02 09:35:38 -04:00 committed by JP Abgrall
parent ac568b8f78
commit 157b00171a
9 changed files with 122 additions and 59 deletions

View file

@ -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

View file

@ -36,7 +36,6 @@
#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
@ -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");
}

View file

@ -30,7 +30,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
@ -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())

View file

@ -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 */

View file

@ -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

View file

@ -50,10 +50,17 @@
#endif
#include <asm/byteorder.h>
#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;
}

View file

@ -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;

View file

@ -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;

69
fastboot/util.c Normal file
View file

@ -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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#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);
}