android11上bcm gps 2.1 hal 库运行不起来问题调试
一. GPS hal层主要流程
- 1.1 android.hardware.gnss@2.1-service.rc 此文件中会启动一个service,执行对应的bin文件/vendor/bin/hw/android.hardware.gnss@2.1-service-google
service gnss-2-1 /vendor/bin/hw/android.hardware.gnss@2.1-service-google
class hal
user system
group system
- 1.2 .此bin文件就是bcm实现的gnss的hal接口. 对应的还有一个库文件android.hardware.gnss@2.1-impl-brcm.so
- hal 接口就与framework 层的gnss service通信.
二.目前问题是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官方文档更有用.