热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AndroidOTreble架构下Binder对象的转换过程

上文中详细分析了Hal的整个启动过程,这里将补充上文中没有详细分析的Binder对象转换过程,下图为hidl服务的完整注册过程:1.Hwc

上文中详细分析了Hal的整个启动过程,这里将补充上文中没有详细分析的Binder对象转换过程,下图为hidl服务的完整注册过程:

1.  HwcHal继承于IBase类,是对hw_module_t的封装,该对象位于Hal进程空间;
2.  通过hwservicemanager的binder代理将HwcHal对象注册到hwservicemanager进程空间;
3. 在IPC调用过程中,HwcHal对象的身份一直在变化,到达hwservicemanager进程后,变成BpHwBase对象,该对象封装了BpHwBinder,并保存在hwservicemanager进程中。


创建HIDL服务的本地binder对象


我们知道,binder通信可以传输的数据类型包括:
1. 普通数据类型;
2. fd句柄类型;
3. IBinder类型;
4. 经过序列化的自定义类型;
在注册HwcHal这个hidl服务对象时,由于HwcHal继承IBase类,并非binder类型,而在BpHwServiceManager::_hidl_add函数中会通过以下代码段将HwcHal这个对象发送给hwservicemanager进程,那么发送的是否是HwcHal对象本身呢?

if (service &#61;&#61; nullptr) { _hidl_err &#61; _hidl_data.writeStrongBinder(nullptr); } else { ::android::sp<::android::hardware::IBinder> _hidl_binder &#61; ::android::hardware::toBinder< ::android::hidl::base::V1_0::IBase>(service); if (_hidl_binder.get() !&#61; nullptr) { _hidl_err &#61; _hidl_data.writeStrongBinder(_hidl_binder); } else { _hidl_err &#61; ::android::UNKNOWN_ERROR; } }

::android::hardware::toBinder<::android::hidl::base::V1_0::IBase>(service)system\libhidl\transport\include\hidl\HidlBinderSupport.h

template <typename IType, typename ProxyType>
sp toBinder(sp iface) { IType *ifacePtr &#61; iface.get(); if (ifacePtr &#61;&#61; nullptr) { return nullptr; } if (ifacePtr->isRemote()) { return ::android::hardware::IInterface::asBinder(static_cast(ifacePtr)); } else { std::string myDescriptor &#61; details::getDescriptor(ifacePtr); if (myDescriptor.empty()) { // interfaceDescriptor fails return nullptr; } auto func &#61; details::gBnConstructorMap.get(myDescriptor, nullptr); if (!func) { return nullptr; } return sp(func(static_cast<void *>(ifacePtr))); }
}

这里首先判断IComposer这个业务对象是否是BpHwComposer&#xff0c;如果是&#xff0c;那么调用asBinder来得到BpHwBinder对象。在BpHwComposer中&#xff0c;isRemote()默认为true&#xff0c;而在IComposer中&#xff0c;isRemote()默认为false。

struct BpHwComposer : public ::android::hardware::BpInterface<IComposer>, public ::android::hardware::details::HidlInstrumentor { explicit BpHwComposer(const ::android::sp<::android::hardware::IBinder> &_hidl_impl); typedef IComposer Pure; virtual bool isRemote() const override { return true; } struct IComposer : public ::android::hidl::base::V1_0::IBase { virtual bool isRemote() const override { return false; }

这里注册的是HwcHal对象&#xff0c;他实现了IComposer接口。因此将根据接口描述符从gBnConstructorMap中找到对应的构造函数指针&#xff0c;然后回调构造函数&#xff1a;

composer\2.1\android.hardware.graphics.composer&#64;2.1_genc&#43;&#43;\gen\android\hardware\graphics\composer\2.1\ComposerAll.cpp

const char* IComposer::descriptor("android.hardware.graphics.composer&#64;2.1::IComposer"); __attribute__((constructor))static void static_constructor() { ::android::hardware::details::gBnConstructorMap.set(IComposer::descriptor, [](void *iIntf) -> ::android::sp<::android::hardware::IBinder> { return new BnHwComposer(static_cast(iIntf)); }); ::android::hardware::details::gBsConstructorMap.set(IComposer::descriptor, [](void *iIntf) -> ::android::sp<::android::hidl::base::V1_0::IBase> { return new BsComposer(static_cast(iIntf)); });
}; __attribute__((destructor))static void static_destructor() { ::android::hardware::details::gBnConstructorMap.erase(IComposer::descriptor); ::android::hardware::details::gBsConstructorMap.erase(IComposer::descriptor);
};

这里会创建一个BnHwComposer对象&#xff0c;并将HwcHal保存到其变量_hidl_mImpl中&#xff1a;

BnHwComposer::BnHwComposer(const ::android::sp &_hidl_impl) : ::android::hidl::base::V1_0::BnHwBase(_hidl_impl, "android.hardware.graphics.composer&#64;2.1", "IComposer") { _hidl_mImpl &#61; _hidl_impl; auto prio &#61; ::android::hardware::details::gServicePrioMap.get(_hidl_impl, {SCHED_NORMAL, 0}); mSchedPolicy &#61; prio.sched_policy; mSchedPriority &#61; prio.prio;
}

所以toBinder函数功能如下&#xff1a;


  1. 如果是BpHwComposer对象&#xff0c;则得到BpHwComposer的成员变量BpHwBinder对象&#xff1b;

  2. 如果是BpHwComposer对象&#xff0c;则创建BnHwComposer对象&#xff1b;
    这里写图片描述
    由于这里转换的是HwcHal对象&#xff0c;该对象实现了IComposer接口&#xff0c;但并不是BpHwComposer类型&#xff0c;因此将创建并返回一个BnHwComposer对象&#xff0c;接着通过_hidl_data.writeStrongBinder(_hidl_binder)将这个BnHwComposer对象传输给hwservicemanager进程&#xff0c;我们知道&#xff0c;binder驱动可以传输binder实体对象&#xff0c;binder驱动自动识别binder实体对象&#xff0c;并转化为binder代理对象&#xff0c;对端进程将得到binder代理对象。

system\libhwbinder\Parcel.cpp

status_t Parcel::writeStrongBinder(const sp& val)
{ return flatten_binder(ProcessState::self(), val, this);
} status_t flatten_binder(const sp& /*proc*/, const wp& binder, Parcel* out)
{ flat_binder_object obj; obj.flags &#61; 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; if (binder !&#61; NULL) { sp real &#61; binder.promote(); if (real !&#61; NULL) { IBinder *local &#61; real->localBinder(); if (!local) { BpHwBinder *proxy &#61; real->remoteBinder(); if (proxy &#61;&#61; NULL) { ALOGE("null proxy"); } const int32_t handle &#61; proxy ? proxy->handle() : 0; obj.type &#61; BINDER_TYPE_WEAK_HANDLE; obj.binder &#61; 0; /* Don&#39;t pass uninitialized stack data to a remote process */ obj.handle &#61; handle; obj.COOKIE &#61; 0; } else { obj.type &#61; BINDER_TYPE_WEAK_BINDER; obj.binder &#61; reinterpret_cast(binder.get_refs()); obj.COOKIE &#61; reinterpret_cast(binder.unsafe_get()); } return finish_flatten_binder(real, obj, out); } // XXX How to deal? In order to flatten the given binder, // we need to probe it for information, which requires a primary // reference... but we don&#39;t have one. // // The OpenBinder implementation uses a dynamic_cast<> here, // but we can&#39;t do that with the different reference counting // implementation we are using. ALOGE("Unable to unflatten Binder weak reference!"); obj.type &#61; BINDER_TYPE_BINDER; obj.binder &#61; 0; obj.COOKIE &#61; 0; return finish_flatten_binder(NULL, obj, out); } else { obj.type &#61; BINDER_TYPE_BINDER; obj.binder &#61; 0; obj.COOKIE &#61; 0; return finish_flatten_binder(NULL, obj, out); }
}

创建HIDL服务的binder代理对象

Hal进程将BnHwComposer对象传递给hwservicemanager后&#xff0c;hwservicemanager进程通过_hidl_err&#61;_hidl_data.readNullableStrongBinder(&_hidl_service_binder);拿到client进程发送过来的BnHwComposer对象&#xff0c;binder实体到达目的端进程将变为binder代理对象&#xff1a;

system\libhwbinder\Parcel.cpp

sp Parcel::readStrongBinder() const
{ sp val; // Note that a lot of code in Android reads binders by hand with this // method, and that code has historically been ok with getting nullptr // back (while ignoring error codes). readNullableStrongBinder(&val); return val;
} status_t Parcel::readNullableStrongBinder(sp* val) const
{ return unflatten_binder(ProcessState::self(), *this, val);
} status_t unflatten_binder(const sp& proc, const Parcel& in, sp* out)
{ const flat_binder_object* flat &#61; in.readObject(); if (flat) { switch (flat->type) { case BINDER_TYPE_BINDER: *out &#61; reinterpret_cast(flat->COOKIE); return finish_unflatten_binder(NULL, *flat, in); case BINDER_TYPE_HANDLE: *out &#61; proc->getStrongProxyForHandle(flat->handle); return finish_unflatten_binder( static_cast(out->get()), *flat, in); } } return BAD_TYPE;
}

system\libhwbinder\ProcessState.cpp

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{ sp<IBinder> result; AutoMutex _l(mLock); handle_entry* e &#61; lookupHandleLocked(handle); if (e !&#61; NULL) { // We need to create a new BpHwBinder if there isn&#39;t currently one, OR we // are unable to acquire a weak reference on this current one. See comment // in getWeakProxyForHandle() for more info about this. IBinder* b &#61; e->binder; if (b &#61;&#61; NULL || !e->refs->attemptIncWeak(this)) { b &#61; new BpHwBinder(handle); e->binder &#61; b; if (b) e->refs &#61; b->getWeakRefs(); result &#61; b; } else { // This little bit of nastyness is to allow us to add a primary // reference to the remote proxy when this team doesn&#39;t have one // but another team is sending the handle to us. result.force_set(b); e->refs->decWeak(this); } } return result;
}

因此hwservicemanager进程通过readStrongBinder()函数将得到BpHwBinder对象&#xff0c;然后通过fromBinder函数将binder代理对象转换为业务代理对象&#xff1a;

service &#61; ::android::hardware::fromBinder

template <typename IType, typename ProxyType, typename StubType>
sp fromBinder(const sp& binderIface) { using ::android::hidl::base::V1_0::IBase; using ::android::hidl::base::V1_0::BnHwBase; if (binderIface.get() &#61;&#61; nullptr) { return nullptr; } if (binderIface->localBinder() &#61;&#61; nullptr) { return new ProxyType(binderIface); } sp base &#61; static_cast(binderIface.get())->getImpl(); if (details::canCastInterface(base.get(), IType::descriptor)) { StubType* stub &#61; static_cast(binderIface.get()); return stub->getImpl(); } else { return nullptr; }
}

因此fromBinder函数功能如下&#xff1a;


  1. 如果是binder代理&#xff0c;则基于binder代理创建业务代理对象&#xff1b;

  2. 如果是binder实体&#xff0c;则得到业务实现类对象&#xff1b;
    这里写图片描述
    通过fromBinder函数后&#xff0c;这里将创建一个BpHwBase对象&#xff0c;并将BpHwBinder保存到其成员变量_hidl_impl中。

BpHwBase::BpHwBase(const ::android::sp<::android::hardware::IBinder> &_hidl_impl) : BpInterface<IBase>(_hidl_impl), ::android::hardware::details::HidlInstrumentor("android.hidl.base&#64;1.0", "IBase") {
}

Hal进程在向hwservicemanager进程注册IComposer接口服务时&#xff0c;通过服务实现类对象HwcHal经过toBinder函数将在Hal进程地址空间中创建binder实体对象BnHwComposer&#xff0c;然后将BnHwComposer发送给hwservicemanager进程&#xff0c;hwservicemanager进程将得到其binder代理对象BpHwBinder&#xff0c;然后经过fromBinder函数在自身进程地址空间中创建BpHwBase对象&#xff0c;如下图所示&#xff1a;
这里写图片描述
因此BnHwComposer和BpHwBinder才是真正的IBinder对象&#xff0c;hwservicemanager进程中的BpHwBase和Hal进程中的HwcHal就是通过BnHwComposer和BpHwBinder建立关联的&#xff0c;在Treble的binder架构中&#xff0c;无论是Client端还是Server端都是采用代理模式来实现的&#xff0c;这里与普通的binder通信框架有所区别&#xff0c;普通binder通信框架中&#xff0c;BpBinder和BnBinder都继承IBinder类&#xff0c;Client端的业务代理和Binder代理直接采用代理模式&#xff0c;而在Server端&#xff0c;业务实现在本地Binder的子类中。hwBinder下&#xff0c;命名有所混乱&#xff0c;让人很容易误以为BpHwXXX和BnHwXXX是binder通信下的代理对象和本地对象。
这里写图片描述


Treble架构下的Hal进程模型变化

在AndroidO以前&#xff0c;Hal采用Legacy模式&#xff0c;Framework Server进程直接dlopen hal库&#xff0c;如下图所示&#xff1a;
这里写图片描述
但在AndroidO以后&#xff0c;所有的Hal独立运行在自己的进程空间&#xff0c;Framework Server进程通过binder访问Hal&#xff0c;为了兼容之前版本的hal实现&#xff0c;在hal库之上定义了一个hal实现类&#xff0c;用于封装hal接口&#xff0c;编译为XXX&#64;impl.so&#xff0c;hal进程在启动时通过dlopen该so库库得到Hal接口类对象&#xff0c;而XXX&#64;impl.so中又会dlopen真正的hal实现库。
这里写图片描述
上图说明对于Hal进程来说&#xff0c;默认使用PassthroughServiceManager来加载XXX&#64;impl.so库&#xff0c;并得到Hidl服务接口类对象&#xff0c;而对于要访问Hal的Client进程&#xff0c;比如Framework server进程&#xff0c;需要根据当前访问的hidl服务的Transport类型来决定获取方式&#xff0c;如果当前访问的hidl服务是hwbinder&#xff0c;那么就从hwservicemanager中查询&#xff0c;如果当前方位的hidl服务是PASSTHROUGH&#xff0c;那么久会采用PassthroughServiceManager将XXX&#64;impl.so库加载到当前进程地址空间。


推荐阅读
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
author-avatar
sucbenson-lee_905
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有