在命令行执行adb devices,你会得到连接上的设备,结果里面有每个设备的标识(serial number)。在adb的其他命令中,你可以用adb –s 来指定用某一个设备来执行命令,但是每个设备的serial number都不一样,adb是如何得到的呢?查看adb的源码后,发现其获取serial number的代码如下:
//D:/project/android/android-1.5/development/host/windows/usb/api/adb_interface.cpp bool AdbInterfaceObject::GetSerialNumber(void* buffer, unsigned long* buffer_char_size, bool ansi) { if (!IsOpened()) { SetLastError(ERROR_INVALID_HANDLE); return false; } // Open USB device for this intefface HANDLE usb_device_handle = CreateFile(interface_name().c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (INVALID_HANDLE_VALUE == usb_device_handle) return NULL; WCHAR serial_number[512]; // Send IOCTL DWORD ret_bytes = 0; BOOL ret = DeviceIoControl(usb_device_handle, ADB_IOCTL_GET_SERIAL_NUMBER, NULL, 0, serial_number, sizeof(serial_number), &ret_bytes, NULL); // Preserve error accross CloseHandle ULONG error = ret ? NO_ERROR : GetLastError(); ::CloseHandle(usb_device_handle); if (NO_ERROR != error) { SetLastError(error); return false; } unsigned long str_len = static_cast(wcslen(serial_number) + 1); if ((NULL == buffer) || (*buffer_char_size < str_len)) { *buffer_char_size = str_len; SetLastError(ERROR_INSUFFICIENT_BUFFER); return false; } if (!ansi) { // If user asked for wide char name just return it wcscpy(reinterpret_cast(buffer), serial_number); return true; } // We need to convert name from wide char to ansi string int res = WideCharToMultiByte(CP_ACP, 0, serial_number, static_cast(str_len), reinterpret_cast(buffer), static_cast(*buffer_char_size), NULL, NULL); return (res != 0); }
从上面的代码可以看到,adb是通过DeviceIoControl发送ADB_IOCTL_GET_SERIAL_NUMBER获取的,而上面CreateFile使用的interface_name是adb设备的全路径,格式如"////?//usb#vid_xxxx&pid_xxxx&mi_xx#123456789abcdef#{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX},创建adb设备的代码如下:
//D:/project/android/android-1.5/development/host/windows/usb/api/adb_api.cpp ADBAPIHANDLE AdbCreateInterface(GUID class_id, unsigned short vendor_id, unsigned short product_id, unsigned char interface_id) { // Enumerate all active interfaces for the given class AdbEnumInterfaceArray interfaces; if (!EnumerateDeviceInterfaces(class_id, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT, true, true, &interfaces)) { return NULL; } if (interfaces.empty()) { SetLastError(ERROR_DEVICE_NOT_AVAILABLE); return NULL; } // Now iterate over active interfaces looking for the name match. // The name is formatted as such: // "////?//usb#vid_xxxx&pid_xxxx&mi_xx#123456789abcdef#{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" // where // vid_xxxx is for the vendor id (xxxx are hex for the given vendor id), // pid_xxxx is for the product id (xxxx are hex for the given product id) // mi_xx is for the interface id (xx are hex for the given interface id) // EnumerateDeviceInterfaces will guarantee that returned interface names // will have our class id at the end of the name (those last XXXes in the // format). So, we only need to match the beginning of the name wchar_t match_name[64]; if (0xFF == interface_id) { // No interface id for the name. swprintf(match_name, L"////?//usb#vid_%04x&pid_%04x#", vendor_id, product_id); } else { // With interface id for the name. swprintf(match_name, L"////?//usb#vid_%04x&pid_%04x&mi_%02x#", vendor_id, product_id, interface_id); } size_t match_len = wcslen(match_name); for (AdbEnumInterfaceArray::iterator it = interfaces.begin(); it != interfaces.end(); it++) { const AdbInstanceEnumEntry& next_interface = *it; if (0 == wcsnicmp(match_name, next_interface.device_name().c_str(), match_len)) { // Found requested interface among active interfaces. return AdbCreateInterfaceByName(next_interface.device_name().c_str()); } } SetLastError(ERROR_DEVICE_NOT_AVAILABLE); return NULL; }
adb是每个1秒没有所有的usb设备(classid:{0xf72fe0d4, 0xcbcb, 0x407d, {0x88, 0x14, 0x9e, 0xd6, 0x73, 0xd0, 0xdd, 0x6b}}),所以插上usb后起码要1秒adb devices才能发现新设备。
//D:/project/android/android-1.5/system/core/adb/usb_windows.c void* device_poll_thread(void* unused) { D("Created device thread/n"); while(1) { find_devices(); adb_sleep_ms(1000); } return NULL; }
如果你用windows监听usb设备的方式去监听adb设备,你可以在PDEV_BROADCAST_DEVICEINTERFACE结构体的dbcc_name字段获得GetSerialNumber函数所使用的interface_name。