Android 获取USB设备的类型

版权声明:本文为博主原创文章,遵循 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

扫描二维码关注公众号,回复: 8880306 查看本文章

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/

发布了36 篇原创文章 · 获赞 162 · 访问量 62万+

猜你喜欢

转载自blog.csdn.net/qq_19004627/article/details/103383370