环境:ubuntu14.04虚拟机
最近做android系统开发,adb时不时的找不到设备,如下:
什么也没有,莫名其妙,浪费了不少时间。最近任务没那么紧张,这个问题又冒出来了。这次下决心要找到原因。这次从adb原理着手分析,下载了adb进行跟踪,有下面一段代码
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 ;
busdir = opendir(base);
if(busdir == 0) return;
while((de = readdir(busdir)) != 0) {
if(badname(de->d_name)) continue;
snprintf(busname, sizeof busname, "%s/%s", base, de->d_name);
devdir = opendir(busname);
if(devdir == 0) continue;
DBGX("[ scanning %s ]\n", busname);
while((de = readdir(devdir))) {
unsigned char devdesc[4096];
unsigned char* bufptr = devdesc;
unsigned char* bufend;
struct usb_device_descriptor* device;
struct usb_config_descriptor* config;
struct usb_interface_descriptor* interface;
struct usb_endpoint_descriptor *ep1, *ep2;
unsigned zero_mask = 0;
unsigned vid, pid;
size_t desclength;
if(badname(de->d_name)) continue;
snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
if(known_device(devname)) {
DBGX("skipping %s\n", devname);
continue;
}
DBGX("[ scanning %s ]\n", devname);
if((fd = unix_open(devname, O_RDONLY)) < 0) {
continue;
}
desclength = adb_read(fd, devdesc, sizeof(devdesc));
bufend = bufptr + desclength;
// should have device and configuration descriptors, and atleast two endpoints
if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) {
D("desclength %d is too small\n", desclength);
adb_close(fd);
continue;
}
device = (struct usb_device_descriptor*)bufptr;
bufptr += USB_DT_DEVICE_SIZE;
if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) {
adb_close(fd);
continue;
}
vid = device->idVendor;
pid = device->idProduct;
DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid);
// should have config descriptor next
config = (struct usb_config_descriptor *)bufptr;
bufptr += USB_DT_CONFIG_SIZE;
if (config->bLength != USB_DT_CONFIG_SIZE || config->bDescriptorType != USB_DT_CONFIG) {
D("usb_config_descriptor not found\n");
adb_close(fd);
continue;
}
// loop through all the descriptors and look for the ADB interface
while (bufptr < bufend) {
unsigned char length = bufptr[0];
unsigned char type = bufptr[1];
if (type == USB_DT_INTERFACE) {
interface = (struct usb_interface_descriptor *)bufptr;
bufptr += length;
if (length != USB_DT_INTERFACE_SIZE) {
D("interface descriptor has wrong size\n");
break;
}
DBGX("bInterfaceClass: %d, bInterfaceSubClass: %d,"
"bInterfaceProtocol: %d, bNumEndpoints: %d\n",
interface->bInterfaceClass, interface->bInterfaceSubClass,
interface->bInterfaceProtocol, interface->bNumEndpoints);
if (interface->bNumEndpoints == 2 &&
is_adb_interface(vid, pid, interface->bInterfaceClass,
interface->bInterfaceSubClass, interface->bInterfaceProtocol)) {
DBGX("looking for bulk endpoints\n");
// looks like ADB...
ep1 = (struct usb_endpoint_descriptor *)bufptr;
bufptr += USB_DT_ENDPOINT_SIZE;
ep2 = (struct usb_endpoint_descriptor *)bufptr;
bufptr += USB_DT_ENDPOINT_SIZE;
if (bufptr > devdesc + desclength ||
ep1->bLength != USB_DT_ENDPOINT_SIZE ||
ep1->bDescriptorType != USB_DT_ENDPOINT ||
ep2->bLength != USB_DT_ENDPOINT_SIZE ||
ep2->bDescriptorType != USB_DT_ENDPOINT) {
D("endpoints not found\n");
break;
}
// both endpoints should be bulk
if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK ||
ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) {
D("bulk endpoints not found\n");
continue;
}
/* aproto 01 needs 0 termination */
if(interface->bInterfaceProtocol == 0x01) {
zero_mask = ep1->wMaxPacketSize - 1;
}
// we have a match. now we just need to figure out which is in and which is out.
if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
local_ep_in = ep1->bEndpointAddress;
local_ep_out = ep2->bEndpointAddress;
} else {
local_ep_in = ep2->bEndpointAddress;
local_ep_out = ep1->bEndpointAddress;
}
register_device_callback(devname, local_ep_in, local_ep_out,
interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
break;
}
} else {
bufptr += length;
}
} // end of while
adb_close(fd);
} // end of devdir while
closedir(devdir);
} //end of busdir while
closedir(busdir);
}
void* device_poll_thread(void* unused)
{
D("Created device thread\n");
for(;;) {
/* XXX use inotify */
find_usb_device("/dev/bus/usb", register_device);
kick_disconnected_devices();
sleep(1);
}
return NULL;
}
void usb_init()
{
adb_thread_t tid;
struct sigaction actions;
memset(&actions, 0, sizeof(actions));
sigemptyset(&actions.sa_mask);
actions.sa_flags = 0;
actions.sa_handler = sigalrm_handler;
sigaction(SIGALRM,& actions, NULL);
if(adb_thread_create(&tid, device_poll_thread, NULL)){
fatal_errno("cannot create input thread");
}
}
大概的原理是adb会搜索"/dev/bus/usb"目录下所有的设备节点,打开并读取节点的设备描述符信息,找到adb设备。跟踪发现有个026的设备打开失败了,这个026设备正是adb设备,为什么打开失败了呢?看下面
原来这个设备所在组是audio,其他用户只读权限都没有,而我正好符合其他用户。到这里肯定知道怎么解决这个问题了,把自己添加到audio用户组问题就解决了。如下
貌似需要重启shell才会生效,再搜索下试试
果然OK了!!!
这里我们在跟踪一下,找一下这个文件是哪条规则创建的,首先lsusb看一下新加入的usb设备,如下
通过插拔知道Bus 001 Device 026: ID 2207:0006这个设备是adb设备,001总线,026节点,vendor是2207,product是0006,搜索一下rules,如下
正好有这个条目,mode是660,原来就是它创建的。