持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
Android系统架构
在去了解Binder之前,先看下Binder在Android系统架构中的位置,如图:
该Android的架构从下往上大体功能如下:
-
1)Linux Kernel:Linux内核。像Audio、Camera等硬件对应的软件层的驱动程序、线程和内存管理、Binder等;
-
2)HAL:硬件抽象层。向Java层输出手机硬件的功能。在Linux Kernel中都是直接通过C来读写手机硬件,而HAL是对这些操作的进一层封装,让C++可以更方便的来使用这些功能。
-
3)Android Runtime:Android应用程序运行的环境,用来将运行程序语言转化成机器可以识别的机器语言。连接了Framework和Library,包括core lib和虚拟机(DVM)。
-
4)C++:在Android系统中核心组件和服务都是通过C和C++编写,那么在Framework在调用这些功能的时候,就需要通过JNI来访问这些内容;
-
5)Java API Framework:给APP调用系统核心组件和服务的API;
-
6)System APP:系统应用 Binder其实就是工作在Linux Kernel,其实Binder更通俗点来讲就是访问内存空间的驱动程序。
(1)APP进程的创建过程
在Linux系统中,所有的进程都是有init进程(Linux内核系统启动的第一个用户级进程)的子孙进程,所有的进程都是有init进程直接或间接fork出来的。
在Android系统中,当然启动的第一个进程仍然为init进程,在init进程启动Zygote进程。该Zygote进程来创建Android系统后续的其他进程。那么Android的其他进程的启动流程如下:
-
1)Android系统启动,启动init进程;
-
2)init进程创建Zygote进程;
-
3)Zygote进程在创建的时候,需要完成如下工作:“创建一个Server端的Socket,等待AMS的请求创建APP的进程-->-->预加载类和资源-->-->fork出SystemServer进程”;
-
4)SystemServer进程在创建的时候,需要完成如下工作:“启动Binder线程池-->-->创建SystemServiceManager(对系统服务进行创建、启动、生命周期管理)-->-->启动各种关键系统服务(如AMS、WMS等)”;
-
5)AMS启动Launcher;
-
6)当点击APP的icon,AMS就会通过Socket通道,通知Zygote创建一个APP进程
(2)什么是Binder
所谓的Binder,是一种通信机制,目前是实现IPC,整个架构采用的是C/S架构。其中有四个组件:Client、Server、Binder驱动以及ServiceManager:
-
1)ServerManager:可以理解为路由器。管理各种Service的注册与查询。ServerManager会将这些字符串的Binder转化成该Binder的引用。
-
2)Client:可以理解为客户端。如果访问Server进程,需要先从ServerMananger中查询Service,得到访问的Server的代理对象;
-
3)Server:可以理解为服务器。提供服务,需要将Service注册到ServerManager中。是一个Binder对象,接收从Binder驱动发送过来的消息,收到消息后,就会执行onTransact();
-
4)Binder驱动:可以理解为访问内存空间的驱动程序。负责管理数据的接收缓存。持有每个Server进程在内核空间的Binder实体,并且给Client进程提供Binder实体的引用。主要作用通过内存映射传递进程间数据和线程控制。
-
在Binder驱动中包括binder的binder_open()、binder_mmap()、binder_ioctl()、管理内核缓冲区等操作。
Client、Server、ServiceManager运行在用户空间,分别都是单独的进程;而Binder驱动运行在内核空间。
1.对几个常见的字符串的概念区分:
在Natvie层调用binder_open()/binder_mmap()/binder_ioctl(),最后都会调用到Binder驱动程序的对应方法,完成了用户空间访问和操作内核空间;
copy_from_user()、copy_to_user()是Linux提供的用户空间和内核空间传递数据的方法:从用户空间传递到内核空间使用的是copy_from_user(),而将内核空间传递给用户空间使用的是copy_to_user()
2.Binder在进行进程通信之前的准备工作:
需要创建ServerManager进程、Client进程以及Server进程
(3)Binder的通信机制
Client、Server、ServiceManager工作为用户空间,Binder驱动工作在内核空间。所以其中Client、Server在ServiceManager中查询和注册服务是不可以之间通信的,而是需要通过Binder驱动(open和ioctl文件操作)来进行间接通信,其流程大体如下:
第一步:注册
-
1)Server进程向Binder驱动发送注册服务的请求;
-
2)Binder驱动将该请求发送给ServiceManager进程;
-
3)ServiceManager进程进行添加该Server进程的引用;
上述过程ServiceManager进程拥有了Server进程的信息。
第二步:查询
-
4)Client进程向Binder驱动发送服务的名字,以获取服务;
-
5)Binder驱动将该请求发送给ServiceManager进程,ServiceManager进程根据服务的名字找到对应的Server的服务信息;
-
6)ServiceManager进程通过Binder驱动将服务信息返回给Client进程;
此时该Client进程已经与Server进程建立了连接,这个过程就是Binder中的IPC。
第三步:使用
Binder在传递数据的时候只需要拷贝一次数据,性能上仅次于共享内存。
在创建APP进程的时候,既会在在用户空间创建一块虚拟内存,同时也会在内核空间创建一块虚拟内存,并且申请一块物理内存同时映射到这两块虚拟内存中;同样Service进程在创建的时候也会有相同的操作。那么通过内存映射实现了将数据拷贝到Client进程的用户空间和Server进程的用户空间只需要通过一次拷贝完成数据传递
补充一点:
1.消息队列和管道需要将数据先从发送方缓存区拷贝到内核开辟的缓冲区,然后再从内核缓冲区拷贝到接收方的缓冲区,需要两次拷贝;
2.共享内存无需拷贝,但控制复杂;
3.socket传输效率低,通常用于跨网络的进程间通信
在内核空间,Binder驱动传递数据是通过内存来传递数据,所以Binder会创建一块内存用来传递数据大体的传递流程如下:
-
7)Client进程将要传递的数据放入(通过copy_from_user)到Client进程在内核空间对应的虚拟内存区;(当前进程被挂起,处于中断等待状态)
-
8)从Client进程在内核空间对应的虚拟内存拷贝到Binder驱动的内存,从由于Binder驱动创建的内存和Server进程在内核空间对应的虚拟内存是同一内存地址,所以相当于直接拷贝到,通知Server进程读取数据(之前Server进程启动之后,就会进入到中断等待状态);
-
9)Server进程接到通知之后,就会从线程池中取出对应的线程,解析数据,并将最后的处理结果写入到Server进程在内核空间对应的虚拟内存中;
-
10)将Server进程在内核空间对应的虚拟内存中的数据拷贝到Binder驱动的内存中,同样由于内存映射的原因,相当于直接拷贝到了Client进程在内核空间对应的虚拟内存中,并通知Client进程读取数据;
-
11)Client进程接到通知之后,Client进程读取在内核空间对应的虚拟内存中的数据。(当前线程被唤起)
此时就是Client进程就实现了和Server进程之间传递数据,这个过程就是Binder中的RPC(Remote ProcessCall)远程过程调用。
遗留问题:Binder中的线程池的概念
(4)Android中的API Binder驱动是运行在内核空间,使用的C来实现的,而最终需要实现的用户空间的数据共享,准确的说是应用层的不同用户空间的数据共享,而应用层的相关实现都是用Java实现的,那么从代码实现来看Binder需要包括以下几部分:
-
1)在Framework层对上层应用的封装,也有对Native的封装Client、Server、ServiceManager的封装;
-
2)在Native对Client、Server、ServiceManager的封装;
-
3)在Kernel对Binder驱动的封装。
4.总结
1.系统中运行的每个APP都可以认为是一个进程,进程是系统资源分配的最小单位;而一个进程是有线程组成的。
2.系统每运行一个APP,都会分配一个进程,在进程中就会分配独立的dalivk虚拟机来运行APP。dalivk虚拟机是专门用来运行Android程序;
3.当然一个APP也可以分配多个进程,就会对应多个dalivk实例;
4.Linux系统把4G的虚拟内存空间的0G~3G作为用户空间,高3G~4G作为内核空间:APP运行在用户空间;
5.不同APP所在的用户空间是无法进行通信的,必须通过系统调用到内核才可以完成不同APP之间的通信;
6.内核空间有访问最底层硬件设备的所有权限;内核空间是共享的;
7.由于APP的单个进程有内存限制,所以就可以通过在APP中增加进程的方式来增大APP可用的内存空间,所以需要引入多进程;
8.处在不同进程中的两个APP之间数据通信的时候,所以就需要引入多进程之间的通信IPC;
9.在Android中常用的IPC有AIDL、ContentProvider、Bundle等;
10.如果一个APP有多个进程,那么这些进程之间都保持自己单独的静态成员变量和单例,并且拥有单独的Application实例;
11.在Android中通过在内核空间的Binder驱动来实现IPC;
12.在Android的Binder机制中有四个重要角色:ServiceManager、Server、Client以及Binder驱动:其中前三个运行在用户空间,Binder驱动运行在内核空间;
13.在创建ServiceManager、Server、Client进程的时候,都会在对应的用户空间创建虚拟内存,同样也会在内核空间创建虚拟内存,同时会有一块物理空间同时映射到这两块虚拟内存;
如果觉得文章内容对你有所帮助的话,可以点赞转发分享一下哦~
最后祝各位开发者攀登上更高的高峰