解说==Android的核心心脏binder

来源:互联网 发布:最便宜的域名虚拟机 编辑:程序博客网 时间:2024/05/21 06:26

Android的核心心脏binder


在这里我找了一个最简单的项目作为解释说明binder这个知识点,这里就不详细说概念什么的,因为觉得用例子讲胜过说这个.

我找的例子就是获取手机电池信息的功能项目

现在来看看我们的角色有那些?

1.binder驱动

它是linux常规的驱动程序,内置linux内核里,功能大概就是高效组织和利用内存来维护一组对象的注册和查询,其实本质就是用来告诉调用者的方法函数的调用指针地址,

就是相当于c/c++的函数指针调用一样,也相当于组成心脏的心脏细胞


2.servicemanager守护进程

这个你可以想象它就是方法函数的dns服务来的,提供注册和查询功能,是一直运行的程序,如果它挂掉了,整个android系统都会崩溃的,也可以说就是心脏跳动的动力.

而binder驱动就是它的基石,实际就是ioctrl binder驱动在linux应用层的一个封装


3.healthd守护进程

这个就是获取手机电池信息功能的真正实现地方,(记得当时找这个功能的庐山真面幕时,都找了好久,都给binder框架的复杂给弄得头头转),它也是一直运行的程序

相当于某个内脏器官一样提供相关功能


4.libbinder库

这是提供c/c++ binder框架的标准规范白皮书,相当于遍布全身的血管


5.libbatteryservice库

这个是服务的接口声明,是c/c++ binder框架的实现,相当于一条具体的毛细血管一样,提供血液输送的管道,而方法函数的调用指针地址相当于血管里的红细胞一样,灌通在全身血管里


6.vold c/c++本地客户端 和BatteryManager.java java层 客户端 的调用

这两个相当于人体外部组织,例如毛发的生长需要营养,就要通过吸取血管营养一样,其实就是客户端调用服务


然后简单说一下获取电池信息的整个binder调用过程

1.linux系统的启动,会自动加载内核驱动之一的binder驱动,加载之后就可以通过系统函数ioctrl来进行与上层应用沟通了

2.然后linux内核系统完成后,平台的第一个程序就会被调用启动就是init, init会进行一系列.rs文件的解释并长期维护着这个文件里配置的东西,里面包含着很多要维护的东西,这里我们只关心servicemanager守护进程的启动,到这里binder的运行基础环境可以说是完成了,接下来就是怎么添加想要的服务和提供服务的入口

3.healthd守护进程也是从init里启动的,是实现获取电池信息的真正代码地方,其实实现原理很简单,就是读取/sys/class/目录下的文件内容而已,这里又一次证明了linux的一切皆是文件.在这里不仅仅是实现功能这么简单的,它还向servicemanager守护进程注册了一个名为batteryproperties的服务,并且功能的实现是结合ibbinder库和libbatteryservice库来实现的,这里也是代码理解最复杂最难看的地方,这里你只要记住这就是玩binder游戏的一条必备规则,其实如果你熟悉这条规则,然后看其他服务的实现就会很容易的,因为无论你写什么样的服务规则都是一个样的,无不例外.

看到这里可能还不明白binder到底是什么个运行机制的?

我就通俗的说一下

你可以想象一下你有一个守护进程A不停的运行在内存里是常住的那种,进程里已包含了可调用的函数方法的实现,可以随时随地调用使用的.不过使用范围就只限于这个进程里.

现在问题来了,怎样才可以让其他进程也可以调用使用呢?

答案就是利用binder,首先向servicemanager守护进程为守护进程A注册用户账号,就像出境登陆一样.其实就是保存守护进程A相关内存的地址到binder驱动所管理下的内存里进行维护.说白了就是用户账号和内存地址的影射管理.如果有客户端想调用守护进程A里的函数方法,就会像servicemanager守护进程声明使用守护进程A注册时使用的用户账号来获取内存地址,只要地址获取后,就没有servicemanager守护进程的事了,你可以闪开了.所以servicemanager守护进程不会在binder调用里全程参与的,这就是为什么我说像dns服务了.

现在问题又来了,既然有声明用户账号来获取内存地址,那有没有匿名的账号来获取内存地址?

答案是有的,这个是比较高级的用法,我这里就暂不说,不过可以剧透一下,需要在一次声明的基础下才可以匿名的,也就是说要进行两次获取内存地址的

现在内存地址都拿到了,你说是不是想做什么都行了.当然原理是简单,但是实现起来就很复杂了,所以现在到binder游戏的一系列的规则出场了,只要你按规则办事,实现提供好接口,那其他进程只要拿着你的那份接口就可以好像自己本地进程那要调用了


代码详情解说

这里不一一把全部代码都说一片,只是详情讲讲binder游戏规则要怎么个遵守,怎么去看和理解规则

主要看到的项目有两个

frameworks/native/libs/binder/

frameworks/native/services/batteryservice/

 在理解之前我要说一下我们正常理解c/c++的代码顺序,通常就是头文件的声明,然后是实现的文件.刚开始看的时候就是使用这种方法去看,结果,靠,看不下去了,为什么,应为在追踪一个方法的时候,会突然间奔出另一个方法出来,可头文件,实现文件怎么找也找不到,明明都没有出现过,偏偏就可以调用啊!!!你要知道当你从很远处的代码跳到这里,以为可以就快知道真相的时刻,突然间跳不下出了,这是多么悲剧,应为这时我脑海里的线路一直保持清晰的,看到这估计我这条线路又要从新跳过了,应为我暂时的记忆力很快就没了(其实这样说可能不明白,当实战看代码就会feel到的),那要怎么看?

应为google在写binder框架时,提供了很多模板类和宏定义需要整合,所以其实你看到的类的声明和实现是不完整的,也就是说看之前要把它们全部展开成一个完整的文件后,才开始看代码,那就正确了.刚开始的时候我真的还原了文件来看,后来就不用了,脑补全文件,看来看android源代码真的可以提高脑力记忆的.


IBatteryPropertiesRegistrar.h

IBatteryPropertiesRegistrar.cpp

这两个文件就是主角,也是实现binder规则的简单例子参考

其实解说代码的最痛苦的,只要是程序员看一眼代码,胜过我解释壹万句话.你懂的.

这里我只说我遇到看不明白的地方

1.IBatteryPropertiesRegistrar类 声明下的方法就是要对外提供的接口方法,代码文件没有全展开的时候,也就是说找IXXXXXXX类的头文件就知道有什么服务方法可以提供了

2.BnBatteryPropertiesRegistrar和BpBatteryPropertiesRegistrar这两个类理解比较困难

扎眼下看代码怎么都没有联系,但是偏偏又连上了

先从类名称的前缀字符说起,

首先是Bn 猜想就是BinderNative, 这个应该很好理解,就是最终要给真实实现功能的类继承的例如就是healthd下的BatteryPropertiesRegistrar类,简单来说要开始遵守binder规则的地方.

然后Bp猜想就是BinderProxy, 代理,其实看了也不知道做什么的,其实就是binder函数调用请求的开始代码,你可以这样认为的.


在这里要搞清楚getProperty这个函数方法在不同位置的含义

1.BpBatteryPropertiesRegistrar::getProperty

这个是创建binder请求并应答调用者返回数据的地方

里面的remote()->transact(GET_PROPERTY, data, &reply)调用之后就会调用BnBatteryPropertiesRegistrar::onTransact方法

2.BnBatteryPropertiesRegistrar::onTransact->getProperty

这个是真实调用功能方法getProperty,也就是BatteryPropertiesRegistrar::getProperty

3.BatteryPropertiesRegistrar::getProperty

这个是真实功能实现的地方


那么说了这么多,最关键的问题是怎么解决的拉,就是Bn和Bp是怎么关联的????

答案是宏IMPLEMENT_META_INTERFACE的定义里的asInterface方法

intr = new Bp##INTERFACE(obj);这句代码就是关键了,

还有一个模板方法interface_cast

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

刚开始还以为是关键字来的,看错了

到这里基本说完了binder框架代码实现的详细介绍了


最后就是c/c++ 层和java层的客户端调用了,这里就不说了,自己直接去看代码就知道怎么使用刚才弄好的服务接口

可以参考

/frameworks/base/core/java/android/os/BatteryManager.java
/frameworks/base/services/core/java/com/android/server/BatteryService.java
/system/vold/CheckBattery.cpp





以下是本文涉及到的代码路径

frameworks/native/services/batteryservice/Android.mk

frameworks/native/libs/binder/Android.mk

system/core/healthd/Android.mk

frameworks/native/cmds/servicemanager/Android.mk





















0 0
原创粉丝点击