首页 > 其他分享 >Android UsbDeviceManager 代码分析

Android UsbDeviceManager 代码分析

时间:2024-08-19 23:49:38浏览次数:10  
标签:FUNCTION functions USB UsbManager 代码 new UsbDeviceManager Android usb

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;
        

标签:FUNCTION,functions,USB,UsbManager,代码,new,UsbDeviceManager,Android,usb
From: https://www.cnblogs.com/linhaostudy/p/18368396

相关文章

  • AES常用的代码示例
    AESAES是对称加密。对称加密是指加密和解密使用相同的密钥的加密算法。非对称加密是指加密和解密使用不同的密钥的加密算法。AES加密解密加密模式,有ECB模式和CBC模式等等,ECB不需要iv偏移量,而CBC需要。密钥,可以自定义。填充方式,有PKCS5、PKCS7、NoPadding。......
  • 【LGR-196-Div.4】洛谷入门赛 #26 题A - H 详细题解--优化思路简洁代码(C++,Python语
    前言:    觉得这个比赛很有意思的,都是暴力题,涉及一些细节,难度比较适合刚学编程语言的,可以很好的锻炼基础还有手速,最后两题也是比较有意思,之后也准备更新atc的比赛题解和洛谷的一些高质量比赛题解(算法网瘾就是想参加各种比赛)   如果觉得有帮助,或者觉得我写的好,......
  • 生产者消费者问题-C++代码实现
    生产者消费者问题C++代码本文主要记录面试中手撕代码环节比较经常考察的生产者消费者问题,方便后续巩固和查看#include<iostream>#include<thread>#include<mutex>#include<condition_variable>#include<queue>#include<functional>usingnamespacestd;classProd......
  • Android libusb
    一、环境:配置NDK环境1、下载libusb源码:https://github.com/libusb/libusb/releases,如下图所示2、删除一些和Android平台无关的文件,删除后的文件如下图所示:思考问题:Android是怎么获取usb设备?如上图所示:连接adbshell,然后cd到/sys/bus/usb/devices/目录,命令ll可以看到里......
  • Android开发 - DisplayMetrics 类控制布局图形的缩放显示解析
    DisplayMetrics是什么DisplayMetrics类在Android中用于获取设备的显示属性(像素等)DisplayMetrics的主要属性metrics.density:屏幕密度,用于决定屏幕上每英寸的像素数DisplayMetricsmetrics=newDisplayMetrics();density=metrics.density;常见值:0.75(低密度)、1.0......
  • yolov8双目测距(包含有前端的源码和无前端的源码Sgbm双目测距算法)-内含测距代码,视差图
    YOLOv8:YOLOv8是一个目标检测模型,它是YOLO(YouOnlyLookOnce)系列的一部分,用于实时物体检测。YOLOv8能够快速准确地检测视频或图像中的对象。双目测距:双目测距是指使用两个摄像头(或一个立体相机)从不同角度拍摄同一场景,通过比较两个摄像头捕捉到的图像差异来计算物体的距......
  • YOLOV5单目测距+车辆检测+车道线检测+行人检测(教程-代码)
     YOLOv5是一种高效的目标检测算法,结合其在单目测距、车辆检测、车道线检测和行人检测等领域的应用,可以实现多个重要任务的精确识别和定位。首先,YOLOv5可以用于单目测距。通过分析图像中的目标位置和尺寸信息,结合相机参数和几何关系,可以推断出目标与相机之间的距离。这对于......
  • C/C++语言基础--指针三大专题详解2(指针与数组关系,动态内存分配,代码均可)
    本专栏目的更新C/C++的基础语法,包括C++的一些新特性前言指针是C/C++的灵魂,和内存地址相关联,运行的时候速度快,但是同时也有很多细节和规范要注意的,毕竟内存泄漏是很恐怖的指针打算分三篇文章进行讲解,本专题是二,介绍了指针和数组的关系、动态内存如何分配和释放等问题专题......
  • 「代码随想录算法训练营」第四十一天 | 单调栈 part1
    739.每日温度题目链接:https://leetcode.cn/problems/daily-temperatures/文章讲解:https://programmercarl.com/0739.每日温度.html题目难度:中等视频讲解:https://www.bilibili.com/video/BV1my4y1Z7jj/题目状态:看题解思路:定义一个单调栈,该栈存放下标,规则是要保持其下标对......
  • 通过代码添加的控件的事件如何编写?
    0背景这两天在重新复习事件,比如Winform控件的事件,利用vs很方便地实现。比如:想要在窗体加载时,修改窗口的标题;我们只需要双击Form1的标题栏即可;vs便会给我们生成如下代码,且光标自动定位到方法体中:privatevoidForm1_Load(objectsender,EventArgse){}然后我......