最近在学习 Binder 机制,在网上查阅了大量的资料,也看了老罗的 Binder 系列的博客和 Innost 的深刻理解 Binder 系列的博客,都是从底层开始讲的,全是 C 代码,虽然以前学过 C 和 C++,然而各类函数之间花式跳转,看的我都怀疑人生。绝不夸张的讲每看一遍都是新的内容,跟没看过同样。后来又看到了 Gityuan 的博客看到了一些图解仿佛发现了新大陆。
2019秋招必备面试题汇总+阿里P6P7安卓进阶资料分享
下面就以图解的方式介绍下 Binder 机制,相信你看这篇文章,必定有所收获。node
Binder进程间通讯原理 视频详解 须要密码私聊我便可
连接: https://share.weiyun.com/5GOZsQF
Binder 是 Android 系统中进程间通信(IPC)的一种方式,也是 Android 系统中最重要的特性之一。Android 中的四大组件 Activity,Service,Broadcast,ContentProvider,不一样的 App 等都运行在不一样的进程中,它是这些进程间通信的桥梁。正如其名“粘合剂”同样,它把系统中各个组件粘合到了一块儿,是各个组件的桥梁。面试
理解 Binder 对于理解整个 Android 系统有着很是重要的做用,若是对 Binder 不了解,就很难对 Android 系统机制有更深刻的理解。缓存
有了服务端,客户端就能够跟服务端通信了,通信以前须要先获取到服务,拿到服务的代理,也能够理解为引用。好比下面的代码:安全
//获取WindowManager服务引用WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);
获取服务端的方式就是经过 ServiceManager 向 svcinfo 列表中查询一下返回服务端的代理,svcinfo 列表就是全部已注册服务的通信录,保存了全部注册的服务信息。网络
怎么样是否是很简单,以上就是 Binder 机制的主要通信方式,下面咱们来看看具体实现。架构
咱们先来了解下用户空间与内核空间是怎么交互的。ide
先了解一些概念函数
详细解释能够参考 Kernel Space Definition;简单理解以下:oop
Kernel space 是 Linux 内核的运行空间,User space 是用户程序的运行空间。为了安全,它们是隔离的,即便用户的程序崩溃了,内核也不受影响。学习
Kernel space 能够执行任意命令,调用系统的一切资源;User space 只能执行简单的运算,不能直接调用系统资源,必须经过系统接口(又称 system call),才能向内核发出指令。
虽然从逻辑上抽离出用户空间和内核空间;可是不可避免的的是,总有那么一些用户空间须要访问内核的资源;好比应用程序访问文件,网络是很常见的事情,怎么办呢?
Kernel space can be accessed by user processes only through the use of system calls.
用户空间访问内核空间的惟一方式就是系统调用;经过这个统一入口接口,全部的资源访问都是在内核的控制下执行,以避免致使对用户程序对系统资源的越权访问,从而保障了系统的安全和稳定。用户软件参差不齐,要是它们乱搞把系统玩坏了怎么办?所以对于某些特权操做必须交给安全可靠的内核来执行。
当一个任务(进程)执行系统调用而陷入内核代码中执行时,咱们就称进程处于内核运行态(或简称为内核态)此时处理器处于特权级最高的(0级)内核代码中执行。当进程在执行用户本身的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。处理器在特权等级高的时候才能执行那些特权CPU指令。
经过系统调用,用户空间能够访问内核空间,那么若是一个用户空间想与另一个用户空间进行通讯怎么办呢?很天然想到的是让操做系统内核添加支持;传统的 Linux 通讯机制,好比 Socket,管道等都是内核支持的;可是 Binder 并非 Linux 内核的一部分,它是怎么作到访问内核空间的呢?Linux 的动态可加载内核模块(Loadable Kernel Module,LKM)机制解决了这个问题;模块是具备独立功能的程序,它能够被单独编译,但不能独立运行。它在运行时被连接到内核做为内核的一部分在内核空间运行。这样,Android系统能够经过添加一个内核模块运行在内核空间,用户进程之间的经过这个模块做为桥梁,就能够完成通讯了。
在 Android 系统中,这个运行在内核空间的,负责各个用户进程经过 Binder 通讯的内核模块叫作 Binder 驱动;
驱动程序通常指的是设备驱动程序(Device Driver),是一种可使计算机和设备通讯的特殊程序。至关于硬件的接口,操做系统只有经过这个接口,才能控制硬件设备的工做;
驱动就是操做硬件的接口,为了支持 Binder 通讯过程,Binder 使用了一种“硬件”,所以这个模块被称之为驱动。
熟悉了上面这些概念,咱们再来看下上面的图,用户空间中 binder_open(), binder_mmap(), binder_ioctl() 这些方法经过 system call 来调用内核空间 Binder 驱动中的方法。内核空间与用户空间共享内存经过 copy_from_user(), copy_to_user() 内核方法来完成用户空间与内核空间内存的数据传输。Binder驱动中有一个全局的 binder_procs 链表保存了服务端的进程信息。
对于底层Binder驱动,经过 binder_procs 链表记录全部建立的 binder_proc 结构体,binder 驱动层的每个 binder_proc 结构体都与用户空间的一个用于 binder 通讯的进程一一对应,且每一个进程有且只有一个 ProcessState 对象,这是经过单例模式来保证的。在每一个进程中能够有不少个线程,每一个线程对应一个 IPCThreadState 对象,IPCThreadState 对象也是单例模式,即一个线程对应一个 IPCThreadState 对象,在 Binder 驱动层也有与之相对应的结构,那就是 Binder_thread 结构体。在 binder_proc 结构体中经过成员变量 rb_root threads,来记录当前进程内全部的 binder_thread。
Binder 线程池:每一个 Server 进程在启动时建立一个 binder 线程池,并向其中注册一个 Binder 线程;以后 Server 进程也能够向 binder 线程池注册新的线程,或者 Binder 驱动在探测到没有空闲 binder 线程时主动向 Server 进程注册新的的 binder 线程。对于一个 Server 进程有一个最大 Binder 线程数限制,默认为16个 binder 线程,例如 Android 的 system_server 进程就存在16个线程。对于全部 Client 端进程的 binder 请求都是交由 Server 端进程的 binder 线程来处理的。
了解了 Binder 驱动,怎么与 Binder 驱动进行通信呢?那就是经过 ServiceManager,好多文章称 ServiceManager 是 Binder 驱动的守护进程,大管家,其实 ServiceManager 的做用很简单就是提供了查询服务和注册服务的功能。下面咱们来看一下 ServiceManager 启动的过程。
好了,这里只是从实现逻辑上简单介绍了下 Binder 机制的工做原理,想要深刻理解 Binder 机制,还得本身下功夫,看源码,尽管这个过程很痛苦。一遍看不懂就再来一遍,说实话本人理解能力比较差,跟着博客思路看了不下十遍。努力总会有收获,好好欣赏 native 层各方法之间花式跳转的魅力吧。最后你将发现新世界的大门在向你敞开。
网上资料不少,我的以为比较好的以下:
Binder进程间通讯原理 视频详解 须要密码私聊我便可
连接: https://share.weiyun.com/5GOZsQF