android11上bcm gps 2.1 库运行不起来问题调试

458 阅读4分钟

android11上bcm gps 2.1 hal 库运行不起来问题调试

一. GPS hal层主要流程

service gnss-2-1 /vendor/bin/hw/android.hardware.gnss@2.1-service-google
    class hal
    user system
    group system

二.目前问题是service gnss-2-1 无法运行起来,ps -ef查看进程无相关的gnss进程

  • 2.1 查看log
E init    : Control message: Could not ctl.start for 'gnss-2-1' from pid: 8668 (setprop ctl.start gnss-2-1): File /vendor/bin/hw/android.hardware.gnss@2.1-service(labeled "u:object_r:vendor_file:s0") has incorrect label or no domain transition from u:r:init:s0 to another SELinux domain defined. Have you configured your service correctly? https://source.android.com/security/selinux/device-policy#label_new_services_and_address_denials
  • 发现是start service就没成功, 虽然selinux处于permissive模式,但是 selinux对于domain的切换还是需要的.
  • 根据log错误提示增加相关te文件
  • 首先新增一个bcm_gnss.te文件
type bcm_gnss, domain;
type bcm_gnss_exec, exec_type, file_type, vendor_file_type;
init_daemon_domain(bcm_gnss)
  • 然后在file_contexts文件中增加 gnss bin文件的定义
/vendor/bin/hw/android.hardware.gnss@2.1-service-google  u:object_r:bcm_gnss_exec:s0
  • 2.2 重新编译刷机,发现service被启动到了. bcm的bin文件中有打印如下log
android.hardware.gnss@2.1-service-google: Register IGNSS 2.1 Passthrough service
  • 去注册hal service. 紧接着会如下注册不成功的log
Could not get passthrough implementation for android.hardware.gnss@2.1::IGnss/default
  • 此处代码在LegacySupport.cpp中
__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
        const std::string& interfaceName, const std::string& expectInterfaceName,
        RegisterServiceCb registerServiceCb, const std::string& serviceName) {
    sp service =
            getRawServiceInternal(interfaceName, serviceName, true /*retry*/, true /*getStub*/);

    if (service == nullptr) {
        ALOGE("Could not get passthrough implementation for %s/%s.", interfaceName.c_str(),
              serviceName.c_str());
        return EXIT_FAILURE;
    }

    status_t status = registerServiceCb(service, serviceName);
    if (status == OK) {
        ALOGI("Registration complete for %s/%s.", interfaceName.c_str(), serviceName.c_str());
    } else {
        ALOGE("Could not register service %s/%s (%d).", interfaceName.c_str(), serviceName.c_str(),
              status);
    }

    return status;
}
  • get到的service一直为null. log中一直在重复打印重启service的log
init    : starting service 'gnss-2-1'...
init    : Service 'gnss-2-1' (pid 743) exited with status 1
  • 感觉就是这个这个bcm的bin文件启动不成功一直报错, 然后系统一直重试
  • 根据bcm fae反馈他们2.1的hal用的passthrough 模式. 于是在manifest中改为passthrough 模式
<hal format="hidl"> 
<name>android.hardware.gnss</name> 
<transport arch="32">passthrough</transport> 
<version>2.1</version> 
<interface> 
    <name>IGnss</name> 
    <instance>default</instance> 
</interface> 
<fqname>@2.1::IGnss/default</fqname> 
</hal>
  • 重新编译刷机,错误log一样,依然是get service一直为null
  • 2.3 查阅android官方文档,发现对于hidl 有如下描述
For the HAL to work in passthrough mode, you must have the function HIDL_FETCH_IModuleName residing in /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl(OPTIONAL_IDENTIFIER).so where OPTIONAL_IDENTIFIER is a string identifying the passthrough implementation. The passthrough mode requirements are met automatically by the above commands

HAl 使用passthrough 模式时, impl的so库应该是在/vendor/lib/hw下面.

而目前编译方式是放在/vendor/lib下面.

于是把bcm的so文件移到/vendor/lib/hw下面

又产生新的错误

E HidlServiceManagement:Service android.hardware.gnss@2.1::IGnss/defaultmust be in VINTF manifest in order to register/get."

代码在ServiceManagement.cpp

status_t registerAsServiceInternal(const sp& service, const std::string& name) {
    if (service == nullptr) {
        return UNEXPECTED_NULL;
    }

    sp sm = defaultServiceManager1_2();
    if (sm == nullptr) {
        return INVALID_OPERATION;
    }

    const std::string descriptor = getDescriptor(service.get());

    if (kEnforceVintfManifest && !isTrebleTestingOverride()) {
        using Transport = IServiceManager1_0::Transport;
        Transport transport = sm->getTransport(descriptor, name);

        if (transport != Transport::HWBINDER) {
            LOG(ERROR) << "Service " << descriptor << "/" << name
                       << " must be in VINTF manifest in order to register/get.";
            return UNKNOWN_ERROR;
        }
    }

此处有判断transport 不是HWBIINDER模式就return error.

强行修改此处代码,不return err. 然后流程继续跑下去. 发现service可以正常注册成功了.

但是在加载so库文件时发生新的错误

03-05 06:17:22.836   728   728 E vndksupport: Could not load /vendor/lib/hw/android.hardware.gnss@2.1-impl-brcm.so from sphal
namespace: dlopen failed: library "android.hardware.gnss@2.0.so" not found: needed by /vendor/lib/hw/android.hardware.gnss@2.1
-impl-brcm.so in namespace sphal.

意思是android 的vndk机制, vendor下的库文件无法链接访问system 下面的库

android.hardware.gnss@2.1-impl-brcm.so 是bcm提供库文件,在vendor/lib下面

android.hardware.gnss@2.0.so 是android提供的,在system/lib下面

于是将相关依赖的so文件从system/lib下面copy到vendor/lib. 错误解决

gnss hal service能正常加载了. 测试gpsTest app定位功能也正常.

servier能正常注册了,整个hal层服务流程全部跑通

I HidlServiceManagement: Registered android.hardware.gnss@2.1::IGnss/default (start delay of 356ms)
I HidlServiceManagement: Removing namespace from process name android.hardware.gnss@2.1-service-google to gnss@2.1-service-google.
I LegacySupport: Registration complete for android.hardware.gnss@2.1::IGnss/default.

安装gpsTest app测试搜星定位一切正常. 这种方式修改了android libhiadl默认流程代码. 感觉不应该这样修改.

于是把修改代码还原,manifest中依然使用hwbinder的方式


 <hal format="hidl">
 <name>android.hardware.gnss</name> 
 <transport>hwbinder</transport> 
 <version>2.1</version> 
 <interface> 
 <name>IGnss</name> 
 <instance>default</instance> 
 </interface>
 </hal>  
    

重新编译刷机,发现一切正常了,service能正常注册,gnss hal层全部跑通. 看起来根本原因是android.hardware.gnss@2.1-impl-brcm.so没有放置到正确的路径下.

三. 遇到的坑.

  • 3.1 bcm的bin文件/vendor/bin/hw/android.hardware.gnss@2.1-service-google 运行报错时 ,没用错误log输出,并没有加载不到so库文件或者so文件路径不对等其他提示
  • 3.2 bcm fae说他们hal库使用passthrough 模式,于是将manifext配置为了passthrough 模式,导致libhidl流程全部走错,一直在跟踪错误的log信息.

总结:

当从log中无法获得有效信息时,有时多去查询android官方文档更有用.