一篇文章了解相见恨晚的 Android Binder 进程间通讯机制- https://blog.csdn.net/freekiteyu/article/details/70082302

-- 为什么 Android 要采用 Binder 作为 IPC 机制?https://www.zhihu.com/question/39440766/answer/89210950

AIDL中支持的数据类型有:Java基本类型,String,CharSequence, List, Map,其他AIDL定义的AIDL接口,实现Parcelable的类

  binder底层是共享内存方式。基于aidl远程服务本质上沿袭了分布式计算的原理。

-- Linux现有的所有进程间IPC方式:
 1. 管道:在创建时分配一个page大小的内存,缓存区大小比较有限;
 2. 消息队列:信息复制两次,额外的CPU消耗;不合适频繁或信息量大的通信;
 3. 共享内存:无须复制,共享缓冲区直接付附加到进程虚拟地址空间,速度快;但进程间的同步问题操作系统无法实现,必须各进程利用同步工具解决;
 4. 套接字:作为更通用的接口,传输效率低,主要用于不通机器或跨网络的通信;
 5. 信号量:常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
 6. 信号: 不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死某个进程等;

-- 从5个角度来展开对Binder的分析:
(1)从性能的角度 数据拷贝次数:Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次,但共享内存方式一次内存拷贝都不需要;从性能角度看,Binder性能仅次于共享内存。
(2)从稳定性的角度Binder是基于C/S架构的,简单解释下C/S架构,是指客户端(Client)和服务端(Server)组成的架构,Client端有什么需求,直接发送给Server端去完成,架构清晰明朗,Server端与Client端相对独立,稳定性较好;而共享内存实现方式复杂,没有客户与服务端之别, 需要充分考虑到访问临界资源的并发同步问题,否则可能会出现死锁等问题;从这稳定性角度看,Binder架构优越于共享内存。仅仅从以上两点,各有优劣,还不足以支撑google去采用binder的IPC机制,那么更重要的原因是:
(3)从安全的角度传统Linux IPC的接收方无法获得对方进程可靠的UID/PID,从而无法鉴别对方身份;而Android作为一个开放的开源体系,拥有非常多的开发平台,App来源甚广,因此手机的安全显得额外重要;对于普通用户,绝不希望从App商店下载偷窥隐射数据、后台造成手机耗电等等问题,传统Linux IPC无任何保护措施,完全由上层协议来确保。 Android为每个安装好的应用程序分配了自己的UID,故进程的UID是鉴别进程身份的重要标志,前面提到C/S架构,Android系统中对外只暴露Client端,Client端将任务发送给Server端,Server端会根据权限控制策略,判断UID/PID是否满足访问权限,目前权限控制很多时候是通过弹出权限询问对话框,让用户选择是否运行。Android 6.0,也称为Android M,在6.0之前的系统是在App第一次安装时,会将整个App所涉及的所有权限一次询问,只要留意看会发现很多App根本用不上通信录和短信,但在这一次性权限权限时会包含进去,让用户拒绝不得,因为拒绝后App无法正常使用,而一旦授权后,应用便可以胡作非为。
 (4)从语言层面的角度大家多知道Linux是基于C语言(面向过程的语言),而Android是基于Java语言(面向对象的语句),而对于Binder恰恰也符合面向对象的思想,将进程间通信转化为通过对某个Binder对象的引用调用该对象的方法,而其独特之处在于Binder对象是一个可以跨进程引用的对象,它的实体位于一个进程中,而它的引用却遍布于系统的各个进程之中。可以从一个进程传给其它进程,让大家都能访问同一Server,就像将一个对象或引用赋值给另一个引用一样。Binder模糊了进程边界,淡化了进程间通信过程,整个系统仿佛运行于同一个面向对象的程序之中。从语言层面,Binder更适合基于面向对象语言的Android系统,对于Linux系统可能会有点“水土不服”。
  Android OS中的Zygote进程的IPC采用的是Socket(套接字)机制,Android中的Kill Process采用的signal(信号)机制等等。而Binder更多则用在system_server进程与上层App层的IPC交互。
  (5) 从公司战略的角度总所周知,Linux内核是开源的系统,所开放源代码许可协议GPL保护,该协议具有“病毒式感染”的能力,怎么理解这句话呢?受GPL保护的Linux Kernel是运行在内核空间,对于上层的任何类库、服务、应用等运行在用户空间,一旦进行SysCall(系统调用),调用到底层Kernel,那么也必须遵循GPL协议。
  而Android 之父 Andy Rubin对于GPL显然是不能接受的,为此,Google巧妙地将GPL协议控制在内核空间,将用户空间的协议采用Apache-2.0协议(允许基于Android的开发商不向社区反馈源码),同时在GPL协议与Apache-2.0之间的Lib库中采用BSD证授权方法,有效隔断了GPL的传染性,仍有较大争议,但至少目前缓解Android,让GPL止步于内核空间,这是Google在GPL Linux下 开源与商业化共存的一个成功典范。

-- 通过Binder传递的对象有两种,Parcel和 IBinder。
  Binder Server 的实现是线程池的方式,而不是单线程队列的方式,区别在于,单线程队列的话,Server 的代码是线程安全的,线程池的话,Server 的代码则不是线程安全的,需要开发者自己做好多线程同步。
  Binder IPC 属于 C/S 架构,包括 Client、Driver、Server 三个部分;
  Client 可以手动调用 Driver 的 transact 接口,也可以通过 AIDL 生成的 Proxy 调用;
  Server 中会启动一个「线程池」来处理 Client 的调用请求,处理完成后将结果返回给 Driver,Driver 再返回给 Client。
 -- ContentProvider 中的 CRUD 是否是线程安全的?又例如在使用 AIDL 的时候,在 Service 中实现的接口是否是线程安全的?
  这里就回答了开篇提问的两个问题:Service 中通过 AIDL 提供的接口并不是线程安全的,同理 ContentProvider 底层也是使用 Binder,同样不是线程安全的,至于是否需要做多线程保护,看业务而定,最好是做好多线程同步,以防万一。

> Android中mmap原理及应用简析-  https://juejin.im/post/5cd239116fb9a0321d73c127
 mmap是Linux中常用的系统调用API,用途广泛,Android中也有不少地方用到,比如匿名共享内存,Binder机制等。
 mmap属于系统调用,用户控件间接通过swi指令触发软中断,进入内核态(各种环境的切换),进入内核态之后,便可以调用内核函数进行处理。 mmap->mmap64->__mmap2->sys_mmap2-> sys_mmap_pgoff ->do_mmap_pgoff.
 Binder机制中mmap的最大特点是一次拷贝即可完成进程间通信。Android应用在进程启动之初会创建一个单例的ProcessState对象,其构造函数执行时会同时完成binder mmap,为进程分配一块内存,专门用于Binder通信。
 Linux的内存分用户空间跟内核空间,同时页表有也分两类,用户空间页表跟内核空间页表,每个进程有一个用户空间页表,但是系统只有一个内核空间页表。而Binder mmap的关键是:也更新用户空间对应的页表的同时也同步映射内核页表,让两个页表都指向同一块地址,这样一来,数据只需要从A进程的用户空间,直接拷贝拷贝到B所对应的内核空间,而B多对应的内核空间在B进程的用户空间也有相应的映射,这样就无需从内核拷贝到用户空间了。
  binder一次拷贝的关键是,完成内存的时候,同时完成了内核空间跟用户空间的映射,也就是说,同一份物理内存,既可以在用户空间,用虚拟地址访问,也可以在内核空间用虚拟地址访问。

  普通文件的访问方式有两种:第一种是通过read/write系统调访问,先在用户空间分配一段buffer,然后,进入内核,将内容从磁盘读取到内核缓冲,最后,拷贝到用户进程空间,至少牵扯到两次数据拷贝;同时,多个进程同时访问一个文件,每个进程都有一个副本,存在资源浪费的问题。

- 普通文件mmap原理
普通文件的访问方式有两种:
  第一种是通过read/write系统调访问,先在用户空间分配一段buffer,然后,进入内核,将内容从磁盘读取到内核缓冲,最后,拷贝到用户进程空间,至少牵扯到两次数据拷贝;同时,多个进程同时访问一个文件,每个进程都有一个副本,存在资源浪费的问题。
  另一种是通过mmap来访问文件,mmap()将文件直接映射到用户空间,文件在mmap的时候,内存并未真正分配,只有在第一次读取/写入的时候才会触发,这个时候,会引发缺页中断,在处理缺页中断的时候,完成内存也分配,同时也完成文件数据的拷贝。并且,修改用户空间对应的页表,完成到物理内存到用户空间的映射,这种方式只存在一次数据拷贝,效率更高。同时多进程间通过mmap共享文件数据的时候,仅需要一块物理内存就够了。

- 共享内存中mmap的使用
共享内存是在普通文件mmap的基础上实现的,其实就是基于tmpfs文件系统的普通mmap。

--  Android Linux进程间通讯:
 1.Linux的虚拟内存机制导致内存的隔离,进而导致进程隔离
 2.进程隔离的出现导致对内存的操作被划分为用户空间和内核空间
 3.用户空间需要跨权限去访问内核空间,必须使用系统调用去实现
 4.系统调用需要借助内核模块/驱动去完成
前三步决定了进程间通讯需要借助内核模块/驱动去实现,而Binder驱动就是内核模块/驱动中用来实现进程间通讯的

Linux提供有管道、消息队列、信号量、内存共享、套接字等跨进程方式.

-- Binder对象和Binder驱动
 Binder对象:Binder机制中进行进程间通讯的对象,对于Service端为Binder本地对象,对于Client端为Binder代理对象;
 Binder驱动:Binder机制中进行进程间通讯的介质,Binder驱动会对具有跨进程传递能力的对象做特殊处理,自动完成代理对象和本地对象的转换。
 由于Binder驱动会对具有跨进程传递能力的对象做特殊处理,自动完成代理对象和本地对象的转换,因此在驱动中保存了每一个跨越进程的Binder对象的相关信息,Binder本地对象(或Binder实体)保存在binder_node的数据结构,Binder代理对象(或Binder引用/句柄)保存在binder_ref的数据结构
 BinderProxy的transact方法是native方法,它的实现在native层,它会去借助Binder驱动完成数据的传输,当完成数据传输后,会唤醒Server端,调用了Server端本地对象的onTransact函数。

- Android中要实现IPC,有好多种方式:
1.在Intent中附加extras来传递信息。

2.共享文件。

3.SharedPreferences(不建议在进程间通信中使用,因为在多进程模式下,系统对SharedPreferences的读/写会变得不可靠,面对高并发的读/写访问,有很大几率会丢失数据)。

4.基于Binder的AIDL。

5.基于Binder的Messenger(翻译为“信使”,其实Messenger本质上也是AIDL,只不过系统做了封装以方便上层调用)。
6.Socket。

7.天生支持跨进程访问的ContentProvider。

-- Binder线程池,Android Binder 连接池;  AIDL demo
Binder线程池的主要作用就是将每个业务模块的Binder请求统一转发到远程Servie中去执行,从而避免了重复创建Service的过程。
https://github.com/breezehan/AndroidKnowledgeSummary/blob/master/ipc/src/main/java/com/breezehan/ipc/binderpool/BinderPool.java
Binder线程池- https://blog.csdn.net/hds2011/article/details/77428640

-- Binder IPC原理

-- Binder架构

-- Android Binder IPC(进程间通信)的过程


 

更多相关文章

  1. Android日期空间(DatePickerDialog)中的年月日不全部显示
  2. Android中的Logcat方法查看内核的日志
  3. 谷歌Android篡改Linux内核的真相
  4. Android(安卓)IPC 通讯机制源码分析
  5. Android(安卓)AIDL 实现两个APP之间的跨进程通信实例
  6. Android系统开发小问题-启动过程中android字符没有显示出来 .
  7. 从NDK在非Root手机上的调试原理探讨Android的安全机制
  8. android笔记 AIDL 实现进程间通信
  9. Dalvik虚拟机是如何执行程序的

随机推荐

  1. Android中图片占用内存的计算
  2. Android 事件分发机制
  3. android中的sqlite数据库加密
  4. android source code online
  5. 在Android中使用Handler和Thread线程执行
  6. Android ImageView 总结【转载】
  7. Android ImageView图片显示点击背景切换
  8. android退出应用程序解决方案
  9. xmlns:android的作用
  10. Android定时器实现的几种方法