Android-Gnss/GPS HAL层实现直通式修改为绑定式示例
为了能够让Android O之前的版本升级到Android O,Android设计了Passthrough模式,经过转换,可以方便的使用已经存在代码,不需要重新编写相关的HAL。
HIDL分为两种模式:Passthrough:翻译成直通式HAL。Binderized:翻译成绑定式HAL
一个编译成so库,供System分区的进程和应用直接加载调用,两者在同一个进程中,这种叫直通式 HAL(passthrough)模式,
另外一种是直接编译成一个daemon可运行的服务,然后System分区的进程通过HwBinder的IPC通信方式来调用,两者在各自独立的进程中,这种称为绑定式HAL(Binderized)模式。
直通式与绑定式最大的区别就是直通模式没有一个独立运行的服务进程,而绑定模式是作为一个独立运行的服务相当于Deamon进程在运行。
直通模式是将android 8.0之前的版本的module 封装起来,供System以上的服务进行调用,上层直接调用 HIDL_FETCH_XXX 来调用此接口的。
调用时都是通过 HIDL 工具生成的 getService() 来调用的,
getService() --> getServiceInternal() --> getRawServiceInternal();
然后后面的处理有所不同
直通模式,先通过 getPassthroughServiceManager(),获取IServiceManager的句柄
getPassthroughServiceManager() {
return new PassthroughServiceManager();
}
然后再get得到对应的服务,
get() {
openLibs() {
// 遍历so文件尝试查找 HIDL_FETCH_ 对应的接口并 registerPassthroughClient();
const std::string sym = "HIDL_FETCH_" + ifaceName;
function(void* handle, const std::string &lib, const std::string &sym) {
IBase* (*generator)(const char* name);
*(void **)(&generator) = dlsym(handle, sym.c_str());//返回值是void*,指向函数的地址,供调用使用
//generator 即 HIDL_FETCH_ 函数地址
if(!generator) {
const char* error = dlerror();
dlclose(handle);
return true;
}
ret = (*generator)(name.c_str()); //ret即 HIDL_FETCH_ 函数 返回的实例
if (ret == nullptr) {
dlclose(handle);
return true; // this module doesn't provide this instance name
}
// Actual fqname might be a subclass.
// This assumption is tested in vts_treble_vintf_test
using ::android::hardware::details::getDescriptor;
std::string actualFqName = getDescriptor(ret.get());
CHECK(actualFqName.size() > 0);
registerReference(actualFqName, name);
return false;
}
}
return ret; //ret即 HIDL_FETCH_ 函数 返回的实例
}
绑定模式就直接通过IServiceManager->get的方法去获取,直接对Binder驱动的操作来完成数据交换;
先来看一下 Gnss/GPS HAL service 直通式的实现方式
直接提供 HIDL_FETCH_IGnss 接口,该接口返回Gnss的实例对象;
IGnss* HIDL_FETCH_IGnss(const char* /* hal */) {
hw_module_t* module;
IGnss* iface = nullptr;
int err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
hw_device_t* device;
err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
if (err == 0) {
iface = new Gnss(reinterpret_cast(device));
} else {
ALOGE("gnssDevice open %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
}
} else {
ALOGE("gnss hw_get_module %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
}
return iface;
}
直通式是通过 HIDL_FETCH_IGnss() 直接获取到Gnss实例对象,然后直接在framework的进程空间操作(在framework的进程空间openLibs并获取到实例对象进行调用);
绑定式可以用两种方式来绑定服务,第一种通过 defaultPassthroughServiceImplementation 的调用来注册服务,另外一种是直接调用RegisterAsService来注册服务。
方式一
using android::hardware::gnss::V1_0::IGnss;
using android::hardware::defaultPassthroughServiceImplementation;
int main() {
android::ProcessState::initWithDriver("/dev/vndbinder");
return defaultPassthroughServiceImplementation();
}
其中 defaultPassthroughServiceImplementation 的定义在 system\libhidl\transport\include\hidl\LegacySupport.h
template
__attribute__((warn_unused_result))
status_t defaultPassthroughServiceImplementation(std::string name, size_t maxThreads = 1) {
configureRpcThreadpool(maxThreads, true); //配置binder线程个数
status_t result = registerPassthroughServiceImplementation(name);
if (result != OK) {
return result;
}
joinRpcThreadpool();
return 0;
}
template
__attribute__((warn_unused_result))
status_t registerPassthroughServiceImplementation(
std::string name = "default") {
sp service = Interface::getService(name, true /* getStub */); //从当前进程空间中拿到接口类对象
if (service == nullptr) {
ALOGE("Could not get passthrough implementation for %s/%s.",
Interface::descriptor, name.c_str());
return EXIT_FAILURE;
}
LOG_FATAL_IF(service->isRemote(), "Implementation of %s/%s is remote!",
Interface::descriptor, name.c_str());
status_t status = service->registerAsService(name);//通过IServicemanager的add 接口,添加到服务列表中
if (status == OK) {
ALOGI("Registration complete for %s/%s.",
Interface::descriptor, name.c_str());
} else {
ALOGE("Could not register service %s/%s (%d).",
Interface::descriptor, name.c_str(), status);
}
return status;
}
其中 registerAsService() 是通过hidl工具生成的
::android::status_t IDemo::registerAsService(const std::string &serviceName){
::android::hardware::details::onRegistration("android.hardware.demo@1.0", "IDemo", serviceName);
const ::android::sp<::android::hidl::manager::v1_0::iservicemanager> sm = ::android::hardware::defaultServiceManager();
::android::hardware::Return ret = sm->add(serviceName.c_str(), this);
return ret.isOk() && ret ? ::android::OK :: android::UNKNOWN_ERROR;
}
方式二
首先增加如下头文件
#include
#include
#include
#include "Gnss.h"
参考原来直通式接口 HIDL_FETCH_IGnss() 中的实现,
同样需要new一个Gnss实例; 绑定式需要注册为服务即调用方法 registerAsService();
参考代码如下
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::gnss::V1_0::implementation::Gnss;
int main() {
configureRpcThreadpool(4, true);
Gnss *gnssHalService = nullptr;
hw_module_t* module;
int err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
hw_device_t* device;
err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
if (err == 0) {
gnssHalService = new Gnss(reinterpret_cast(device));
} else {
ALOGE("gnssDevice open %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
}
} else {
ALOGE("gnss hw_get_module %s failed: %d", GPS_HARDWARE_MODULE_ID, err);
}
if (gnssHalService == nullptr) {
return -1;
}
auto status = gnssHalService->registerAsService();
if (android::OK != status)
{
ALOGW("%s: Failed to register Gnss HAL implementation", __func__);
return -1;
}
ALOGI("Gnss registerAsService OK.");
joinRpcThreadpool();
return status; joinRpcThreadpool shouldn't exit
}
以上修改是绑定+so的实现方式,仍然需要打开一个so文件,不过是在hal service中打开so并运行的;
也可以将so中的实现一起整合到hal service中,不再编译单独的so文件;