USB 功能简介

USB OTG: USB On-The-Go的简称,是USB 2.0规定的补充标准,它可以使手机等作为USB主机,和其他USB设备连接通信,例如U盘,另外的手机,USB Hub等。

Android对Usb的支持是从3.1开始的,显然是加强Android平板的对外扩展能力。而对Usb使用更多的,是Android在工业中的使用。Android工业板子一般都会提供多个U口和多个串口,它们是连接外设的手段与桥梁。

USB OTG是通过OTG线连接通信,OTG线一头是公头连接手机USB HOST,一头母头接外设。如图一连接通信。

Android USB代码分析

在路径/frameworks/base/core/java/android/hardware/usb/下,这个包内包含了USB相关的类。

1,USBManager:定义了USB的action和参数,获取USB的状态,与连接的USB设备通信。

方法getDeviceList获取到所有连接的USB device的HashMap

方法openDevice 与USB设备通信

当有USB设备连接时,会发送广播ACTION_USB_DEVICE_ATTACHED。

public static final StringACTION_USB_DEVICE_ATTACHED =

           "android.hardware.usb.action.USB_DEVICE_ATTACHED";

当有USB设备移除时,会发送广播ACTION_USB_DEVICE_DETACHED。

 publicstatic final String ACTION_USB_DEVICE_DETACHED =

           "android.hardware.usb.action.USB_DEVICE_DETACHED";


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常量的定义。


  Settings中USB界面

Settings界面代码主要由UsbModeChooserActivity和UsbBackend显示USB选项,

UsbBackend中通过方法setUsbFunction调用UsbManager中setCurrentFunction,设置不同的USB连接模式,如

       mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MTP, true);

设置USB模式为MTP,同理也可设置为PTP,MIDI等。这个方法第二参数true/false是设置是否可以通过USB连接传输数据,当为true时,就可以传输数据,当为false时,USB连接仅为充电,无法访问手机上文件。

通过方法getUsbDataMode()可以获取当前USB连接模式,UsbModeChooserActivity通过这个方法显示当前的USB连接模式。

方法isModeSupported判断这种USB模式是否支持,只有支持的模式才会在选项中显示。

UsbModeChooserActivity弹出的USB选项Dialog,包含支持的USB连接模式。



3.3 USB OTG界面

手机通过OTG线连接U盘之类的外设,会通过SystemUI中StorageNotification,添加了对Storage的监听,

当volume状态发生变化时,会在onVolumeStateChangedInternal做对应提示。

   private final StorageEventListener mListener = newStorageEventListener() {

        @Override

        public void onVolumeStateChanged(VolumeInfo

vol, int oldState, intnewState) {

            onVolumeStateChangedInternal(vol);

        }


 刚通过OTG线连接U盘,调用onVolumeChecking显示checking U盘的提示。

   privateNotificationonVolumeChecking(VolumeInfo vol) {

        finalDiskInfo disk = vol.getDisk();

        final CharSequence title = mContext.getString(

                R.string.ext_media_checking_notification_title, disk.getDescription());

        final CharSequence text = mContext.getString(

                R.string.ext_media_checking_notification_message, disk.getDescription());


        returnbuildNotificationBuilder(vol, title, text)

                .setCategory(Notification.CATEGORY_PROGRESS)

                .setOngoing(true)

                .build();

   }

 当U盘状态为MOUNTED时,调用onVolumeMounted更新U盘提示,当U盘移除时,调用onVolumeRemoved或者onVolumeBadRemoval,提示已经移除U盘。

 这个通过OTG线连接U盘,显示的提示和插入SD卡类似,都可以点击Notification进入DocumentsUI,浏览和操作U盘中的文件。


手机通过OTG线与另外手机连接时,在MtpDocumentsProvider这个应用中有ReceiverActivity有监听

android.hardware.usb.action.USB_DEVICE_ATTACHED 这个广播,当主机通过OTG线连接另一台手机时,

接收到这个广播,从广播中获取到连接设备信息,创建相应的Uri,把Uri传给启动DocumentsUI的intent,

在启动DocumentsUI后,另外一台手机的USB连接模式未MTP,PTP时,主机就能查看和操作从机的文件。当是charging only状态,主机无法访问从机文件。

public class ReceiverActivity extends Activity {

   @Override

   protected voidonCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        if(UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(getIntent().getAction())) {

            final UsbDevice device = getIntent().getParcelableExtra(UsbManager.EXTRA_DEVICE);

            try{

                finalMtpDocumentsProvider provider =MtpDocumentsProvider.getInstance();

                provider.openDevice(device.getDeviceId());

                finalString deviceRootId =provider.getDeviceDocumentId(device.getDeviceId());

                finalUri uri = DocumentsContract.buildRootUri(

                        MtpDocumentsProvider.AUTHORITY,deviceRootId);


                final Intent intent = newIntent(Intent.ACTION_VIEW);

                intent.setDataAndType(uri,DocumentsContract.Root.MIME_TYPE_ITEM);

                intent.addCategory(Intent.CATEGORY_DEFAULT);

                this.startActivity(intent);

            }catch(IOException exception) {

                Log.e(MtpDocumentsProvider.TAG,"Failed to open

device", exception);

            }

        }

        finish();

   }

}

 同时也是在MtpDocumentsProvider的UsbIntentReceiver,这个receiver会监听OTG插拔两个广播

android.hardware.usb.action.USB_DEVICE_ATTACHEDandroid.hardware.usb.action.USB_DEVICE_DETACHED


public class UsbIntentReceiver extendsBroadcastReceiver {

   @Override

   public voidonReceive(Context context, Intent intent) {

        final UsbDevice device = intent.getExtras().getParcelable(UsbManager.EXTRA_DEVICE);

        switch(intent.getAction()) {

            case UsbManager.ACTION_USB_DEVICE_ATTACHED:

                MtpDocumentsProvider.getInstance().resumeRootScanner();

                break;

            case UsbManager.ACTION_USB_DEVICE_DETACHED:

                try{

                    MtpDocumentsProvider.getInstance().closeDevice(device.getDeviceId());

                }catch(IOException | InterruptedException e) {

                    Log.e(MtpDocumentsProvider.TAG,"Failed to close

device", e);

                }

                break;

        }

   }

}

 通过在MtpDocumentsProvider中初始化ServiceIntentSender,通过调用sendUpdateNotificationIntent显示手机连接的提示。


USB和底层交互

在android中很多地方使用到了UEvent机制,如图:像HDMI,Battery,USB相关等;当我们需要接受底层的UEvent的时候,我们就需要注册一个UEventObserver。Kernel层和framework层交互通过UeventObserver。在USB插拔时,在UsbDeviceManager中有注册UEventObserver,监听USB的uevent,当有uevent事件上传,获取对应的USB状态,和连接的设备之类。


    /*

     * Listensfor uevent messages from the kernel to monitor the USB state

     */

    private final UEventObserver mUEventObserver = newUEventObserver() {

        @Override

        public voidonUEvent(UEventObserver.UEvent event) {

            if (DEBUG) Slog.v(TAG, "USB UEVENT:

" + event.toString());


            Stringstate = event.get("USB_STATE");

            Stringaccessory = event.get("ACCESSORY");

            if (state != null) {

                mHandler.updateState(state);

            }else if ("START".equals(accessory)) {

                if (DEBUG) Slog.d(TAG, "got

accessory start");

                startAccessoryMode();

            }

        }

    };


mUEventObserver通过 startObserving加入想要监听的uevent,当对应事件上传,就会在对应onUEvent作出对应处理。

                // Watch for USB configuration

changes

                mUEventObserver.startObserving(USB_STATE_MATCH);

                mUEventObserver.startObserving(ACCESSORY_START_MATCH);

startObserving这个方法转到UEventThread中,UEventThread是UeventObserver的内部类,run中一个死循环,不断监听底层的uevent,然后发送uevent。

        @Override

        public voidrun() {

            nativeSetup();


            while (true) {

                Stringmessage =nativeWaitForNextEvent();

                if (message != null) {

                   if (DEBUG) {

                       Log.d(TAG, message);

                   }

                   sendEvent(message);

                }

            }

        }


USB插拔的后续处理就根据uevent上传的状态在updateState方法中赋值connected,configured,通过Handler发送Message:MSG_UPDATE_STATE,包含connected,configured,在UsbHandler中handleMessage中更新USB,adb的Notification,上层界面显示。

        public void  updateState(String state){

            int connected, configured;


            if ("DISCONNECTED".equals(state)) {

                connected= 0;

                configured= 0;

            }else if ("CONNECTED".equals(state)) {

                connected= 1;

                configured= 0;

            }else if ("CONFIGURED".equals(state)) {

                connected= 1;

                configured= 1;

            }else{

                Slog.e(TAG, "unknown

state "+ state);

                return;

            }

            removeMessages(MSG_UPDATE_STATE);

            Messagemsg = Message.obtain(this, MSG_UPDATE_STATE);

            msg.arg1= connected;

            msg.arg2= configured;

            // debounce disconnects to avoid

problems bringing up USB tethering

            sendMessageDelayed(msg,(connected == 0) ?UPDATE_DELAY: 0);

        }

UsbHostManager中从jni回调beginUsbDeviceAdded-》addUsbConfiguration-》addUsbInterface-》addUsbEndpoint-》endUsbDeviceAdded

通过这些方法把USB OTG device挂载上,手机当成USB主机,可以通过USB连接模式,传输数据等。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,008评论 25 707
  • 最近天气真的很冷,早晨我都不愿起床,每天都是大儿子喊我起床。想想儿子真的是很有责任心,自从我家的时间由他来支配一来...
    倪梓睿阅读 158评论 0 0
  • 长城怀古 李奇峰 万里长城长又长,今日登临来观仰。 烟霭沉沉遮望眼,古道铁马任想象!
    简德萌阅读 228评论 0 0
  • 姑娘,你错了,这世上本就没有真真正正爱你的人,除了你自己之外,便是父母。 有个很熟的女生跟我说,她男朋友对她很好,...
    楚璃洛阅读 794评论 3 9
  • 我今天迟到了。因为我发生了一件很神奇的事情。 那个不认识的女孩从一栋正在建的建筑物上失足坠楼,好像是被人推下去的。...
    凌小七的故事阅读 247评论 0 0