Android跨进程之Binder机制概述

Binder(机制)

首先Binder是一个类,实现了IBinder接口,其次从IPC角度来看,就是Android中跨进程通信机制。

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

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

这里写图片描述

这是罗升阳博客Android系统Binder机制中的四个组件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::addServcie和Binder驱动程序交互)
  • Service Manager:实际也是Server,更是一种守护线程,管理Server,并向Client提供查询Server接口
  • Binder驱动:搭建进程之间通信的建立,并且支持data数据包的传输

举个栗子 这里使用MediaService

MediaService

在native层可以找到MediaService的源码:

int main(int argc, char** argv)

{

//获得一个ProcessState实例

sp<ProcessState> proc(ProcessState::self());

//得到一个ServiceManager对象

    sp<IServiceManager> 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知道了三点作用:
  1. 打开了Binder设备
  2. 告诉Binder驱动设备,自己就是Binder的上下文管理者,也就是守护线程
  3. 进入一个无线循环,充当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方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值