Android 10 USB用途切换失败分析

问题现象

最近处理一个USB的问题,偶现,现象如下:

usb用途切换失败

快速切换USB的用途,会导致切换失败,最后变为不进行数据传输状态。

源码梳理

首先按照惯例,得先把切换USB的流程梳理清楚,当前界面的UI在packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java

里面有四个controller,分别控制该页面的四个部分

@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class UsbDetailsFragment extends DashboardFragment {
    
    
    //省略部分代码
    private static List<UsbDetailsController> createControllerList(Context context,
            UsbBackend usbBackend, UsbDetailsFragment fragment) {
    
    
        List<UsbDetailsController> ret = new ArrayList<>();
        ret.add(new UsbDetailsHeaderController(context, fragment, usbBackend));
        ret.add(new UsbDetailsDataRoleController(context, fragment, usbBackend));
        //添加USB用途切换的控制器
        ret.add(new UsbDetailsFunctionsController(context, fragment, usbBackend));
        ret.add(new UsbDetailsPowerRoleController(context, fragment, usbBackend));
        return ret;
    }
    //省略部分代码
}

控制USB用途的controller为UsbDetailsFunctionsController,该控制器中实现了用途RadioButton的点击监听

/**
 * This class controls the radio buttons for choosing between different USB functions.
 */
public class UsbDetailsFunctionsController extends UsbDetailsController
        implements RadioButtonPreference.OnClickListener {
    
    
    
    protected final UsbBackend mUsbBackend;
    //省略部分代码
	@Override
    public void onRadioButtonClicked(RadioButtonPreference preference) {
    
    
        String key = preference.getKey();
        //获取当前选择的USB用途
        final long function = UsbBackend.usbFunctionsFromString(key);
        //获取之前的USB用途
        final long previousFunction = mUsbBackend.getCurrentFunctions();
        Log.d(TAG, "onRadioButtonClicked: currentFunction="+function+", previousFunction:"+previousFunction);
        if (function != previousFunction && !Utils.isMonkeyRunning()) {
    
    
            mPreviousFunction = previousFunction;

            if (function == UsbManager.FUNCTION_RNDIS) {
    
    
                //选择USB网络共享
                //Update the UI in advance to make it looks smooth
                final RadioButtonPreference prevPref =
                        (RadioButtonPreference) mProfilesContainer.findPreference(
                                UsbBackend.usbFunctionsToString(mPreviousFunction));
                if (prevPref != null) {
    
    
                    prevPref.setChecked(false);
                    preference.setChecked(true);
                }

                // We need to have entitlement check for usb tethering, so use API in
                // ConnectivityManager.
                mConnectivityManager.startTethering(TETHERING_USB, true /* showProvisioningUi */,
                        mOnStartTetheringCallback);
            } else {
    
    
                //选择其他用途
                mUsbBackend.setCurrentFunctions(function);
            }
        }
    }
    //省略部分代码
}

测试中没有切换到USB网络共享,所以执行mUsbBackend.setCurrentFunctions(function);,mUsbBackendUsbBackend对象,它提供了对底层系统USB功能的访问

/**
 * Provides access to underlying system USB functionality.
 */
public class UsbBackend {
    
    
    private UsbManager mUsbManager;
    //省略部分代码
	public void setCurrentFunctions(long functions) {
    
    
        mUsbManager.setCurrentFunctions(functions);
    }
    //省略部分代码
}

里面执行了UsbManagersetCurrentFunctions()方法,该类允许上层访问USB状态并于USB设备通信

@SystemService(Context.USB_SERVICE)
public class UsbManager {
    
    
    private final IUsbManager mService;
    //省略部分代码
	public void setCurrentFunctions(long functions) {
    
    
        try {
    
    
            mService.setCurrentFunctions(functions);
        } catch (RemoteException e) {
    
    
            throw e.rethrowFromSystemServer();
        }
    }
    //省略部分代码
}

UsbManager又调用远程UsbServicesetCurrentFunctions()(使用aidl),UsbService是一个SystemService,随着Android系统启动的时候而启动

/**
 * UsbService manages all USB related state, including both host and device support.
 * Host related events and calls are delegated to UsbHostManager, and device related
 * support is delegated to UsbDeviceManager.
 */
public class UsbService extends IUsbManager.Stub {
    
    
    private UsbDeviceManager mDeviceManager;
    //省略部分代码
	@Override
    public void setCurrentFunctions(long functions) {
    
    
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
        Preconditions.checkArgument(UsbManager.areSettableFunctions(functions));
        Preconditions.checkState(mDeviceManager != null);
        mDeviceManager.setCurrentFunctions(functions);
    }
    //省略部分代码
}

UsbService里面执行了UsbDeviceManagersetCurrentFunctions()UsbDeviceManager用来管理Usb设备的状态

/**
 * UsbDeviceManager manages USB state in device mode.
 */
public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObserver {
    
    
	private UsbHandler mHandler;
    //省略部分代码
	/**
     * Adds function to the current USB configuration.
     *
     * @param functions The functions to set, or empty to set the charging function.
     */
    public void setCurrentFunctions(long functions) {
    
    
        if (DEBUG) {
    
    
            Slog.d(TAG, "setCurrentFunctions(" + UsbManager.usbFunctionsToString(functions) + ")");
        }
        if (functions == UsbManager.FUNCTION_NONE) {
    
    
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_CHARGING);
        } else if (functions == UsbManager.FUNCTION_MTP) {
    
    
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MTP);
        } else if (functions == UsbManager.FUNCTION_PTP) {
    
    
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_PTP);
        } else if (functions == UsbManager.FUNCTION_MIDI) {
    
    
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MIDI);
        } else if (functions == UsbManager.FUNCTION_RNDIS) {
    
    
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_RNDIS);
        } else if (functions == UsbManager.FUNCTION_ACCESSORY) {
    
    
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_ACCESSORY);
        }
        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
    }
    //省略部分代码
}

此方法里面通过UsbHandler发了一条消息,同时在handleMessage()方法里处理此消息

public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObserver {
    
    
    //省略部分代码
	abstract static class UsbHandler extends Handler {
    
    
        //省略部分代码
        @Override
        public void handleMessage(Message msg) {
    
    
            switch (msg.what) {
    
    
         		//省略部分代码
                case MSG_SET_CURRENT_FUNCTIONS:
                    long functions = (Long) msg.obj;
                    setEnabledFunctions(functions, false);
                    break;
                //省略部分代码
            }
        }
        
        /**
         * Evaluates USB function policies and applies the change accordingly.
         */
        protected abstract void setEnabledFunctions(long functions, boolean forceRestart);
        //省略部分代码
    }
    //省略部分代码
}

UsbHandlerUsbDeviceManager的一个抽象静态内部类,在handleMessage()方法中调用setEnabledFunctions()方法来处理消息,而setEnabledFunctions()是个抽象方法,UsbHandler有两个子类来实现该方法,分别是UsbDeviceManager.UsbHandlerHalUsbDeviceManager.UsbHandlerLegacy,在UsbDeviceManager的构造方法中,会根据实际场景来创建相对应的对象

public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObserver {
    
    
    //省略部分代码
	public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
            UsbSettingsManager settingsManager) {
    
    
        //省略部分代码
    	boolean halNotPresent = false;
        try {
    
    
            //获取hal层服务,如果获取成功,说明hal服务准备就绪,否则会抛出RemoteException
            IUsbGadget.getService(true);
        } catch (RemoteException e) {
    
    
            Slog.e(TAG, "USB GADGET HAL present but exception thrown", e);
        } catch (NoSuchElementException e) {
    
    
            halNotPresent = true;
            Slog.i(TAG, "USB GADGET HAL not present in the device", e);
        }
        //省略部分代码
        if (halNotPresent) {
    
    
            /**
             * Initialze the legacy UsbHandler
             */
            mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(), mContext, this,
                    alsaManager, settingsManager);
        } else {
    
    
            /**
             * Initialize HAL based UsbHandler
             */
            mHandler = new UsbHandlerHal(FgThread.get().getLooper(), mContext, this,
                    alsaManager, settingsManager);
        }
    }
    //省略部分代码
}

可以看到,如果USB设备有hal层服务支持,则交由UsbHandlerHal处理,否则交由UsbHandlerLegacy处理,此处通过打印日志得知我的设备是没有hal支持的,所以逻辑在UsbHandlerLegacy中,即上面的MSG_SET_CURRENT_FUNCTIONS消息在UsbHandlerLegacy中的setEnabledFunctions()方法中处理

public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObserver {
    
    
    //省略部分代码
	private static final class UsbHandlerLegacy extends UsbHandler {
    
    
        //省略部分代码
		@Override
        protected void setEnabledFunctions(long usbFunctions, boolean forceRestart) {
    
    
            boolean usbDataUnlocked = isUsbDataTransferActive(usbFunctions);
            if (DEBUG) {
    
    
                Slog.d(TAG, "setEnabledFunctions functions=" + usbFunctions + ", "
                        + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
            }

            if (usbDataUnlocked != mUsbDataUnlocked) {
    
    
                mUsbDataUnlocked = usbDataUnlocked;
                //更新通知栏
                updateUsbNotification(false);
                forceRestart = true;
            }

            /**
             * Try to set the enabled functions.
             */
            final long oldFunctions = mCurrentFunctions;
            final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
            Log.d("jason", "setEnabledFunctions: first attempt");
            //设置新模式
            if (trySetEnabledFunctions(usbFunctions, forceRestart)) {
    
    
                Log.d("jason", "setEnabledFunctions: first attempt success");
                return;
            }

            /**
             * Didn't work.  Try to revert changes.
             * We always reapply the policy in case certain constraints changed such as
             * user restrictions independently of any other new functions we were
             * trying to activate.
             */
            //如果设置失败,则恢复为原来的设置
            if (oldFunctionsApplied && oldFunctions != usbFunctions) {
    
    
                Slog.e(TAG, "Failsafe 1: Restoring previous USB functions.");
                Log.d("jason", "setEnabledFunctions: first attempt fail,second attempt");
                if (trySetEnabledFunctions(oldFunctions, false)) {
    
    
                    Log.d("jason", "setEnabledFunctions: second attempt success");
                    return;
                }
            }

            /**
             * Still didn't work.  Try to restore the default functions.
             */
            //如果仍然失败,则恢复默认的设置,即不进行数据传输
            Slog.e(TAG, "Failsafe 2: Restoring default USB functions.");
            Log.d("jason", "setEnabledFunctions: second attempt fail,third attempt");
            if (trySetEnabledFunctions(UsbManager.FUNCTION_NONE, false)) {
    
    
                Log.d("jason", "setEnabledFunctions: third attempt success");
                return;
            }

            /**
             * Now we're desperate.  Ignore the default functions.
             * Try to get ADB working if enabled.
             */
            //如果还是失败,则表示adb可能挂掉了,此时尝试重启adb
            Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled).");
            Log.d("jason", "setEnabledFunctions: third attempt fail,try to get adb working");
            if (trySetEnabledFunctions(UsbManager.FUNCTION_NONE, false)) {
    
    
                Log.d("jason", "setEnabledFunctions: adb is successfully working");
                return;
            }

            /**
             * Ouch.
             */
            //还是失败,说明usb不可用
            Log.d("jason", "setEnabledFunctions: usb is unable");
            Slog.e(TAG, "Unable to set any USB functions!");
        }
        //省略部分代码
    }
    //省略部分代码
}

为防止设置失败,此方法里面尝试三次尝试,第一次设置用户选择的模式,如果设置失败,则恢复到之前的模式,如果还失败,则恢复默认设置,如果仍然失败,则尝试重启adb,如果还是失败,说明usb已经不可用了,不用处理。看一下trySetEnabledFunctions()的具体处理逻辑

public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObserver {
    
    
    //省略部分代码
	private static final class UsbHandlerLegacy extends UsbHandler {
    
    
        private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
        //省略部分代码
		private boolean trySetEnabledFunctions(long usbFunctions, boolean forceRestart) {
    
    
            String functions = null;
            if (usbFunctions != UsbManager.FUNCTION_NONE) {
    
    
                functions = UsbManager.usbFunctionsToString(usbFunctions);
            }
            mCurrentFunctions = usbFunctions;
            if (functions == null || applyAdbFunction(functions)
                    .equals(UsbManager.USB_FUNCTION_NONE)) {
    
    
                functions = getSystemProperty(getPersistProp(true),
                            UsbManager.USB_FUNCTION_NONE);

                if (functions.equals(UsbManager.USB_FUNCTION_NONE))
                functions = UsbManager.usbFunctionsToString(getChargingFunctions());
            }
            functions = applyAdbFunction(functions);

            String oemFunctions = applyOemOverrideFunction(functions);

            if (!isNormalBoot() && !mCurrentFunctionsStr.equals(functions)) {
    
    
                setSystemProperty(getPersistProp(true), functions);
            }

            if ((!functions.equals(oemFunctions)
                    && !mCurrentOemFunctions.equals(oemFunctions))
                    || !mCurrentFunctionsStr.equals(functions)
                    || !mCurrentFunctionsApplied
                    || forceRestart) {
    
    
                Slog.i(TAG, "Setting USB config to " + functions);
                mCurrentFunctionsStr = functions;
                mCurrentOemFunctions = oemFunctions;
                mCurrentFunctionsApplied = false;

                /**
                 * Kick the USB stack to close existing connections.
                 */
                //先关闭现有的usb连接
                setUsbConfig(UsbManager.USB_FUNCTION_NONE);
                //等待连接关闭成功
                if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
    
    
                    Slog.e(TAG, "Failed to kick USB config");
                    return false;
                }

                /**
                 * Set the new USB configuration.
                 */
                //设置新模式
                setUsbConfig(oemFunctions);

                if (mBootCompleted
                        && (containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
                        || containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
    
    
                    /**
                     * Start up dependent services.
                     */
                    updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
                }

                //等待新模式设置完毕
                if (!waitForState(oemFunctions)) {
    
    
                    Slog.e(TAG, "Failed to switch USB config to " + functions);
                    return false;
                }
				//标识位设为true,表示完成设置
                mCurrentFunctionsApplied = true;
            }
            return true;
        }
        
        private boolean waitForState(String state) {
    
    
            // wait for the transition to complete.
            // give up after 1 second.
            String value = null;
            //轮询二十次去获取当前usb的配置,每次轮询120毫秒
            for (int i = 0; i < 20; i++) {
    
    
                // State transition is done when sys.usb.state is set to the new configuration
                value = getSystemProperty(USB_STATE_PROPERTY, "");
                if (state.equals(value)) return true;
                //代码1:休眠120毫秒,原值为50
                SystemClock.sleep(120);
            }
            Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value);
            return false;
        }
        
        private void setUsbConfig(String config) {
    
    
            if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
            /**
             * set the new configuration
             * we always set it due to b/23631400, where adbd was getting killed
             * and not restarted due to property timeouts on some devices
             */
            //USB_CONFIG_PROPERTY的值为sys.usb.config
            setSystemProperty(USB_CONFIG_PROPERTY, config);
        }
        
        protected void setSystemProperty(String prop, String val) {
    
    
            SystemProperties.set(prop, val);
        }
        //省略部分代码
    }
    //省略部分代码
}

此方法核心思路就是,先关闭现在usb连接,如果当前usb不是不进行数据传输模式,比如当前是文件传输模式,那必定是存在一个usb连接,那么要先关闭这个连接,Android中,开启/关闭连接是一个耗时任务,所以通过轮询的方式去查找当前usb的配置,如果跟目标配置一致,说明任务完成了。然后再设置新模式,然后再次通过轮询的方式等待配置完成。而配置方式就是修改一个系统属性sys.usb.config的值,系统底层会监听此属性的变化,当此值被修改时,会往上层发送一个uevent消息,上层只要注册了这个监听,就可以收到此消息。底层监听在init.msm.usb.configfs.rc文件中

//省略部分代码
//此配置表示当sys.usb.config的值为accessory,audio_source并且sys.usb.configfs的值为1时执行下面的逻辑
on property:sys.usb.config=accessory,audio_source && property:sys.usb.configfs=1
	//写入供应商id
    write /config/usb_gadget/g1/idVendor 0x18d1
    //写入产品id
    write /config/usb_gadget/g1/idProduct 0x2d04

on property:sys.usb.config=accessory,audio_source,adb && property:sys.usb.configfs=1
    write /config/usb_gadget/g1/idVendor 0x18d1
    write /config/usb_gadget/g1/idProduct 0x2d05

on property:sys.usb.config=midi && property:sys.usb.configfs=1
    write /config/usb_gadget/g1/idVendor 0x18d1
    write /config/usb_gadget/g1/idProduct 0x4ee8

on property:sys.usb.config=midi,adb && property:sys.usb.configfs=1
    write /config/usb_gadget/g1/idVendor 0x18d1
    write /config/usb_gadget/g1/idProduct 0x4ee9
//省略部分代码

UsbDeviceManager在初始化时就注册了上层监听

public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObserver {
    
    
    private final UEventObserver mUEventObserver;
    //省略部分代码
	public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
            UsbSettingsManager settingsManager) {
    
    
        //省略部分代码
        //注册USB状态变化监听
    	// Watch for USB configuration changes
        mUEventObserver = new UsbUEventObserver();
        mUEventObserver.startObserving(USB_STATE_MATCH);
        mUEventObserver.startObserving(USB_STATE_MATCH_SEC);
        mUEventObserver.startObserving(ACCESSORY_START_MATCH);
    }
    
    /*
     * Listens for uevent messages from the kernel to monitor the USB state
     */
    private final class UsbUEventObserver extends UEventObserver {
    
    
        //usb状态变化会回调此方法
        @Override
        public void onUEvent(UEventObserver.UEvent event) {
    
    
            if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());

            String state = event.get("USB_STATE");
            String accessory = event.get("ACCESSORY");
            Log.d("jason", "onUEvent: state="+state+", accessory="+accessory);
            if (state != null) {
    
    
                //收到usb状态变化的消息,更新UI
                mHandler.updateState(state);
            } else if ("START".equals(accessory)) {
    
    
                if (DEBUG) Slog.d(TAG, "got accessory start");
                startAccessoryMode();
            }
        }
    }
    
    abstract static class UsbHandler extends Handler {
    
    
        //省略部分代码
        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);
            if (connected == 1) removeMessages(MSG_FUNCTION_SWITCH_TIMEOUT);
            Message msg = Message.obtain(this, MSG_UPDATE_STATE);
            msg.arg1 = connected;
            msg.arg2 = configured;
            // debounce disconnects to avoid problems bringing up USB tethering
            //代码2:如果connected为断开状态,则延迟3秒发送消息,原值为1秒
            sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY*3 : 0);
        }
        
        @Override
        public void handleMessage(Message msg) {
    
    
            switch (msg.what) {
    
    
                case MSG_UPDATE_STATE:
                    mConnected = (msg.arg1 == 1);
                    mConfigured = (msg.arg2 == 1);
					//更新通知栏
                    updateUsbNotification(false);
                    updateAdbNotification(false);
                    if (mBootCompleted) {
    
    
                        //发送一条usb状态变化的广播
                        updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
                    }
                    if ((mCurrentFunctions & UsbManager.FUNCTION_ACCESSORY) != 0) {
    
    
                        updateCurrentAccessory();
                    }
                    if (mBootCompleted) {
    
    
                        if (!mConnected && !hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT)
                                && !hasMessages(MSG_FUNCTION_SWITCH_TIMEOUT)) {
    
    
                            // restore defaults when USB is disconnected
                            if (!mScreenLocked
                                    && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
    
    
                                setScreenUnlockedFunctions();
                            } else {
    
    
                                setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
                            }
                        }
                        updateUsbFunctions();
                    } else {
    
    
                        mPendingBootBroadcast = true;
                    }
                    break;
                //省略部分代码
            }
        }
        //省略部分代码
    }
    //省略部分代码
}

监听消息无非就是为了更新UI,这里有一点需要说明一下,每次切换USB用途时,其状态都会经历DISCONNECTED->CONNECTED->CONFIGURED

以上就是USB切换的流程,整个流程图如下

usb用途切换

问题分析

通过上述分析可以看到,在设置USB新模式时,会执行waitForState()等待设置生效,这个等待通过轮询的方式,开启了一个20次的for循环,每次等待50毫秒,也就是最大等待时间为20*50=1000毫秒,而在收到UEvent消息之后,也会发送一个延迟消息,延迟时间为1000毫秒,可以看出,这个等待时间就是为了让设置生效之后再通知UI更新。这里有两处设计都使用了延迟的做法,那么我们尝试增大延迟时间,让整个操作有充分的时间去完成,我们将代码1和代码2处的值分别由原来的50ms增大到120ms,1000ms增大到3000ms,发现有效果,bug复现概率大大降低,说明我们的考虑思路是对的,但即便如此,仍然无法完全修复此问题,因为底层处理时间是不可控的,上层不可能无限增大这个延迟时间。

我们进一步反过来想,既然它会恢复默认设置,那必定是设置了一次UsbManager.FUNCTION_NONE,因此将所有设置此值的代码处打上log,然后看看是在哪儿执行了默认操作,最终发现是在handleMessage()中执行了

public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObserver {
    
    
    //省略部分代码
    abstract static class UsbHandler extends Handler {
    
    
        //省略部分代码
		@Override
        public void handleMessage(Message msg) {
    
    
            switch (msg.what) {
    
    
                case MSG_UPDATE_STATE:
                    mConnected = (msg.arg1 == 1);
                    mConfigured = (msg.arg2 == 1);

                    updateUsbNotification(false);
                    updateAdbNotification(false);
                    if (mBootCompleted) {
    
    
                        updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
                    }
                    if ((mCurrentFunctions & UsbManager.FUNCTION_ACCESSORY) != 0) {
    
    
                        updateCurrentAccessory();
                    }
                    if (mBootCompleted) {
    
    
                        if (!mConnected && !hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT)
                                && !hasMessages(MSG_FUNCTION_SWITCH_TIMEOUT)) {
    
    
                            // restore defaults when USB is disconnected
                            if (!mScreenLocked
                                    && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
    
    
                                setScreenUnlockedFunctions();
                            } else {
    
    
                                Log.d("jason", "handleMessage: update usb state, but the usb connected,mCurrentFunction:"+function2Name(mCurrentFunctions));
                                //代码3,执行了这里
                                setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
                            }
                        }
                        updateUsbFunctions();
                    } else {
    
    
                        mPendingBootBroadcast = true;
                    }
                    break;
            }
            //省略部分代码
        }
        //省略部分代码
    }
    //省略部分代码
}

而此处的逻辑是接收到消息后,如果此时usb断开链接,将恢复到默认设置,此时的mConnected为false,那为什么usb会断开连接呢,顺藤摸瓜,这个mConntected是消息中的arg1的值,而这个消息是在接收到uevent消息时发过来的,那么在uevent消息接收处打印该消息的内容

public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObserver {
    
    
    //省略部分代码
	private final class UsbUEventObserver extends UEventObserver {
    
    
        @Override
        public void onUEvent(UEventObserver.UEvent event) {
    
    
            if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());

            String state = event.get("USB_STATE");
            String accessory = event.get("ACCESSORY");
            //打印state
            Log.d("jason", "onUEvent: state="+state);
            if (state != null) {
    
    
                //更新状态
                mHandler.updateState(state);
            } else if ("START".equals(accessory)) {
    
    
                if (DEBUG) Slog.d(TAG, "got accessory start");
                startAccessoryMode();
            }
        }
    }
    //省略部分代码

    abstract static class UsbHandler extends Handler {
    
    
        //省略部分代码
		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);
            if (connected == 1) removeMessages(MSG_FUNCTION_SWITCH_TIMEOUT);
            Message msg = 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*3 : 0);
        }
        //省略部分代码
    }
    //省略部分代码
}

打印出来的日志为

日志2

可以发现,当切换一次usb用途时,usb的状态分别会有DISCONNECTED->CONNECTED->DISCONNECTED->CONNECTED->CONFIGURED,为什么执行两次DISCONNECTED呢,因为我们前面分析了,切换usb用途时会执行两次setUsbConfig(),第一次是断开现有的usb连接,第二次才是设置新值,所以执行两次DISCONNECTED和CONNECTED,而最终会变成CONFIGURED,表示配置成功了。而我们发现,当bug复现时的日志打印为

日志1

可以看到当上一次的操作结果还停留在DISCONNECTED时就切换usb用途,此时会执行代码3处,最终我们看到的现象就是USB恢复默认设置了。

那么问题的根本原因找到了,我们只需要在usb断开连接时不恢复默认操作即可,这里可以有两种做法

  • 不作任何操作,即代码3处注释掉setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
  • 保存最后一次的设置,即代码3处改为setEnabledFunctions(mCurrentFunctions, false);

经自测,两种方式都生效。此问题分析处理完毕。

总结

此问题能复现的根本原因还是在于底层切换usb太慢了,当上层暴力测试时,会出现两次操作的状态混乱,其实Google考虑到了这种情况,但它给的方案是恢复默认设置,我们只需要根据自己的需求更改方案即可。

猜你喜欢

转载自blog.csdn.net/u013936727/article/details/129129647