Android Native 之 adbd & usbd进程分析

目录

一、adb

1、adbd守护进程

2、adbd权限降级

3、adbd命令解析

1)adb shell

2)adb root

3)adb reboot

4、AdbService

1)AdbService的启动

2)如何监听Settings调试功能开关

3)如何启动adbd守护进程

二、usb

1、usbd进程

1)usbd进程特性

2)usbd主函数

3)setCurrentUsbFunctions函数

2、usb.config属性的配置

1)persist.sys.usb.config属性的初始化

2)persist.vendor.usb.config属性的初始化

3)sys.usb.config和vendor.usb.config

3、高通A14项目的日志跟踪

1)高通A14 userdebug版本

2)高通A14 user 定制版本:persist.vendor.usb.config

3)高通A14 user定制版本:usbd

三、相关案例

1、属性总结

 1)service.adb.root

2)ro.adb.secure

3)ro.debuggable

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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诸神黄昏EX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值