hidl

#framework—> Vendor Interface —> hal

###Vendor Interface:

`Android O` 新增加的一个机制,用于将`framework` 与 `hal` 分开,便于在系统升级时,`OEM` 厂商 跳过`SoC` 厂商,先对`framework`进行升级。例如:
8.0 之前:

frameworkhal 是紧耦合的存在于 system.img 中,因此进行版本升级时需要: OEM 厂商适配frameworkSoC厂商适配hal, 之后将修改打包到system.img,生成OTA升级包,推送到手机进行OTA升级。

8.0 之后:

frameworkhal 进行了解耦, framework存在于system.imghal 存在于vendor.img ,进行版本升级时,分为两次升级:

  • framework 升级: OEM 厂商适配 framework,将修改打包到system.img, 生成OTA 升级包,推送到手机进行OTA 升级(framework 发生改变,hal 层未变)。

  • hal 升级:SoC 厂商适配 hal, 将修改打包到vendor.img, 生成OTA 升级包,推送到手机进行OTA升级(framework发生改变,hal 层发生改变)。

疑问:
  • OEM 厂商在8.0 之前,通过2 次升级的方式,也可以达到快速升级的目的啊。
  • 要将hal 层的修改打包到 vendor.img 就可以达到 目的,为什么要出一个 Vendor Interface 机制呢。
解答:
  • 在8.0 之前如果想要通过 2次升级的方式,达到快速升级的目的,需要进行的为:

    a、 framework 升级: OEM 厂商 将原有的所有 hal 的实现、修改 分别找出,合入到新版本的代码中, 编译出 system.img ,生成OTA 包,推送升级

    b、hal 升级: SoC 厂商 将适配后的hal 释放给 OEM 厂商, 在编译一个system.img , 生成OTA 包,推送升级.

缺点:

​ 因为hal 的实现,分布在不同的位置,也有的是直接提供的so库, OEM 厂商需要一个个找出替换,然后编译成包,进行升级。 等SoC 厂商释放出修改后,OEM 厂商需要在一个个替换会去,然后编译成包,进行二次升级, OEM 厂商工作量较大,且过程过于繁琐,容易出错。

  • hal的修改,打包到 Vendor.img 中就可以达到 快速升级的目的,为什么要出一个 Vendor Interface 的机制呢?

    8.0 之前,是在jni 中打开相关的so库,对hal 进行操作的, framework 可以随时通过jnihal 进行访问修改,它存在 frameworkhal 耦合性较高、两者通信的接口定义不明确等问题。为了规范通信接口,将frameworkhal 进行隔离,google 引入了Vendor Interface 机制( 存疑,这只是我的理解,对不对存疑 )。

###hidl(Hardware Interface Definition Language):
类似aidl 的东西,frameworkhwservice 进行数据通信的接口定义语言。

hwService 的启动

gnss 服务为例:

1. gnss服务在开机时, 通过 rc 文件启动
AndroidO/hardware/interfaces/gnss/1.0/default/[email protected] 
service gnss_service /vendor/bin/hw/[email protected] 
    class hal
    user gps
    group system gps radio
AndroidO/hardware/interfaces/gnss/1.0/default/service.cpp
using android::hardware::gnss::V1_0::IGnss;
using android::hardware::defaultPassthroughServiceImplementation;

int main() {
    android::ProcessState::initWithDriver("/dev/vndbinder");
    return defaultPassthroughServiceImplementation();
}

模式:passthrough或者binderized

passthrough: 直通模式,创建服务 并添加到 hwservice_manager 时使用

binderized: 绑定模式,用于提供给client 使用

此处是通过调用 defaultPassthroughServiceImplementation 方法走直通模式。

2. 直通模式:
AndroidO/system/libhidl/transport/include/hidl/LegacySupport.h
template
__attribute__((warn_unused_result))
status_t defaultPassthroughServiceImplementation(size_t maxThreads = 1) 
{
    return defaultPassthroughServiceImplementation("default", maxThreads);
}

template
__attribute__((warn_unused_result))
status_t defaultPassthroughServiceImplementation(std::string name, size_t maxThreads = 1) {
    configureRpcThreadpool(maxThreads, true); //设置用于 IPC 通信的进程数
    //使用直通模式,创建 gnss 服务, 并将其添加到 hwService_manager
    status_t result = registerPassthroughServiceImplementation(name);
    //service 端开始循环等待 client 端的连接
    joinRpcThreadpool();
    return 0;
}
template                                                                
__attribute__((warn_unused_result))
status_t registerPassthroughServiceImplementation(std::string name = "default") {
    // 通过 hidl 的模板代码,创建 gnss 服务
    sp service = Interface::getService(name, true /* getStub */);
    //通过模板代码,将创建的服务,添加进入 hwService_manager 中
    status_t status = service->registerAsService(name);
    return status;
}
3. 模板代码创建 gnss 服务, 并添加到 hwService_manager
out/soong/.intermediates/hardware/interfaces/gnss/1.0/[email protected]_genc++/gen/android/hardware/gnss/1.0/GnssAll.cpp
::android::sp IGnss::getService(const std::string &serviceName, const bool getStub) {
    using ::android::hardware::defaultServiceManager;
    using ::android::hardware::details::waitForHwService;
    using ::android::hardware::getPassthroughServiceManager;
    using ::android::hardware::Return;
    using ::android::sp;
    using Transport = ::android::hidl::manager::V1_0::IServiceManager::Transport;

    sp iface = nullptr;
    
    //获取hwService_manager 的client端 代理对象
    const sp<::android::hidl::manager::V1_0::IServiceManager> sm=defaultServiceManager();
  
	// IGnss::descriptor("[email protected]::IGnss");
    // 从 /system/manifest.xml
    //    /vendor/manifest.xml
    //获取 gnss 通信的 类型
    //  system/hwservicemanager/Vintf.cpp --->  /system/libvintf/VintfObject.cpp
    Return transportRet = sm->getTransport(IGnss::descriptor, serviceName);
    Transport transport = transportRet;
	//判断是直通模式 还是 代理模式  
    const bool vintfHwbinder = (transport == Transport::HWBINDER);
    const bool vintfPassthru = (transport == Transport::PASSTHROUGH);

    //代理模式,会从hwservice_manager 中获取 service 的代理对象,并返回
    for (int tries = 0; !getStub && (vintfHwbinder || (vintfLegacy && tries == 0)); tries++) {
        if (vintfHwbinder && tries > 0) {
            waitForHwService(IGnss::descriptor, serviceName);
        }
        Return> ret =
                sm->get(IGnss::descriptor, serviceName);
            sp<::android::hidl::base::V1_0::IBase> base = ret;
        Return> castRet = IGnss::castFrom(base, true /* emitError */);
        iface = castRet;
        return iface;
    }
  
    //直通模式, 创建service 对象,并返回, 此处 getStub 的传入值为true,所以此处走的是直通模式
    if (getStub || vintfPassthru || vintfLegacy) {
        const sp<::android::hidl::manager::V1_0::IServiceManager> pm = getPassthroughServiceManager();
        if (pm != nullptr) {
            Return> ret =
                    pm->get(IGnss::descriptor, serviceName);
            if (ret.isOk()) {
                sp<::android::hidl::base::V1_0::IBase> baseInterface = ret;
                if (baseInterface != nullptr) {
                    iface = new BsGnss(IGnss::castFrom(baseInterface));
                }
            }
        }
    }
    return iface;
}
const char* IGnss::descriptor("[email protected]::IGnss");
4. getPassthroughServiceManager 获取直通模式的 PassthroughServiceManager
AndroidO/system/libhidl/transport/ServiceManagement.cpp
sp getPassthroughServiceManager() {                           
    return getPassthroughServiceManager1_1();
}
sp getPassthroughServiceManager1_1() {
    static sp manager(new PassthroughServiceManager());
    return manager;
}
5. pm->get(IGnss::descriptor, serviceName)PassthroughServiceManager 获取 service 的代理对象

IGnss::descriptor : "[email protected]::IGnss"

serviceName : "default"

get 方法 调用 openLibs 方法来 打开对应 so 库, 实例化 servcie 对象

    Return> get(const hidl_string& fqName,
                          const hidl_string& name) override {
        sp ret = nullptr;
        
        //调用openLibs 函数,并传入一个匿名函数,此函数会在 openLibs中回调,
      	//此匿名函数的 参数为:
        //handle   service 对应so库的句柄
        // lib : so库对象
        // sym : service对象初始化的入口方法
        //此匿名方法的作用: 使用handle句柄找出so文件中sym方法, 然后调用此方法,创建出service对象
        openLibs(fqName, [&](void* handle, std::string &lib, std::string &sym) {
            IBase* (*generator)(const char* name);
            // 找到 service 对象 初始化的入口方法 sym
            *(void **)(&generator) = dlsym(handle, sym.c_str());
            //调用 入口方法,创建初始化 service 对象
            ret = (*generator)(name.c_str());
            //将此 service的信息 注册到 hwservice_manager 中
            registerReference(fqName, name);
            return false;
        });
        return ret;
    }
6. openLibs 打开指定 so 库,获取初始化函数,创建 service 对象

fqName"[email protected]::IGnss"

std::functionget 中传入的匿名方法

struct PassthroughServiceManager : IServiceManager1_1 {
  
    static void openLibs(const std::string& fqName,
            std::function eachLib) {

        size_t idx = fqName.find("::");
        
        //packageAndVersion :[email protected]
        //packageAndVersion 用于组成so库文件名
        std::string packageAndVersion = fqName.substr(0, idx);
      
        //ifaceName : IGnss
        //用于组成 service 的初始化函数名
        std::string ifaceName = fqName.substr(idx + strlen("::"));

        //prefix : [email protected]
        // prefix : so 库文件名
        const std::string prefix = packageAndVersion + "-impl";
       
        //sym :HIDL_FETCH_IGnss
        //sym : 初始化函数名
        const std::string sym = "HIDL_FETCH_" + ifaceName;

        const int dlMode = RTLD_LAZY;
        void *handle = nullptr;

        //会从一下目录搜索对应 service 的so 库
        std::vector paths = {
          	/odm/lib64/hw/   			  HAL_LIBRARY_PATH_ODM, 
            /vendor/lib64/hw/             HAL_LIBRARY_PATH_VENDOR,
            /system/lib64/vndk-sp/hw/     HAL_LIBRARY_PATH_VNDK_SP, 
            /system/lib64/hw/             HAL_LIBRARY_PATH_SYSTEM};

        // 遍历 paths 查找名为prefix 的 so库
        for (const std::string& path : paths) {
            std::vector libs = search(path, prefix, ".so");
            for (const std::string &lib : libs) {
                const std::string fullPath = path + lib;
                if (path != HAL_LIBRARY_PATH_SYSTEM) {
                    handle = android_load_sphal_library(fullPath.c_str(), dlMode);
                } else {
                    //打开查找到的so 库文件
                    handle = dlopen(fullPath.c_str(), dlMode);
                }
 				//调用get方法中传入的匿名方法
                //handle :打开so库的句柄文件
                //lib : so库对象
                //sym : service初始化方法的方法名
                if (!eachLib(handle, lib, sym)) {                     
                    return;
                }
            }
        }
    }
7. 开始初始化 service 对象

get—>openLibs 中会 找到 service 的入口方法(方法名一般为:HIDL_FETCH_***), 然后调用此方法初始化构建 service 对象

AndroidO/hardware/interfaces/gnss/1.0/default/Gnss.cpp
IGnss* HIDL_FETCH_IGnss(const char* /* hal */) {
    hw_module_t* module;
    IGnss* iface = nullptr;
    //打开service 对应的模块,并获取module结构体,
    // 在此处对应的为 gps 模块
    //GPS_HARDWARE_MODULE_ID  gps
    int err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);

    if (err == 0) {
        hw_device_t* device;
        // 如果正确打开对应模块,并获取到了 module 结构体,那么调用模块内对应的open 方法,获取 device 驱动对象
        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
        if (err == 0) {
          	//使用device 对象,构建出 Gnss service对象
            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);
    }
    //将Gnss service 对象返回给 openLibs 函数
    return iface;
}
8 . 打开对应硬件模块

通过 hw_get_module 方法,打开对应模块的so库

/hardware/libhardware/hardware.c

id: 在此处为 gps

module : 需要初始化的 模块对象

int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);  
}
int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int i = 0;
    char prop[PATH_MAX] = {0};
    char path[PATH_MAX] = {0};
    char name[PATH_MAX] = {0};
    char prop_name[PATH_MAX] = {0};
    //此处 inst 为 null, 将name cpy为 gsp
    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);

    //拼接 prop_name 为: ro.hardware.gps
    //从property 中查找 此配置项, 如果存在调用 hw_module_exists 获取 module 对应的so库
    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
    if (property_get(prop_name, prop, NULL) > 0) {
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }
     /* static const char *variant_keys[] = {                                    
         "ro.hardware", 
         "ro.product.board",
         "ro.board.platform",
         "ro.arch"
       }; */
	//遍历 HAL_VARIANT_KEYS_COUNT ,查找他们的配置项,如果存在对应配置项,根据hw_module_exists 获取 module 对应的so
    // 此配置项一般为 product 名
    for (i=0 ; i
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib/hw"
// 此函数会在 以上三个路径中,进行判断 指定 so库 是否存在
//gps 对应的为 HAL_LIBRARY_PATH/gps.subname.so
static int hw_module_exists(char *path, size_t path_len, const char *name, char *subname)
{
    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH3, name, subname);
    if (access(path, R_OK) == 0)
        return 0;

    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH2, name, subname);
    if (access(path, R_OK) == 0)
        return 0;

    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH1, name, subname);
    if (access(path, R_OK) == 0)
        return 0;
    return -ENOENT;
}

######9. 模块内部的初始化

int err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);

最后调用到模块内部为:

AndroidO/hardware/qcom/gps/msm8960/loc_api/libloc_api_50001/gps.c

首先将 HAL_MODULE_INFO_SYM 初始化到 module

struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .module_api_version = 1,
    .hal_api_version = 0,
    .id = GPS_HARDWARE_MODULE_ID,
    .name = "loc_api GPS Module",
    .author = "Qualcomm USA, Inc.",
    .methods = &gps_module_methods, };      
static struct hw_module_methods_t gps_module_methods = {
    .open = open_gps                                                      
};

然后调用moduleopen方法,此处对应的 为 gps_module_methods 中的open_gps方法,

在此方法中,会构建出一个dev 对象,并将它赋值为 传入的hw_device_t结构体

static int open_gps(const struct hw_module_t* module, char const* name,
        struct hw_device_t** device)
{
    struct gps_device_t *dev = (struct gps_device_t *) malloc(sizeof(struct gps_device_t));
    memset(dev, 0, sizeof(*dev));
    dev->common.tag = HARDWARE_DEVICE_TAG;
    dev->common.version = 0;
    dev->common.module = (struct hw_module_t*)module;
    dev->get_gps_interface = gps__get_gps_interface;
    *device = (struct hw_device_t*)dev;
    return 0;
}

在之后 使用 hw_device_t 结构体 构建出gnss 服务对象,gnss 的初始化方法中会调用 devget_gps_interface 方法,获取hal的方法接口对象:

10. gnss 服务对象的初始化
 err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
 iface = new Gnss(reinterpret_cast(device));

gnss 获取hal 的方法接口对象

~/source/AndroidO/hardware/interfaces/gnss/1.0/default/Gnss.cpp
Gnss::Gnss(gps_device_t* gnssDevice) : mDeathRecipient(new GnssHidlDeathRecipient(this)) {
    //获取所有的方法接口对象
    mGnssIface = gnssDevice->get_gps_interface(gnssDevice);
}                                                                

get_gps_interfacehal 层的实现为:

extern "C" const GpsInterface* get_gps_interface()
{
    unsigned int target = TARGET_DEFAULT;
    loc_eng_read_config();                                                            
    target = get_target();
    if( getTargetGnssType(target) == GNSS_GSS ) {
        gps_conf.CAPABILITIES &= ~(GPS_CAPABILITY_MSA | GPS_CAPABILITY_MSB);
        gss_fd = open("/dev/gss", O_RDONLY);  //hal 层会通过 /dev/gss 节点操作gps
    }
    return &sLocEngInterface; //hal 层 对外暴露的 方法接口对象
}

你可能感兴趣的:(源码分析)