打开 “USB 调试” 开关流程
在开发者模式中打开 “USB调试” 开关,程序会调用如下代码:
public void onAdbDialogConfirmed() {
writeAdbSetting(true);
}
其中 writeAdbSetting 在 com.android.settingslib.development.AbstractEnableAdbPreferenceController 类中定义:
protected void writeAdbSetting(boolean enabled) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.ADB_ENABLED, enabled ? ADB_SETTING_ON : ADB_SETTING_OFF);
notifyStateChanged();
}
修改 Settings.Global.ADB_ENABLED 设置项,并发送广播:
private void notifyStateChanged() {
LocalBroadcastManager.getInstance(mContext)
.sendBroadcast(new Intent(ACTION_ENABLE_ADB_STATE_CHANGED));
}
在 com.android.settings.development.DevelopmentSettingsDashboardFragment 类中处理了该广播:
private void registerReceivers() {
LocalBroadcastManager.getInstance(getContext())
.registerReceiver(mEnableAdbReceiver, new IntentFilter(
AdbPreferenceController.ACTION_ENABLE_ADB_STATE_CHANGED));
final IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED);
getActivity().registerReceiver(mBluetoothA2dpReceiver, filter);
}
广播接收器:
private final BroadcastReceiver mEnableAdbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
for (AbstractPreferenceController controller : mPreferenceControllers) {
if (controller instanceof AdbOnChangeListener) {
((AdbOnChangeListener) controller).onAdbSettingChanged();
}
}
}
};
上面的广播接收器主要处理 view 的状态,指示调试模式已经打开。
重点看 Settings.Global.ADB_ENABLED 设置项控制的代码,在 com.android.server.adb.AdbService 类中会监测该设置项变化:
mContentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
false, new AdbSettingsObserver());
使用 AdbSettingsObserver 对 Settings.Global.ADB_ENABLED 设置项进行观察:
private class AdbSettingsObserver extends ContentObserver {
AdbSettingsObserver() {
super(null);
}
@Override
public void onChange(boolean selfChange) {
boolean enable = (Settings.Global.getInt(mContentResolver,
Settings.Global.ADB_ENABLED, 0) > 0);
mHandler.sendMessage(MSG_ENABLE_ADB, enable);
}
}
当设置项发生改变时,通过 mHandler 发送 MSG_ENABLE_ADB 消息,消息处理如下:
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ENABLE_ADB:
setAdbEnabled(msg.arg1 == 1);
break;
case MSG_BOOT_COMPLETED:
if (mDebuggingManager != null) {
mDebuggingManager.setAdbEnabled(mAdbEnabled);
}
break;
}
}
通过 setAdbEnabled 来设置 ADB 使能。
private void setAdbEnabled(boolean enable) {
if (DEBUG) Slog.d(TAG, "setAdbEnabled(" + enable + "), mAdbEnabled=" + mAdbEnabled);
if (enable == mAdbEnabled) {
return;
}
mAdbEnabled = enable;
for (IAdbTransport transport : mTransports.values()) {
try {
transport.onAdbEnabled(enable);
} catch (RemoteException e) {
Slog.w(TAG, "Unable to send onAdbEnabled to transport " + transport.toString());
}
}
if (mDebuggingManager != null) {
mDebuggingManager.setAdbEnabled(enable);
}
}
mTransports 是集合类型,通过内部类 AdbManagerInternalImpl 的 registerTransport 函数增加新的元素。在 com.android.server.usb.UsbDeviceManager 类中注册了 Transport。
LocalServices.getService(
AdbManagerInternal.class).registerTransport(new AdbTransport(this));
那么 AdbTransport 的 onAdbEnabled 函数会被调用,此函数发送了 MSG_ENABLE_ADB 消息。本地函数 setAdbEnabled 处理了该消息:
private void setAdbEnabled(boolean enable) {
if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
if (enable) {
setSystemProperty(USB_PERSISTENT_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_ADB);
} else {
setSystemProperty(USB_PERSISTENT_CONFIG_PROPERTY, "");
}
setEnabledFunctions(mCurrentFunctions, true);
updateAdbNotification(false);
}
其中 USB_PERSISTENT_CONFIG_PROPERTY 定义如下:
protected static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
该属性会持久化保存到文件系统中。紧接着调用 setEnabledFunctions 函数:
@Override
protected void setEnabledFunctions(long usbFunctions, boolean forceRestart) {
...
if (trySetEnabledFunctions(usbFunctions, forceRestart)) {
return;
}
...
}
多次调用 trySetEnabledFunctions 来配置 USB 的功能:
private boolean trySetEnabledFunctions(long usbFunctions, boolean forceRestart) {
...
if ((!functions.equals(oemFunctions)
&& !mCurrentOemFunctions.equals(oemFunctions))
|| !mCurrentFunctionsStr.equals(functions)
|| !mCurrentFunctionsApplied
|| forceRestart) {
...
setUsbConfig(UsbManager.USB_FUNCTION_NONE);
if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
Slog.e(TAG, "Failed to kick USB config");
return false;
}
setUsbConfig(oemFunctions);
...
}
return true;
}
最关键的函数 setUsbConfig :
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);
}
其中 USB_CONFIG_PROPERTY 定义为:
private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
在 init.msm.usb.configfs.rc 中会监测此属性,根据属性切换不同的 usb 模式:
on property:sys.usb.config=diag,adb,serial_cdev && property:sys.usb.configfs=1
start adbd
如果 sys.usb.config 属性等于 diag,adb,serial_cdev 并且 sys.usb.configfs 为 1,则启动 adbd 服务。其中 sys.usb.configfs 为 1 表示 kernel 启用的 configfs,这个属性在 device/qcom/common/rootdir/etc/init.qcom.usb.sh 中初始化:
# check configfs is mounted or not
if [ -d /config/usb_gadget ]; then
# Chip-serial is used for unique MSM identification in Product string
msm_serial=`cat /sys/devices/soc0/serial_number`;
msm_serial_hex=`printf %08X $msm_serial`
machine_type=`cat /sys/devices/soc0/machine`
product_string="$machine_type-$soc_hwplatform _SN:$msm_serial_hex"
echo "$product_string" > /config/usb_gadget/g1/strings/0x409/product
# ADB requires valid iSerialNumber; if ro.serialno is missing, use dummy
serialnumber=`cat /config/usb_gadget/g1/strings/0x409/serialnumber 2> /dev/null`
if [ "$serialnumber" == "" ]; then
serialno=1234567
echo $serialno > /config/usb_gadget/g1/strings/0x409/serialnumber
fi
setprop vendor.usb.configfs 1
fi
判断 configfs 是否已经挂载,如果已经挂载,则设置 vendor.usb.configfs 属性为 1。
总结:
1、开发者模式中打开 “USB 调试” 开关,对应的 Settings.Global.ADB_ENABLED 设置项会被修改。
2、AdbService 监测设置项,触发设置 adb 使能逻辑。
3、UsbDeviceManager 响应 adb 使能逻辑,修改 persist.sys.usb.config 和 sys.usb.config 的值,其中 persist.sys.usb.config 属性用于开机恢复上一次 usb 设置,修改 sys.usb.config 属性,会直接触发 init.rc 中的 action,触发对 usb 进行配置(configfs)、启动 adbd 等动作。
开机 USB 默认模式
AdbService 在 system_server 中启动,它的构造函数包含以下代码:
private AdbService(Context context) {
...
mHandler = new AdbHandler(FgThread.get().getLooper());
LocalServices.addService(AdbManagerInternal.class, new AdbManagerInternalImpl());
}
这里 new 了一个 AdbHandler 对象。在看 AdbHandler 的构造函数,
AdbHandler(Looper looper) {
super(looper);
try {
/*
* Use the normal bootmode persistent prop to maintain state of adb across
* all boot modes.
*/
mAdbEnabled = containsFunction(
SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""),
UsbManager.USB_FUNCTION_ADB);
// register observer to listen for settings changes
mContentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
false, new AdbSettingsObserver());
} catch (Exception e) {
Slog.e(TAG, "Error initializing AdbHandler", e);
}
}
首先判断 persist.sys.usb.config 属性的值,是否包含 “adb” 字段,如果包含则将 mAdbEnabled 设置为 true。AMS 启动后,会调用所有系统服务的 systemReady 函数:
public void systemReady() {
if (DEBUG) Slog.d(TAG, "systemReady");
// make sure the ADB_ENABLED setting value matches the current state
try {
Settings.Global.putInt(mContentResolver,
Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
} catch (SecurityException e) {
// If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed.
Slog.d(TAG, "ADB_ENABLED is restricted.");
}
}
这里会将 mAdbEnabled 的值,设置到 Settings.Global.ADB_ENABLED 设置项,之后会执行打开 “USB调试” 开关流程。persist.sys.usb.config 保存的是上一次开机最后一次 setUsbConfig 的值,默认情况下会恢复上一次的 usb 状态。
高通进行了定制化,在 init.qcom.usb.rc 中有以下配置:
on property:persist.vendor.usb.config=*
setprop persist.sys.usb.config ${persist.vendor.usb.config}
persist.vendor.usb.config 的值在 init.qcom.usb.sh 设置:
#
# Override USB default composition
#
# If USB persist config not set, set default configuration
if [ "$(getprop persist.vendor.usb.config)" == "" -a \
"$(getprop init.svc.vendor.usb-gadget-hal-1-0)" != "running" ]; then
if [ "$esoc_name" != "" ]; then
setprop persist.vendor.usb.config diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl,rmnet,adb
else
case "$(getprop ro.baseband)" in
"apq")
setprop persist.vendor.usb.config diag,adb
;;
*)
case "$soc_hwplatform" in
"Dragon" | "SBC")
setprop persist.vendor.usb.config diag,adb
;;
*)
case "$soc_machine" in
"SA")
if [ "$product" == "gvmq" ]; then
setprop persist.vendor.usb.config adb
else
setprop persist.vendor.usb.config diag,adb
fi
;;
*)
case "$target" in
"msm8996")
setprop persist.vendor.usb.config diag,serial_cdev,serial_tty,rmnet_ipa,mass_storage,adb
;;
"msm8909")
setprop persist.vendor.usb.config diag,serial_smd,rmnet_qti_bam,adb
;;
"msm8937")
if [ -d /config/usb_gadget ]; then
setprop persist.vendor.usb.config diag,serial_cdev,rmnet,dpl,adb
else
case "$soc_id" in
"313" | "320")
setprop persist.vendor.usb.config diag,serial_smd,rmnet_ipa,adb
;;
*)
setprop persist.vendor.usb.config diag,serial_smd,rmnet_qti_bam,adb
;;
esac
fi
;;
"msm8953")
if [ -d /config/usb_gadget ]; then
setprop persist.vendor.usb.config diag,serial_cdev,rmnet,dpl,adb
else
setprop persist.vendor.usb.config diag,serial_smd,rmnet_ipa,adb
fi
;;
"msm8998" | "sdm660" | "apq8098_latv")
setprop persist.vendor.usb.config diag,serial_cdev,rmnet,adb
;;
"sdm845" | "sdm710")
setprop persist.vendor.usb.config diag,adb,serial_cdev
;;
"msmnile" | "sm6150" | "trinket" | "lito" | "atoll" | "bengal")
setprop persist.vendor.usb.config diag,serial_cdev,rmnet,dpl,qdss
;;
*)
setprop persist.vendor.usb.config diag,adb
;;
esac
;;
esac
;;
esac
;;
esac
fi
fi
因此每次开机都会还原成默认设置。