【Android FrameWork】④进程通信相关

1,053 阅读8分钟

1. Android FrameWork用到了哪些IPC方式?

考察点

  • 看你是否了解Linux常用的跨进程通信方式
  • 是否研究过Android Framework并了解一些实现原理
  • 是否了解Framework各组件之间的通信原理

Linux IPC方式

  • 管道
    • 半双工的,单向的,要么读,要么写
    • 一般是在父子进程之间使用
    • 可以跨进程使用,也可以在进程内部使用
    • 如图74
      • fd1负责写 fd0负责读
    • 在安卓4.4的FrameWork代码中,looper用到了管道,looper的java层在native层对应了一个同名类,这个类的构造函数中就会创建一个管道
      • 如图75
  • Socket,这里的socket不是网络的socket,而是本地的socket
    • 全双工的,既可以读又可以写
    • 两个进程之间无需存在亲缘关系(不像管道父子关系那样)
    • 在安卓framework中,zygote使用到了socket
    • 如图76
  • 共享内存
    • 很快,不需要多次拷贝(socket和管道都需要至少两次的数据拷贝,数据传输量不能太大),拿到文件描述符后,把它同时映射到两个进程的内存空间,这样一个进程写数据,另外一个进程就能读到,所以很快
    • 进程之间无需存在亲缘关系
    • 在安卓FrameWork中,涉及到大数据量传输的主要是图像相关的,这里主要分析安卓的共享内存,以MemoryFile为例
      • 如图77
  • 信号
    • 单向的,发出去之后怎么处理是别人的事,自己并不知道
    • 只能带个信号,不能带别的参数
    • 知道进程pid就能发信号了,也可以一次给一群进程发信号(需要权限授权)
    • 在安卓FrameWork中,杀掉应用进程用的就是信号
      • 如图78
  • Binder,后续详解

2. 谈谈对Binder的理解

考察点

  • binder是干嘛的?->跨进程通信
  • binder存在的意义是什么?
  • binder的架构原理是怎样的?

binder是干嘛的 binder是用来通信的

  • binder分为两端,即Client端和Server端
  • Client端和Server端可以在一个进程,也可以不在一个进程
  • Clinet端可以向Server端发起远程的函数调用,也可以传输数据
    • 如图79,Client端要对Server端发起call函数的远程调用,需要先序列化参数到一个buffer中,然后通过linux各种跨进程通信方式将buffer传输到Server端,在Server端将buffer数据反序列化还原各个参数,然后调用call函数,之后将函数执行结果原路返回给Client端
    • 图79
  • 跨进程传输要保证性能好、方便、安全等特性,而binder机制就符合这些特性

binder存在的意义是什么?(为什么安卓选择binder作为最主要的IPC通信机制)

binder是跑在驱动层的,没有用到linux的跨进程通信技术,它是自己发明的一套机制

  • 性能:只需要拷贝一次
    • 由于管道,socket在跨进程通信的时候需要内核中转,这意味着两次数据拷贝,一次是从应用层拷贝到内核,另外一次是从内核拷贝到应用层,
    • binder是将一块物理内存同时映射到内核和目标进程的用户空间,这样只需要将数据拷贝到内核空间就可以了
  • 方便易用:逻辑简单直接,不易出问题
    • 共享内存虽然性能好,但是使用起来复杂,远不如binder好用
  • 安全
    • 普通的linux跨进程通信方式不够安全,如socket,IP地址都是开放的,容易被人恶意利用,主要是因为拿不到调用方可靠的身份信息
    • 可靠的方式是身份标记只能由IPC机制本身在内核态添加,这点binder做到了

binder的通信架构

  • 四方参与:Client端,Server端,ServiceManager,binder驱动
  • 注意:这个图展示的是系统服务的binder通信,只有系统服务才能注册到ServiceManager,应用服务的binder是不能注册到ServiceManager的(通过不了权限验证)
  • 这里Client是应用进程,Server 是系统服务,Server可能跑在system_sever进程,也可能是单独的进程
  • ServiceManager是单独的系统进程
  • 这里不论哪个进程,启动是都需要先启用binder机制,这是binder机制的前提
    • 如何启用binder机制
      • 打开binder驱动
      • 内存映射,分配缓冲区
      • 启动binder线程,进入loop循环,不断跟binder驱动进行交互,等待Client和Server的请求

ServiceManager
从ServiceManager入口函数main看起,如图81

  • Server启动时要把自己的binder对象注册到ServiceManager
  • 以SurfaceFlinger为例
    • 如图82

Binder通信分层架构

  • 三个角色:Client、Server、binder驱动
  • 分层角度看:应用层、FrameWork层(java层和native层)、驱动层
  • 从binder对象的角度看,分为两端:代理端,实体端
  • 从Client端看起:
    • 拿到一个binder的Proxy时,发起IPC调用,向下丢给BinderProxy,再向下丢给native层的proxy即BpBinder对象,bpBinder对象又会把请求转交给IPC Thread state,通过transact发送请求到binder驱动
    • 驱动转发,发到Server进程
    • Server进程的binder线程处理执行ontransact函数,再一层层向上传到应用层

3. 一次完整的IPC通信流程是怎样的?

考察点

  • 了解binder的整体架构原理(详见上题)
  • 了解应用和binder驱动的交互方式
  • 从client端开始binder调用到调用结束,整个流程是什么样的?
  • 了解IPC过程中的通信协议

如图84

协议通信过程

  • Client端向Server端发起IPC调用,首先向Binder驱动写了BC_TRANSACTION指令
  • Binder驱动收到之后,给Client端一个回执BR_TRANSACTION_COMPLETE
  • Binder驱动转发请求给Server端,通过BR_TRANSACTION指令
  • Server端收到之后,处理这个请求,处理完成后回会给Binder驱动BC_REPLAY
  • Binder驱动收到Server端的回复之后,会给Server一个回执BR_TRANSACTION_COMPLETE
  • 最后Binder驱动把Server端的返回结果转发给Client端,通过BR_REPLY
  • CLIENT端在等待回复过程中处于休眠状态
  • Server端binder线程在处理请求之外也是处于休眠状态

4. binder对象跨进程传递原理是怎么样的?

考察点

  • binder传递有哪些方式?
  • binder在传递过程中是怎么存储的?
  • binder对象序列化和反序列化过程?
  • binder对象传递过程中驱动层做了什么?

binder机制太过复杂,这里省略代码及贴图

总结

答题要点

  • Parcel的writeStrongBinder和readStrongBinder
  • binder在Parcel中存储原理,flat_binder_object
  • 说清楚binder_node, binder_ref
  • 目标进程根据binder_ref的handle创建BpBinder
  • 由BpBinder再往上到BinderProxy到业务层的Proxy

总结

  • binder通过Parcel跨进程传输,通过writeStrongBinder写到Parcel,目标进程通过readStrongBinder读取出来
  • binder在Parcel中通过flat_binder_object存储,flat_binder_object是在binder缓冲区存储,Parcel有一个数组,专门保存flat_binder_object的偏移,所以parcel到了目标进程之后就可以根据这个偏移还原出flat_binder_object
  • parcel传到binder驱动之后,驱动从parcel中取出flat_binder_object,根据里面的binder对象,创建一系列数据结构,包括为binder实体对象创建binder_node以及binder引用binder_ref,一个binder实体可能对应多个binder引用对象
  • binder_ref在目标进程会对应一个handle,handle向上传递会创建一个BpBinder,这是binder在FrameWork native层的对象
  • BpBinder再往上到BinderProxy,BinderProxy在往上就会封装一个业务层的Proxy对象

5.说一说binder的oneway机制

考察点

  • binder的oneway是什么意思?
  • oneway有哪些特性?
  • 它的实现原理是怎样的?

oneway的通信过程协议图

  • 由于是oneway的,所以对于client端来说,oneway是异步的,也不需要Server端的返回结果,所以整体流程看起来比非oneway的要简单
    • 图86
  • Client端向Server端发起IPC调用,首先向Binder驱动写了BC_TRANSACTION指令
  • Binder驱动收到之后,给Client端一个回执BR_TRANSACTION_COMPLETE
  • 然后Binder驱动转发请求给Server端,通过BR_TRANSACTION指令,Server端处理完成之后无需做其他事情

oneway在Framework中的应用 oneway在Framework中的应用场景比较多,主要适用于系统服务向应用端发起binder调用,这些接口基本都是oneway的,如图88

  • 以lanchActivity为例:系统服务向应用端发起调用,让应用端启动activity,注意这里的reply是null,并且带有FLAG_ONEWAY标志,所以这是一个典型的oneway
  • IWindow也是oneway的,WMS向应用端发起调用
  • IServiceConnection是binderService的时候应用端向AMS注册的一个binder对象,AMS拿到binder对象也可以向应用端发起binder调用
  • IIntentReceiver是应用端注册广播的时候把binder对象注册到AMS,AMS拿到binder对象向应用端发起调用

oneway用的比较多的原因有两点:

  • 一是oneway是异步的,所以即使应用端处理这些请求非常耗时也不会阻塞系统服务
  • 二是oneway是串行化的,驱动会一个一个地分发binder调用到应用端,而不是一股脑地全部丢给应用端

总结

  • oneway是异步binder调用(不需要等待返回结果,可以继续做下一件事)
  • server端串行化处理
  • oneway的实现机制