Android-Gnss/GPS HAL層實現直通式修改成綁定式示例android
爲了可以讓Android O以前的版本升級到Android O,Android設計了Passthrough模式,通過轉換,能夠方便的使用已經存在代碼,不須要從新編寫相關的HAL。
HIDL分爲兩種模式:Passthrough:翻譯成直通式HAL。Binderized:翻譯成綁定式HAL
一個編譯成so庫,供System分區的進程和應用直接加載調用,二者在同一個進程中,這種叫直通式 HAL(passthrough)模式,
另一種是直接編譯成一個daemon可運行的服務,而後System分區的進程經過HwBinder的IPC通訊方式來調用,二者在各自獨立的進程中,這種稱爲綁定式HAL(Binderized)模式。
ide
直通式與綁定式最大的區別就是直通模式沒有一個獨立運行的服務進程,而綁定模式是做爲一個獨立運行的服務至關於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驅動的操做來完成數據交換;this
先來看一下 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<gps_device_t*>(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<IGnss>(); }
其中 defaultPassthroughServiceImplementation 的定義在 system\libhidl\transport\include\hidl\LegacySupport.h
template<class Interface>
__attribute__((warn_unused_result))
status_t defaultPassthroughServiceImplementation(std::string name, size_t maxThreads = 1) {
configureRpcThreadpool(maxThreads, true); //配置binder線程個數
status_t result = registerPassthroughServiceImplementation<Interface>(name);
code
if (result != OK) {
return result;
}
對象
joinRpcThreadpool();
return 0;
}
template<class Interface>
__attribute__((warn_unused_result))
status_t registerPassthroughServiceImplementation(
std::string name = "default") {
sp<Interface> 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<bool> ret = sm->add(serviceName.c_str(), this);
return ret.isOk() && ret ? ::android::OK :: android::UNKNOWN_ERROR;
}
方式二
首先增長以下頭文件
#include <hardware/fused_location.h>
#include <hardware/gps.h>
#include <hidl/Status.h>
#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<gps_device_t*>(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文件;