目录
1)persist.sys.usb.config属性的初始化
2)persist.vendor.usb.config属性的初始化
3)sys.usb.config和vendor.usb.config
2)高通A14 user 定制版本:persist.vendor.usb.config
2、案例之实现不需要执行adb root命令自动具有root权限
3、案例之实现不需要RSA认证直接能够使用adb shell命令
本篇主要围绕android native层的adbd和usbd进程进行展开,涉及到user以及debug调试相关的功能进行分析。adbd的功能基于usbd,user和debug版本分别针对他们的特性对adbd以及usbd展开了相关的定制,所以他们总是关联出现。
一、adb
adb源码的架构,其实在system/packages/modules/adb/中有注释,如下两个方向:
- PC主机与adb设备的拓扑图
根据下面一段文字的介绍,android设备的adb主要靠守护进程adbd来实现,具体代码实现是在Daemon里面。
1、adbd守护进程
adbd作为android设备的守护进程,android.bp文件定义如下:
回到adbd主函数中调用adbd_main函数里面,源码如下:
//aosp/packages/modules/adb/daemon/main.cpp
int adbd_main(int server_port) {
//...省略...
//重点1:auth_required为true表示进行RSA校验,其默认值根据ro.adb.secure
#if defined(__ANDROID__)
bool device_unlocked = android::base::GetProperty("ro.boot.verifiedbootstate", "") == "orange";
if (device_unlocked || __android_log_is_debuggable()) {
#if defined(__ANDROID_RECOVERY__)
auth_required = false; // Bypass authorization when the device transitions to
#else
// If we're on userdebug/eng or the device is unlocked, permit no-authentication.
auth_required = android::base::GetBoolProperty("ro.adb.secure", false);
#endif
}
#endif
//重点2:是否进行权限降级
#if defined(__ANDROID__)
drop_privileges(server_port);
#endif
#if defined(__ANDROID__)
// A thread gets spawned as a side-effect of initializing the watchdog, so it needs to happen after we drop privileges.
watchdog::Initialize();
#endif
//重点3:证书权限相关校验,如果auth_required为false其adb/daemon/auth.cpp直接返回不需要校验
// adbd_auth_init will spawn a thread, so we need to defer it until after selinux transitions.
adbd_auth_init();
bool is_usb = false;
#if defined(__ANDROID__)
if (access(USB_FFS_ADB_EP0, F_OK) == 0) {
// Listen on USB.
usb_init();
is_usb = true;
}
#endif
// If one of these properties is set, also listen on that port.
// If one of the properties isn't set and we couldn't listen on usb, listen on the default port.
std::vector<std::string> addrs;
std::string prop_addr = android::base::GetProperty("service.adb.listen_addrs", "");
if (prop_addr.empty()) {
//...省略...
} else {
addrs = android::base::Split(prop_addr, ",");
setup_adb(addrs);
}
//重点3:关键日志,adbd启动,如果没有这行日志,说明adbd根本无法使用
LOG(INFO) << "adbd started";
D("adbd_main(): pre init_jdwp()");
init_jdwp();
D("adbd_main(): post init_jdwp()");
D("Event loop starting");
//重点4:进入fd事件轮询,即监听pc端发送过来的数据,最终传递在daemon_service_to_fd函数中进行解析
fdevent_loop();
return 0;
}
总结如上adbd守护进程主函数大致流程如下:
- 设置auth_required状态,为true表示进行RSA校验,其默认值根据ro.adb.secure。重点,我们可以定制ro.adb.secure属性的值来实现不需要设备授权直接使用adb命令
- 通过drop_privileges方法来实现权限降级
- 通过setup_adb设置地址(串口号?),这里除了判断是usb链接还是wifi链接之外,还处理多台usb设备之间的关系
- 进入fdevent_loop事件轮询,监听PC adb端发送过来的命令
2、adbd权限降级
前面已经介绍了drop_privileges来实现权限降级,那么什么是权限降级呢?这涉及到linux dac机制,在android_filesystem_config.h 文件中定义了大量的权限等级:
AID_XXX定义了android系统中基本能分解的所有用户组和权限(0-100000)。其中AID_ROOT等于0被作为最高用户组。咨询AI这其实就是Linux DAC的实现机制。
回到drop_privileges函数如下内容:
static void drop_privileges(int server_port) {
ScopedMinijail jail(minijail_new());
// Add extra groups:
// AID_ADB to access the USB driver
// AID_LOG to read system logs (adb logcat)
// AID_INPUT to diagnose input issues (getevent)
// AID_INET to diagnose network issues (ping)
// AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
// AID_SDCARD_R to allow reading from the SD card
// AID_SDCARD_RW to allow writing to the SD card
// AID_NET_BW_STATS to read out qtaguid statistics
// AID_READPROC for reading /proc entries across UID boundaries
// AID_UHID for using 'hid' command to read/write to /dev/uhid
// AID_EXT_DATA_RW for writing to /sdcard/Android/data (devices without sdcardfs)
// AID_EXT_OBB_RW for writing to /sdcard/Android/obb (devices without sdcardfs)
// AID_READTRACEFS for reading tracefs entries
gid_t groups[] = {AID_ADB, AID_LOG, AID_INPUT, AID_INET,
AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
AID_NET_BW_STATS, AID_READPROC, AID_UHID, AID_EXT_DATA_RW,
AID_EXT_OBB_RW, AID_READTRACEFS};
minijail_set_supplementary_gids(jail.get(), arraysize(groups), groups);
// Don't listen on a port (default 5037) if running in secure mode.
// Don't run as root if running in secure mode.
if (should_drop_privileges()) {
//...省略...
//核心代码:通过minijail_change_gid切换用户组ID为AID_SHELL,属于Linux DAC降低权限
minijail_change_gid(jail.get(), AID_SHELL);
minijail_change_uid(jail.get(), AID_SHELL);
//核心代码:通过minijail_enter执行最终的沙箱隔离操作,属于Linux DAC机制
// minijail_enter() will abort if any priv-dropping step fails.
minijail_enter(jail.get());
//...省略...
D("Local port disabled");
} else {
//核心代码:通过minijail_enter执行最终的沙箱隔离操作,默认是ROOT?
// minijail_enter() will abort if any priv-dropping step fails.
minijail_enter(jail.get());
//防错处理,如果变量root_seclabel设置的selinux安全上下文不是0,即不是root用户,强制属性service.adb.root的在值为0
if (root_seclabel != nullptr) {
if (selinux_android_setcon(root_seclabel) < 0) {
// If we failed to become root, don't try again to avoid a
// restart loop.
android::base::SetProperty("service.adb.root", "0");
LOG(FATAL) << "Could not set SELinux context";
}
}
}
}
如上代码总结如下:
- 通过should_drop_privileges来判断是否需要进行权限降级,返回true进行权限降级
- 进行权限降级:切换用户组为AID_SHELL,来达到降级的目的
- 不进行权限降级:没有地方去切换用户组等级,默认为root组?
接下来继续分析一下should_drop_privileges是如何来判断需要进行权限降级?
- 所以最后的核心:最后通过下一小节可以了解到执行adb root之后就会设置属性service.adb.root为1;执行adb unroot之后就会设置属性service.adb.root为0,即adb root之后,adb终端重启并进入最高用户权限等级。
3、adbd命令解析
PC主机发送过来的adb xxx命令,最后由守护进程adb/daemon/services通过套接字或者fd的方式来接收adb相关命令,如下代码逻辑:
如上代码,解析几条重要的adb xxx命令之后,通过create_service_thread的方式去启动线程来执行对应的命令。
1)adb shell
daemon_service_to_fd方法解析为adb shell,直接调用ShellService来进行命令参数拼接
这里比较核心的方法StartSubprocess,在adb/daemon守护进程里面基本上通过它来创建子进程,然后用shell作为执行源。
2)adb root
我们执行adb root的时候,会执行如下函数,如果不是debug版本直接返回,如果是debug版本设置service.adb.root属性值为1.
3)adb reboot
adb reboot命令同上,但是这里区分一下,并没有使用终端shell方式,第二个参数为null,cmd直接定义为/system/bin/reboot,即后续直接创建子进程,以reboot文件作为执行源。
4、AdbService
前文都是围绕native层的adbd进程展开,这里来说明一下fw层的adbservice,是如何与adbd进行交互的。
1)AdbService的启动
我们先看看fw层的AdbService的定义如下:
//frameworks/base/services/core/java/com/android/server/adb/AdbService.java
public class AdbService extends IAdbManager.Stub {
static final String ADBD = "adbd"; //adbd守护进程
static final String CTL_START = "ctl.start";//启动adbd进程的命令
static final String CTL_STOP = "ctl.stop"; //停止adbd进程的命令
//属于system_server进程,并向系统注册服务"adb"
public static class Lifecycle extends SystemService {
private AdbService mAdbService;
public Lifecycle(Context context) {
super(context);
}
@Override
public void onStart() {
//流程1:实例化AdbService服务,并像系统服务注册
mAdbService = new AdbService(getContext());
publishBinderService(Context.ADB_SERVICE, mAdbService);
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
//流程2:监听PHASE_ACTIVITY_MANAGER_READY阶段,调用systemReady进行初始化
mAdbService.systemReady();
} else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
//流程3:监听PHASE_BOOT_COMPLETED,触发AdbService::bootCompleted方法
FgThread.getHandler().sendMessage(obtainMessage( AdbService::bootCompleted, mAdbService));
}
}
}
//实现aidl接口
private class AdbManagerInternalImpl extends AdbManagerInternal {
//....省略..
}
}
AdbService附属与system_server进程,他的声明周期跟随SystemService,依次调用 systemReady和bootCompleted方法。
2)如何监听Settings调试功能开关
我们接着跟踪一下AdbService的构造函数 -> systemReady -> bootCompleted
public class AdbService extends IAdbManager.Stub {
private static final String TAG = "AdbService";
private static final boolean DEBUG = false;
private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
private static final String WIFI_PERSISTENT_CONFIG_PROPERTY = "persist.adb.tls_server.enable";
private final Context mContext;
private final ContentResolver mContentResolver;
private final ArrayMap<IBinder, IAdbTransport> mTransports = new ArrayMap<>();
private boolean mIsAdbUsbEnabled;
private boolean mIsAdbWifiEnabled;
private AdbDebuggingManager mDebuggingManager;
private ContentObserver mObserver;
//流程1:构造函数
private AdbService(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
mDebuggingManager = new AdbDebuggingManager(context);
registerContentObservers();
LocalServices.addService(AdbManagerInternal.class, new AdbManagerInternalImpl());
}
//流程2:主要逻辑判断persist.sys.usb.config属性中是否配置adb,就去使能数据库里面关于adb的配置
public void systemReady() {
if (DEBUG) Slog.d(TAG, "systemReady");
//判断persist.sys.usb.config属性的值是否包含了adb
mIsAdbUsbEnabled = containsFunction( SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""), UsbManager.USB_FUNCTION_ADB);
boolean shouldEnableAdbUsb = mIsAdbUsbEnabled || SystemProperties.getBoolean( TestHarnessModeService.TEST_HARNESS_MODE_PROPERTY, false);
//判断persist.adb.tls_server.enable属性是否支持wifi adb
mIsAdbWifiEnabled = "1".equals( SystemProperties.get(WIFI_PERSISTENT_CONFIG_PROPERTY, "0"));
//设置Settings数据库的值,同步给UI
try {
Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, shouldEnableAdbUsb ? 1 : 0);
Settings.Global.putInt(mContentResolver, Settings.Global.ADB_WIFI_ENABLED, mIsAdbWifiEnabled ? 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.");
}
}
//流程3:启动adbd守护进程
public void bootCompleted() {
if (DEBUG) Slog.d(TAG, "boot completed");
if (mDebuggingManager != null) {
//设置usb adb
mDebuggingManager.setAdbEnabled(mIsAdbUsbEnabled, AdbTransportType.USB);
//设置wifi adb
mDebuggingManager.setAdbEnabled(mIsAdbWifiEnabled, AdbTransportType.WIFI);
}
}
//ADB数据库UI里面的监听器
private class AdbSettingsObserver extends ContentObserver {
private final Uri mAdbUsbUri = Settings.Global.getUriFor(Settings.Global.ADB_ENABLED);
private final Uri mAdbWifiUri = Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED);
AdbSettingsObserver() {
super(null);
}
//当Settings里面有值进行了变更回调改方法
@Override
public void onChange(boolean selfChange, @NonNull Uri uri, @UserIdInt int userId) {
if (mAdbUsbUri.equals(uri)) {
boolean shouldEnable = (Settings.Global.getInt(mContentResolver, Settings.Global.ADB_ENABLED, 0) > 0);
//调用 AdbService::setAdbEnabled方法
FgThread.getHandler().sendMessage(obtainMessage( AdbService::setAdbEnabled, AdbService.this, shouldEnable, AdbTransportType.USB));
} else if (mAdbWifiUri.equals(uri)) {
boolean shouldEnable = (Settings.Global.getInt(mContentResolver, Settings.Global.ADB_WIFI_ENABLED, 0) > 0);
//调用AdbService::setAdbEnabled方法
FgThread.getHandler().sendMessage(obtainMessage(
AdbService::setAdbEnabled, AdbService.this, shouldEnable,
AdbTransportType.WIFI));
}
}
}
}
3)如何启动adbd守护进程
二、usb
1、usbd进程
1)usbd进程特性
usbd属于native层的一个普通进程,被定义为usbd,被init启动,被定义为oneshot,即就启动一次。
2)usbd主函数
usbd进程非常简单,就只有一个main函数,在main函数中主要逻辑就是根据persist.sys.usb.config属性的值去掉用usb hal层,设置对应的function。
//system/core/usbd/usbd.cpp
#define LOG_TAG "usbd"
int main(int /*argc*/, char** /*argv*/) {
//充电模式直接退出
if (GetProperty("ro.bootmode", "") == "charger") exit(0);
//native进程的binder线程池初始化
int operationId = sUsbOperationCount++;
ABinderProcess_setThreadPoolMaxThreadCount(1);
ABinderProcess_startThreadPool();
const std::string service_name = std::string(aidl::android::hardware::usb::gadget::IUsbGadget::descriptor).append("/default");
//获取系统属性persist.sys.usb.config,其值可能为adb,在init进程的update_sys_usb_config函数中初始化值,其逻辑动态设置adb或者none
std::string function = GetProperty("persist.sys.usb.config", "");
if (function == "adb") {
LOG(INFO) << "persistent prop is adb";
SetProperty("ctl.start", "adbd"); //启动adbd进程
}
//获取USB AIDL HAL,在A14之后google建议使用AIDL替代之前HIDL
if (AServiceManager_isDeclared(service_name.c_str())) {
shared_ptr<aidl::android::hardware::usb::gadget::IUsbGadget> gadget_aidl =
aidl::android::hardware::usb::gadget::IUsbGadget::fromBinder(ndk::SpAIBinder(AServiceManager_waitForService(service_name.c_str())));
ScopedAStatus ret;
if (gadget_aidl != nullptr) {
//找到usb hal
LOG(INFO) << "Usb AIDL HAL found.";
if (function == "adb") {
//如果function是adb,设置当前function为adb
ret = gadget_aidl->setCurrentUsbFunctions( static_cast<uint64_t>(GadgetFunction::ADB), nullptr, 0, operationId);
} else {
//如果function是mtp,设置当前function为mtp
LOG(INFO) << "Signal MTP to enable default functions";
ret = gadget_aidl->setCurrentUsbFunctions( static_cast<uint64_t>(GadgetFunction::MTP), nullptr, 0, operationId);
}
if (!ret.isOk()) LOG(ERROR) << "Error while invoking usb hal";
} else {
LOG(INFO) << "Usb AIDL HAL not found";
}
} else {
//获取USB HIDL HAL,兼容A14之前的版本
android::sp<android::hardware::usb::gadget::V1_0::IUsbGadget> gadget = android::hardware::usb::gadget::V1_0::IUsbGadget::getService();
Return<void> ret;
if (gadget != nullptr) {
LOG(INFO) << "Usb HAL found.";
if (function == "adb") {
ret = gadget->setCurrentUsbFunctions(static_cast<uint64_t>(GadgetFunction::ADB), nullptr, 0);
} else {
LOG(INFO) << "Signal MTP to enable default functions";
ret = gadget->setCurrentUsbFunctions(static_cast<uint64_t>(GadgetFunction::MTP), nullptr, 0);
}
if (!ret.isOk()) LOG(ERROR) << "Error while invoking usb hal";
} else {
LOG(INFO) << "Usb HAL not found";
}
}
exit(0);
}
3)setCurrentUsbFunctions函数
接着上文native层的usbd进程直接调用usb hal的setCurrentUsbFunctions接口来设置usb的function,我们先看看改接口的定义,如下:
setCurrentUsbFunctions函数的实现如下:
//hardware/interfaces/usb/gadget/1.1/default/UsbGadget.cpp
//setCurrentUsbFunctions函数用于动态切换Android设备的USB功能模式(如ADB/MTP等)
//functions参数为USB功能模式,可能值diag,serial_cdev,rmnet,dpl,qdss,adb或者none
Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions, const sp<V1_0::IUsbGadgetCallback>& callback, uint64_t timeout) {
std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
mCurrentUsbFunctions = functions;
mCurrentUsbFunctionsApplied = false;
//流程1:卸载当前USB功能驱动(如断开ADB/MTP链接)Unlink the gadget and stop the monitor if running.
V1_0::Status status = tearDownGadget();
if (status != V1_0::Status::SUCCESS) {
goto error;
}
ALOGI("Returned from tearDown gadget");
//流程2:等待主机(如PC)检测到USB断开,即延迟等待 Leave the gadget pulled down to give time for the host to sense disconnect.
usleep(kDisconnectWaitUs);
//流程3:如果要设置NONE,即卸载当前USB功能驱动,所以直接return即可
if (functions == static_cast<uint64_t>(V1_0::GadgetFunction::NONE)) {
if (callback == NULL) return Void();
Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);//回调给客户端
if (!ret.isOk())
ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
return Void();
}
//流程4:验证并设置VID/PID,根据功能配置验证并设置USB厂商/产品ID(如ADB和MTP的ID不同),例如高通的90DB等这些端口
status = validateAndSetVidPid(functions);
if (status != V1_0::Status::SUCCESS) {
goto error;
}
//流程5:设置USB的功能,例如adb,diag等,加载对应内核模块(如ffs.adb或ffs.mtp)并激活功能
status = setupFunctions(functions, callback, timeout);
if (status != V1_0::Status::SUCCESS) {
goto error;
}
//流程6:整个流程成功,日志打印
ALOGI("Usb Gadget setcurrent functions called successfully");
return Void();
//流程7:整个流程失败,错误处理
error:
ALOGI("Usb Gadget setcurrent functions failed");
if (callback == NULL) return Void();
Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);
if (!ret.isOk())
ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
return Void();
}
总计如下几个流程:
- 流程1:tearDownGadget函数卸载当前USB功能驱动(如断开ADB/MTP链接)
- 流程2:如果functions是none,那么函数直接退出
- 流程3:validateAndSetVidPid校验设置VID和PID
- 流程4:setupFunctions设置functions
重点在看看setupFunctions是如何设置function的呢?如下代码,重点是根据vendor的几个属性来获取:
//vendor/qcom/opensource/usb/hal/UsbGadget.cpp
#define VENDOR_USB_PROP "vendor.usb.config"
#define PERSIST_VENDOR_USB_PROP "persist.vendor.usb.config"
#define PERSIST_VENDOR_USB_EXTRA_PROP "persist.vendor.usb.config.extra"
2、usb.config属性的配置
由此可见,usbd进程到usb hal之间协同作用,设置usb的工作模式,这个过程中不仅仅关联了如下几个属性,有persist.sys. 还有persist.vendor. 等,感觉非常的乱。
这里依次对她们进行一个整理。总共相关联的如下几个,在不同的平台和不同的android版本可能不一致:
- [persist.sys.usb.config]: [adb]
- [persist.vendor.usb.config]: [diag,serial_cdev,rmnet,dpl,qdss,adb]
- [persist.vendor.usb.config.extra]: [none]
- [sys.usb.config]: [diag,serial_cdev,rmnet,dpl,qdss,adb]
- [sys.usb.configfs]: [2]
- [vendor.usb.config]: [diag,serial_cdev,rmnet,dpl,qdss,adb]
- [vendor.usb.configfs]: [1]
1)persist.sys.usb.config属性的初始化
这段代码是在init进程初始化系统属性的时候,通过PropertyLoadBootDefaults函数去加载默认属性的时候调用,梳理如下逻辑:
- 如果persist.sys.usb.config属性为空,如果debug版本,设置改属性为adb,用来支持开发者调试
- 如果persist.sys.usb.config属性为空,如果非debug版本,设置改属性为none,默认不允许调试
- 如果persist.sys.usb.config属性有值,如果debug版本,并且属性值没有adb,那么加上adb用来支持开发者调试。
- 在usbd进程启动过程中,会根据persist.sys.usb.config的值去对HAL层设置function功能,这里只看到了adb和mtp两种功function。
2)persist.vendor.usb.config属性的初始化
此属性在MTK平台不存在,主要是在高通平台上面,高通平台通过一个sh脚本主动去设置初始值,如果是debug版本就主动设置为diag,diag_mdm,qdss,qdss_mdm,serial_cdev,dpl,rmnet,adb,后续根据高通不同平台去设置不同的值,可能高通不同芯片架构支持的能力不一样。
这个脚本什么时候启动呢?是init进程运行过程中启动:
3)sys.usb.config和vendor.usb.config
persist.sy.usb.config和persist.vendor.usb.config的值分别会影响sys.usb.config和vendor.usb.config,但是他们的相互影响比较混乱,详细的可以参考init.qcom.usb.rc
这里整理一下大致的如下:
#on boot的时候触发,把persist.vendor.usb.config的值赋值给sys.usb.config
on boot
setprop sys.usb.config ${persist.vendor.usb.config}
on boot && property:vendor.usb.use_gadget_hal=1
setprop sys.usb.configfs 2
#如果sys.usb.configfs强化模式支持,把sys.usb.config的值赋值给vendor.usb.config
on property:sys.usb.config=* && property:sys.usb.configfs=2
setprop vendor.usb.config ${sys.usb.config}
#如果sys.usb.configfs强化模式支持,usb.config属性变动启动usbd进程
on property:vendor.usb.config=* && property:sys.usb.configfs=2
start usbd
on property:vendor.usb.controller=* && property:vendor.usb.use_gadget_hal=0
setprop sys.usb.controller ${vendor.usb.controller}
setprop sys.usb.configfs 1
#如果vendor.usb.use_gadget_hal=0,把persist.vendor.usb.config赋值给persist.sys.usb.config
on property:persist.vendor.usb.config=* && property:vendor.usb.use_gadget_hal=0
setprop persist.sys.usb.config ${persist.vendor.usb.config}
on boot && property:ro.boot.usbconfigfs=true
setprop sys.usb.configfs 1
#如果sys.usb.configfs=1普通模式支持,后续通过rc来触发sys.usb.config属性的所有动作
on property:sys.usb.config=none && property:sys.usb.configfs=1
on property:sys.usb.config=* && property:sys.usb.configfs=1
rm /config/usb_gadget/g1/os_desc/b.1
on property:sys.usb.config=none && property:sys.usb.configfs=1
rm /config/usb_gadget/g1/configs/b.1/f1
rm /config/usb_gadget/g1/configs/b.1/f2
rm /config/usb_gadget/g1/configs/b.1/f3
rm /config/usb_gadget/g1/configs/b.1/f4
rm /config/usb_gadget/g1/configs/b.1/f5
rm /config/usb_gadget/g1/configs/b.1/f6
rm /config/usb_gadget/g1/configs/b.1/f7
rm /config/usb_gadget/g1/configs/b.1/f8
rm /config/usb_gadget/g1/configs/b.1/f9
rm /config/usb_gadget/g1/configs/b.1/f10
rm /config/usb_gadget/g1/configs/b.1/f11
rm /config/usb_gadget/g1/configs/b.1/f12
rm /config/usb_gadget/g1/configs/b.1/f13
rm /config/usb_gadget/g1/configs/b.1/f14
on property:sys.usb.config=mass_storage && property:sys.usb.configfs=1
#....省略...
这段rc配置把几个属性完全耦合,我们只需要明白
sys.usb.configfs属性的值为1的时候,不会赋值到vendor.usb.config,我在此值为1的手上调试发现基本上不会存在vendor.usb.config,即sys.ubs.config在rc文件中执行响应控制usb相关节点
sys.usb.configfs属性的值为2的时候,直接赋值到vendor.usb.config,并通过启动usbd进程去响应,usbd进程里面获取persist.sys.usb.config,还会启动usb hal,在usb hal中会参考persist.vendor.usb.config去影响vendor.usb.config默认值,但是最终还是由vendor.usb.config来决定当前如何控制usb
3、高通A14项目的日志跟踪
1)高通A14 userdebug版本
这次使用的版本是高通a14 debug版本,因此属性如下:
- persist.sys.usb.config默认没有配置,因为是debug版本,所以在init进程update_sys_usb_config函数中被默认设置为adb
- persist.vendor.usb.config默认在init进程的on-post-fs-data阶段启动init.qcom.usb.sh脚本设置为diag,serial_cdev,rmnet,dpl,qdss,adb
C:\Users\pengcheng.ding>adb shell getprop | findstr "usb.config"
[persist.sys.usb.config]: [adb]
[persist.vendor.usb.config]: [diag,serial_cdev,rmnet,dpl,qdss,adb]
[persist.vendor.usb.config.extra]: [none]
[sys.usb.config]: [diag,serial_cdev,rmnet,dpl,qdss,adb]
[sys.usb.configfs]: [2]
[vendor.usb.config]: [diag,serial_cdev,rmnet,dpl,qdss,adb]
[vendor.usb.configfs]: [1]
2)高通A14 user 定制版本:persist.vendor.usb.config
这次使用的是高通A14 user版本,定制了在update_sys_usb_config的时候强制如下属性:persist.sys.usb.config]: [diag,serial_cdev,rmnet,dpl,qdss,adb]
- 因为persist.sys.usb.config非adb,所以在原生的usbd代码中直接进入mtp流程
- 因为user版本,所以persist.vendor.usb.config在init.qcom.usb.sh脚本中根本不会设置
C:\Users\pengcheng.ding>adb shell getprop | findstr "usb.config"
[persist.sys.usb.config]: [diag,serial_cdev,rmnet,dpl,qdss,adb]
[persist.vendor.usb.config.extra]: [none]
[sys.usb.config]: [diag,serial_cdev,rmnet,dpl,qdss,adb]
[sys.usb.configfs]: [2]
[vendor.usb.config]: [diag,serial_cdev,rmnet,dpl,qdss,adb]
[vendor.usb.configfs]: [1]
针对如上属性组合,开机流程会经过如下两个阶段:
- 大约开机动画显示的时候:此时init进程系统属性服务启动的时候,去设置persist.sys.usb.config会直接导致usbd启动,并进行匹配非adb,因此进入MTP模式,在usb hal里面切换为None和MTP,这个时候adb是断开的
- 在开机完成进入lancher的时候:会响应on boot把persist.sys.usb.config的值赋值到vendor.usb.config,这个时候居然去启动了adbd和usb hal,在hal中判断vendor.usb.config的值包含adb,因此添加了所有的功能
3)高通A14 user定制版本:usbd
针对如上情况,persist.vendor.usb.config定制为diag,serial_cdev,rmnet,dpl,qdss,adb,但是在开机动画阶段确没有adb,这个情况感觉个人觉得不是很合理,明明包含adb,为什么usbd判断出来非adb呢?因此针对usbd进程做了如下的修改:
此时在开机动画阶段,usbd进程启动的时候就不会进入mtp流程,而是直接切换为adb功能,adbd就不会在开机动画过程中中断,如下日志:
三、相关案例
1、属性总结
1)service.adb.root
值为1:表示设备当前处于root状态,即adb shell进程处于root用户组。执行adb root之后此属性会被值为1。
值为0:表示设备当前未处于root状态,即adb shell进程处于shell用户组。执行adb unroot之后此属性会被值为0。
默认值:默认的设备上,相当于值0的表现。
2)ro.adb.secure
值为1:表示adb调试之前需要弹出对话框"是否允许USB调试?",即需要手动点击进行RSA秘钥验证之后才能够进行adb shell
值为0:表示adb调试之前不需要进行RSA秘钥验证,只要有adb端口,既可以直接adb shell链接设备。
默认值:默认的设备上默认是没有这个属性的,这个时候的表现现状和值为1的一致
3)ro.debuggable
值为1:表示可以进行debuggable进行调试
值为0:表示不可以进行debuggable进行调试
解读:用于控制系统的调试能力和开发功能。当属性值为1时,表示系统处于可调试模式,允许开发者启用应用调试功能(如通过ADB调试任何应用程序)、获得root权限访问本地shell、或降级SELinux至“permissive”模式,从而便于系统调试和优化。当属性值为0时,表示系统无法进行高级调试模式。通常user版本的这个属性被设置为0,userdebug版本的这个属性被设置为1。android aosp很多进程,涉及到相关调试能力,都会来check此属性,如下我发现的几个地方:
- 执行adb root命令的时候,会直接打印"adbd cannot run as root in production builds"
2、案例之实现不需要执行adb root命令自动具有root权限
根据adbd权限降级和adb root命令执行可以了解如下逻辑:
- 执行adb root之后:service.adb.root 为1,在drop_privileges中使用了root用户组
- 执行adb unroot之后:service.adb.root 为0,在drop_privileges中使用了shell用户组
因此如果我们想绕过adb root命令,直接带有root用户组权限,那么可以强制函数should_drop_privileges返回false。如下案例:
3、案例之实现不需要RSA认证直接能够使用adb shell命令
安卓设备通过usb链接电脑之后,我们在开发者模式菜单开启usb调试之后,通常还无法直接通过adb shell链接设备。会弹出如下对话框进行授权
如果我们想跳过这个对话框的显示,那么可以根据adbd守护进程中讲解的,强制属性ro.adb.secure的值为false即可,在debug版本或者解锁版本中,此值如果没有设置默认当成false。