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:
parent
ac568b8f78
commit
157b00171a
9 changed files with 122 additions and 59 deletions
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
69
fastboot/util.c
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue