Android Review - Binder机制(一)
简介
Binder机制是Android特有的一种跨进程通信的方式,在日常应用开发中四大组件底层通信机制、Activity传递对象以及AIDL的使用等,都涉及到Binder机制。
Linux内核基础
一:进程隔离
Android系统为了保护进程互不干扰,采用了虚拟空间的技术,所有进程表面是共享了系统,但是数据是不能共享的。若果两个进程需要进行通信,就需要一种通信机制,也就是Binder机制。
二:内核共享
对于用户空间,不同进程之间彼此是不能共享的,而内核空间却是可共享的。
三:访问内核
内核有保护机制,告诉应用程序,只能访问一些许可资源。
内核与上层应用(用户空间)分离开,用户可以通过系统调用,让用户空间访问内核的一些程序。
四:Binder驱动
在 Android 系统中,这个运行在内核空间,负责各个用户进程通过 Binder 实现通信的内核模块就叫 Binder 驱动(Binder Driver)。
为什么使用Binder
Android的系统底层是Linux系统,Linux本身就有很多种IPC的方式,为啥Android要设计Binder机制呢?
Linux的IPC共有8种:
- 管道 (PIPE),实际是用于进程间通信的一段共享内存。缺点:需要将一块内存拷贝两次,第一次拷贝到共享区,第二次拷贝到目标进程,效率低。
- 命名管道(FIFO),是一种特殊类型的文件。缺点:是基于文件的io操作,性能差。
- 信号 (signal),是一种以事件为驱动的通信方式。缺点:不适合信息的传递。
- 消息队列(Message queues),是内核地址空间中的内部链表,通过linux内核在各个进程直接传递内容。缺点:跟管道一样。
- 信号量(Semaphore),是一种计数器,用于控制对多个进程共享的资源进行的访问。缺点:跟信号一样。
- 共享内存(Share Memory),是在多个进程之间共享内存区域的一种进程间的通信方式。缺点:需要自己实现进程间的同步。
- 内存映射(Memory Map),是由一个文件到一块内存的映射。缺点:需要自己实现进程间的同步。
- 套接字 (Socket),是一种跨网络的通信方式。缺点:传输效率低,开销大。
Android的IPC方式:
- 文件系统
- Socket
- Pipes管道
- 共享内存
- 隐式Intent
- ContentProvider
- Broadcast
Binder比以上的IPC方式,具有2个优点
- 性能好。Binder采用内存映射的机制,Binder数据的拷贝只要一次。
- 更安全。Linux的IPC方式无法获取目标进程的UID/PID,无法鉴别身份;Android可以获取目标进程的进程的UID/PID,从而控制访问权限。协议本身对通信双方做身份校验,因为安全性大大提升
Binder通信的流程
Binder通信流程在进入通信流程之前我们先来了解图上的一些概念~
-
Client进程(客户端)
使用服务的进程 -
Server进程(服务端)
提供服务的进程 -
ServiceManager
ServiceManager是在系统初始化的时候init进程启动的进程,是binder驱动的守护进程。serviceManager向用户层提供查询binder服务和注册binder服务的功能,是binder的大管家 -
Binder驱动
负责各个用户进程通过 Binder 实现通信 -
binder_proces全局链表
这个链表保存在内核中,链表中存储着所有已经注册的binder服务的信息 -
svcinfo
在这个里面保存着所有已经注册的binder服务的代理,所谓代理意思是这个代理不是真的binder服务,只是与binder服务有着相同的接口,客户端使用该接口可以访问服务端实现的功能。
通信流程可以分为3步:注册服务、获取服务、使用服务。
一:注册服务
- 服务端向service_manager发出注册服务的请求
- service_manager向binder驱动发出注册服务的请求
- binder驱动响应请求,将被注册的服务信息保存到内核中的binder_procs全局链表中
- binder驱动返回被注册服务的代理
- service_manager将服务的代理保存到svcinfo中
- 返回到服务端
二:获取服务
- 客户端向service_manager发出获取服务请求
- service_manager在binder驱动的帮助下查询对应服务端,在svcinfo中查询对应服务端的代理
- 给客户端返回服务端的代理
三:使用服务
- 客户端调用代理中的接口,输入参数
- binder驱动分别在在内核空间和服务端开辟缓存区,建立服务端和内核空间的内存映射。
- 使用copy_from_user将参数从用户空间复制到内核空间中的缓存区。
- 服务端读取缓存区数据,计算结果,将结果写到缓存区中。
- binder驱动使用copy_to_user将结果返回给客户端。
- 客户端接收到结果,完成通信。
提示:整个调用的过程是一个同步过程,因此客户端调用的过程中不应该在主线程
PS:本文
整理
自以下博客
安卓移动架构07-Binder核心机
通过一张图来学习安卓的binder机制
若有发现问题请致邮 caoyanglee92@gmail.com