当前位置: 移动技术网 > IT编程>移动开发>Android > Android跨进程之Binder机制概述

Android跨进程之Binder机制概述

2018年11月01日  | 移动技术网IT编程  | 我要评论

北方影院子夜心跳,军迷非法邮寄枪支,张佑赫

binder(机制)

首先binder是一个类,实现了ibinder接口,其次从ipc角度来看,就是android中跨进程通信机制。

为什么使用binder作为跨进程机制?

linux中使用管道(pipe)做为进程之间的通信方式,虽然android内核也是使用的linux,但是作为移动端,性能和内存角度考虑,使用binder是最好的方式。管道和socket数据拷贝的次数为2次,文件共享0次,但是其安全性低太多,binder数据拷贝次数为1次,也能为发送端提供身份验证。

这里写图片描述

这是罗升阳博客androidbinder机制中的四个client、server、service manager和binder驱动程序中的关系图

binder机制涉及到最重要的四个组件client、server、service manager和binder驱动设备

client和server都是在应用层实现的,server、client都是运行在独立的进程中,两者之间的通信就是ipc的方式,其中就要通过service manager和binder驱动设备。

client:客户端(调用iservicemanager::getservice和binder驱动程序交互) server: 服务端(调用iservicemanager::addserie和binder驱动程序交互) service manager:实际也是server,更是一种守护线程,管理server,并向client提供查询server接口 binder驱动:搭建进程之间通信的建立,并且支持data数据包的传输

举个栗子 这里使用mediaservice

mediaservice

在native层可以找到mediaservice的:

int main(int argc, char** argv)

{

//获得一个processstate实例

sp proc(processstate::self());

//得到一个servicemanager对象

    sp sm = defaultservicemanager();

    mediaplayerservice::instantiate();//初始化mediaplayerservice服务

    processstate::self()->startthreadpool();//看名字,启动process的线程池?

    ipcthreadstate::self()->jointhreadpool();//将自己加入到刚才的线程池?

}

最重要的servicemanager是通过defaultservicemanager()获取到的,中间还要获取servicemanager的binder代理,实在太复杂,不想多说,然后初始化mediaplayerservice服务,也是打开binder驱动设备,设置looper循环。

servicemanager存在的意义:

server先add到servicemanager中几种管理,client想要和server交互,需要先到servicemanager中查询service信息,然后通过sm返回的东西和server交互

在servicemanager中其源码service_manager知道了三点作用:

打开了binder设备 告诉binder驱动设备,自己就是binder的上下文管理者,也就是守护线程 进入一个无线循环,充当server的角色

binder的使用场景:

1 activity启动

activity的启动需要用到activitymanagerservice,但是我们的app进程和activitymanagerservice所在的进程不是同一个进程,所以就需要用到进程间通讯了。在app进程中我们拿到的是activitymanagerservice的一个分身,也就是activitymanagerproxy,这个activitymanagerproxy与activitymanagerservice都实现了iactivitymanager接口,因此它们具有相同的功能,但是activitymanagerproxy只是做了一个中转,创建两个parcel对象,一个用于携带请求的参数,一个用于拿到请求结果,然后调用transact方法,通过binder驱动,activitymanagerservice的ontransact方法会被调用,然后根据相应的code,调用相应的方法,并把处理结果返回。

在这个过程中,我们的app进程就是client,activitymanagerservice所在的进程是service

但是activity的启动过程还没有完,activitymanagerservice还会调用我们app所在进程的applicationthread来最终完成activity的启动,其实activitymanagerservice拿到的也是applicationthread的一个分身applicationthreadproxy,通过这个分身,applicationthread相应的方法会被调用。

在这个过程中,我们的app端是server,activitymanagerservice所在的进程是client。

还有一个问题我们要注意,activitythread有一个内部类h(一个hander),applicationthread方法内部都会通过这个handler来发送消息,最终调用到activitythread的方法。为什么要这么做呢?

在分析源码的过程中,很长一段时间,这个问题都困扰着我,直到有一天对binder的理解加深了,我才明白:binder服务端的方法都是运行在binder线程池的一个线程中的,所以要通过hander,把方法的调用切换到主线程中来。

2 intent传递数据

我们都知道intent可以传递的数据包含:基本类型、string、实现了serializable接口或者parcelable接口的类以及对应的数组或者集合类。其实intent中的数据都是通过bundle来携带的,那么我们就要有个疑问了,为什么限定只能是这些类型的数据,而不是任意的数据类型呢?

归根结底,限制这些类型的是parcel这个类。如果我们查看源码的话就会看到,bundle其实也是用到了parcel这个类。

parcel
,“包裹的意思”,它的作用就是为了在ipc过程中存放数据。我们要知道一点,进程间传递数据,实际上就是二进制数据,所以对于非基本类型,必然存在着序列化和反序列过程,这也是为什么要求intent传递的非基本类型数据必须实现serializable或者parcelable接口的原因。

至于parcel在ipc过程中使用到的地方,我们可以看一段代码,这个是我仿造着aidl生成的文件,自己手写的一个binder服务端。看一下proxy类的add方法,实际上就是先创建两个parcel对象,一个通过调用
writexxx 方法用于存放请求数据,一个是通过调用 readxxx
方法获取结果。proxy真正干的就是这些,真正计算的还是服务端stub的实现类。当proxy调用
mremote.transact(transaction_add, _data, _reply, 0);
方法后,stub的ontransact方法会被调用,进而调用真正的add方法。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网