栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

android9.0 UsbManager源码解析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

android9.0 UsbManager源码解析

文章目录

前言一、UsbManager是什么?二、每个类的简介总结


前言

安卓手机可以通过USB连接外设,比如键盘,鼠标,摄像头。还可以与电脑互联进行数据传输,加强了对外扩展的能力。

这功能无疑十分方便,但是根据安卓的系统架构来看,就有一个专门的类来管理USB设备的连接,提供一些最基础的服务和方法公开发者和用户使用。

现在来看一下USBManager这个类吧。


一、UsbManager是什么?

USBManager作为一个用户在开发APk是会用到的一个类,主要是起着提供接口的功能,当然也是个服务,但其主要逻辑工作是在UsbService里面做的,但无妨,我们先来分析它。

我们会尽可能的对其中每一个变量和每一个方法都分析。

这个类允许访问USB的状态并与USB设备通信,目前,公共API中仅支持主机模式。

所谓主机模式,就是当你的Android手机在USB主机模式下,它充当USB主机,开启设备,并列举已连接的USB设备。

注:USB是由Host端控制整个总线的数据传输的。单个USB总线上,只能有一个Host。

先叙述一下这个USB连接的整个过程,当你看完本文之后再回过头来看这段话会有更深的理解:

在和USB设备交互的时候,通常情况下,你需要用到所有的这些类(除了交互的时候,只需要用到 UsbRequest)。总的来说,你首先需要获取 UsbManager对象来查询目标设备 UsbDevice。当获得设备 UsbDevice之后,你需要找到适当的UsbInterface以及该接口对应UsbEndpoint,从而进行交互。一旦拿到真确的端点,打开连接 UsbDeviceConnection,以此和USB设备进行交互。

接下来是每个类的简介:

二、每个类的简介

1、UsbManager:获得Usb的状态,与连接的Usb设备通信。
2、UsbDevice:Usb设备的抽象,它包含一个或多个UsbInterface,而每个UsbInterface包含多个UsbEndpoint。Host与其通信,先打开UsbDeviceConnection,使用UsbRequest在一个端点(endpoint)发送和接收数据。
3、UsbInterface:定义了设备的功能集,一个UsbDevice包含多个UsbInterface,每个Interface都是独立的。
4、UsbEndpoint:endpoint是interface的通信通道。
5、UsbDeviceConnection:host与device建立的连接,并在endpoint传输数据。
6、UsbRequest:usb 请求包。可以在UsbDeviceConnection上异步传输数据。注意是只在异步通信时才会用到它。
7、UsbConstants:usb常量的定义,对应linux/usb/ch9.h

xref: /frameworks/base/core/java/android/hardware/usb/UsbManager.java

这个描述的是USB目前的状态,也就是连上之后主要是做什么工作的,比如adb,音频,midi接口等等。

 public static final String ACTION_USB_STATE =
         "android.hardware.usb.action.USB_STATE";
public static final String ACTION_USB_PORT_CHANGED =
        "android.hardware.usb.action.USB_PORT_CHANGED";    广播操作:USB端口更改的广播。
 
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_USB_DEVICE_ATTACHED =
        "android.hardware.usb.action.USB_DEVICE_ATTACHED"; 用户连接USB设备时发送的activity intent。
 
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_USB_DEVICE_DETACHED =
        "android.hardware.usb.action.USB_DEVICE_DETACHED"; 广播操作:USB设备分离事件的广播。
 
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_USB_ACCESSORY_ATTACHED =
        "android.hardware.usb.action.USB_ACCESSORY_ATTACHED"; 用户连接USB附件时发送的活动意图。
 
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_USB_ACCESSORY_DETACHED =
        "android.hardware.usb.action.USB_ACCESSORY_DETACHED"; 用户断开连接USB附件时发送的活动意图。
 
下面这个是定义的USB连接功能的字符串
 
public static final String USB_ConNECTED = "connected";             表示USB是连接还是断开 
 
public static final String USB_HOST_ConNECTED = "host_connected";   指示USB是否作为主机连接或断开连接。
 
public static final String USB_ConFIGURED = "configured";           指示是否配置了USB。
 
public static final String USB_DATA_UNLOCKED = "unlocked";          指示是否应在USB连接上提供机密用户数据,如照片。仅当用户明确要求解锁此数据时,才会设置此变量。
 
public static final String USB_FUNCTION_NONE = "none";              表示未指定USB功能的占位符。
 
public static final String USB_FUNCTION_ADB = "adb";                usb连接作为adb的功能。
 
public static final String USB_FUNCTION_RNDIS = "rndis";            RNDIS以太网USB功能的名称。
 
public static final String USB_FUNCTION_MTP = "mtp";                MTP连接模式,一般作为USB的默认连接方式。
 
public static final String USB_FUNCTION_PTP = "ptp";                PTP连接模式,一种USB传输协议。
 
public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";  USB连接被用作音频播放源
 
public static final String USB_FUNCTION_MIDI = "midi";              USB连接被用作MIDI数字化传输
 
public static final String USB_FUNCTION_ACCESSORY = "accessory";    accessory连接模式,一般电脑对手机都是这种模式,手机是accessory
 
public static final String EXTRA_PORT = "port";                     {@link#ACTION_USB_PORT_CHANGED}的额外名称
 
public static final String EXTRA_PORT_STATUS = "portStatus";        {@link#ACTION_USB_PORT_CHANGED}的额外名称
 
public static final String EXTRA_DEVICE = "device";                 “同上”
 
public static final String EXTRA_ACCESSORY = "accessory";           “同上”
 
public static final String EXTRA_PERMISSION_GRANTED = "permission"; ...
 
public static final long FUNCTION_NONE = 0;                         ...
 
public static final long FUNCTION_MTP = GadgetFunction.MTP;         ...
 
public static final long FUNCTION_PTP = GadgetFunction.PTP;         ...
 
public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS;     ...
 
public static final long FUNCTION_MIDI = GadgetFunction.MIDI;       ...
 
public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY; ...
 
public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE;   ...

下面这个是其构造方法,但是我们一般都用getSystemService来获取这个USBManager

```c


public UsbManager(Context context, IUsbManager service) {
    mContext = context;
    mService = service;
}

获取所有的USB设备(当前连接的),一个很重要的方法。

@RequiresFeature(PackageManager.FEATURE_USB_HOST)   //需要权限
public HashMap getDeviceList() {
    HashMap result = new HashMap(); //这个容器里面key是字符串名字,value就是对应的USBDevice
    if (mService == null) {
        return result;
    }
    Bundle bundle = new Bundle();           //跨进程传输的数据携带者
    try {
        mService.getDeviceList(bundle);     //利用UsbService获取到当前的设备列表,它们之间的通信方式是AIDL,USBservice实现了USBManager.aidl
        for (String name : bundle.keySet()) {
            result.put(name, (UsbDevice)bundle.get(name));
        }
        return result;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

打开设备的方法,使之能接受或发送数据

@RequiresFeature(PackageManager.FEATURE_USB_HOST)
public UsbDeviceConnection openDevice(UsbDevice device) {
    try {
        String deviceName = device.getDeviceName();
        ParcelFileDescriptor pfd = mService.openDevice(deviceName, mContext.getPackageName());//仍然是调UsbService里面的方法来打开设备
        if (pfd != null) {
            UsbDeviceConnection connection = new UsbDeviceConnection(device);   //如果设备文件被打开,创建连接类
            boolean result = connection.open(deviceName, pfd, mContext);        //利用生成的文件描述符和设备名,建立连接,usb这里有专门的连接类来处理这一块的工作
            pfd.close();
            if (result) {
                return connection;
            }
        }
    } catch (Exception e) {
        Log.e(TAG, "exception in UsbManager.openDevice", e);
    }
    return null;
}

这个方法很简单,就是获取当前连接上的accessories的列表,但是这当前的连接只能有一个,也就是可以生效的。

@RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
public UsbAccessory[] getAccessoryList() {
    if (mService == null) {
        return null;
    }
    try {
        UsbAccessory accessory = mService.getCurrentAccessory();
        if (accessory == null) {
            return null;
        } else {
            return new UsbAccessory[] { accessory };    //看这里,其实确实只是返回了一个
        }
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

打开accessory,发送或者接收数据,很简单,但返回的是一个ParcelFileDescriptor

@RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
    try {
        return mService.openAccessory(accessory);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

获取给定函数的functionfs控制文件描述符,其中usb描述符和字符串已写入。函数实现使用文件描述符来处理事件和控制请求。

也就是说,我们想要控制这些usb操作中的一个功能,我们就用到了这个函数,传进去功能long值,返回它的文件描述符,就可以操作了。

public ParcelFileDescriptor getControlFd(long function) {
    try {
        return mService.getControlFd(function);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

这个函数主要是来判断某个Usbdevice是否有系统接入的权限。

权限可能是通过requestPermission方法临时授予的,或者是用户选择调用者作为设备的默认应用程序授予的。

针对安卓9及以上版本的客户端,只有在其具有{@link android.Manifest.Permission#CAMERA}权限的情况下,才能授予{@link UsbConstants#USB#class_VIDEO}类USB设备的权限。

也就是说不能随便访问摄像头,也是加强用户隐私和安全的一种手段。

@RequiresFeature(PackageManager.FEATURE_USB_HOST)
public boolean hasPermission(UsbDevice device) {
    if (mService == null) {
        return false;
    }
    try {
        return mService.hasDevicePermission(device, mContext.getPackageName());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

这个方法主要是为给定包请求访问设备的临时权限。

如果尚未授予权限,这可能会导致向用户显示系统对话框。成功或失败通过{@link android.app.pendingent}pi返回。

如果成功,这将授予调用方访问设备的权限,直到设备断开连接

@RequiresFeature(PackageManager.FEATURE_USB_HOST)
public void requestPermission(UsbDevice device, PendingIntent pi) {
    try {
        mService.requestDevicePermission(device, mContext.getPackageName(), pi);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

授予USB设备权限而不显示系统对话框。只有系统组件才能调用此功能。

内部的接口,外边的不让用。

public void grantPermission(UsbDevice device) {
    grantPermission(device, Process.myUid());
}

如果在设备模式下指定的USB功能当前已启用,则返回true。

@Deprecated
public boolean isFunctionEnabled(String function) {
    try {
        return mService.isFunctionEnabled(function);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

当连上usb时,设置当前是以什么功能作为连接状态。

此方法用于在主要USB功能中进行选择,系统可根据其他设置和状态自动激活附加功能,比如adb。

参数0表示设备正在充电,并且可以为此选择任何适当的功能。

注意:此函数是异步的,在不应用请求的更改的情况下可能会自动失败。

public void setCurrentFunctions(long functions) {
    try {
        mService.setCurrentFunctions(functions);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

不多说了,和上面的那个方法是一对儿。

public long getCurrentFunctions() {
    try {
        return mService.getCurrentFunctions();
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

设置屏幕解锁功能,当屏幕解锁时,这些功能将被保留并设置为当前功能。

零掩码具有关闭此功能的效果,因此屏幕解锁时功能不再改变。

*注意:当屏幕打开时,此方法将应用给定函数作为当前函数,这是异步的,可能会在不应用请求的更改的情况下无声地失败。

public void setScreenUnlockedFunctions(long functions) {
    try {
        mService.setScreenUnlockedFunctions(functions);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}
 

public long getScreenUnlockedFunctions() {
    try {
        return mService.getScreenUnlockedFunctions();
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

下面的这几个方法是关于端口的操作,都是系统去调用的,用户接触不到。

getPorts是获取USB物理端口列表。

getPortStatus是查询端口当前的状态,很简单。

setPortRoles是设置所需的端口角色组合。

public UsbPort[] getPorts() {
    if (mService == null) {
        return null;
    }
    try {
        return mService.getPorts();
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}
 

public UsbPortStatus getPortStatus(UsbPort port) {
    Preconditions.checkNotNull(port, "port must not be null");
 
    try {
        return mService.getPortStatus(port.getId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}
 

public void setPortRoles(UsbPort port, int powerRole, int dataRole) {
    Preconditions.checkNotNull(port, "port must not be null");
    UsbPort.checkRoles(powerRole, dataRole);
 
    Log.d(TAG, "setPortRoles Package:" + mContext.getPackageName());
    try {
        mService.setPortRoles(port.getId(), powerRole, dataRole);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}
总结

这里基本上把UsbManager里面几个重要的方法分析了一遍,都不难掌握。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/771093.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号