ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Android 跨进程通信方式

Android 跨进程通信方式 管道半双工通信单向的一个进程发送另一个进程接收通常在父子进程、兄弟进程间通信socket 通信由网络 socket 发展而来 不需要经过网络协议栈打包和拆包。 只需要将应用层数据从一个进程拷贝到另一个进程消息队列消息队列是一个消息的链表具备异步能力同时克服了拥有同样能力的信号承载信息量少的问题具有数据传输能力克服了管道缓冲区大小受限1页 4kb的问题 有 16kb总容量单词 8KB应用Android 线程通信使用的就是 消息队列共享内存将一块物理地址映射到多个进程的用户地址空间 但是会有安全问题多线程通信时需要对 共享区域加锁例如信号量信号标记事件的整型数据异步通信机制通知接收进程某个事件的发生。通过注册响应函数完成对事件的处理应用 程序出现ANR问题就会发送 SIGNALQUIT 信号可以 使用 sigaction 函数 注册该信号的响应以监听 ANR信号量信号量实际上可以看成是一个计数器用来控制多个进程对共享资源的访问。主要作为进程间以及同一进程内不同线程之间的同步手段信号量会有初值0每当有进程申请使用信号量通过一个P操作来对信号量进行-1操作当计数器减到0的时候就说明没有资源了其他进程要想访问就必须等待当该进程执行完这段工作我们称之为临界区之后就会执行V操作来对信号量进行1操作。为什么Android选择Binder作为应用程序中主要的IPC机制Binder基于C/S架构进行跨进程通信数据拷贝只需要一次而管道、消息队列、Socket都需要2次共享内存方式一次内存拷贝都不需要从性能角度看Binder性能虽然比管道等方式好但是不如共享内存。但是传统Linux IPC的接收方无法获得对方进程可靠的UID/PID (权限校验、安全管控)只能由使用者在传递的数据包里填入UID/PID伪造身份非常简单而Binder不同可靠的身份标记只有由IPC机制本身在内核中添加binder就是这么做的不由用户应用程序控制直接在内核向数据中添加了进程身份标记。因此综合考虑Binder更加适合system_server进程与上层App层的IPC交互。PIDProcess ID进程 ID内核用来标识一个进程。UIDUser IDAndroid 重点代表应用身份标识Binder 是一种跨进程通信的方式传统的跨进程通信需要数据拷贝两次也就是 从 用户空间 复制到内核空间的内核缓存区然后再将数据复制到另一个进程的用户空间Binder 机制 使用了内存映射只需要数据拷贝1次具体原理Binder驱动在内核空间创建了一块 接收缓存区将发送进程的内核缓存区 和 接收进程的用户空间地址 同时映射在同一个共享接收缓存中同一个物理内存。发送进程将数据发送到内核缓存区数据拷贝一次由于 内核缓存区 与 接收进程的用户空间地址存在映射因此相当于发送到了接收进程的用户空间地址。所以一次通信只需要数据拷贝一次具体流程角色模型Binder 跨进程通信机制基于 Client - Server 模式Client 进程 表示使用服务 的进程Server 进程 是 提供服务的进程ServiceManager 管理 Service 的注册 和 查询 。类似于路由器Binder 驱动是 连接 Service 进程、Client 进程 和 ServiceManager 的桥梁 通过内存映射 传递进程间的数据具体流程步骤一首先服务端 向 ServiceManager 注册服务Server 进程 创建Binder对象继承 IBinder实现具体的业务逻辑Server 进程 通过 Binder 驱动向 ServiceManager.addService() 发起服务注册请求将 Binder对象 和 服务名称绑定步骤二客户端从ServiceManager获取服务代理Proxy客户端 通过Binder 驱动向 ServiceManager传递 服务名称如 “android.app.ActivityManager” getServicde() 发起查询ServiceManager 在注册表查找对应服务并通过Binder驱动向客户端返回一个Binder引用内核分配的句柄客户端将该引用封装为Proxy对象 后续通过Proxy调用服务端方法步骤三客户端通过 Proxy 调用服务端方法客户端调用 Proxy 的方法如startActivity()Proxy 将参数打包为 Parcel 对象Proxy 通过transact()方法向 Binder 驱动发送请求传入目标服务的句柄、方法编号、Parcel 数据Binder 驱动通过句柄找到对应的服务端进程将 Parcel 数据从客户端用户空间拷贝到内核空间内核唤醒服务端进程将数据从内核空间映射到服务端用户空间服务端的 Binder 对象接收数据解析后调用实际方法如 AMS 的startActivity()服务端将返回结果打包为 Parcel通过 Binder 驱动回传客户端客户端 Proxy 解析 Parcel获取返回结果。Binder 架构中ServiceManager、客户端和服务端都运行在用户空间Binder 驱动运行在 Linux 内核空间负责进程间通信。Binder默认采用同步通信方式如果 AIDL 方法声明 oneway则变成异步调用。Binder 驱动会为每个进程维护事务缓冲区大小约为 1MB一次事务的数据需要写入接收方的 Binder 缓冲区因此受到该限制。多个未处理事务会共享该空间其中 oneway 异步事务最多占用约一半。由于这个限制Intent、Bundle、AIDL 参数等不能传递过大的数据。 这块区域就是 接收方用户空间 和 内核缓冲区 映射的大小。Binder 相比于 其他 跨进程通信机制优势性能更好只需要拷贝一次方便易用逻辑更加简单直接安全Binder将进程的 UID/PID 与通信对象绑定接收方可以直接验证发送方身份防止恶意进程伪装系统服务如 AMS参考12
返回列表