Android Qualcomm USB 专题系列【篇二:UsbGadget模式配置】

接该系列前文,本篇继续围绕高通定制usb架构,针对设备作为usb device模式下的相关逻辑梳理。

本篇先介绍usbgadget hal服务的代码实现,然后逆推native层的usbd,以及fw和settings usb模式切换的完整调用链。

一、USB Gadget HAL

UsbGadget.cpp实现了USB Gadget Hal服务的完整代码,他往往被上层进行调用,上层可以通过它来改变当期设备作为usb device模式下.

端口应该配置成什么?应该支持什么样的功能?是否可以使用adb的功能?是否可以使用diag的功能?或者是否可以进行音视频数据传输?

1、UsbGadget主函数

如上A14和A16的代码对比,可以看出来A16以及使用了AIDL接口,A14还是HIDL接口,其他基本上一致,都是启动一个HAL服务进程,他们的一些差别总结如下:

特性 usb a14 usb a16
HAL 类型 HIDL (Hardware Interface Definition Language) AIDL (Android Interface Definition Language)
接口版本 android.hardware.usb.gadget@1.1 aidl::android::hardware::usb::gadget
LOG_TAG "android.hardware.usb.gadget@1.1-service-qti" "android.hardware.usb.gadget-service.qti"

2、UsbGadget向量表

接下来我们看看UsbGadget的初始化流程:

析了conf配置表添加到向量表supported_compositions 中,这个很重要后续会使用到,就是https://blog.csdn.net/qq_27672101/article/details/156097668中介绍的usb device支持的模式:

如上配置会添加到向量表**supported_compositions中,**后续上层通过usb.config属性设置gadget模式的时候,就跟根据这个向量表去设置底层驱动VID和PID端口。

3、getCurrentUsbFunctions

UsbGadget对外提供的最核心的接口之一,该接口的作用就是查询当前已设置的 USB 功能状态,返回usb functions。

mCurrentUsbFunctions就是当前usb被启用的功能的掩码,被定义为 uint64_t类型,如下配置:

功能 枚举值 说明 示例值(二进制)
NONE 0x0 无功能 0000 0000
ADB 0x1 Android Debug Bridge 0000 0001
MTP 0x2 Media Transfer Protocol 0000 0010
PTP 0x4 Picture Transfer Protocol 0000 0100
RNDIS 0x8 USB 网络共享 0000 1000
MIDI 0x10 MIDI 音频 0001 0000
ACCESSORY 0x20 Android Accessory 0010 0000
AUDIO_SOURCE 0x40 音频源 0100 0000
NCM 0x80 Network Control Model 1000 0000
UVC 0x100 USB Video Class 0001 0000 0000

4、AOSP标准功能 VS 高通特有功能

这里系统性的介绍一下usb作为device模式的时候,到底有哪些功能,为什么有的地方使用function来表达,但是又有地方使用字符串来表达。两者傻傻的分不清

1)AOSP标准功能

其实就是如上mCurrentUsbFunctions中定义的子网掩码,包括ADB、MTP等,这些功能都是AOSP原生定义的,即只要是android系统,都必须支持usb的这几种功能。

因此USB Gadget HAL对上层只提供了getCurrentUsbFunctions这样的接口,同样对外也只提供setCurrentUsbFunctions接口,目的就是为了和aosp fw进行匹配

functions 枚举 配置文件字符串 说明
GadgetFunction::ADB "adb" Android Debug Bridge
GadgetFunction::MTP "mtp" Media Transfer Protocol
GadgetFunction::PTP "ptp" Picture Transfer Protocol
GadgetFunction::RNDIS "rndis" USB 网络共享
GadgetFunction::NCM "ncm" Network Control Model
GadgetFunction::UVC "uvc" USB Video Class

2)Qualcomm特有功能

这类功能属于高通特有,所以不可能存在于AOSP标准功能中,即不可能存在AOSP定义的GadgetFunction枚举中,那么高通如何兼容这些特有功能呢?高通对xxx.usb.config属性进行了扩展:

aosp标准的GadgetFunction::ADB对应属性值为adb,这个是aosp和高通都支持配置

高通特有的diag功能,就在该属性值上面进行扩展为"diag,adb"或者"diag"的ADB,因为这是高通自己加的,所以GadgetFunction里面是不可能存在的。高通的做法就是在UsbGadget HAL里面进行适配,那么如何适配的,请参考setCurrentUsbFunctions函数

配置文件字符串 说明 是否在 functions 中
"diag" 诊断接口 ❌ 不在
"diag_mdm" 调制解调器诊断 ❌ 不在
"qdss" Qualcomm 调试子系统 ❌ 不在
"rmnet" 远程网络接口 ❌ 不在
"serial_cdev" 串口设备 ❌ 不在
"dpl" 数据路径日志 ❌ 不在
"ccid" 智能卡接口 ❌ 不在
"uac2" USB 音频(Qualcomm 实现) ❌ 不在
"mass_storage" U盘模式 ❌ 不在
"ipcr" 处理器间通信 ❌ 不在

PS:正式因为高通的这种骚操作,到时aosp usbd的代码无法适配,在高通项目上面出现了一类通用bug,详细参考案例分析

5、setCurrentUsbFunctions

UsbGadget对外提供的最核心的接口之一,该接口的作用是设置启动usb一个或者多个功能,同上,该函数对外支持的接口也只针对AOSP标准功能,因此该函数参数也是一个uint64_t类型,也是通过mCurrentUsbFunctions变量来存储当前functions。

1)AOSP标准流程

cpp 复制代码
//la.um/vendor/qcom/opensource/usb/hal/UsbGadget.cpp
//setCurrentUsbFunctions函数用于动态切换Android设备的USB功能模式(如ADB/MTP等)
//functions参数为USB功能模式,只能是AOSP标准功能如ADB MTP等,不可能传递高通特有的diag,serial_cdev等字符串
ScopedAStatus UsbGadget::setCurrentUsbFunctions(int64_t functions, const shared_ptr<IUsbGadgetCallback> &callback, int64_t timeout, int64_t in_transactionId) {
  std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
  mCurrentUsbFunctions = functions;
  mCurrentUsbFunctionsApplied = false;
  //流程1:卸载当前USB功能驱动(如断开ADB/MTP链接)Unlink the gadget and stop the monitor if running.
  Status status = tearDownGadget();
  if (status != Status::SUCCESS) goto error;
  //流程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>(GadgetFunction::NONE)) {
    if (callback == nullptr)
      return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
    ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions,  Status::SUCCESS, in_transactionId); //回调给客户端
    if (!ret.isOk()) ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
    return ret;
  }
  //流程4:验证并设置VID/PID‌,根据功能配置验证并设置USB厂商/产品ID(如ADB和MTP的ID不同),例如高通的90DB等这些端口
  status = validateAndSetVidPid(functions);
  if (status != Status::SUCCESS)  goto error;
  //流程5:设置USB的功能,这个很重要
  status = setupFunctions(functions, callback, timeout, in_transactionId);
  if (status != Status::SUCCESS) goto error;
  //流程6:整个流程成功,日志打印
  ALOGI("Usb Gadget setcurrent functions called successfully");
  return ScopedAStatus::ok();
//流程7:整个流程失败,错误处理
error:
  ALOGI("Usb Gadget setcurrent functions failed");
  if (callback == nullptr)
    return ScopedAStatus::fromServiceSpecificErrorWithMessage(-1, "Usb Gadget setcurrent functions failed");
  ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, status, in_transactionId);
  if (!ret.isOk()) {
    ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
    return ret;
  }
  return ScopedAStatus::fromServiceSpecificErrorWithMessage(-1, "Usb Gadget setcurrent functions failed");
}

如上代码的核心流程还是参照aosp原生流程进行处理,在设置usb功能的时候,先卸载断开当前usb,然后验证VID/PID,然后通过setupFunctions来实现具体功能的启用。

2)高通定制setupFunctions

cpp 复制代码
//la.um/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"
Status UsbGadget::setupFunctions( int64_t functions, const shared_ptr<IUsbGadgetCallback> &callback, int64_t timeout, int64_t in_transactionId) {
  //functions参数为aosp标准功能,例如ADB MTP等,不可能是高通特有的diag等字符串
  bool ffsEnabled = false;
  int i = 0;
  //核心流程1:获取属性vendor.usb.config和persist.vendor.usb.config的值
  //          获取高通定制的功能,例如diag,adb将被获取出来
  std::string gadgetName = GetProperty(USB_CONTROLLER_PROP, "");
  std::string vendorProp = GetProperty(VENDOR_USB_PROP, GetProperty(PERSIST_VENDOR_USB_PROP, ""));
  std::string vendorExtraProp = GetProperty(PERSIST_VENDOR_USB_EXTRA_PROP, "none");
  //......
  //核心分支A:如果设置AOSP标准RNDIS/NCM网络共享功能
  //          GadgetFunction::RNDIS和GadgetFunction::NCM是AOSP标准功能
  if (((functions & GadgetFunction::RNDIS) != 0) || ((functions & GadgetFunction::NCM) != 0)) {
    ALOGI("setCurrentUsbFunctions rndis");
    std::string tetherComp = (functions & GadgetFunction::RNDIS) ? "rndis" : "ncm";
    //如果persist.vendor.usb.config.extra属性有值,那么追加adb功能
    if (vendorExtraProp != "none") tetherComp += "," + vendorExtraProp;
    if (functions & GadgetFunction::ADB)  tetherComp += ",adb";
    //通过addFunctionsFromPropString去启用属性字符串的功能
    if (addFunctionsFromPropString(tetherComp, ffsEnabled, i)) return Status::ERROR;
  }
  //核心分支B:如果设置AOSP标准ADB,且vendor.usb.config不等于adb
  //          例如vendor.usb.config=diag.adb,这个时候上层应该传递GadgetFunction::ADB,但是还得添加高通定制的diag功能
  else if (functions == static_cast<uint64_t>(GadgetFunction::ADB) && !vendorProp.empty() && vendorProp != "adb") {
    if (vendorProp.find("adb") == std::string::npos)  vendorProp += ",adb";
    // 先打印vendor.usb.config值,即要设置的功能,其值可能包含多个功能
    ALOGI("setting composition from %s: %s", VENDOR_USB_PROP, vendorProp.c_str());
    // look up & parse prop string and link each function into the composition
    //通过addFunctionsFromPropString去添加所有的高通指定的功能
    if (addFunctionsFromPropString(vendorProp, ffsEnabled, i)) {
      // if failed just fall back to adb-only
      unlinkFunctions(CONFIG_PATH);
      i = 0;
      ffsEnabled = true;
      if (addAdb(&mMonitorFfs, &i) != ::android::hardware::usb::gadget::V1_0::Status::SUCCESS)
        return Status::ERROR;
    }
  } else { 
    //核心分支C:android标准功能添加,例如单纯的MTP或者PTP
    WriteStringToFile("android", CONFIG_STRING);
    if ((functions & GadgetFunction::UVC) == 0) {
      if (addGenericAndroidFunctions(&mMonitorFfs, functions, &ffsEnabled, &i) != ::android::hardware::usb::gadget::V1_0::Status::SUCCESS)
        return Status::ERROR;
    } else {
        ALOGI("setCurrentUsbFunctions uvc");
        if (linkFunction("uvc.0", i++))   return Status::ERROR;
    }
    if ((functions & GadgetFunction::ADB) != 0) {
      ffsEnabled = true;
      if (addAdb(&mMonitorFfs, &i) != ::android::hardware::usb::gadget::V1_0::Status::SUCCESS)
        return Status::ERROR;
    }
  }
  //........
  //ffs相关功能启用判断
  ALOGI("Started monitor for FFS functions");
  //........
  return Status::SUCCESS;
}

如上代码核心逻辑,先获取了vendor.usb.config和persist.vendor.usb.config属性的值,然后进行了如下三条分支判断:

  • function参数是RNDIS/NCM:表示启用aosp标准的网络共享功能,判断如果xxx.usb.config包含adb,那么通过addFunctionsFromPropString函数添加adb功能
  • function参数是ADB:判断如果xxx.usb.config不等于adb,那么说明除了adb还有其他功能,例如高通特有功能,那么通过addFunctionsFromPropString函数添加字符串功能
  • function参数是其他asop标准功能:走aosp标准流程

3)addFunctionsFromPropString

4)MTP场景

vendor.usb.config = adb 或者 vendor.usb.config = diag,adb

hal->setCurrentUsbFunctions(static_cast<uint64_t>(GadgetFunction::MTP), nullptr, 0);

因为hal调用传递的参数是MTP,所以直接走核心分支C,也不会添加高通特有功能diag

5)RNDIS场景 + adb

vendor.usb.config = rndis,adb

hal->setCurrentUsbFunctions(static_cast<uint64_t>(GadgetFunction::RNDIS), nullptr, 0);

因为hal调用传递的参数是RNDIS,所以直接走核心分支A,后判断xxx.usb.config包含adb,因此会通过addFunctionsFromPropString添加adb功能

6)ADB场景 + 高通字符串

vendor.usb.config = adb

hal->setCurrentUsbFunctions(static_cast<uint64_t>(GadgetFunction::ADB), nullptr, 0);

因为hal调用传递的参数是ADB,所以直接走核心分支B,但是判断没有高通特定的功能,所以也不会调用addFunctionsFromPropString

vendor.usb.config = diag,serial_cdev,rmnet,dpl,qdss,adb

hal->setCurrentUsbFunctions(static_cast<uint64_t>(GadgetFunction::ADB), nullptr, 0);

因为hal调用传递的参数是ADB,所以直接走核心分支B,判断xxx.usb.config不等于adb,所以会调用addFunctionsFromPropString依次遍历添加高通特有功能,如下日志:

bash 复制代码
12-17 12:21:29.554   890   890 I servicemanager: Caller(pid=13885,uid=0,sid=u:r:usbd:s0) Found android.hardware.usb.gadget.IUsbGadget/default in device VINTF manifest.
12-17 12:21:29.672  1480  1480 I android.hardware.usb.gadget-service.qti: setting composition from vendor.usb.config: diag,serial_cdev,rmnet,dpl,qdss,adb
12-17 12:21:29.672  1480  1480 E android.hardware.usb.gadget-service.qti: vid 0x05C6 pid 0x90DB
12-17 12:21:29.673  1480  1480 I android.hardware.usb.gadget-service.qti: Adding diag
12-17 12:21:29.674  1480  1480 I android.hardware.usb.gadget-service.qti: Adding serial_cdev
12-17 12:21:29.675  1480  1480 I android.hardware.usb.gadget-service.qti: Adding rmnet
12-17 12:21:29.676  1480  1480 I android.hardware.usb.gadget-service.qti: Adding dpl
12-17 12:21:29.678  1480  1480 I android.hardware.usb.gadget-service.qti: Adding qdss
12-17 12:21:29.680  1480  1480 I android.hardware.usb.gadget-service.qti: Adding adb
12-17 12:21:29.686  1480  1480 I android.hardware.usb.gadget-service.qti: Started monitor for FFS functions
12-17 12:21:29.686  1480  1480 I android.hardware.usb.gadget-service.qti: Usb Gadget setcurrent functions called successfully

二、usbd进程

usbd属于native层的一个普通进程,被定义为usbd,被init启动,被定义为oneshot,即就启动一次。

1)usbd主函数

usbd进程非常简单,就只有一个main函数,在main函数中主要逻辑就是根据persist.sys.usb.config属性的值去掉用usb hal层,设置对应的function。

cpp 复制代码
//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);
}

usbd主函数的逻辑非常的简单,通过如上代码可以总结如下:

  • 如果persist.sys.usb.config属性值为adb,那么就启动adbd守护进程
  • 如果persist.sys.usb.config属性值为adb,那么就调用HAL设置usb功能GadgetFunction::ADB
  • 如果persist.sys.usb.config属性值非adb,那么就调用HAL设置usb功能GadgetFunction::MTP
  • A14包括之前使用的HIDL接口,A16使用的就是AIDL
  • 注意:其实这里的判断会有bug,后文会详细介绍

2)A14 setCurrentUsbFunctions函数

接着上文native层的usbd进程直接调用usb hal的setCurrentUsbFunctions接口来设置usb的function,我们先看看改接口的定义,如下:

setCurrentUsbFunctions函数的实现如下:

cpp 复制代码
//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的几个属性来获取:

cpp 复制代码
//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

这里整理一下大致的如下:

bash 复制代码
#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、sys.usb.configfs模式配置

sys.usb.configfs 是 Android 系统中用于控制 USB 配置方式的核心属性,该属性决定使用哪种内核机制来配置 USB 功能:

  • 0:表示传统模式(基于 android_usb.ko 驱动)‌,该方式在A12之后已经被弃用,此处不作任何介绍
  • 1:表示现代 ConfigFS 模式(基于 /config/usb_gadget 动态配置)‌,即可以通过init.qcom.usb.rc文件配置的sys.usb.config属性动态配置生效
  • 2:最新usb hal采用usb_compositions.conf的配置来实现

4、高通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
bash 复制代码
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脚本中根本不会设置
bash 复制代码
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就不会在开机动画过程中中断,如下日志:

相关推荐
诸神黄昏EX2 小时前
Android Qualcomm USB 专题系列【总篇:USB HAL架构】
android·linux·网络
原神启动12 小时前
Ansible(三)—— 使用Ansible自动化部署LNMP环境
android·自动化·ansible
前端老白2 小时前
webview在微信小程序中,安卓加载失败,IOS正常加载
android·ios·微信小程序·webview
2501_937154932 小时前
适配中兴主流机型 纯净版刷机固件技术优势合集
android·源码·源代码管理·机顶盒
2501_915106322 小时前
用 HBuilder 上架 iOS 应用时如何管理Bundle ID、证书与描述文件
android·ios·小程序·https·uni-app·iphone·webview
TheNextByte12 小时前
如何通过OTG或不使用OTG将文件从Android传到U盘
android
2501_915909062 小时前
资源文件混淆在 iOS 应用安全中的实际价值
android·安全·ios·小程序·uni-app·iphone·webview
2501_915918412 小时前
iOS App 性能测试中常被忽略的运行期问题
android·ios·小程序·https·uni-app·iphone·webview
天勤量化大唯粉3 小时前
基于距离的配对交易策略:捕捉价差异常偏离的均值回归机会(天勤量化代码实现)
android·开发语言·python·算法·kotlin·开源软件·策略模式