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:
Mike Lockwood 2009-08-08 12:37:44 -04:00
parent 4e3fb86156
commit 0927bf9690
5 changed files with 160 additions and 122 deletions

View file

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

View file

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

View file

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

View file

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

View file

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