版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u013686019/article/details/50409421
Version info:
Linux: 3.10
Android: 4.2
一、问题
现在有USB设备插入Android系统,那么如何得知插入的设备类型?是USB打印机,U盘,还是USB鼠标?
二、USB类型规定
对于USB类型,USB组织是有规定的,见:http://www.usb.org/
比如:
Base Class
Descriptor Usage
Description
00h
Device
Use class information in the Interface Descriptors
01h
![](/qrcode.jpg)
Interface
Audio
02h
Both
Communications and CDC Control
03h
Interface
HID (Human Interface Device)
05h
Interface
Physical
06h
Interface
Image
07h
Interface
Printer
三、Linux对USB设备类型定义
在kernel中,有两个结构体的相关成员表征USB设备的类型,第一个usb_device_descriptor:
include/uapi/linux/usb/ch9.h
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
} __attribute__ ((packed));
bDeviceClass成员值区别不同的USB设备,如果该值为0呢?看上边:
Base Class
Descriptor Usage
Description
00h
Device
Use class information in the Interface Descriptors
就在第二个结构体usb_interface_descriptor中:
include/uapi/linux/usb/ch9.h
struct usb_interface_descriptor {
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
} __attribute__ ((packed));
bInterfaceClass成员即是。
比如,对于USB打印机设备,定义如下:
include/uapi/linux/usb/ch9.h
/*
* Device and/or Interface Class codes
* as found in bDeviceClass or bInterfaceClass
* and defined by www.usb.org documents
*/
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PHYSICAL 5
#define USB_CLASS_STILL_IMAGE 6
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_CDC_DATA 0x0a
#define USB_CLASS_CSCID 0x0b /* chip+ smart card */
#define USB_CLASS_CONTENT_SEC 0x0d /* content security */
#define USB_CLASS_VIDEO 0x0e
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
#define USB_CLASS_MISC 0xef
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
drivers/usb/gadget/printer.c
static struct usb_interface_descriptor intf_desc = {
.bLength = sizeof intf_desc,
.bDescriptorType = USB_DT_INTERFACE,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_PRINTER,
.bInterfaceSubClass = 1, /* Printer Sub-Class */
.bInterfaceProtocol = 2, /* Bi-Directional */
.iInterface = 0
};
对上了,不是?!
四、JNI和Framework层
JNI层的usbhost.c文件为我们获取Linux driver中USB设备的信息提供了便利,除了USB设备类型,还可以得到USB设备的厂商名称、产品名称、序列号等:
system/core/libusbhost/usbhost.c
usbhost.c该文件中提供的方法在JNI中调用:
frameworks/base/services/jni/com_android_server_UsbHostManager.cpp
上面代码截图信息量很大!很重要!很重要!很重要!很重要!重要的地方说四遍。
1、调用usbhost.c文件中方法获取USB设备信息
2、获取的信息一部分传到UsbInterface.java,APP部分调用UsbInterface类获取信息
frameworks/base/core/java/android/hardware/usb/UsbInterface.java
public class UsbInterface implements Parcelable {
private final int mId;
private final int mClass;
private final int mSubclass;
private final int mProtocol;
private final Parcelable[] mEndpoints;
}
3、获取的信息另一部分通过调用UsbHostManager.java中的usbDeviceAdded(4.4+版本是beginUsbDeviceAdded/endUsbDeviceAdded)方法,把信息写到UsbDevice.java中,APP部分调用UsbDevice类获取信息:
frameworks/base/core/java/android/hardware/usb/UsbDevice.java
public class UsbDevice implements Parcelable {
private final String mName;
private final int mVendorId;
private final int mProductId;
private final int mClass;
private final int mSubclass;
private final int mProtocol;
private final Parcelable[] mInterfaces;
}
接下来,我们就看下如此关键的usbDeviceAdded(4.4+版本是beginUsbDeviceAdded/endUsbDeviceAdded)方法:
frameworks/base/services/java/com/android/server/usb/UsbHostManager.java
private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID,
int deviceClass, int deviceSubclass, int deviceProtocol,
String manufacturerName, String productName, String serialNumber) {
// 位于BlackListed中的USB设备系统不予管理,比如USB HUB,USB鼠标等
if (isBlackListed(deviceName) ||
isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
return false;
}
synchronized (mLock) {
if (mDevices.get(deviceName) != null) {
Slog.w(TAG, "device already on mDevices list: " + deviceName);
return false;
}
if (mNewDevice != null) {
Slog.e(TAG, "mNewDevice is not null in endUsbDeviceAdded");
return false;
}
mNewDevice = new UsbDevice(deviceName, vendorID, productID,
deviceClass, deviceSubclass, deviceProtocol,
manufacturerName, productName, serialNumber);
mNewConfigurations = new ArrayList<UsbConfiguration>();
mNewInterfaces = new ArrayList<UsbInterface>();
mNewEndpoints = new ArrayList<UsbEndpoint>();
}
return true;
}
private void endUsbDeviceAdded() {
synchronized (mLock) {
if (mNewDevice != null) {
mNewDevice.setConfigurations(
mNewConfigurations.toArray(new UsbConfiguration[mNewConfigurations.size()]));
mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
}
}
}
五、APP层
经过上面分析,获取USB设备类型等信息,已经心有成竹了,使用UsbDevice、UsbInterface两个类即可。其中,UsbInterface类是包含在UsbDevice类中的:
frameworks/base/core/java/android/hardware/usb/UsbDevice.java
public class UsbDevice implements Parcelable {
private final Parcelable[] mInterfaces;
/**
* Returns the {@link UsbInterface} at the given index.
*
* @return the interface
*/
public UsbInterface getInterface(int index) {
return (UsbInterface)mInterfaces[index];
}
}
之后,就是如何使用UsbDevice类了。
USB设备属于热插拔设备,一旦系统监测到其热插拔时间,会有相应事件上报:
frameworks/base/core/java/android/hardware/usb/UsbManager.java
/**
* This intent is sent when a USB device is attached to the USB bus when in host mode.
*/
public static final String ACTION_USB_DEVICE_ATTACHED =
"android.hardware.usb.action.USB_DEVICE_ATTACHED";
/**
* This intent is sent when a USB device is detached from the USB bus when in host mode.
*/
public static final String ACTION_USB_DEVICE_DETACHED =
"android.hardware.usb.action.USB_DEVICE_DETACHED";
所以,注册监听事件的广播即可,如:
class UsbDeviceEventReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
}
}
mReceiver = new UsbDeviceEventReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(mReceiver, filter);
六、结束
Android流程:driver->JNI->Framework->APP,几乎所有模块都是这个模式,对于一个外设,如果这几个部分都清楚的话心里会特别明亮。
————————————————
版权声明:本文为CSDN博主「__2017__」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013686019/article/details/50409421/