【BUG分析】手机插着USB时手动重启,USB功能选择菜单点不动

Bug复现条件:手机插着USB到PC上时重启,USB功能选择菜单点不动

Android版本:7.1.2

内核版本:3.18

  1. 首先,查看USB选择菜单是如何建立的。代码路径 :

android-7.1.2_r1\packages\apps\Settings\src\com\android\settings\deviceinfo\UsbModeChooserActivity.java

有一个广播接收器,代码如下:

    private BroadcastReceiver mDisconnectedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (UsbManager.ACTION_USB_STATE.equals(action)) {
                boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
                boolean hostConnected =
                        intent.getBooleanExtra(UsbManager.USB_HOST_CONNECTED, false);
                if (!connected && !hostConnected) {
                    mDialog.dismiss();
                }
            }
        }
    };

当connected和hostConnected都为false时,该Diaglog会消失。这两个变量都是由广播获取的。通过Log查看,开机时,有时这两个变量都为flase

2.查看广播的发送。代码路径: frameworks\base\services\usb\java\com\android\server\usb\UsbDeviceManager.java

发送广播在函数updateUsbStateBroadcastIfNeeded()中。这是个粘性广播。

手机开机首次调用这个函数是在handleMessage()中,代码如下:

                case MSG_SYSTEM_READY:
                    updateUsbNotification();
                    updateAdbNotification();
                    updateUsbStateBroadcastIfNeeded();
                    updateUsbFunctions();
                    break;
private void updateUsbStateBroadcastIfNeeded() {
            // 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_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() && mUsbDataUnlocked);

            if (mCurrentFunctions != null) {
                String[] functions = mCurrentFunctions.split(",");
                for (int i = 0; i < functions.length; i++) {
                    final String function = functions[i];
                    if (UsbManager.USB_FUNCTION_NONE.equals(function)) {
                        continue;
                    }
                    intent.putExtra(function, true);
                }
            }

            // send broadcast intent only if the USB state has changed
            if (!isUsbStateChanged(intent)) {
                if (DEBUG) {
                    Slog.d(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras());
                }
                return;
            }

            if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " extras: " + intent.getExtras());
            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
            mBroadcastedIntent = intent;
        }

函数updateUsbStateBroadcastIfNeeded()发送广播时的携带的变量mConnected。

3.查找mConnected第一次赋值的地方。代码如下:

case MSG_UPDATE_STATE:
                    mConnected = (msg.arg1 == 1);
                    mConfigured = (msg.arg2 == 1);

                    updateUsbNotification();
                    updateAdbNotification();
                    if (UsbManager.containsFunction(mCurrentFunctions,
                            UsbManager.USB_FUNCTION_ACCESSORY)) {
                        updateCurrentAccessory();
                    } else if (!mConnected) {
                        // restore defaults when USB is disconnected
                        setEnabledFunctions(null, false, false);
                    }
                    if (mBootCompleted) {
                        updateUsbStateBroadcastIfNeeded();
                        updateUsbFunctions();
                    }
                    break;

4. 找出发送MSG_UPDATE_STATE消息的地方,

 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);
            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 : 0);
        }

5.找到调用updateState函数的地方,有两处,第一处是在onUevent()函数的地方,代码如下:

private final UEventObserver mUEventObserver = new 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");
            if (state != null) {
                mHandler.updateState(state);
            } else if ("START".equals(accessory)) {
                if (DEBUG) Slog.d(TAG, "got accessory start");
                startAccessoryMode();
            }
        }
    };

该mUEventObserver主要是为了监听kernel层发送的uevent事件。 

另一处是在UsbHandler的构造函数中,

        public UsbHandler(Looper looper) {
            super(looper);
            try {
                // Restore default functions.
                mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
                        UsbManager.USB_FUNCTION_NONE);
                mCurrentFunctionsApplied = mCurrentFunctions.equals(
                        SystemProperties.get(USB_STATE_PROPERTY));
                mAdbEnabled = UsbManager.containsFunction(getDefaultFunctions(),
                        UsbManager.USB_FUNCTION_ADB);

                /**
                 * Remove MTP from persistent config, to bring usb to a good state
                 * after fixes to b/31814300. This block can be removed after the update
                 */
                String persisted = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY);
                if (UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_MTP)) {
                    SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY,
                            UsbManager.removeFunction(persisted, UsbManager.USB_FUNCTION_MTP));
                }

                setEnabledFunctions(null, false, false);

                String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
                updateState(state);

                // register observer to listen for settings changes
                mContentResolver.registerContentObserver(
                        Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
                                false, new AdbSettingsObserver());

                // Watch for USB configuration changes
                mUEventObserver.startObserving(USB_STATE_MATCH);
                mUEventObserver.startObserving(ACCESSORY_START_MATCH);
            } catch (Exception e) {
                Slog.e(TAG, "Error initializing UsbHandler", e);
            }
        }

6.造成该问题的主要原因是,kernel还未发送uevent事件,以更新状态。该广播已经发送出去了。所以,connected和hostConnected都为false。

7.修改,将updateUsbStateBroadcastIfNeeded()移动到case MSG_BOOT_COMPLETED中,延后广播的发送。

    case MSG_SYSTEM_READY:
                    updateUsbNotification();
                    updateAdbNotification();
                    //updateUsbStateBroadcastIfNeeded(); 删掉
                    updateUsbFunctions();
                    break;
                case MSG_BOOT_COMPLETED:
                    updateUsbStateBroadcastIfNeeded();//加上
                    mBootCompleted = true;
                    if (mCurrentAccessory != null) {
                        getCurrentSettings().accessoryAttached(mCurrentAccessory);
                    }
                    if (mDebuggingManager != null) {
                        mDebuggingManager.setAdbEnabled(mAdbEnabled);
                    }
                    break;

Android O上已经修改过来了。Android O的代码如下,

  case MSG_SYSTEM_READY:
                    updateUsbNotification();
                    updateAdbNotification();
                    updateUsbFunctions();
                    break;
                case MSG_BOOT_COMPLETED:
                    mBootCompleted = true;
                    if (mPendingBootBroadcast) {
                        updateUsbStateBroadcastIfNeeded(false);
                        mPendingBootBroadcast = false;
                    }
                    setEnabledFunctions(null, false, false);
                    if (mCurrentAccessory != null) {
                        getCurrentSettings().accessoryAttached(mCurrentAccessory);
                    }
                    if (mDebuggingManager != null) {
                        mDebuggingManager.setAdbEnabled(mAdbEnabled);
                    }
                    break;

总的来说,出现该问题的主要原因在于kernel与framework之间启动时序有问题,也有可能是kernel识别USB的速度慢造成的。

你可能感兴趣的:(Android框架,USB)