Android UsbDeviceManager 程式碼分析

yooooooo發表於2024-08-19

USBDeviceManager是一個Android系統中用於管理USB裝置的類,它是系統服務之一。其主要功能是控制USB裝置的連線和斷開,以及管理USB裝置的許可權和狀態。下面是對USBDeviceManager程式碼的簡要分析:

USBDeviceManager的建構函式:
在USBDeviceManager的建構函式中,它會呼叫系統服務框架的registerService方法,將自己註冊為系統服務。在註冊完成後,會建立一個名為"usb"的UEventObserver物件,並透過該物件註冊監聽USB裝置插入和拔出事件的廣播接收器。同時,它還會建立一個名為"android.hardware.usb.UsbDeviceManager.action.USB_STATE"的IntentFilter物件,並透過該物件註冊監聽USB裝置狀態變化的廣播接收器。

onReceive方法:
當收到廣播事件時,會呼叫onReceive方法來處理事件。在該方法中,它會獲取廣播中包含的裝置狀態資訊,並根據狀態資訊來執行不同的操作,例如檢查許可權、傳送USB裝置插入/拔出的廣播、更新USB裝置的狀態等。

getDeviceList方法:
該方法用於獲取當前已連線的USB裝置列表。它會呼叫系統服務的getUsbManager方法來獲取UsbManager物件,然後呼叫UsbManager物件的getDeviceList方法來獲取裝置列表。

setDevicePackage方法:
該方法用於設定USB裝置的包名。它會檢查包名是否存在,並將包名儲存到SharedPreferences中。

setCurrentUser方法:USBDeviceManager是一個Android系統中用於管理USB裝置的類,它是系統服務之一。其主要功能是控制USB裝置的連線和斷開,以及管理USB裝置的許可權和狀態。下面是對USBDeviceManager程式碼的簡要分析:

USBDeviceManager的建構函式:
在USBDeviceManager的建構函式中,它會呼叫系統服務框架的registerService方法,將自己註冊為系統服務。在註冊完成後,會建立一個名為"usb"的UEventObserver物件,並透過該物件註冊監聽USB裝置插入和拔出事件的廣播接收器。同時,它還會建立一個名為"android.hardware.usb.UsbDeviceManager.action.USB_STATE"的IntentFilter物件,並透過該物件註冊監聽USB裝置狀態變化的廣播接收器。

onReceive方法:
當收到廣播事件時,會呼叫onReceive方法來處理事件。在該方法中,它會獲取廣播中包含的裝置狀態資訊,並根據狀態資訊來執行不同的操作,例如檢查許可權、傳送USB裝置插入/拔出的廣播、更新USB裝置的狀態等。

getDeviceList方法:
該方法用於獲取當前已連線的USB裝置列表。它會呼叫系統服務的getUsbManager方法來獲取UsbManager物件,然後呼叫UsbManager物件的getDeviceList方法來獲取裝置列表。

setDevicePackage方法:
該方法用於設定USB裝置的包名。它會檢查包名是否存在,並將包名儲存到SharedPreferences中。

setCurrentUser方法:
該方法用於設定當前使用者。它會將當前使用者ID儲存到SharedPreferences中。

setPermission方法:
該方法用於設定USB裝置的許可權。它會檢查當前應用程式是否具有許可權,如果沒有,則向使用者發出請求。如果使用者同意,則呼叫UsbManager物件的grantPermission方法授予許可權。

總的來說,USBDeviceManager類是Android系統中用於管理USB裝置的重要類之一。透過它可以實現USB裝置的連線和斷開、許可權的控制、狀態的管理等功能,為上層應用提供方便的USB裝置管理介面。

UsbDeviceManager的建構函式

public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
            UsbSettingsManager settingsManager, UsbPermissionManager permissionManager) {
    mContext = context;
    mContentResolver = context.getContentResolver();
    PackageManager pm = mContext.getPackageManager();
    mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
    initRndisAddress();

    int operationId = sUsbOperationCount.incrementAndGet();
    boolean halNotPresent = false;

    mUsbGadgetHal = UsbGadgetHalInstance.getInstance(this, null);
    Slog.d(TAG, "getInstance done");

    mControlFds = new HashMap<>();
    FileDescriptor mtpFd = nativeOpenControl(UsbManager.USB_FUNCTION_MTP);
    if (mtpFd == null) {
        Slog.e(TAG, "Failed to open control for mtp");
    }
    mControlFds.put(UsbManager.FUNCTION_MTP, mtpFd);
    FileDescriptor ptpFd = nativeOpenControl(UsbManager.USB_FUNCTION_PTP);
    if (ptpFd == null) {
        Slog.e(TAG, "Failed to open control for ptp");
    }
    mControlFds.put(UsbManager.FUNCTION_PTP, ptpFd);

    if (mUsbGadgetHal == null) {
        /**
         * Initialze the legacy UsbHandler
         */
        mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(), mContext, this,
                alsaManager, permissionManager);
    } else {
        /**
         * Initialize HAL based UsbHandler
         */
        mHandler = new UsbHandlerHal(FgThread.get().getLooper(), mContext, this,
                alsaManager, permissionManager);
    }

    mHandler.handlerInitDone(operationId);

    if (nativeIsStartRequested()) {
        if (DEBUG) Slog.d(TAG, "accessory attached at boot");
        startAccessoryMode();
    }

    BroadcastReceiver portReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            ParcelableUsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT, android.hardware.usb.ParcelableUsbPort.class);
            UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS, android.hardware.usb.UsbPortStatus.class);
            mHandler.updateHostState(
                    port.getUsbPort(context.getSystemService(UsbManager.class)), status);
        }
    };

    BroadcastReceiver chargingReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
            boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
            mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging);
        }
    };

    BroadcastReceiver hostReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Iterator devices = ((UsbManager) context.getSystemService(Context.USB_SERVICE))
                    .getDeviceList().entrySet().iterator();
            if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
                mHandler.sendMessage(MSG_UPDATE_HOST_STATE, devices, true);
            } else {
                mHandler.sendMessage(MSG_UPDATE_HOST_STATE, devices, false);
            }
        }
    };

    BroadcastReceiver languageChangedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            mHandler.sendEmptyMessage(MSG_LOCALE_CHANGED);
        }
    };

    mContext.registerReceiver(portReceiver,
            new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
    mContext.registerReceiver(chargingReceiver,
            new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

    IntentFilter filter =
            new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
    filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
    mContext.registerReceiver(hostReceiver, filter);

    mContext.registerReceiver(languageChangedReceiver,
            new IntentFilter(Intent.ACTION_LOCALE_CHANGED));

    // Watch for USB configuration changes
    mUEventObserver = new UsbUEventObserver();
    mUEventObserver.startObserving(USB_STATE_MATCH);
    mUEventObserver.startObserving(ACCESSORY_START_MATCH);

    sEventLogger = new EventLogger(DUMPSYS_LOG_BUFFER, "UsbDeviceManager activity");
}

這段程式碼是 Android 系統中的 UsbDeviceManager 類的建構函式,用於初始化和管理 Android 裝置作為 USB 裝置時的各種功能和狀態。這是一個核心部分,負責處理 USB 相關的任務。讓我們分段分析這段程式碼:

1. Context 和初始化

mContext = context;
mContentResolver = context.getContentResolver();
PackageManager pm = mContext.getPackageManager();
mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
initRndisAddress();
  • 這些行程式碼儲存了 ContextContentResolver,並檢查裝置是否支援 USB 附件(Accessory)功能,同時呼叫 initRndisAddress() 來初始化 RNDIS(Remote Network Driver Interface Specification)地址。

2. USB Gadget HAL 例項化

int operationId = sUsbOperationCount.incrementAndGet();
boolean halNotPresent = false;

mUsbGadgetHal = UsbGadgetHalInstance.getInstance(this, null);
Slog.d(TAG, "getInstance done");
  • 這段程式碼遞增了 USB 操作計數器,並嘗試獲取 UsbGadgetHalInstance 的例項。UsbGadgetHal 是用於管理 USB Gadget(裝置端)的 HAL(Hardware Abstraction Layer)。獲取例項後會輸出一條日誌。

3. 檔案描述符初始化

mControlFds = new HashMap<>();
FileDescriptor mtpFd = nativeOpenControl(UsbManager.USB_FUNCTION_MTP);
if (mtpFd == null) {
    Slog.e(TAG, "Failed to open control for mtp");
}
mControlFds.put(UsbManager.FUNCTION_MTP, mtpFd);
FileDescriptor ptpFd = nativeOpenControl(UsbManager.USB_FUNCTION_PTP);
if (ptpFd == null) {
    Slog.e(TAG, "Failed to open control for ptp");
}
mControlFds.put(UsbManager.FUNCTION_PTP, ptpFd);
  • 這部分程式碼透過本地方法 nativeOpenControl() 開啟控制 USB 功能的檔案描述符(MTP 和 PTP),並將它們儲存在 mControlFds HashMap 中。如果無法開啟檔案描述符,系統會記錄錯誤日誌。

4. USB Handler 初始化

if (mUsbGadgetHal == null) {
    /**
     * Initialze the legacy UsbHandler
     */
    mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(), mContext, this,
            alsaManager, permissionManager);
} else {
    /**
     * Initialize HAL based UsbHandler
     */
    mHandler = new UsbHandlerHal(FgThread.get().getLooper(), mContext, this,
            alsaManager, permissionManager);
}

mHandler.handlerInitDone(operationId);
  • 根據 UsbGadgetHal 是否可用,初始化適當的 USB Handler。UsbHandlerLegacy 用於不支援 HAL 的情況,UsbHandlerHal 用於支援 HAL 的情況。初始化完成後,呼叫 handlerInitDone() 方法。

5. 處理啟動時的配件模式

if (nativeIsStartRequested()) {
    if (DEBUG) Slog.d(TAG, "accessory attached at boot");
    startAccessoryMode();
}
  • 檢查是否請求啟動,如果在啟動時連線了 USB 配件(Accessory),系統會啟動配件模式。

6. 註冊系統廣播接收器

BroadcastReceiver portReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        ParcelableUsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT, android.hardware.usb.ParcelableUsbPort.class);
        UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS, android.hardware.usb.UsbPortStatus.class);
        mHandler.updateHostState(
                port.getUsbPort(context.getSystemService(UsbManager.class)), status);
    }
};

BroadcastReceiver chargingReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
        boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
        mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging);
    }
};

BroadcastReceiver hostReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Iterator devices = ((UsbManager) context.getSystemService(Context.USB_SERVICE))
                .getDeviceList().entrySet().iterator();
        if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
            mHandler.sendMessage(MSG_UPDATE_HOST_STATE, devices, true);
        } else {
            mHandler.sendMessage(MSG_UPDATE_HOST_STATE, devices, false);
        }
    }
};

BroadcastReceiver languageChangedReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        mHandler.sendEmptyMessage(MSG_LOCALE_CHANGED);
    }
};

mContext.registerReceiver(portReceiver,
        new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
mContext.registerReceiver(chargingReceiver,
        new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

IntentFilter filter =
        new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
mContext.registerReceiver(hostReceiver, filter);

mContext.registerReceiver(languageChangedReceiver,
        new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
  • 註冊了多個廣播接收器:
    • portReceiver: 監聽 USB 埠狀態變化(UsbManager.ACTION_USB_PORT_CHANGED)。
    • chargingReceiver: 監聽充電狀態變化(Intent.ACTION_BATTERY_CHANGED)。
    • hostReceiver: 監聽 USB 裝置連線和斷開(UsbManager.ACTION_USB_DEVICE_ATTACHEDUsbManager.ACTION_USB_DEVICE_DETACHED)。
    • languageChangedReceiver: 監聽系統語言變化(Intent.ACTION_LOCALE_CHANGED)。

7. 啟動 UEvent 觀察者

mUEventObserver = new UsbUEventObserver();
mUEventObserver.startObserving(USB_STATE_MATCH);
mUEventObserver.startObserving(ACCESSORY_START_MATCH);

sEventLogger = new EventLogger(DUMPSYS_LOG_BUFFER, "UsbDeviceManager activity");
  • 建立並啟動了 UsbUEventObserver,用於監聽核心事件(UEvent),這些事件通常與 USB 狀態變化有關。USB_STATE_MATCHACCESSORY_START_MATCH 是要觀察的事件模式。

  • 最後,初始化了一個事件日誌記錄器 sEventLogger,用於記錄 USB 裝置管理器的活動。

該方法用於設定當前使用者。它會將當前使用者ID儲存到SharedPreferences中。

setPermission方法:
該方法用於設定USB裝置的許可權。它會檢查當前應用程式是否具有許可權,如果沒有,則向使用者發出請求。如果使用者同意,則呼叫UsbManager物件的grantPermission方法授予許可權。

總的來說,USBDeviceManager類是Android系統中用於管理USB裝置的重要類之一。透過它可以實現USB裝置的連線和斷開、許可權的控制、狀態的管理等功能,為上層應用提供方便的USB裝置管理介面。

UsbDeviceManager 中 UsbHandlerLegacy 物件

UsbDeviceManager 中,UsbHandlerLegacy 物件是一個處理 USB 相關事件的類。它主要負責處理 USB 裝置的連線、斷開、資料傳輸等操作。

	private static final class UsbHandlerLegacy extends UsbHandler {
        /**
         * The non-persistent property which stores the current USB settings.
         */
        private static final String USB_CONFIG_PROPERTY = "sys.usb.config";

        /**
         * The non-persistent property which stores the current USB actual state.
         */
        private static final String USB_STATE_PROPERTY = "sys.usb.state";

        private HashMap<String, HashMap<String, Pair<String, String>>> mOemModeMap;
        private String mCurrentOemFunctions;
        private String mCurrentFunctionsStr;
        private boolean mUsbDataUnlocked;

        /**
         * Keeps track of the latest setCurrentUsbFunctions request number.
         */
        private int mCurrentRequest = 0;

        UsbHandlerLegacy(Looper looper, Context context, UsbDeviceManager deviceManager,
                UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
            super(looper, context, deviceManager, alsaManager, permissionManager);
            try {
                readOemUsbOverrideConfig(context);
                // Restore default functions.
                mCurrentOemFunctions = getSystemProperty(getPersistProp(false),
                        UsbManager.USB_FUNCTION_NONE);
                if (isNormalBoot()) {
                    mCurrentFunctionsStr = getSystemProperty(USB_CONFIG_PROPERTY,
                            UsbManager.USB_FUNCTION_NONE);
                    mCurrentFunctionsApplied = mCurrentFunctionsStr.equals(
                            getSystemProperty(USB_STATE_PROPERTY, UsbManager.USB_FUNCTION_NONE));
                } else {
                    mCurrentFunctionsStr = getSystemProperty(getPersistProp(true),
                            UsbManager.USB_FUNCTION_NONE);
                    mCurrentFunctionsApplied = getSystemProperty(USB_CONFIG_PROPERTY,
                            UsbManager.USB_FUNCTION_NONE).equals(
                            getSystemProperty(USB_STATE_PROPERTY, UsbManager.USB_FUNCTION_NONE));
                }
                mCurrentFunctions = UsbManager.FUNCTION_NONE;
                mCurrentUsbFunctionsReceived = true;

                mUsbSpeed = UsbSpeed.UNKNOWN;
                mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_NOT_SUPPORTED;

                String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
                updateState(state);
            } catch (Exception e) {
                Slog.e(TAG, "Error initializing UsbHandler", e);
            }
        }

        @Override
        public void handlerInitDone(int operationId) {
        }

        private void readOemUsbOverrideConfig(Context context) {
            String[] configList = context.getResources().getStringArray(
                    com.android.internal.R.array.config_oemUsbModeOverride);

            if (configList != null) {
                for (String config : configList) {
                    String[] items = config.split(":");
                    if (items.length == 3 || items.length == 4) {
                        if (mOemModeMap == null) {
                            mOemModeMap = new HashMap<>();
                        }
                        HashMap<String, Pair<String, String>> overrideMap =
                                mOemModeMap.get(items[0]);
                        if (overrideMap == null) {
                            overrideMap = new HashMap<>();
                            mOemModeMap.put(items[0], overrideMap);
                        }

                        // Favoring the first combination if duplicate exists
                        if (!overrideMap.containsKey(items[1])) {
                            if (items.length == 3) {
                                overrideMap.put(items[1], new Pair<>(items[2], ""));
                            } else {
                                overrideMap.put(items[1], new Pair<>(items[2], items[3]));
                            }
                        }
                    }
                }
            }
        }

        private String applyOemOverrideFunction(String usbFunctions) {
            if ((usbFunctions == null) || (mOemModeMap == null)) {
                return usbFunctions;
            }

            String bootMode = getSystemProperty(BOOT_MODE_PROPERTY, "unknown");
            Slog.d(TAG, "applyOemOverride usbfunctions=" + usbFunctions + " bootmode=" + bootMode);

            Map<String, Pair<String, String>> overridesMap =
                    mOemModeMap.get(bootMode);
            // Check to ensure that the oem is not overriding in the normal
            // boot mode
            if (overridesMap != null && !(bootMode.equals(NORMAL_BOOT)
                    || bootMode.equals("unknown"))) {
                Pair<String, String> overrideFunctions =
                        overridesMap.get(usbFunctions);
                if (overrideFunctions != null) {
                    Slog.d(TAG, "OEM USB override: " + usbFunctions
                            + " ==> " + overrideFunctions.first
                            + " persist across reboot "
                            + overrideFunctions.second);
                    if (!overrideFunctions.second.equals("")) {
                        String newFunction;
                        if (isAdbEnabled()) {
                            newFunction = addFunction(overrideFunctions.second,
                                    UsbManager.USB_FUNCTION_ADB);
                        } else {
                            newFunction = overrideFunctions.second;
                        }
                        Slog.d(TAG, "OEM USB override persisting: " + newFunction + "in prop: "
                                + getPersistProp(false));
                        setSystemProperty(getPersistProp(false), newFunction);
                    }
                    return overrideFunctions.first;
                } else if (isAdbEnabled()) {
                    String newFunction = addFunction(UsbManager.USB_FUNCTION_NONE,
                            UsbManager.USB_FUNCTION_ADB);
                    setSystemProperty(getPersistProp(false), newFunction);
                } else {
                    setSystemProperty(getPersistProp(false), UsbManager.USB_FUNCTION_NONE);
                }
            }
            // return passed in functions as is.
            return usbFunctions;
        }

        private boolean waitForState(String state) {
            // wait for the transition to complete.
            // give up after 1 second.
            String value = null;
            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;
                SystemClock.sleep(50);
            }
            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
             */
            setSystemProperty(USB_CONFIG_PROPERTY, config);
        }

        @Override
        protected void setEnabledFunctions(long usbFunctions,
                boolean forceRestart, int operationId) {
            boolean usbDataUnlocked = isUsbDataTransferActive(usbFunctions);
            if (DEBUG) {
                Slog.d(TAG, "setEnabledFunctions functions=" + usbFunctions +
                        " ,forceRestart=" + forceRestart +
                        " ,usbDataUnlocked=" + usbDataUnlocked +
                        " ,operationId=" + operationId);
            }

            if (usbDataUnlocked != mUsbDataUnlocked) {
                mUsbDataUnlocked = usbDataUnlocked;
                updateUsbNotification(false);
                forceRestart = true;
            }

            /**
             * Try to set the enabled functions.
             */
            final long oldFunctions = mCurrentFunctions;
            final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
            if (trySetEnabledFunctions(usbFunctions, forceRestart)) {
                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.");
                if (trySetEnabledFunctions(oldFunctions, false)) {
                    return;
                }
            }

            /**
             * Still didn't work.  Try to restore the default functions.
             */
            Slog.e(TAG, "Failsafe 2: Restoring default USB functions.");
            if (trySetEnabledFunctions(UsbManager.FUNCTION_NONE, false)) {
                return;
            }

            /**
             * Now we're desperate.  Ignore the default functions.
             * Try to get ADB working if enabled.
             */
            Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled).");
            if (trySetEnabledFunctions(UsbManager.FUNCTION_NONE, false)) {
                return;
            }

            /**
             * Ouch.
             */
            Slog.e(TAG, "Unable to set any USB functions!");
        }

        private boolean isNormalBoot() {
            String bootMode = getSystemProperty(BOOT_MODE_PROPERTY, "unknown");
            return bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown");
        }

        protected String applyAdbFunction(String functions) {
            // Do not pass null pointer to the UsbManager.
            // There isn't a check there.
            if (functions == null) {
                functions = "";
            }
            if (isAdbEnabled()) {
                functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
            } else {
                functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
            }
            return functions;
        }

        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 = 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) {
                mCurrentFunctionsStr = functions;
                mCurrentOemFunctions = oemFunctions;
                mCurrentFunctionsApplied = false;

                /**
                 * Kick the USB stack to close existing connections.
                 */
                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;
                }

                mCurrentFunctionsApplied = true;
            }
            return true;
        }

        private String getPersistProp(boolean functions) {
            String bootMode = getSystemProperty(BOOT_MODE_PROPERTY, "unknown");
            String persistProp = USB_PERSISTENT_CONFIG_PROPERTY;
            if (!(bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"))) {
                if (functions) {
                    persistProp = "persist.sys.usb." + bootMode + ".func";
                } else {
                    persistProp = "persist.sys.usb." + bootMode + ".config";
                }
            }
            return persistProp;
        }

        private static String addFunction(String functions, String function) {
            if (UsbManager.USB_FUNCTION_NONE.equals(functions)) {
                return function;
            }
            if (!containsFunction(functions, function)) {
                if (functions.length() > 0) {
                    functions += ",";
                }
                functions += function;
            }
            return functions;
        }

        private static String removeFunction(String functions, String function) {
            String[] split = functions.split(",");
            for (int i = 0; i < split.length; i++) {
                if (function.equals(split[i])) {
                    split[i] = null;
                }
            }
            if (split.length == 1 && split[0] == null) {
                return UsbManager.USB_FUNCTION_NONE;
            }
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < split.length; i++) {
                String s = split[i];
                if (s != null) {
                    if (builder.length() > 0) {
                        builder.append(",");
                    }
                    builder.append(s);
                }
            }
            return builder.toString();
        }

        static boolean containsFunction(String functions, String function) {
            int index = functions.indexOf(function);
            if (index < 0) return false;
            if (index > 0 && functions.charAt(index - 1) != ',') return false;
            int charAfter = index + function.length();
            if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
            return true;
        }

        /**
         * This callback function is only applicable for USB Gadget HAL,
         * USBHandlerLegacy does not supported it.
         */
        @Override
        public void setCurrentUsbFunctionsCb(long functions,
                    int status, int mRequest, long mFunctions, boolean mChargingFunctions){
        }

        /**
         * This callback function is only applicable for USB Gadget HAL,
         * USBHandlerLegacy does not supported it.
         */
        @Override
        public void getUsbSpeedCb(int speed){
        }

        /**
         * This callback function is only applicable for USB Gadget HAL,
         * USBHandlerLegacy does not supported it.
         */
        @Override
        public void resetCb(int status){
        }
    }

這段程式碼定義了一個名為 UsbHandlerLegacy 的類,該類繼承自 UsbHandler,用於處理 Android 系統中的 USB 配置和管理。以下是程式碼的主要功能和流程的簡要說明:

建構函式 UsbHandlerLegacy

  • 初始化方法,負責讀取 OEM USB 覆蓋配置 (readOemUsbOverrideConfig),恢復預設功能,並更新 USB 狀態。
  • 根據裝置的啟動模式(普通啟動或其他模式)來獲取並設定當前 USB 的功能狀態。

核心方法:

  1. readOemUsbOverrideConfig

    • 讀取 OEM 的 USB 模式覆蓋配置,儲存到 mOemModeMap 中。該配置可能包含與不同啟動模式相關的 USB 功能。
  2. applyOemOverrideFunction

    • 根據當前啟動模式和 USB 功能,應用 OEM 的覆蓋功能,調整系統的 USB 設定。
  3. waitForState

    • 等待 USB 狀態的轉換完成,透過檢查 USB_STATE_PROPERTY 的值來確認是否完成。
  4. setUsbConfig

    • 設定新的 USB 配置,通常透過更改 USB_CONFIG_PROPERTY 的值來實現。
  5. setEnabledFunctions

    • 啟用指定的 USB 功能,並在必要時強制重新啟動 USB 子系統。如果設定失敗,則嘗試恢復到先前的功能或預設功能。
  6. trySetEnabledFunctions

    • 嘗試設定啟用的 USB 功能,應用 ADB 和 OEM 的覆蓋配置,更新系統屬性,並透過呼叫 waitForState 確認配置是否生效。
  7. applyAdbFunction

    • 根據當前 ADB(Android 除錯橋)的狀態,新增或移除 USB 功能字串中的 ADB 功能。
  8. getPersistProp

    • 根據裝置的啟動模式,返回適當的持久化屬性名稱。

回撥方法:

  • setCurrentUsbFunctionsCb, getUsbSpeedCb, resetCb:這些方法在 USB Gadget HAL(硬體抽象層)中是適用的,但在 UsbHandlerLegacy 中沒有實現。

整體流程:

UsbHandlerLegacy的建構函式大致分為三步。首先看第一步,讀取oem廠商的關於usb功能的覆蓋配置。

        private void readOemUsbOverrideConfig(Context context) {
            // 陣列每一項的格式為[bootmode]:[original USB mode]:[USB mode used]
            String[] configList = context.getResources().getStringArray(
                    com.android.internal.R.array.config_oemUsbModeOverride);

            if (configList != null) {
                for (String config : configList) {
                    String[] items = config.split(":");
                    if (items.length == 3 || items.length == 4) {
                        if (mOemModeMap == null) {
                            mOemModeMap = new HashMap<>();
                        }
                        HashMap<String, Pair<String, String>> overrideMap =
                                mOemModeMap.get(items[0]);
                        if (overrideMap == null) {
                            overrideMap = new HashMap<>();
                            mOemModeMap.put(items[0], overrideMap);
                        }

                        // Favoring the first combination if duplicate exists
                        if (!overrideMap.containsKey(items[1])) {
                            if (items.length == 3) {
                                overrideMap.put(items[1], new Pair<>(items[2], ""));
                            } else {
                                overrideMap.put(items[1], new Pair<>(items[2], items[3]));
                            }
                        }
                    }
                }
            }
        }

讀取的是config_oemUsbModeOverride陣列,然後儲存到mOemModeMap中。陣列每一項的格式為[bootmode]:[original USB mode]:[USB mode used],儲存的格式可以大致描述為HashMap<bootmode, HashMap<original_usb_mode, Pair<usb_mode_used, "">。我的專案中,這個陣列為空。

然後第二步,讀取了各種屬性值(只考慮正常啟動模式),如下。

  1. mCurrentOemFunctions的值是persist.sys.usb.config屬性的值。按照原始碼註釋,這個屬性值儲存了adb的開啟狀態(如果開啟了adb,那麼這個值會包含adb字串)。另外,原始碼註釋說這個屬性也可以運營商定製的一些功能,但是隻用於測試目的。
  2. mCurrentFunctionsStr的值是sys.usb.config屬性值。這個屬性表示當前設定的usb功能的值。在日常工作中,我們可以透過adb shell命令設定這個屬性值來切換usb功能,例如adb shell setprop sys.usb.config mtp,adb可以切換到mtp功能。
  3. 如果透過sys.usb.config屬性切換功能成功,那麼sys.usb.state屬性值就與sys.usb.config屬性值一樣。也就是說sys.usb.state代表usb的實際功能的值。所以,可以透過比較這兩個屬性值來判斷usb所有功能是否切換成功,如果成功了,mCurrentFunctionsApplied的值為1,否則為0。

第三步,讀取了當前usb狀態,並且做了一次更新操作。更新操作會傳送相關通知,以及傳送廣播,但是現在處理服務建立階段,這個操作都無法執行,因此這裡不做分析。但是當處理系統就緒階段或系統啟動完畢階段,就可以做相應的操作,在後面的分析中可以看到。

系統就緒階段

根據前面的程式碼,在系統就緒階段,會呼叫UsbService的systemRead()方法,然後轉到UsbDeviceManager的systemRead()方法

    public void systemReady() {
        // 註冊一個關於螢幕狀態的回撥,有兩個方法
        LocalServices.getService(ActivityTaskManagerInternal.class).registerScreenObserver(this);

        mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
    }

首先註冊了一個關於螢幕的回撥,這個回撥用於處理在安全鎖屏下,設定usb的功能。但是這個功能好像處於開發階段,只能透過adb shell命令操作,透過輸入adb shell svc usb可以檢視使用幫助。

接下來,傳送了一個訊息MSG_SYSTEM_READY,我們來看下這個訊息是如何處理的

        case MSG_SYSTEM_READY:
            // 獲取到notification服務介面
            mNotificationManager = (NotificationManager)
                    mContext.getSystemService(Context.NOTIFICATION_SERVICE);

            // 向adb service註冊一個回撥,用於狀態adb相關的狀態
            LocalServices.getService(
                    AdbManagerInternal.class).registerTransport(new AdbTransport(this));

            // Ensure that the notification channels are set up
            if (isTv()) {
                // ...
            }
            // 設定系統就緒的標誌位
            mSystemReady = true;
            // 此時系統還沒有啟動完成,這裡沒有做任何事
            // 這應該是歷史原因造成的程式碼冗餘
            finishBoot();
            break;

系統啟動完畢階段

現在來看下最後一個階段,系統啟動完畢階段。根據前面的程式碼,會呼叫UsbService的bootcompleted()方法,然後呼叫UsbDeviceManager的bootcompleted()方法

    public void bootCompleted() {
        mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
    }

只是傳送了一條訊息,看下訊息如何處理的

        case MSG_BOOT_COMPLETED:
			// 設定系統啟動完成的標誌
            mBootCompleted = true;
            finishBoot();
            break;

finishBoot()方法

很簡單,設定了一個啟動標誌,然後就呼叫finishBoot()方法完成最後的任務

protected void finishBoot(int operationId) {
    if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) {
        if (mPendingBootBroadcast) {
            updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
            mPendingBootBroadcast = false;
        }
        if (!mScreenLocked
                && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
            setScreenUnlockedFunctions(operationId);
        } else {
            setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
        }
        if (mCurrentAccessory != null) {
            mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
            broadcastUsbAccessoryHandshake();
        } else if (mPendingBootAccessoryHandshakeBroadcast) {
            broadcastUsbAccessoryHandshake();
        }

        mPendingBootAccessoryHandshakeBroadcast = false;
        updateUsbNotification(false);
        updateAdbNotification(false);
        updateUsbFunctions();
    }
}

這個函式名為 finishBoot,在 Android 系統中用於完成裝置啟動過程中與 USB 相關的操作。該函式確保在裝置啟動完成後,USB 功能配置正確,並處理與 USB 相關的任務。下面是函式的主要功能和操作步驟:

函式功能:

finishBoot 函式在裝置啟動完成後執行,並根據當前的系統狀態和 USB 狀態做出相應的處理。函式的執行依賴於以下三個條件:

  1. mBootCompleted:表示裝置啟動已完成。
  2. mCurrentUsbFunctionsReceived:表示當前 USB 功能已經接收並處理。
  3. mSystemReady:表示系統已準備好(可能指系統服務或其他依賴已啟動)。

主要操作步驟:

  1. 廣播 USB 狀態更新:

    • 如果 mPendingBootBroadcasttrue,表示有掛起的 USB 狀態廣播需要傳送。函式會呼叫 updateUsbStateBroadcastIfNeeded 傳送廣播,更新 USB 狀態,然後將 mPendingBootBroadcast 設定為 false
  2. 設定螢幕解鎖後的 USB 功能:

    • 如果裝置螢幕未鎖定 (mScreenLockedfalse),並且 mScreenUnlockedFunctions 的值不為 UsbManager.FUNCTION_NONE(即有特定功能要在解鎖後啟用),則呼叫 setScreenUnlockedFunctions 設定這些功能。
    • 否則,呼叫 setEnabledFunctions,將 USB 功能設定為 UsbManager.FUNCTION_NONE
  3. 處理 USB 附件:

    • 如果當前有連線的 USB 附件 (mCurrentAccessory 不為 null),則通知 USB 裝置管理器(mUsbDeviceManager)附件已連線,並廣播 USB 附件握手事件。
    • 如果沒有連線的 USB 附件但有掛起的握手廣播 (mPendingBootAccessoryHandshakeBroadcasttrue),則廣播 USB 附件握手事件。
  4. 更新狀態和通知:

    • mPendingBootAccessoryHandshakeBroadcast 設定為 false,表示不再有掛起的 USB 附件握手廣播。
    • 呼叫 updateUsbNotification(false) 更新 USB 相關的通知。
    • 呼叫 updateAdbNotification(false) 更新 ADB 相關的通知。
    • 呼叫 updateUsbFunctions() 更新當前的 USB 功能配置。

如果現在手機沒有透過USB線連線電腦,那麼第一步的傳送USB狀態廣播,第三步的USB通知,第四步adb通知,都無法執行。唯一能執行的就是第二步,設定USB功能為NONE。

setEnabledFunctions函式:

OK,現在終於到最關鍵的一步,設定USB功能,它呼叫的是setEnabledFunctions()方法。這個方法本身是一想抽象方法,在我的專案中,實現類為UsbHandlerLegacy

 /**
 * Evaluates USB function policies and applies the change accordingly.
 */
protected abstract void setEnabledFunctions(long functions,
        boolean forceRestart, int operationId);
        
 protected void setEnabledFunctions(long functions, boolean forceRestart, int operationId) {
            if (DEBUG) {
                Slog.d(TAG, "setEnabledFunctionsi " +
                        "functions=" + functions +
                        ", forceRestart=" + forceRestart +
                        ", operationId=" + operationId);
            }
            if (mCurrentGadgetHalVersion < UsbManager.GADGET_HAL_V1_2) {
                if ((functions & UsbManager.FUNCTION_NCM) != 0) {
                    Slog.e(TAG, "Could not set unsupported function for the GadgetHal");
                    return;
                }
            }
            if (mCurrentFunctions != functions
                    || !mCurrentFunctionsApplied
                    || forceRestart) {
                Slog.i(TAG, "Setting USB config to " + UsbManager.usbFunctionsToString(functions));
                mCurrentFunctions = functions;
                mCurrentFunctionsApplied = false;
                // set the flag to false as that would be stale value
                mCurrentUsbFunctionsRequested = false;

                boolean chargingFunctions = functions == UsbManager.FUNCTION_NONE;
                functions = getAppliedFunctions(functions);

                // Set the new USB configuration.
                setUsbConfig(functions, chargingFunctions, operationId);

                if (mBootCompleted && isUsbDataTransferActive(functions)) {
                    // Start up dependent services.
                    updateUsbStateBroadcastIfNeeded(functions);
                }
            }
        }

首先判斷要設定的新的USB功能的資料是否是解鎖狀態,只有MTP和PTP模式的資料是解鎖狀態,這是為何你能在設定MTP或PTP模式後,在PC端能看到手機中的檔案,然而這個檔案只是手機記憶體中檔案的對映,並不是檔案本身。

然後處理資料解鎖狀態改變的情況,如果是,那麼會更新狀態,更新usb廣播,然後最重要的是設定forceRestart變數的值為true,這個變數代表要強制重啟usb功能。

最後,設定新usb功能。如果失敗了,就回退。現在來看下trySetEnabledFunctions()方法如何設定新功能

@Override
protected void setEnabledFunctions(long functions, boolean forceRestart, int operationId) {
    if (DEBUG) {
        Slog.d(TAG, "setEnabledFunctionsi " +
                "functions=" + functions +
                ", forceRestart=" + forceRestart +
                ", operationId=" + operationId);
    }
    if (mCurrentGadgetHalVersion < UsbManager.GADGET_HAL_V1_2) {
        if ((functions & UsbManager.FUNCTION_NCM) != 0) {
            Slog.e(TAG, "Could not set unsupported function for the GadgetHal");
            return;
        }
    }
    if (mCurrentFunctions != functions
            || !mCurrentFunctionsApplied
            || forceRestart) {
        Slog.i(TAG, "Setting USB config to " + UsbManager.usbFunctionsToString(functions));
        mCurrentFunctions = functions;
        mCurrentFunctionsApplied = false;
        // set the flag to false as that would be stale value
        mCurrentUsbFunctionsRequested = false;

        boolean chargingFunctions = functions == UsbManager.FUNCTION_NONE;
        functions = getAppliedFunctions(functions);

        // Set the new USB configuration.
        setUsbConfig(functions, chargingFunctions, operationId);

        if (mBootCompleted && isUsbDataTransferActive(functions)) {
            // Start up dependent services.
            updateUsbStateBroadcastIfNeeded(functions);
        }
    }
}

程式碼功能概述:

setEnabledFunctions 的主要作用是在滿足一定條件的情況下,將裝置的 USB 功能配置為指定的功能集。如果這些功能與當前功能配置不同,或者需要強制重新啟動 USB 堆疊,它將應用新的配置並更新相關狀態。

主要操作步驟:

  1. 除錯資訊輸出:
    • 如果 DEBUG 標誌為真,則透過 Slog.d 輸出除錯資訊,包括傳入的 functionsforceRestartoperationId 的值。
  2. Gadget HAL 版本檢查:
    • 如果當前的 GadgetHal 版本低於 UsbManager.GADGET_HAL_V1_2,並且傳入的 functions 中包含 UsbManager.FUNCTION_NCM(Network Control Model),則記錄錯誤日誌並返回,因為該版本不支援 NCM 功能。
  3. 判斷是否需要重新配置 USB 功能:
    • 重新配置的條件包括:當前功能配置 mCurrentFunctions 與傳入的 functions 不同,或者當前功能配置尚未應用 (mCurrentFunctionsAppliedfalse),或者 forceRestart 標誌為真。
    • 如果滿足上述條件之一,表示需要重新設定 USB 功能。
  4. 設定 USB 功能配置:
    • 更新 mCurrentFunctions 為傳入的 functions,並將 mCurrentFunctionsApplied 設定為 false,表示新的配置尚未應用。
    • mCurrentUsbFunctionsRequested 設定為 false,表示當前的 USB 功能請求狀態為過時值,需要重新設定。
  5. 檢查是否為充電功能:
    • 如果 functions 等於 UsbManager.FUNCTION_NONE,表示裝置處於僅充電狀態。
    • 呼叫 getAppliedFunctions(functions) 獲取實際應用的 USB 功能配置。
  6. 應用新的 USB 配置:
    • 呼叫 setUsbConfig(functions, chargingFunctions, operationId) 方法,應用新的 USB 配置。
    • chargingFunctions 引數指示是否為僅充電功能。
  7. 更新 USB 狀態:
    • 如果裝置已經完成啟動 (mBootCompleted 為真) 且 USB 資料傳輸功能被啟用(即 functions 包含資料傳輸功能),則呼叫 updateUsbStateBroadcastIfNeeded(functions) 方法,啟動相關服務並更新 USB 狀態廣播。

trySetEnabledFunctions函式:

        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 = 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) {
                mCurrentFunctionsStr = functions;
                mCurrentOemFunctions = oemFunctions;
                mCurrentFunctionsApplied = false;

                /**
                 * Kick the USB stack to close existing connections.
                 */
                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;
                }

                mCurrentFunctionsApplied = true;
            }
            return true;
        }

我把這裡的邏輯分為了三步.

第一步,把待設定的USB功能轉化為字串,有兩種情況

  1. 如果新功能為FUNCTION_NONE,那麼轉化後的值從persist.sys.usb.config獲取,如果獲取值為NONE,就判斷adb是否開啟,如果開啟了,轉化後的值為adb,如果沒有開啟,轉化後的值為mtp。前面分析說過,persist.sys.usb.config主要包含用於判斷adb是否開啟在值,然後還包含一些廠商定製且用於測試目的的功能。例如,高通專案,這個值可能為adb,diag,這個diag就是高通自己的功能。
  2. 如果新功能不為FUNCTION_NONE,把直接轉化。例如新功能為FUNCTION_MTP,那麼轉化後的字串為mtp

轉化字串後,根據adb是否開啟,來決定從轉化後的字串中增加adb屬性還是移除adb屬性。

第二步,獲取oem覆蓋的功能。前面說過,預設系統是沒有使用覆蓋功能,所以這裡獲取的覆蓋後的功能與新功能轉化後的字串是一樣的。

我在分析程式碼的時候,腦海裡一直在想,這個覆蓋功能如何使用。根據我的對程式碼的分析,唯一的規則就是主要功能不能覆蓋。舉個例子,如果新設定的功能的字串為mtp,那麼覆蓋陣列中的其中一項元素的值應該是normal:mtp:mtp,diag,其中nomral表示正常啟動,mtp表示原始的功能,mtp,diag表示覆蓋後的功能,請注意,覆蓋後的功能一定要儲存mtp這個主功能。當然這只是我個人對程式碼分析得出的結論,還沒驗證。這裡我要吐槽一下這個功能的設計者,難道寫個例子以及注意事項就這麼難嗎?

第三步,設定新功能。不過設定新功能前,首先要斷開已經存在的連線,然後再設定新功能。設定新功能是透過setUsbConfig()方法,來看下實現

        private void setUsbConfig(String config) {
            // 設定sys.usb.config
            setSystemProperty(USB_CONFIG_PROPERTY, config);
        }

震驚!原來就是設定sys.usb.config的屬性值,還記得嗎,在前面的分析中,也解釋過這個屬性值,它就是代表當前設定的usb功能,從這裡就可以得到證明。

這其實也在提示我們,其實可以透過adb shell setprop命令設定這個屬性,從而控制usb功能的切換。在實際的工作中,屢試不爽。

設定這個屬性後如何判斷設定成功了呢?這就是waitForState()所做的

        private boolean waitForState(String state) {
            String value = null;
            for (int i = 0; i < 20; i++) {
                // 獲取sys.usb.stat值
                value = getSystemProperty(USB_STATE_PROPERTY, "");
                // 與剛才設定的sys.usb.config屬性值相比較
                if (state.equals(value)) return true;
                SystemClock.sleep(50);
            }
            return false;
        }

說實話,我看到這段程式碼,確實吃了一鯨! 這段程式碼在1秒內執行20次,獲取sys.usb.state屬性值,然後與設定的sys.usb.config屬性值相比較,如果相等就表示功能設定成功。

還記得嗎?在前面的分析中,我也解釋過sys.usb.state屬性的作用,它代表usb實際的功能,從這裡就可以得到驗證。

那麼現在有一個問題,底層如何實現usb功能切換呢?當然是響應屬性sys.usb.config屬性改變

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}

根據註釋,你應該就可以很清楚瞭解這個過程了。

so, 你以為這就完了嗎?還沒呢,如果新設定的功能是MTP或PTP,那麼還要更新廣播呢。

        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);
            // 儲存了usb狀態值
            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));
            
            // 儲存了要設定的新功能的值,例如設定的是MTP,那麼引數的key為mtp,值為true
            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;
        

相關文章