请选择 进入手机版 | 继续访问电脑版

进程间通信(IPC) 相关

[复制链接]
为你演绎 发表于 2021-1-1 18:31:35 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
通过引入相关问题来举行纪录思考:
1.简述 IPC?

  IPC 就是指进程之间的通信机制,在 Android 系统中启动 Activity/Service 等都涉及跨进程调用的过程。
2.Android中的IPC 方式有哪些:

  Bundle,文件共享,Messenger,AIDL,ContentProvider,Socket等
3.如何开启Android中的多进程:

  

  • (通例)在AndroidMenifest中给四大组件指定属性android:process。
  • (不通例)通过JNI在native层fork一个新的进程。
进程名的默认规则:
  默认进程:
  

  • 没有指定该属性则运行在默认进程,其进程名就是包名。
以“:”开头的进程:
  

  • 省略包名,如android:process=":remote",表现进程名为com.example.myapplication:remote。
  • 属于当前应用的私有进程,其他进程的组件不能跟它跑在同一进程中。
完整定名的进程:
  

  • 如android:process="com.example.myapplication.remote"。
  • 属于全局进程,其他应用可以通过**ShareUID**方式和它跑在用一个进程中。
  • UID: Android系统会为每个应用分配一个唯一的UID,具有相同的UID才气共享数据。
    两个应用通过ShareUID跑在同一个进程中的条件:具有相同的ShareUID和签名。
  • 满意上述条件的两个应用,无论是否跑在同一进程,它们可共享data目次,组件信息。
  • 若跑在同一进程,它们除了可共享data目次、组件信息,还可共享内存数据。它们就像是一个应用的两个部门。
4.多进程的运行机制会导致哪些问题?

  Android为每一个进程分配了一个独立的虚拟机,不同虚拟机在内存分配上有不同的地址空间,这也导致了不同虚拟机中访问同一个对象会产生多份副本。
  一般来说使用多进程会带来以下四个方面的问题:
  

  • 静态变量和单例模式失效 原因:不同虚拟机没有存储在同一个空间上;
  • 线程同步机制失效 原因:线程处于不同的进程,无法同步
  • SharedPreference的可靠性下降 原因:底层是通过读写XML文件实现的,发生并发问题。
  • Application多次创建- 原因:Android系统会为新的进程分配独立虚拟机,相当于应用重新启动了一次。
 5.为什么要设计 Binder?

  在Linux中,进程通信的方式肯定不止Binder这一种,另有以下这些:
  管道(Pipe)
信号(Signal)
消息队列(Message)
共享内存(Share Memory)
套接字(Socket)
  Binder在这之后主要有以下优点:
效率上 :Socket 作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。消息队列和管道采取存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到吸收方缓存区,至少有两次拷贝过程。共享内存虽然无需拷贝,但控制复杂,难以使用。Binder 只需要一次数据拷贝,性能上仅次于共享内存。
稳定性:Binder 基于 C|S 架构,客户端(Client)有什么需求就丢给服务端(Server)去完成,架构清晰、职责明确又相互独立,稳定性好。共享内存虽然无需拷贝,但是控制负责,难以使用。从稳定性的角度讲,Binder 机制是优于内存共享的。
安全性:Binder 通过在内核层为客户端添加身份标志 UID|PID,来作为身份校验的标志,保障了通信的安全性。 传统 IPC 访问接入点是开放的,无法创建私有通道。比如,定名管道的名称,SystemV 的键值,Socket 的 ip 地址或文件名都是开放的,只要知道这些接入点的步调都可以和对端创建连接,无法阻止恶意步调通过推测吸收方地址得到连接。
  注:熟悉Zygote的朋侪大概知道,在fork()进程的时候,也就是向Zygote进程发出创建进程的消息的时候,用到的进程间通信方式就不是Binder了,而换成了Socket,这主要是因为fork不允许存在多线程,Binder通讯偏偏就是多线程。
6.Binder通信过程和原理

  

  首先要明确的是客户端进程是无法直接利用服务端中的类和方法的,因为不同进程之间是不共享资源的。所以客户端这边利用的只是服务端进程的一个署理对象,也就是一个服务端的类引用,也就是Binder引用。
  总体通信流程就是:
  

  • 客户端通过署理对象向服务器发送请求。
  • 署理对象通过Binder驱动发送到服务器进程
  • 服务器进程处置惩罚请求,并通过Binder驱动返回处置惩罚效果给署理对象
  • 署理对象将效果返回给客户端。
再看看在我们应用中常常用到的工作模子,上图:
  

  这就是在应用层面我们常用的工作模子,通过ServiceManager去获取各种系统进程服务。这里的通信过程如下:
  

  • 服务端跨进程的类都要继承Binder类,所以也就是服务端对应的Binder实体。这个类并不是实际真实的远程Binder对象,而是一个Binder引用(即服务端的类引用),会在Binder驱动里还要做一次映射。
  • 客户端要调用远程对象函数时,只需把数据写入到Parcel,在调用所持有的Binder引用的transact()函数
  • transact函数执行过程中会把参数、标识符(标志远程对象及其函数)等数据放入到Client的共享内存,Binder驱动从Client的共享内存中读取数据,根据这些数据找到对应的远程进程的共享内存。
  • 然后把数据拷贝到远程进程的共享内存中,并通知远程进程执行onTransact()函数,这个函数也是属于Binder类。
  • 远程进程Binder对象执行完成后,将得到的写入自己的共享内存中,Binder驱动再将远程进程的共享内存数据拷贝到客户端的共享内存,并叫醒客户端线程。
所以通信过程中比力重要的就是这个服务端的Binder引用,通过它来找到服务端并与之完成通信。
  看到这里大概有的人疑惑了,图中线程池怎么没用到啊?
  

  • 可以从第一张图中看出,Binder线程池位于服务端,它的主要作用就是将每个业务模块的Binder请求统一转发到远程Servie中去执行,从而制止了重复创建Service的过程。也就是服务端只有一个,但是可以处置惩罚多个不同客户端的Binder请求。
7.说下你对进程与线程的明确

  一个进程就是一个执行单位,在 Android 中,一个应用默认只有一个进程,每个进程都有自己独立的资源和内存空间,别的进程不能任意访问当前进程的内存和资源,系统给每个进程分配的内存会有限制。实现的方式很简单就是在 Manifest 中注册 Activity 等的时候,使用 process 属性指定一个进程即可。process 分私有进程和全局进程,以 : 号开头的属于私有进程,其他应用组件不可以和他跑在同一个进程中;不以 : 号开头的属于全局进程,其他应用可以通过 ShareUID 的方式和他跑在同一个进程中
  Android 系统启动的时候会先启动 Zygote 进程,当我们需要创建应用步调进程的时候的会通过 Socket 与之通信,Zygote 通过 fork 自身来创建我们的应用步调的进程。
  线程是 CPU 调理的最小单位,一个进程可包罗多个线程。Java 线程的实现是基于一对一的线程模子,即通过语言级别层面步调去间接调用系统的内核线程。内核线程由利用系统内核支持,由利用系统内核来完成线程切换,内核通过利用调理器进而对线程执行调理,并将线程的任务映射到各个处置惩罚器上。由于我们编写的多线程步调属于语言层面的,步调一般不会直接去调用内核线程,取而代之的是一种轻量级的进程(Light Weight Process),也是通常意义上的线程。由于每个轻量级进程都会映射到一个内核线程,因此我们可以通过轻量级进程调用内核线程,进而由利用系统内核将任务映射到各个处置惩罚器。这种轻量级进程与内核线程间1对1的关系就称为一对一的线程模子。

 

来源:https://blog.csdn.net/jb_home/article/details/111954036
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )