Android MTP模式切换分析

Android MTP之服务端UsbService启动 已经分析了mtp服务端的启动,本文来分析下切换mtp模式是如何实现的.

当点击usb通知的时候,会弹出一个usb功能选择界面,当选择File Transfer,也就是mtp模式,会调用如下代码

mUsbManager = context.getSystemService(UsbManager.class);
mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MTP, true);

它会相应的调用服务端UsbServicesetCurrentFunction()方法

public void setCurrentFunctions(long functions) {
    // 需要声明权限
    mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
    mDeviceManager.setCurrentFunctions(functions);
}

UsbService把这个切换mtp的工作交给了UsbDeviceManager,它会向自己(一个Handler)发送一个消息,然后调用setEnabledFunctions()方法来处理

case MSG_SET_CURRENT_FUNCTIONS:
	long functions = (Long) msg.obj;
	setEnabledFunctions(functions, false);

Android MTP之服务端UsbService启动 说过,由于我的项目不支持hal层,因此setEnabledFunctions()方法的实现类是UsbHandlerLegacy

    protected void setEnabledFunctions(long usbFunctions, boolean forceRestart) {
        // mtp, ptp模式,数据状态是解锁的
        boolean usbDataUnlocked = isUsbDataTransferActive(usbFunctions);

        // 如果数据解锁状态改变,就会更新usb通知
        if (usbDataUnlocked != mUsbDataUnlocked) {
            mUsbDataUnlocked = usbDataUnlocked;
                pdateUsbNotification(false);
            forceRestart = true;
        }

        // 首先保存旧状态,以免设置新功能失败后,可以回退
        final long oldFunctions = mCurrentFunctions;
        final boolean oldFunctionsApplied = mCurrentFunctionsApplied;

        /**
         * 设置新USB功能
         */
        if (trySetEnabledFunctions(usbFunctions, forceRestart)) {
            return;
        }

        /**
         * 新USB功能设置失败,回退
         */
        if (oldFunctionsApplied && oldFunctions != usbFunctions) {
            if (trySetEnabledFunctions(oldFunctions, false)) {
                return;
            }
        }

        /**
         * 回退还是失败,那就恢复默认USB功能
         */
        if (trySetEnabledFunctions(UsbManager.FUNCTION_NONE, false)) {
            return;
        }

        /**
         * 恢复默认都失败了,最后再尝试一次
         */
        if (trySetEnabledFunctions(UsbManager.FUNCTION_NONE, false)) {
            return;
        }

        // Game over.
    }

可以看出设置mtp模式的功能交给了trySetEnabledFunctions()处理

        private boolean trySetEnabledFunctions(long usbFunctions, boolean forceRestart) {
            // ...

            if ((!functions.equals(oemFunctions)
                    && !mCurrentOemFunctions.equals(oemFunctions))
                    || !mCurrentFunctionsStr.equals(functions)
                    || !mCurrentFunctionsApplied
                    || forceRestart) {
                mCurrentFunctionsStr = functions;
                mCurrentOemFunctions = oemFunctions;
                mCurrentFunctionsApplied = false;

                // 1.先关闭现在的usb功能
                setUsbConfig(UsbManager.USB_FUNCTION_NONE);
                // 如果设置失败就返回
                if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
                    return false;
                }

                // 2.再设置新的usb功能
                setUsbConfig(oemFunctions);

                // 3. 如果usb状态改变就发送广播
                if (mBootCompleted
                        && (containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
                        || containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
                    updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
                }
                // 如果失败就返回
                if (!waitForState(oemFunctions)) {
                    return false;
                }

                mCurrentFunctionsApplied = true;
            }
            return true;
        }

从这段代码,可以看出,成功设置一个usb功能,其实有两步

  1. 通过setUsbConfig()设置usb功能.
  2. 通过waitForState()等待验证usb是否设置成功.
    private void setUsbConfig(String config) {
		// 设置sys.usb.config
        setSystemProperty(USB_CONFIG_PROPERTY, config);
    }
    
    private boolean waitForState(String state) {
        String value = null;
        // 最多等待1秒
        for (int i = 0; i < 20; i++) {
			// 获取sys.usb.state属性值
            value = getSystemProperty(USB_STATE_PROPERTY, "");
            if (state.equals(value)) return true;
            SystemClock.sleep(50);
        }
        return false;
    }

底层在检测到sys.usb.config属性改变后,会启动对应的usb功能.以下代码截取自底层部分代码

on property:sys.usb.config=mtp,adb && property:sys.usb.configfs=0
	# 先写0
    write /sys/class/android_usb/android0/enable 0
    # 写序列号
    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
    # 写vid, pid
    write /sys/class/android_usb/android0/idVendor 05C6
    write /sys/class/android_usb/android0/idProduct 9039
    # 设置USB功能为mtp,adb
    write /sys/class/android_usb/android0/functions mtp,adb
    # 再写1启动功能
    write /sys/class/android_usb/android0/enable 1
    # 启动adb
    start adbd
    # 设置 sys.usb.state属性值为sys.usb.config的属性值
    setprop sys.usb.state ${sys.usb.config}

这段底层代码在检测到sys.usb.config属性改变为mtp,adb时,会设置usb功能为mtp, adb,并且如果设置成功,就会把sys.usb.state属性的值设置与sys.usb.config一样.这个sys.usb.state正好就是刚刚waitForState()所使用的,它就是用来检测usb功能是否设置成功的标志.

假设现在已经成功切换到mtp模式,上层在trySetEnabledFunctions()中还做了一件事,那就是使用updateUsbStateBroadcastIfNeeded()发送usb状态改变的广播.

        protected void updateUsbStateBroadcastIfNeeded(long functions) {
            // send a sticky broadcast containing current USB state
            Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
                    | Intent.FLAG_RECEIVER_FOREGROUND);
            intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
            intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected);
            intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
            intent.putExtra(UsbManager.USB_DATA_UNLOCKED,
                    isUsbTransferAllowed() && isUsbDataTransferActive(mCurrentFunctions));

            long remainingFunctions = functions;
            while (remainingFunctions != 0) {
                intent.putExtra(UsbManager.usbFunctionsToString(
                        Long.highestOneBit(remainingFunctions)), true);
                remainingFunctions -= Long.highestOneBit(remainingFunctions);
            }

            // 状态没改变就不发送广播
            if (!isUsbStateChanged(intent)) {
                return;
            }
			
			// 发送一个sticky类型的广播
            sendStickyBroadcast(intent);
            mBroadcastedIntent = intent;
        }

那么,谁接收这个广播,接收这个广播又干了什么呢,在下一篇文章揭晓.

你可能感兴趣的:(Android,MTP)