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();
- 這些行程式碼儲存了
Context
和ContentResolver
,並檢查裝置是否支援 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_ATTACHED
和UsbManager.ACTION_USB_DEVICE_DETACHED
)。 - languageChangedReceiver: 監聽系統語言變化(
Intent.ACTION_LOCALE_CHANGED
)。
- portReceiver: 監聽 USB 埠狀態變化(
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_MATCH
和ACCESSORY_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 的功能狀態。
核心方法:
-
readOemUsbOverrideConfig
:- 讀取 OEM 的 USB 模式覆蓋配置,儲存到
mOemModeMap
中。該配置可能包含與不同啟動模式相關的 USB 功能。
- 讀取 OEM 的 USB 模式覆蓋配置,儲存到
-
applyOemOverrideFunction
:- 根據當前啟動模式和 USB 功能,應用 OEM 的覆蓋功能,調整系統的 USB 設定。
-
waitForState
:- 等待 USB 狀態的轉換完成,透過檢查
USB_STATE_PROPERTY
的值來確認是否完成。
- 等待 USB 狀態的轉換完成,透過檢查
-
setUsbConfig
:- 設定新的 USB 配置,通常透過更改
USB_CONFIG_PROPERTY
的值來實現。
- 設定新的 USB 配置,通常透過更改
-
setEnabledFunctions
:- 啟用指定的 USB 功能,並在必要時強制重新啟動 USB 子系統。如果設定失敗,則嘗試恢復到先前的功能或預設功能。
-
trySetEnabledFunctions
:- 嘗試設定啟用的 USB 功能,應用 ADB 和 OEM 的覆蓋配置,更新系統屬性,並透過呼叫
waitForState
確認配置是否生效。
- 嘗試設定啟用的 USB 功能,應用 ADB 和 OEM 的覆蓋配置,更新系統屬性,並透過呼叫
-
applyAdbFunction
:- 根據當前 ADB(Android 除錯橋)的狀態,新增或移除 USB 功能字串中的 ADB 功能。
-
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, "">
。我的專案中,這個陣列為空。
然後第二步,讀取了各種屬性值(只考慮正常啟動模式),如下。
- mCurrentOemFunctions的值是
persist.sys.usb.config
屬性的值。按照原始碼註釋,這個屬性值儲存了adb的開啟狀態(如果開啟了adb,那麼這個值會包含adb字串)。另外,原始碼註釋說這個屬性也可以運營商定製的一些功能,但是隻用於測試目的。 - mCurrentFunctionsStr的值是
sys.usb.config
屬性值。這個屬性表示當前設定的usb功能的值。在日常工作中,我們可以透過adb shell命令設定這個屬性值來切換usb功能,例如adb shell setprop sys.usb.config mtp,adb
可以切換到mtp功能。 - 如果透過
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 狀態做出相應的處理。函式的執行依賴於以下三個條件:
mBootCompleted
:表示裝置啟動已完成。mCurrentUsbFunctionsReceived
:表示當前 USB 功能已經接收並處理。mSystemReady
:表示系統已準備好(可能指系統服務或其他依賴已啟動)。
主要操作步驟:
-
廣播 USB 狀態更新:
- 如果
mPendingBootBroadcast
為true
,表示有掛起的 USB 狀態廣播需要傳送。函式會呼叫updateUsbStateBroadcastIfNeeded
傳送廣播,更新 USB 狀態,然後將mPendingBootBroadcast
設定為false
。
- 如果
-
設定螢幕解鎖後的 USB 功能:
- 如果裝置螢幕未鎖定 (
mScreenLocked
為false
),並且mScreenUnlockedFunctions
的值不為UsbManager.FUNCTION_NONE
(即有特定功能要在解鎖後啟用),則呼叫setScreenUnlockedFunctions
設定這些功能。 - 否則,呼叫
setEnabledFunctions
,將 USB 功能設定為UsbManager.FUNCTION_NONE
。
- 如果裝置螢幕未鎖定 (
-
處理 USB 附件:
- 如果當前有連線的 USB 附件 (
mCurrentAccessory
不為null
),則通知 USB 裝置管理器(mUsbDeviceManager
)附件已連線,並廣播 USB 附件握手事件。 - 如果沒有連線的 USB 附件但有掛起的握手廣播 (
mPendingBootAccessoryHandshakeBroadcast
為true
),則廣播 USB 附件握手事件。
- 如果當前有連線的 USB 附件 (
-
更新狀態和通知:
- 將
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 堆疊,它將應用新的配置並更新相關狀態。
主要操作步驟:
- 除錯資訊輸出:
- 如果
DEBUG
標誌為真,則透過Slog.d
輸出除錯資訊,包括傳入的functions
、forceRestart
和operationId
的值。
- 如果
- Gadget HAL 版本檢查:
- 如果當前的
GadgetHal
版本低於UsbManager.GADGET_HAL_V1_2
,並且傳入的functions
中包含UsbManager.FUNCTION_NCM
(Network Control Model),則記錄錯誤日誌並返回,因為該版本不支援NCM
功能。
- 如果當前的
- 判斷是否需要重新配置 USB 功能:
- 重新配置的條件包括:當前功能配置
mCurrentFunctions
與傳入的functions
不同,或者當前功能配置尚未應用 (mCurrentFunctionsApplied
為false
),或者forceRestart
標誌為真。 - 如果滿足上述條件之一,表示需要重新設定 USB 功能。
- 重新配置的條件包括:當前功能配置
- 設定 USB 功能配置:
- 更新
mCurrentFunctions
為傳入的functions
,並將mCurrentFunctionsApplied
設定為false
,表示新的配置尚未應用。 - 將
mCurrentUsbFunctionsRequested
設定為false
,表示當前的 USB 功能請求狀態為過時值,需要重新設定。
- 更新
- 檢查是否為充電功能:
- 如果
functions
等於UsbManager.FUNCTION_NONE
,表示裝置處於僅充電狀態。 - 呼叫
getAppliedFunctions(functions)
獲取實際應用的 USB 功能配置。
- 如果
- 應用新的 USB 配置:
- 呼叫
setUsbConfig(functions, chargingFunctions, operationId)
方法,應用新的 USB 配置。 chargingFunctions
引數指示是否為僅充電功能。
- 呼叫
- 更新 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功能轉化為字串,有兩種情況
- 如果新功能為
FUNCTION_NONE
,那麼轉化後的值從persist.sys.usb.config
獲取,如果獲取值為NONE,就判斷adb是否開啟,如果開啟了,轉化後的值為adb,如果沒有開啟,轉化後的值為mtp。前面分析說過,persist.sys.usb.config
主要包含用於判斷adb是否開啟在值,然後還包含一些廠商定製且用於測試目的的功能。例如,高通專案,這個值可能為adb,diag
,這個diag就是高通自己的功能。 - 如果新功能不為
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;