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

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/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Unity获取AndroidUSB权限需要使用Android的Java层代码,可以通过Unity的AndroidJavaObject类来调用Java代码实现。以下是获取USB权限的示例代码: ```csharp private void GetUsbPermission() { AndroidJavaObject context = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity").Call<AndroidJavaObject>("getApplicationContext"); AndroidJavaObject usbManager = context.Call<AndroidJavaObject>("getSystemService", "usb"); AndroidJavaObject usbDevice = GetUsbDevice(); if (usbDevice != null) { AndroidJavaObject pendingIntent = AndroidJavaObject("android.app.PendingIntent").CallStatic<AndroidJavaObject>("getBroadcast", context, 0, new AndroidJavaObject("android.content.Intent"), 0); AndroidJavaObject intentFilter = AndroidJavaObject("android.content.IntentFilter").CallStatic<AndroidJavaObject>("create", "android.hardware.usb.action.USB_DEVICE_ATTACHED"); AndroidJavaObject broadcastReceiver = new AndroidJavaObject("android.content.BroadcastReceiver"); broadcastReceiver.Call("onReceive", context, new AndroidJavaObject("android.content.Intent")); context.Call("registerReceiver", broadcastReceiver, intentFilter); usbManager.Call("requestPermission", usbDevice, pendingIntent); } } private AndroidJavaObject GetUsbDevice() { AndroidJavaObject context = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity").Call<AndroidJavaObject>("getApplicationContext"); AndroidJavaObject usbManager = context.Call<AndroidJavaObject>("getSystemService", "usb"); AndroidJavaObject usbDevice = null; AndroidJavaObject deviceList = usbManager.Call<AndroidJavaObject>("getDeviceList"); AndroidJavaObject[] deviceArray = AndroidJNIHelper.ConvertFromJNIArray<AndroidJavaObject[]>(deviceList.GetRawObject()); foreach (AndroidJavaObject device in deviceArray) { int deviceClass = device.Call<int>("getDeviceClass"); int deviceSubClass = device.Call<int>("getDeviceSubclass"); if (deviceClass == 0x02 && deviceSubClass == 0x01) { usbDevice = device; break; } } return usbDevice; } ``` 这段代码主要包括两个方法: 1. `GetUsbDevice()`:获取连接的USB设备,判断设备类型是否为USB存储设备。 2. `GetUsbPermission()`:获取USB权限,注册USB设备连接广播,请求USB权限。 需要注意的是,这段代码只是示例代码,具体的实现需要根据实际情况进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值