基于Client-Server的通信方式已经广泛应用于Android,而之前提到过Linux许多的通信方式只有socket、文件共享、管道和消息队列可以支持Client-Server。但是这些IPC方式效率都很低。
消息队列/管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。共享内存虽然无需拷贝,但控制复杂,难以使用。
而Binder基于Client-Server通信模式,传输过程只需一次拷贝,并且为发送方添加UID/PID身份,既支持实名Binder也支持匿名Binder,保证了Socket(ip地址开放)/SystemV(键值开放)所没有的安全性!
对Server来说,Binder是Server提供特殊服务的访问接入点,对Client来说,Binder是通向Server的管道入口,想要和某个Server通信必须要建立这个管道并获得管道入口。
Binder是一个实体位于Server的对象,这个对象包装了一套方法可以对服务进行请求。遍布于Client中的入口可以看做指向这个binder的指针(没错啦,就是Server的binder在Client中的代理类!或者说叫句柄),调用了这个指针的方法和直接调用Server中Binder的方法没有任何区别。
binder驱动为面向对象编程提供了底层支持。
binder有四个主角分别为:Server 、Client (不难理解,因为是基于C/S模式)
ServiceManger 、 Binder驱动。
前三者都作用于用户空间,而Binder驱动作用于内核空间。
这个时候引出用户空间及内核空间的概念,接下来通过一张图来理解这两个概念:
看图说话:每个Android进程包含两个空间,一个是内核空间(占用空间少的),特点是不同进程的内核空间是可以共享的,而用户空间的资源是不可以共享的。
我们不同进程要通信的资源肯定都在用户空间啦~所以这个时候就要利用内核空间中的Binder驱动来管理。用户空间通过ioctl等方法来和内核空间通信。
1. Binder驱动
虽然叫“驱动”,但是和硬件驱动没有任何关系,只是作用和驱动差不多。作用于内核态(内核空间),主要负责进程间Binder通信的建立、Binder在进程间的传递、Binder引用计数的管理、数据包在进程间传递和交互的一系列底层支持。
用户态和内核态是隔离开的,但我们用户态也要访问内核态呀,这个时候用户态访问内核态的唯一空间就是系统调用;通过这个统一入口接口,然后所有的资源访问都是在内核的控制下执行,以免导致对用户程序对系统资源的越权访问,从而保障了系统的安全和稳定。在执行内核态的方法是优先级是0(最高)可以使用CPU特殊的优先方法,而用户态则是3(最低)。
Binder 并不是 Linux 内核的一部分,它是怎么做到访问内核空间的呢? Linux 的动态可加载内核模块(Loadable Kernel Module,LKM)机制解决了这个问题;模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行。这样,Android系统可以通过添加一个内核模块运行在内核空间,用户进程之间的通过这个模块作为桥梁,就可以完成通信了。
熟悉了上面的概念可以来看看下图:
用
用户态中的binder_open()、binder_mmap()、binder_ioctl()就是通过调用System call来调用内核态中的方法。用户态和内核态中的共享内存由内核态来调用copy_from_user和copy_to_user来传输。
Binder驱动中保存了一个binder_procs的全局链表来保存服务端的进程信息。
Binder进程和线程
对于底层Binder的驱动,底层的binder_procs链表就记录着所有创建了binder_proc的结构体,每一个binder_proc结构体都与一个用于binder通信的进程对应,每个进程通过单例模式保证自己唯一的ProcessState对象,每个线程也有自己的IPCThreadState对象(也是单例模式保证唯一),在Binder驱动层也有和它对应的Binder_thread,binder_proc结构体中的rb_root threads就是记录自己进程中的所有线程的Binder_thread,具体看下图:
2. ServiceManager
ServiceManager是Binder驱动的守护进程,其实作用简化来说就是提供了 查询服务 和 注册服务的功能。
下面介绍ServiceManager主要分成三部分,分别为启动、注册服务、获取服务。
首先是ServceManger的启动,看下图:
(1)ServiceManager分为framework层和native层,framework层只是对native层进行了封装,方便调用,图上展示的是native层的SM启动过程。
(2)ServiceManager的启动是系统在开机时,init进程解析了init.rc文件调用了 service_manager.c中的main()方法入口启动的 。native层有一个binder.c封装了一些与Binder驱动交互的方法。
(3)ServieceManager启动分为三步:首先打开驱动创建全局链表binder_procs,然后将自己的ProssStats包装成一个binder_proc插入到链表中,最后开启loop循环不断处理共享内存中的数据,并处理BR_xxx命令(ioctl的命令,BR可以理解为binder reply驱动处理完的相应)
总结
我最近从朋友那里收集到了2020-2021BAT 面试真题解析,内容很多也很系统,包含了很多内容:Android 基础、Java 基础、Android 源码相关分析、常见的一些原理性问题
等等,可以很好地帮助大家深刻理解Android相关知识点的原理以及面试相关知识。
这份资料把大厂面试中常被问到的技术点整理成了PDF,包知识脉络 + 诸多细节;还有 高级架构技术进阶脑图 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
这里也分享给广大面试同胞们,希望每位程序猿们都能面试成功~
Android 基础知识点
Java 基础知识点
Android 源码相关分析
常见的一些原理性问题
腾讯、字节跳动、阿里、百度等BAT大厂 2019-2020面试真题解析
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
csdn.net/topics/618156601)**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!