adb: On Linux, detect USB devices for which adb does not have permissions to communicate with.
adb devices will now list devices without adequate file system permissions in /dev/bus/usb as: List of devices attached ???????????? no permissions Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
parent
4e3fb86156
commit
0927bf9690
5 changed files with 160 additions and 122 deletions
11
adb/adb.h
11
adb/adb.h
|
|
@ -33,7 +33,7 @@
|
|||
#define ADB_VERSION_MAJOR 1 // Used for help/version information
|
||||
#define ADB_VERSION_MINOR 0 // Used for help/version information
|
||||
|
||||
#define ADB_SERVER_VERSION 22 // Increment this when we want to force users to start a new adb server
|
||||
#define ADB_SERVER_VERSION 23 // Increment this when we want to force users to start a new adb server
|
||||
|
||||
typedef struct amessage amessage;
|
||||
typedef struct apacket apacket;
|
||||
|
|
@ -263,14 +263,17 @@ void kick_transport( atransport* t );
|
|||
|
||||
/* initialize a transport object's func pointers and state */
|
||||
int init_socket_transport(atransport *t, int s, int port);
|
||||
void init_usb_transport(atransport *t, usb_handle *usb);
|
||||
void init_usb_transport(atransport *t, usb_handle *usb, int state);
|
||||
|
||||
/* for MacOS X cleanup */
|
||||
void close_usb_devices();
|
||||
|
||||
/* cause new transports to be init'd and added to the list */
|
||||
void register_socket_transport(int s, const char *serial, int port);
|
||||
void register_usb_transport(usb_handle *h, const char *serial);
|
||||
void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable);
|
||||
|
||||
/* this should only be used for transports with connection_state == CS_NOPERM */
|
||||
void unregister_usb_transport(usb_handle *usb);
|
||||
|
||||
int service_to_fd(const char *name);
|
||||
#if ADB_HOST
|
||||
|
|
@ -384,7 +387,7 @@ int connection_state(atransport *t);
|
|||
#define CS_DEVICE 2
|
||||
#define CS_HOST 3
|
||||
#define CS_RECOVERY 4
|
||||
#define CS_ERROR 5
|
||||
#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */
|
||||
|
||||
extern int HOST;
|
||||
|
||||
|
|
|
|||
|
|
@ -584,18 +584,37 @@ static void transport_registration_func(int _fd, unsigned ev, void *data)
|
|||
return;
|
||||
}
|
||||
|
||||
/* don't create transport threads for inaccessible devices */
|
||||
if (t->connection_state != CS_NOPERM) {
|
||||
/* initial references are the two threads */
|
||||
t->ref_count = 2;
|
||||
t->ref_count = 2;
|
||||
|
||||
if(adb_socketpair(s)) {
|
||||
fatal_errno("cannot open transport socketpair");
|
||||
if(adb_socketpair(s)) {
|
||||
fatal_errno("cannot open transport socketpair");
|
||||
}
|
||||
|
||||
D("transport: %p (%d,%d) starting\n", t, s[0], s[1]);
|
||||
|
||||
t->transport_socket = s[0];
|
||||
t->fd = s[1];
|
||||
|
||||
D("transport: %p install %d\n", t, t->transport_socket );
|
||||
fdevent_install(&(t->transport_fde),
|
||||
t->transport_socket,
|
||||
transport_socket_events,
|
||||
t);
|
||||
|
||||
fdevent_set(&(t->transport_fde), FDE_READ);
|
||||
|
||||
if(adb_thread_create(&input_thread_ptr, input_thread, t)){
|
||||
fatal_errno("cannot create input thread");
|
||||
}
|
||||
|
||||
if(adb_thread_create(&output_thread_ptr, output_thread, t)){
|
||||
fatal_errno("cannot create output thread");
|
||||
}
|
||||
}
|
||||
|
||||
D("transport: %p (%d,%d) starting\n", t, s[0], s[1]);
|
||||
|
||||
t->transport_socket = s[0];
|
||||
t->fd = s[1];
|
||||
|
||||
/* put us on the master device list */
|
||||
adb_mutex_lock(&transport_lock);
|
||||
t->next = &transport_list;
|
||||
|
|
@ -604,22 +623,6 @@ static void transport_registration_func(int _fd, unsigned ev, void *data)
|
|||
t->prev->next = t;
|
||||
adb_mutex_unlock(&transport_lock);
|
||||
|
||||
D("transport: %p install %d\n", t, t->transport_socket );
|
||||
fdevent_install(&(t->transport_fde),
|
||||
t->transport_socket,
|
||||
transport_socket_events,
|
||||
t);
|
||||
|
||||
fdevent_set(&(t->transport_fde), FDE_READ);
|
||||
|
||||
if(adb_thread_create(&input_thread_ptr, input_thread, t)){
|
||||
fatal_errno("cannot create input thread");
|
||||
}
|
||||
|
||||
if(adb_thread_create(&output_thread_ptr, output_thread, t)){
|
||||
fatal_errno("cannot create output thread");
|
||||
}
|
||||
|
||||
t->disconnects.next = t->disconnects.prev = &t->disconnects;
|
||||
|
||||
update_transports();
|
||||
|
|
@ -717,6 +720,8 @@ retry:
|
|||
|
||||
adb_mutex_lock(&transport_lock);
|
||||
for (t = transport_list.next; t != &transport_list; t = t->next) {
|
||||
if (t->connection_state == CS_NOPERM) continue;
|
||||
|
||||
/* check for matching serial number */
|
||||
if (serial) {
|
||||
if (t->serial && !strcmp(serial, t->serial)) {
|
||||
|
|
@ -763,6 +768,11 @@ retry:
|
|||
*error_out = "device offline";
|
||||
result = NULL;
|
||||
}
|
||||
if (result && result->connection_state == CS_NOPERM) {
|
||||
if (error_out)
|
||||
*error_out = "no permissions for device";
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
/* check for required connection state */
|
||||
if (result && state != CS_ANY && result->connection_state != state) {
|
||||
|
|
@ -793,6 +803,7 @@ static const char *statename(atransport *t)
|
|||
case CS_DEVICE: return "device";
|
||||
case CS_HOST: return "host";
|
||||
case CS_RECOVERY: return "recovery";
|
||||
case CS_NOPERM: return "no permissions";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
|
@ -807,9 +818,10 @@ int list_transports(char *buf, size_t bufsize)
|
|||
/* XXX OVERRUN PROBLEMS XXX */
|
||||
adb_mutex_lock(&transport_lock);
|
||||
for(t = transport_list.next; t != &transport_list; t = t->next) {
|
||||
len = snprintf(p, end - p, "%s\t%s\n",
|
||||
t->serial ? t->serial : "",
|
||||
statename(t));
|
||||
const char* serial = t->serial;
|
||||
if (!serial || !serial[0])
|
||||
serial = "????????????";
|
||||
len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t));
|
||||
|
||||
if (p + len >= end) {
|
||||
/* discard last line if buffer is too short */
|
||||
|
|
@ -854,18 +866,32 @@ void register_socket_transport(int s, const char *serial, int port)
|
|||
register_transport(t);
|
||||
}
|
||||
|
||||
void register_usb_transport(usb_handle *usb, const char *serial)
|
||||
void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable)
|
||||
{
|
||||
atransport *t = calloc(1, sizeof(atransport));
|
||||
D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
|
||||
serial ? serial : "");
|
||||
init_usb_transport(t, usb);
|
||||
init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
|
||||
if(serial) {
|
||||
t->serial = strdup(serial);
|
||||
}
|
||||
register_transport(t);
|
||||
}
|
||||
|
||||
/* this should only be used for transports with connection_state == CS_NOPERM */
|
||||
void unregister_usb_transport(usb_handle *usb)
|
||||
{
|
||||
atransport *t;
|
||||
adb_mutex_lock(&transport_lock);
|
||||
for(t = transport_list.next; t != &transport_list; t = t->next) {
|
||||
if (t->usb == usb && t->connection_state == CS_NOPERM) {
|
||||
t->next->prev = t->prev;
|
||||
t->prev->next = t->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
adb_mutex_unlock(&transport_lock);
|
||||
}
|
||||
|
||||
#undef TRACE_TAG
|
||||
#define TRACE_TAG TRACE_RWX
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ static void remote_kick(atransport *t)
|
|||
usb_kick(t->usb);
|
||||
}
|
||||
|
||||
void init_usb_transport(atransport *t, usb_handle *h)
|
||||
void init_usb_transport(atransport *t, usb_handle *h, int state)
|
||||
{
|
||||
D("transport: usb\n");
|
||||
t->close = remote_close;
|
||||
|
|
@ -118,7 +118,7 @@ void init_usb_transport(atransport *t, usb_handle *h)
|
|||
t->read_from_remote = remote_read;
|
||||
t->write_to_remote = remote_write;
|
||||
t->sync_token = 1;
|
||||
t->connection_state = CS_OFFLINE;
|
||||
t->connection_state = state;
|
||||
t->type = kTransportUsb;
|
||||
t->usb = h;
|
||||
|
||||
|
|
|
|||
181
adb/usb_linux.c
181
adb/usb_linux.c
|
|
@ -57,6 +57,7 @@ struct usb_handle
|
|||
unsigned char ep_out;
|
||||
|
||||
unsigned zero_mask;
|
||||
unsigned writeable;
|
||||
|
||||
struct usbdevfs_urb urb_in;
|
||||
struct usbdevfs_urb urb_out;
|
||||
|
|
@ -115,7 +116,7 @@ static void kick_disconnected_devices()
|
|||
}
|
||||
|
||||
static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out,
|
||||
int ifc, const char *serial, unsigned zero_mask);
|
||||
int ifc, int serial_index, unsigned zero_mask);
|
||||
|
||||
static inline int badname(const char *name)
|
||||
{
|
||||
|
|
@ -125,19 +126,18 @@ static inline int badname(const char *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int find_usb_device(const char *base,
|
||||
void (*register_device_callback) (const char *, unsigned char, unsigned char, int, const char *, unsigned))
|
||||
static void find_usb_device(const char *base,
|
||||
void (*register_device_callback)
|
||||
(const char *, unsigned char, unsigned char, int, int, unsigned))
|
||||
{
|
||||
char busname[32], devname[32];
|
||||
unsigned char local_ep_in, local_ep_out;
|
||||
DIR *busdir , *devdir ;
|
||||
struct dirent *de;
|
||||
int fd ;
|
||||
int found_device = 0;
|
||||
char serial[256];
|
||||
|
||||
busdir = opendir(base);
|
||||
if(busdir == 0) return 0;
|
||||
if(busdir == 0) return;
|
||||
|
||||
while((de = readdir(busdir)) != 0) {
|
||||
if(badname(de->d_name)) continue;
|
||||
|
|
@ -168,7 +168,7 @@ static int find_usb_device(const char *base,
|
|||
}
|
||||
|
||||
// DBGX("[ scanning %s ]\n", devname);
|
||||
if((fd = unix_open(devname, O_RDWR)) < 0) {
|
||||
if((fd = unix_open(devname, O_RDONLY)) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -263,59 +263,9 @@ static int find_usb_device(const char *base,
|
|||
local_ep_out = ep1->bEndpointAddress;
|
||||
}
|
||||
|
||||
// read the device's serial number
|
||||
serial[0] = 0;
|
||||
memset(serial, 0, sizeof(serial));
|
||||
if (device->iSerialNumber) {
|
||||
struct usbdevfs_ctrltransfer ctrl;
|
||||
__u16 buffer[128];
|
||||
__u16 languages[128];
|
||||
int i, result;
|
||||
int languageCount = 0;
|
||||
|
||||
memset(languages, 0, sizeof(languages));
|
||||
memset(&ctrl, 0, sizeof(ctrl));
|
||||
|
||||
// read list of supported languages
|
||||
ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
|
||||
ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
ctrl.wValue = (USB_DT_STRING << 8) | 0;
|
||||
ctrl.wIndex = 0;
|
||||
ctrl.wLength = sizeof(languages);
|
||||
ctrl.data = languages;
|
||||
|
||||
result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
|
||||
if (result > 0)
|
||||
languageCount = (result - 2) / 2;
|
||||
|
||||
for (i = 1; i <= languageCount; i++) {
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
memset(&ctrl, 0, sizeof(ctrl));
|
||||
|
||||
ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
|
||||
ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
ctrl.wValue = (USB_DT_STRING << 8) | device->iSerialNumber;
|
||||
ctrl.wIndex = languages[i];
|
||||
ctrl.wLength = sizeof(buffer);
|
||||
ctrl.data = buffer;
|
||||
|
||||
result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
|
||||
if (result > 0) {
|
||||
int i;
|
||||
// skip first word, and copy the rest to the serial string, changing shorts to bytes.
|
||||
result /= 2;
|
||||
for (i = 1; i < result; i++)
|
||||
serial[i - 1] = buffer[i];
|
||||
serial[i - 1] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
register_device_callback(devname, local_ep_in, local_ep_out,
|
||||
interface->bInterfaceNumber, serial, zero_mask);
|
||||
interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
|
||||
|
||||
found_device = 1;
|
||||
break;
|
||||
} else {
|
||||
// seek next interface descriptor
|
||||
|
|
@ -332,8 +282,6 @@ static int find_usb_device(const char *base,
|
|||
closedir(devdir);
|
||||
} //end of busdir while
|
||||
closedir(busdir);
|
||||
|
||||
return found_device;
|
||||
}
|
||||
|
||||
void usb_cleanup()
|
||||
|
|
@ -537,26 +485,30 @@ void usb_kick(usb_handle *h)
|
|||
if(h->dead == 0) {
|
||||
h->dead = 1;
|
||||
|
||||
/* HACK ALERT!
|
||||
** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
|
||||
** This is a workaround for that problem.
|
||||
*/
|
||||
if (h->reaper_thread) {
|
||||
pthread_kill(h->reaper_thread, SIGALRM);
|
||||
}
|
||||
if (h->writeable) {
|
||||
/* HACK ALERT!
|
||||
** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
|
||||
** This is a workaround for that problem.
|
||||
*/
|
||||
if (h->reaper_thread) {
|
||||
pthread_kill(h->reaper_thread, SIGALRM);
|
||||
}
|
||||
|
||||
/* cancel any pending transactions
|
||||
** these will quietly fail if the txns are not active,
|
||||
** but this ensures that a reader blocked on REAPURB
|
||||
** will get unblocked
|
||||
*/
|
||||
ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
|
||||
ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
|
||||
h->urb_in.status = -ENODEV;
|
||||
h->urb_out.status = -ENODEV;
|
||||
h->urb_in_busy = 0;
|
||||
h->urb_out_busy = 0;
|
||||
adb_cond_broadcast(&h->notify);
|
||||
/* cancel any pending transactions
|
||||
** these will quietly fail if the txns are not active,
|
||||
** but this ensures that a reader blocked on REAPURB
|
||||
** will get unblocked
|
||||
*/
|
||||
ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
|
||||
ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
|
||||
h->urb_in.status = -ENODEV;
|
||||
h->urb_out.status = -ENODEV;
|
||||
h->urb_in_busy = 0;
|
||||
h->urb_out_busy = 0;
|
||||
adb_cond_broadcast(&h->notify);
|
||||
} else {
|
||||
unregister_usb_transport(h);
|
||||
}
|
||||
}
|
||||
adb_mutex_unlock(&h->lock);
|
||||
}
|
||||
|
|
@ -580,11 +532,11 @@ int usb_close(usb_handle *h)
|
|||
|
||||
static void register_device(const char *dev_name,
|
||||
unsigned char ep_in, unsigned char ep_out,
|
||||
int interface,
|
||||
const char *serial, unsigned zero_mask)
|
||||
int interface, int serial_index, unsigned zero_mask)
|
||||
{
|
||||
usb_handle* usb = 0;
|
||||
int n = 0;
|
||||
char serial[256];
|
||||
|
||||
/* Since Linux will not reassign the device ID (and dev_name)
|
||||
** as long as the device is open, we can add to the list here
|
||||
|
|
@ -610,6 +562,7 @@ static void register_device(const char *dev_name,
|
|||
usb->ep_in = ep_in;
|
||||
usb->ep_out = ep_out;
|
||||
usb->zero_mask = zero_mask;
|
||||
usb->writeable = 1;
|
||||
|
||||
adb_cond_init(&usb->notify, 0);
|
||||
adb_mutex_init(&usb->lock, 0);
|
||||
|
|
@ -618,10 +571,66 @@ static void register_device(const char *dev_name,
|
|||
usb->reaper_thread = 0;
|
||||
|
||||
usb->desc = unix_open(usb->fname, O_RDWR);
|
||||
if(usb->desc < 0) goto fail;
|
||||
D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
|
||||
n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
|
||||
if(n != 0) goto fail;
|
||||
if(usb->desc < 0) {
|
||||
/* if we fail, see if have read-only access */
|
||||
usb->desc = unix_open(usb->fname, O_RDONLY);
|
||||
if(usb->desc < 0) goto fail;
|
||||
usb->writeable = 0;
|
||||
D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
|
||||
} else {
|
||||
D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
|
||||
n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
|
||||
if(n != 0) goto fail;
|
||||
}
|
||||
|
||||
/* read the device's serial number */
|
||||
serial[0] = 0;
|
||||
memset(serial, 0, sizeof(serial));
|
||||
if (serial_index) {
|
||||
struct usbdevfs_ctrltransfer ctrl;
|
||||
__u16 buffer[128];
|
||||
__u16 languages[128];
|
||||
int i, result;
|
||||
int languageCount = 0;
|
||||
|
||||
memset(languages, 0, sizeof(languages));
|
||||
memset(&ctrl, 0, sizeof(ctrl));
|
||||
|
||||
// read list of supported languages
|
||||
ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
|
||||
ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
ctrl.wValue = (USB_DT_STRING << 8) | 0;
|
||||
ctrl.wIndex = 0;
|
||||
ctrl.wLength = sizeof(languages);
|
||||
ctrl.data = languages;
|
||||
|
||||
result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
|
||||
if (result > 0)
|
||||
languageCount = (result - 2) / 2;
|
||||
|
||||
for (i = 1; i <= languageCount; i++) {
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
memset(&ctrl, 0, sizeof(ctrl));
|
||||
|
||||
ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
|
||||
ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
|
||||
ctrl.wIndex = languages[i];
|
||||
ctrl.wLength = sizeof(buffer);
|
||||
ctrl.data = buffer;
|
||||
|
||||
result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
|
||||
if (result > 0) {
|
||||
int i;
|
||||
// skip first word, and copy the rest to the serial string, changing shorts to bytes.
|
||||
result /= 2;
|
||||
for (i = 1; i < result; i++)
|
||||
serial[i - 1] = buffer[i];
|
||||
serial[i - 1] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add to the end of the active handles */
|
||||
adb_mutex_lock(&usb_lock);
|
||||
|
|
@ -631,7 +640,7 @@ static void register_device(const char *dev_name,
|
|||
usb->next->prev = usb;
|
||||
adb_mutex_unlock(&usb_lock);
|
||||
|
||||
register_usb_transport(usb, serial);
|
||||
register_usb_transport(usb, serial, usb->writeable);
|
||||
return;
|
||||
|
||||
fail:
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ static void *usb_open_thread(void *x)
|
|||
usb->fd = fd;
|
||||
|
||||
D("[ usb_thread - registering device ]\n");
|
||||
register_usb_transport(usb, 0);
|
||||
register_usb_transport(usb, 0, 1);
|
||||
}
|
||||
|
||||
// never gets here
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue