仅做个人学习记录
什么是IPC?
inter-process-communication 进程间通信(跨进程通信),两个进程间进行数据交互的过程。
什么是线程?什么是进程?两者的关系?
线程:是CUP调度的最小单元,同时是一种有限的系统资源。
进程:一般指一个执行单元,在PC或移动设备上表示为一个程序或者应用。
一个进程中可以包含过个线程,一个或多个线程系统的组成就是一个程序。
IPC是Android独有的吗?Linux有那些跨进程通信?
任何一个操作系统都需要一套IPC通信机制,比如windows的剪切板、管道...
linux的跨进程通信方式:
- 命名管道
- 消息队列
- 共享内存
- 套接字、信号量、信号
Android有哪些跨进程通信方式?
- Binder
- Bundle
- 文件共享
- AIDL
- Messenger
- ContentProvider
- Socket
Android是基于Linux内核开发的操作系统,为什么不采用Linux的IPC通信方式?
管道:缓存区容量有限,不适合Android大量的进程间通信需求。
消息队列:和命名管道一样每次数据快的容量有限制;消息复制两次(用户空间到内存,内存到用户空间),额外消耗cpu,不适合Android频繁的通信要求。
共享内存:共享内存就是允许两个不相关的进程访问同一个逻辑内存。 共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效 的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以 将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共 享内存中的地址。
无需复制,共享缓冲区,速度快。但是安全问题比较突出。
套接字:效率太低,主要用来跨网络通信。
信号量:常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
信号:不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死某个进程等;
Binder:Binder驱动会在
为何会选Binder:
- 传递性:Binder数据需要进行一次拷贝,而共享内存完全不需要进行数据拷贝。
- 稳定性:Binder采用CS的架构方式,Server端和Client端相对独立,稳定性好。共享内存需要充分考虑临界资源的访问问题,很容易出现死锁问题。
- 安全性:Android端会为每个已安装的应用程序分配一个UID,Binder只对外暴露Client端,Client端会将任务发送给Server端,Server端会根据权限控制策略对UID进行甄别是否满足访问权限。
- 其他原因:Linux是受GPL保护的。
传统的IPC只能由用户在数据包里填写ID;传统IPC接入点也是开放的,无法建立私有通道。
- 临界资源:多进程系统中,它们共享各种资源,然而有很多资源一次只能供一个进程使用。一次仅允许一个进程使用的资源称为临界资源。许多物理设备都属于临界资源,如输入机、打印机、磁带机等。
- GPL:是GNU General Public License的缩写。例如,如果你发布一个程序的副本,不管是收费的还是免费的,你必须将你具有的一切权利给予你的接受者;你必须保证他们能收到或得到源程序;并且将这些条款给他们看,使他们知道他们有这样的权利。
- Binder是基于开源的OpenBinder实现的。
传统的IPC就没有在Android中用到吗?
比如在 Android OS 中的 Zygote 进程的 IPC 采用的是 Socket(套 接字)机制,Android 中的 Kill Process 采用的 signa(l 信号)机制等等。而 Binder 更多则用在 system_server 进程与上层 App 层的 IPC 交互。
开发中有哪些多进程的情况?
- 需要加大一个应用的可使用内存,通过多进程获取多份内存。
- 需要将其他模块运行在独立进程当中,比如进程保活。
- 需要和其他应用通信,相互获取数据。
如何开启多进程模式?
- 给四大组件设置android.process属性
- 通过JNI在native层去孵化一个进程
<activity
android:name="com.ipc.app.page"/>
<activity
android:process=":test"
android:name="com.ipc.app.page1"/>
<activity
android:process="com.ipc.app.test"
android:name="com.ipc.app.page2" />
page会运行在默认的进程(com.ipc.app)当中;
page1会运行在com.ipc.app:test进程当中;
page2会运行在com.ipc.app.test进程当中;
page1和page2不是同一个进程。因为“:”表示,是要在当前进程名前添加当前包名,这是一种简写,并且以“:”开头的进程为当前应用的私有进程,其他应用的组件不可以和他跑在同一个进程当中。
反之不以“:”开头则为全局进程,其他应用通过ShareUID方式可以和他跑在同一个进程。
使用多进程会有哪些问题?
- 静态成员和单列模式失效
- 线程同步机制失效
- sharedPreferences可靠性变差
- application多次创建
解释:Android会为每个进程分配一个独立的虚拟机,不同的虚拟机就会有不同的地址控件,不同的虚拟机访问同一个对象就会产生不同的副本,并且互不干扰,这样就会出现第一种和第二种情况。SharedPreferences虽然是线程安全的,但是不支持多进程操作,可能会导致数据的丢失。开启一个新的进程,就是开启一个新的应用,当然会创建application。
Binder是什么?
- 从IPC的角度来说,它是Android中的一种跨进程通信的方式,Linux系统中没有这种通信方式。
- 从FrameWork角度来说,Binder是ServiceManager链接各种Manger(ActivityManger、WindowManger...)和相应MangerService的桥梁。
- 从Application层来说,Binder是客户端和服务端进行通信的媒介,bindService时候,服务端会返回一个带有服务端业务嗲用的Binder对象,通过这个Binder对象,客户端可以获取服务端提供的服务或者数据,这里的服务包含普通服务和基于AIDL的服务。
Binder的工作流程?
Binder通信有四个很重要的角色:
- Binder驱动:运行在内核控件,负责各个用户进程通过Binder实现通信的内核模块。
- ServiceManger
- BinderClient
- BinderServer
举个例子:
1.从上海回西安,需要把行李快递回家
2.忘了家里的详细地址,通过备忘录找到家里的地址
3.将行李放入蜂巢,快递会把行李从蜂巢运送到家
这样就完成了一次Binder通信,其中上海(BinderClient),西安的家(BinderServer)、备忘录(serviceManger)、蜂巢物流系统(Binder驱动)。
操作系统采用虚拟存储器,在逻辑上将虚拟空间分为内核空间和用户空间,为了保证安全安全性他们之间是隔离的。用户是不能直接操作内核的,但不可避免的用户空间需要访问内核(文件操作,网络访问),为了突破这层隔离就需要进行系统调用。
- 内核空间:系统内核运行的空间
- 用户空间:用户程序运行的空间
- 系统调用是用户访问内核的唯一途径,保证了内核资源的访问都是在内核的监控下完成的,防止了用户空间的越权访问,提升了系统的安全性和稳定性。
系统调用步骤:
1.将数据从用户空间拷贝到内核空间
2.将数据从内核空间拷贝到用户空间
- 消息发送方将消息放入自行开辟的内存缓存区中
- 通过系统调用进入内核运行态(内核态)
- 内核程序开辟一块内核缓存区,将数据从消息发送方的内存缓存区中拷贝过来。
- 内核程序处理完毕后,消息接收方从内核缓存区中将数据拷贝到自己的内存缓存区中。
传统通信存在的问题:
- 需要尽量两次数据拷贝,效率低下。
- 接收方并不知道数据有多大,会开辟很大的内存缓存区来进行数据接受;或者通过其他方式先获取数据大小,浪费时间。
Binder不是系统内核的一部分,如何完成进程通信?
Linux的动态内核可加载模块的机制。