Native层HIDL服务的获取原理

Stella981
• 阅读 1025

摘要:本节主要来讲解Android10.0 Native层HIDL服务的获取原理

阅读本文大约需要花费23分钟。

文章首发微信公众号:IngresGe

专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢!

[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析

[Android取经之路] 系列文章:

《系统启动篇》

  1. Android系统架构
  2. Android是怎么启动的
  3. Android 10.0系统启动之init进程
  4. Android10.0系统启动之Zygote进程
  5. Android 10.0 系统启动之SystemServer进程
  6. Android 10.0 系统服务之ActivityMnagerService
  7. Android10.0系统启动之Launcher(桌面)启动流程
  8. Android10.0应用进程创建过程以及Zygote的fork流程
  9. Android 10.0 PackageManagerService(一)工作原理及启动流程
  10. Android 10.0 PackageManagerService(二)权限扫描
  11. Android 10.0 PackageManagerService(三)APK扫描
  12. Android 10.0 PackageManagerService(四)APK安装流程

《日志系统篇》

  1. Android10.0 日志系统分析(一)-logd、logcat 指令说明、分类和属性
  2. Android10.0 日志系统分析(二)-logd、logcat架构分析及日志系统初始化
  3. Android10.0 日志系统分析(三)-logd、logcat读写日志源码分析
  4. Android10.0 日志系统分析(四)-selinux、kernel日志在logd中的实现​

《Binder通信原理》****:

  1. Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要
  2. Android10.0 Binder通信原理(二)-Binder入门篇
  3. Android10.0 Binder通信原理(三)-ServiceManager篇
  4. Android10.0 Binder通信原理(四)-Native-C\C++实例分析
  5. Android10.0 Binder通信原理(五)-Binder驱动分析
  6. Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击
  7. Android10.0 Binder通信原理(七)-Framework binder示例
  8. Android10.0 Binder通信原理(八)-Framework层分析
  9. Android10.0 Binder通信原理(九)-AIDL Binder示例
  10. Android10.0 Binder通信原理(十)-AIDL原理分析-Proxy-Stub设计模式
  11. Android10.0 Binder通信原理(十一)-Binder总结

《HwBinder通信原理》

  1. HwBinder入门篇-Android10.0 HwBinder通信原理(一)
  2.  HIDL详解-Android10.0 HwBinder通信原理(二)
  3. HIDL示例-C++服务创建Client验证-Android10.0 HwBinder通信原理(三)
  4. HIDL示例-JAVA服务创建-Client验证-Android10.0 HwBinder通信原理(四)
  5. HwServiceManager篇-Android10.0 HwBinder通信原理(五)
  6. Native层HIDL服务的注册原理-Android10.0 HwBinder通信原理(六)
  7. Native层HIDL服务的获取原理-Android10.0 HwBinder通信原理(七)
  8. JAVA层HIDL服务的注册原理-Android10.0 HwBinder通信原理(八)

上一节,我们学习了Native层 HIDL服务的注册原理,这一节我们来看看Native层HIDL服务的获取流程。

5.IDemo的服务获取

   IDemo的HIDL服务获取流程如下图所示:

Native层HIDL服务的获取原理

5.1调用栈如下

Native层HIDL服务的获取原理

5.2 main

[\vendor\ingres\hal_demo\cpp\hal_demo_test.cpp]
int main() {
   //1.获取IDemo这个HIDL服务的代理对象
    android::sp<IDemo> service = IDemo::getService();

    if(service == nullptr) {
        printf("Failed to get service\n");
        return -1;
    }
   //2.调用服务的HIDL接口 getHelloString()
    service->getHelloString("IngresGe", [&](hidl_string result) {
                printf("%s\n", result.c_str());
        });

    return 0;
}

主要分两步:

1.获取IDemo这个HIDL服务的代理对象

2.调用服务的HIDL接口 getHelloString()

5.3 getService()

[/out/soong/.intermediates/vendor/ingres/interfaces/demo/1.0/vendor.ingres.demo@1.0_genc++/gen/vendor/ingres/demo/1.0/DemoAll.cpp]
::android::sp<IDemo> IDemo::getService(const std::string &serviceName, const bool getStub) {
    return ::android::hardware::details::getServiceInternal<BpHwDemo>(serviceName, true, getStub);
}

getService的调用栈如下:

Native层HIDL服务的获取原理

根据上面的调用栈,最终进入getRawServiceInternal()

[/system/libhidl/transport/ServiceManagement.cpp]
sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
                                                             const std::string& instance,
                                                             bool retry, bool getStub) {
    using Transport = ::android::hidl::manager::V1_0::IServiceManager::Transport;
    using ::android::hidl::manager::V1_0::IServiceManager;
    sp<Waiter> waiter;

    sp<IServiceManager1_1> sm;
    Transport transport = Transport::EMPTY;
    if (kIsRecovery) {
        transport = Transport::PASSTHROUGH;
    } else {
            //拿到HwServiceManager的对象,参考[5.4]
        sm = defaultServiceManager1_1();
        if (sm == nullptr) {
            ALOGE("getService: defaultServiceManager() is null");
            return nullptr;
        }
            //获取IDemo服务的transport,确认是直通式PASSTHROUGH,还是绑定式:HWBINDER
            //transport可以在/vendor/etc/vintf/manifest.xml中查看<transport>hwbinder</transport>
        Return<Transport> transportRet = sm->getTransport(descriptor, instance);

        if (!transportRet.isOk()) {
            ALOGE("getService: defaultServiceManager()->getTransport returns %s",
                  transportRet.description().c_str());
            return nullptr;
        }
        transport = transportRet;
    }

    const bool vintfHwbinder = (transport == Transport::HWBINDER); //绑定式服务
    const bool vintfPassthru = (transport == Transport::PASSTHROUGH); //直通式服务
        ...

    for (int tries = 0; !getStub && (vintfHwbinder || vintfLegacy); tries++) {
        if (waiter == nullptr && tries > 0) {
            waiter = new Waiter(descriptor, instance, sm);
        }
        if (waiter != nullptr) {
            waiter->reset();  // don't reorder this -- see comments on reset()
        }
            //如果是绑定式的服务,调用 BpHwServiceManager::get()
        Return<sp<IBase>> ret = sm->get(descriptor, instance);
        if (!ret.isOk()) {
            ALOGE("getService: defaultServiceManager()->get returns %s for %s/%s.",
                  ret.description().c_str(), descriptor.c_str(), instance.c_str());
            break;
        }
        sp<IBase> base = ret;
        if (base != nullptr) {
            Return<bool> canCastRet =
                details::canCastInterface(base.get(), descriptor.c_str(), true /* emitError */);

            if (canCastRet.isOk() && canCastRet) {
                if (waiter != nullptr) {
                    waiter->done();
                }
                return base; // still needs to be wrapped by Bp class.
            }

            if (!handleCastError(canCastRet, descriptor, instance)) break;
        }

        // In case of legacy or we were not asked to retry, don't.
        if (vintfLegacy || !retry) break;

        if (waiter != nullptr) {
            ALOGI("getService: Trying again for %s/%s...", descriptor.c_str(), instance.c_str());
            waiter->wait(true /* timeout */);
        }
    }

    if (waiter != nullptr) {
        waiter->done();
    }

    if (getStub || vintfPassthru || vintfLegacy) {
            //如果是直通式的hidl服务,获取直通式的HwServiceManager对象来获取服务
        const sp<IServiceManager> pm = getPassthroughServiceManager();
        if (pm != nullptr) {
            sp<IBase> base = pm->get(descriptor, instance).withDefault(nullptr);
            if (!getStub || trebleTestingOverride) {
                base = wrapPassthrough(base);
            }
            return base;
        }
    }
    return nullptr;
}

getRawServiceInternal()步骤如下:

1.获取HwServiceManager的代理对象

2.获取IDemo 这个hidl服务的transport,来确认是绑定式服务,还是直通式服务

3.根据transport类型,调用不同的接口来获取服务对象 (我们设计的IDemo是绑定式hidl服务)

5.4 defaultServiceManager1_1

[/system/libhidl/transport/ServiceManagement.cpp]
sp<IServiceManager1_1> defaultServiceManager1_1() {
    return defaultServiceManager1_2();
}

[/system/libhidl/transport/ServiceManagement.cpp]
defaultServiceManager1_2()是用来拿到HwServiceManager的代理对象--BpHwServiceManager
sp<IServiceManager1_2> defaultServiceManager1_2() {
    using android::hidl::manager::V1_2::BnHwServiceManager;
    using android::hidl::manager::V1_2::BpHwServiceManager;

    static std::mutex gDefaultServiceManagerLock;
    static sp<IServiceManager1_2> gDefaultServiceManager;

    {
        std::lock_guard<std::mutex> _l(gDefaultServiceManagerLock);
        if (gDefaultServiceManager != nullptr) {
            return gDefaultServiceManager;
        }
        //1.检查hwbinder的节点是否存在,如果不存在说明不支持hwbinder
        if (access("/dev/hwbinder", F_OK|R_OK|W_OK) != 0) {
            // HwBinder not available on this device or not accessible to
            // this process.
            return nullptr;
        }
        //2.等待属性"hwservicemanager.ready" 变为true,表明hwservicemanager已经启动好
        waitForHwServiceManager();

        while (gDefaultServiceManager == nullptr) {
            //3.拿到HwServiceManager的代理对象
            gDefaultServiceManager =
                fromBinder<IServiceManager1_2, BpHwServiceManager, BnHwServiceManager>(
                    ProcessState::self()->getContextObject(nullptr));
            if (gDefaultServiceManager == nullptr) {
                LOG(ERROR) << "Waited for hwservicemanager, but got nullptr.";
                sleep(1);
            }
        }
    }
    return gDefaultServiceManager;
}

5.4.1 BpHwBinder::transact()

[/system/libhwbinder/BpHwBinder.cpp]
status_t BpHwBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags, TransactCallback /*callback*/)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        //拿到IPCThreadState的对象,调用transact()执行
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

BpBinder::transact()就是调用IPCThreadState::self()->transact() 进行处理

根据如下调用栈所示,BpHwBinder::transact()最终会转到BnHwServiceManager::_hidl_get(),实现流程和注册服务类似,相关源码分析参考上一节《Native层HIDL服务的注册原理》的[4.7.1] - [4.8]

Native层HIDL服务的获取原理

5.5 BnHwServiceManager::_hidl_get()

[/out/soong/.intermediates/system/libhidl/transport/manager/1.2/android.hidl.manager@1.2_genc++/gen/android/hidl/manager/1.2/ServiceManagerAll.cpp]
::android::status_t BnHwServiceManager::_hidl_get(
        ::android::hidl::base::V1_0::BnHwBase* _hidl_this,
        const ::android::hardware::Parcel &_hidl_data,
        ::android::hardware::Parcel *_hidl_reply,
        TransactCallback _hidl_cb) {

        ...
    ::android::status_t _hidl_err = ::android::OK;
    if (!_hidl_data.enforceInterface(BnHwServiceManager::Pure::descriptor)) {
        _hidl_err = ::android::BAD_TYPE;
        return _hidl_err;
    }

    const ::android::hardware::hidl_string* fqName;
    const ::android::hardware::hidl_string* name;

    size_t _hidl_fqName_parent;

        //1.获取hidl服务的fqName
    _hidl_err = _hidl_data.readBuffer(sizeof(*fqName), &_hidl_fqName_parent,  reinterpret_cast<const void **>(&fqName));

    if (_hidl_err != ::android::OK) { return _hidl_err; }

    _hidl_err = ::android::hardware::readEmbeddedFromParcel(
            const_cast<::android::hardware::hidl_string &>(*fqName),
            _hidl_data,
            _hidl_fqName_parent,
            0 /* parentOffset */);

    if (_hidl_err != ::android::OK) { return _hidl_err; }

    size_t _hidl_name_parent;

        //2.获取hidl服务的name
    _hidl_err = _hidl_data.readBuffer(sizeof(*name), &_hidl_name_parent,  reinterpret_cast<const void **>(&name));

    if (_hidl_err != ::android::OK) { return _hidl_err; }

    _hidl_err = ::android::hardware::readEmbeddedFromParcel(
            const_cast<::android::hardware::hidl_string &>(*name),
            _hidl_data,
            _hidl_name_parent,
            0 /* parentOffset */);

    if (_hidl_err != ::android::OK) { return _hidl_err; }

    atrace_begin(ATRACE_TAG_HAL, "HIDL::IServiceManager::get::server");
        ...
        //3.根据hidl服务的fqName和name,从HwServiceManager的hidl service的map中拿到服务对象
    ::android::sp<::android::hidl::base::V1_0::IBase> _hidl_out_service = static_cast<IServiceManager*>(_hidl_this->getImpl().get())->get(*fqName, *name);

        //4.把reply信息写入Parcel
    ::android::hardware::writeToParcel(::android::hardware::Status::ok(), _hidl_reply);

    if (_hidl_out_service == nullptr) {
        _hidl_err = _hidl_reply->writeStrongBinder(nullptr);
    } else {
            //5.把获取的hidl服务转成IBinder对象
        ::android::sp<::android::hardware::IBinder> _hidl_binder = ::android::hardware::getOrCreateCachedBinder(_hidl_out_service.get());
        if (_hidl_binder.get() != nullptr) {
                  //6.把转换后的IBinder对象,写入reply的Parcel数据中
            _hidl_err = _hidl_reply->writeStrongBinder(_hidl_binder);
        } else {
            _hidl_err = ::android::UNKNOWN_ERROR;
        }
    }
    /* _hidl_err ignored! */

    atrace_end(ATRACE_TAG_HAL);
         ..
     //7.通过回调,把reply的Parcel数据给发给client
    _hidl_cb(*_hidl_reply);
    return _hidl_err;
}

_hidl_get流程如下:

       1.获取hidl服务的fqName

       2.获取hidl服务的name

       3.根据hidl服务的fqName和name,从HwServiceManager的hidl service的map中拿到服务对象

       4.把reply信息写入Parcel

       5.把获取的hidl服务转成IBinder对象

       6.把转换后的IBinder对象,写入reply的Parcel数据中

       7.通过回调,把reply的Parcel数据给发给client

5.5.1 ServiceManager::get()

[/system/hwservicemanager/ServiceManager.cpp]
Return<sp<IBase>> ServiceManager::get(const hidl_string& hidlFqName,
                                      const hidl_string& hidlName) {
    const std::string fqName = hidlFqName;
    const std::string name = hidlName;

    if (!mAcl.canGet(fqName, getBinderCallingContext())) {
        return nullptr;
    }

        //1.根据fqName和name找到对应的hidlService
    HidlService* hidlService = lookup(fqName, name);
    if (hidlService == nullptr) {
        tryStartService(fqName, name);
        return nullptr;
    }

    //2.根据hidlService 拿到IBase的对象
    sp<IBase> service = hidlService->getService();
    if (service == nullptr) {
        tryStartService(fqName, name);
        return nullptr;
    }

    hidlService->guaranteeClient();

    hardware::addPostCommandTask([hidlService] {
        hidlService->handleClientCallbacks(false /* isCalledOnInterval */);
    });
    return service;
}

5.7.3 ServiceManager::lookup()

  主要是根据fqName和name从 HwServiceManager的服务map:mServiceMap 中找到对应的hidlservice。

[/system/hwservicemanager/ServiceManager.cpp]
HidlService* ServiceManager::lookup(const std::string& fqName, const std::string& name) {
        //1.根据fqName从 mServiceMap 中 找到一个节点
    auto ifaceIt = mServiceMap.find(fqName);
    if (ifaceIt == mServiceMap.end()) {
        return nullptr;
    }
        //2.从找到的map节点中,拿到PackageInterfaceMap的内容
    PackageInterfaceMap &ifaceMap = ifaceIt->second;
        //3.从PackageInterfaceMap中根据name找到hidlService
    HidlService *hidlService = ifaceMap.lookup(name);
    return hidlService;
}

5.5.2 HidlService::getService()

获取HidlService对象的mService

Native层HIDL服务的获取原理

[/system/hwservicemanager/HidlService.cpp]
sp<IBase> HidlService::getService() const {
    return mService;
}

6. 协议码的转换流程

  Binder通信协议是基于Command-Reply的方式的。

Native层HIDL服务的获取原理

7.IDemo Client\Server交互流程

  在IDemo的服务注册和获取的过程中,IDemo的服务和Client都是作为Client端,HwServiceManager作为Server端。

  在IDemo的服务和client调用过程中,IDemo的服务为Server端,Client为客户端。

Native层HIDL服务的获取原理

8.代码路径


/system/libhwbinder/BpHwBinder.cpp
/system/libhwbinder/IPCThreadState.cpp
/system/libhidl/transport/ServiceManagement.cpp
/system/libhidl/transport/include/hidl/HidlTransportSupport.h
/vendor/ingres/hal_demo/cpp/hal_demo_test.cpp
/out/soong/.intermediates/vendor/ingres/interfaces/demo/1.0/vendor.ingres.demo@1.0_genc++/gen/vendor/ingres/demo/1.0/DemoAll.cpp
/out/soong/.intermediates/system/libhidl/transport/manager/1.2/android.hidl.manager@1.2_genc++/gen/android/hidl/manager/1.2/ServiceManagerAll.cpp

9. 总结

  至此,Native层的HIDL服务注册和获取就梳理完了,主要就是进程和HwBinder驱动、HwServiceManager的交互流程,下一节我们再一起看看JAVA层的hidl服务注册和获取流程。

我的微信公众号:IngresGe

Native层HIDL服务的获取原理

点赞
收藏
评论区
推荐文章
秃头王路飞 秃头王路飞
5个月前
webpack5手撸vue2脚手架
webpack5手撸vue相信工作个12年的小伙伴们在面试的时候多多少少怕被问到关于webpack方面的知识,本菜鸟最近闲来无事,就尝试了手撸了下vue2的脚手架,第一次发帖实在是没有经验,望海涵。languageJavaScript"name":"vuecliversion2","version":"1.0.0","desc
浅梦一笑 浅梦一笑
5个月前
初学 Python 需要安装哪些软件?超级实用,小白必看!
编程这个东西是真的奇妙。对于懂得的人来说,会觉得这个工具是多么的好用、有趣,而对于小白来说,就如同大山一样。其实这个都可以理解,大家都是这样过来的。那么接下来就说一下python相关的东西吧,并说一下我对编程的理解。本人也是小白一名,如有不对的地方,还请各位大神指出01名词解释:如果在编程方面接触的比较少,那么对于软件这一块,有几个名词一定要了解,比如开发环
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
光头强的博客 光头强的博客
5个月前
Java面向对象试题
1、请创建一个Animal动物类,要求有方法eat()方法,方法输出一条语句“吃东西”。创建一个接口A,接口里有一个抽象方法fly()。创建一个Bird类继承Animal类并实现接口A里的方法输出一条有语句“鸟儿飞翔”,重写eat()方法输出一条语句“鸟儿吃虫”。在Test类中向上转型创建b对象,调用eat方法。然后向下转型调用eat()方
刚刚好 刚刚好
5个月前
css问题
1、在IOS中图片不显示(给图片加了圆角或者img没有父级)<div<imgsrc""/</divdiv{width:20px;height:20px;borderradius:20px;overflow:h
小森森 小森森
5个月前
校园表白墙微信小程序V1.0 SayLove -基于微信云开发-一键快速搭建,开箱即用
后续会继续更新,敬请期待2.0全新版本欢迎添加左边的微信一起探讨!项目地址:(https://www.aliyun.com/activity/daily/bestoffer?userCodesskuuw5n)\2.Bug修复更新日历2.情侣脸功能大家不要使用了,现在阿里云的接口已经要收费了(土豪请随意),\\和注意
晴空闲云 晴空闲云
5个月前
css中box-sizing解放盒子实际宽高计算
我们知道传统的盒子模型,如果增加内边距padding和边框border,那么会撑大整个盒子,造成盒子的宽度不好计算,在实务中特别不方便。boxsizing可以设置盒模型的方式,可以很好的设置固定宽高的盒模型。盒子宽高计算假如我们设置如下盒子:宽度和高度均为200px,那么这会这个盒子实际的宽高就都是200px。但是当我们设置这个盒子的边框和内间距的时候,那
艾木酱 艾木酱
5个月前
快速入门|使用MemFire Cloud构建React Native应用程序
MemFireCloud是一款提供云数据库,用户可以创建云数据库,并对数据库进行管理,还可以对数据库进行备份操作。它还提供后端即服务,用户可以在1分钟内新建一个应用,使用自动生成的API和SDK,访问云数据库、对象存储、用户认证与授权等功能,可专
密钥管理系统-为你的天翼云资产上把“锁
本文关键词:数据安全,密码机,密钥管理一、你的云上资产真的安全么?1.2021年1月,巴西的一个数据库30TB数据被破坏,泄露的数据包含有1.04亿辆汽车和约4000万家公司的详细信息,受影响的人员数量可能有2.2亿;2.2021年2月,广受欢迎的音频聊天室应用Clubhouse的用户数据被恶意黑客或间谍窃取。据悉,一位身份不明的用户能够将Clubho
NVIDIA安培架构下MIG技术分析
关键词:NVIDIA、MIG、安培一什么是MIG2020年5月,NVIDIA发布了最新的GPU架构:安培,以及基于安培架构的最新的GPU:A100。安培提供了许多新的特性,MIG是其中一项非常重要的新特性。MIG的全名是MultiInstanceGPU。NVIDIA安培架构中的MIG模式可以在A100GPU上并行运行七个作业。多实
helloworld_28799839 helloworld_28799839
5个月前
常用知识整理
Javascript判断对象是否为空jsObject.keys(myObject).length0经常使用的三元运算我们经常遇到处理表格列状态字段如status的时候可以用到vue