共计 7289 个字符,预计需要花费 19 分钟才能阅读完成。
「Android」Binder 机制入门学习笔记
Binder 是什么
- Binder 是一种过程通信机制
- Binder 是一个虚构物理设施驱动
- Binder 是一个可能发动通信的类
为什么须要多过程
- 晋升稳定性
每个过程相互独立,子过程解体不会影响主过程的稳定性(微信小程序、插件化插件 …) - 冲破内存限度
虚拟机对每个过程限度了内存大小,让某些组件运行在独立过程中,能够升高 OOM 的产生概率,也能够升高被零碎杀死的概率(加载图片…) - 业务须要
某些通信或服务过程须要保活,插件化接入插件开发须要(音讯推送过程 …)
为什么应用 Binder
Linux 现有 IPC 机制
在学习 Binder 机制前,先简略说说 Linux 现有的所有过程间 IPC 机制:
- 管道:在创立时调配一个 page 大小的内存,缓存区大小比拟无限
- 音讯队列:信息复制两次,额定的 CPU 耗费;不适合频繁或信息量大的通信
- 共享内存:毋庸复制,共享缓冲区间接付附加到过程虚拟地址空间,速度快;但过程间的同步问题操作系统无奈实现,必须各过程利用同步工具解决
- 套接字:作为更通用的接口,传输效率低,次要用于不通机器或跨网络的通信
- 信号量:常作为一种锁机制,避免某过程正在访问共享资源时,其余过程也拜访该资源。因而,次要作为过程间以及同一过程内不同线程之间的同步伎俩
- 信号:不适用于信息替换,更实用于过程中断管制,比方非法内存拜访,杀死某个过程等
比照
- 从性能的角度 数据拷贝次数:Binder 数据拷贝只须要一次,而管道、音讯队列、Socket 都须要 2 次,但共享内存形式一次内存拷贝都不须要。从 性能角度 看,Binder 性能仅次于共享内存。
- 从稳定性的角度 Binder 是基于 C / S 架构的,Client 端有什么需要,间接发送给 Server 端去实现,架构清晰清朗,Server 端与 Client 端绝对独立,稳定性较好;而共享内存实现形式简单,没有客户与服务端之别,须要充分考虑到拜访临界资源的并发同步问题,否则可能会呈现死锁等问题。从 稳定性角度 看,Binder 架构优于共享内存。
- 传统 Linux IPC 的接管方无奈取得对方过程牢靠的 UID/PID,从而无奈甄别对方身份,平安保护措施齐全由下层协定来确保;Android 为每个装置好的应用程序调配了本人的 UID,故过程的 UID 是甄别过程身份的重要标记,后面提到 C / S 架构,Android 零碎中对外只裸露 Client 端,Client 端将工作发送给 Server 端,Server 端会依据权限控制策略,判断 UID/PID 是否满足拜访权限。从 安全性角度 看,Binder 架构优于传统 IPC。
- Linux 是基于 C 语言(面向过程),而 Android 是基于 Java 语言(面向对象),而对于 Binder 恰好也合乎面向对象的思维,将过程间通信转化为通过对某个 Binder 对象的援用调用该对象的办法,而其独特之处在于 Binder 对象是一个能够跨过程援用的对象,它的实体位于一个过程中,而它的援用却遍布于零碎的各个过程之中。能够从一个过程传给其它过程,让大家都能拜访同一 Server,就像将一个对象或援用赋值给另一个援用一样。Binder 含糊了过程边界,淡化了过程间通信过程,整个零碎好像运行于同一个面向对象的程序之中。从 语言层面的角度 看,Binder 更适宜基于面向对象语言的 Android 零碎,对于 Linux 零碎可能会有点“水土不服”。
Binder | 共享内存 | Socket | |
---|---|---|---|
性能 | 拷贝一次 | 无需拷贝 | 拷贝两次 |
特点 | 基于 C / S 架构,易用性高 | 管制简单,易用性差 | 基于 C / S 架构,通用接口,传输效率低、开销大 |
平安 | 每个 App 调配 UID,同时反对实名和匿名 | 依赖下层协定,拜访接入点是凋谢的 | 依赖下层协定,拜访接入点是凋谢的 |
Binder 原理
Binder 通信采纳 C / S 架构,从组件视角来说,蕴含 Client、Server、ServiceManager 以及 binder 驱动,其中 ServiceManager 用于管理系统中的各种服务。如下图所示。
无论是注册服务和获取服务的过程都须要 ServiceManager,须要留神的是此处的 Service Manager 是指 Native 层的 ServiceManager(C++),并非指 framework 层的 ServiceManager(Java)。ServiceManager 是整个 Binder 通信机制的大管家,是 Android 过程间通信机制 Binder 的守护过程。当 Service Manager 启动之后,Client 端和 Server 端通信时都须要先获取 Service Manager 接口,能力开始通信服务。
图中 Client/Server/ServiceManage 之间的互相通信都是基于 Binder 机制。既然基于 Binder 机制通信,那么同样也是 C / S 架构,则图中的 3 大步骤都有相应的 Client 端与 Server 端。
- 注册服务(addService):Server 过程要先注册 Service 到 ServiceManager。该过程:Server 是客户端,ServiceManager 是服务端。
- 获取服务(getService):Client 过程应用某个 Service 前,须先向 ServiceManager 中获取相应的 Service。该过程:Client 是客户端,ServiceManager 是服务端。
- 应用服务:Client 依据失去的 Service 信息建设与 Service 所在的 Server 过程通信的通路,而后就能够间接与 Service 交互。该过程:client 是客户端,server 是服务端。
图中的 Client,Server,Service Manager 之间交互都是虚线示意,是因为它们彼此之间不是间接交互的,而是都通过与 Binder 驱动进行交互的,从而实现 IPC 通信形式。其中 Binder 驱动位于内核空间,Client,Server,Service Manager 位于用户空间。Binder 驱动和 Service Manager 能够看做是 Android 平台的基础架构,而 Client 和 Server 是 Android 的应用层,开发人员只需自定义实现 Client、Server 端,借助 Android 的基本平台架构便能够间接进行 IPC 通信。
Binder 的利用:AIDL
AIDL = Android Interface Definition Language,次要目标是简化调用 Binder 的流程。
在 Android 中应用 AIDL 须要首先编写 xxx.aidl 文件,而后 Android Studio 会依据该.aidl 文件主动生成 xxx.java 文件
-
手动编写:xxx.aidl
package com.example.serverdemo; interface IDemoAidlInterface {void functionA(int arg); void functionB(String arg); }
-
主动生成:xxx.java
/* * This file is auto-generated. DO NOT MODIFY. */ package com.example.serverdemo; public interface IDemoAidlInterface extends android.os.IInterface {public void functionA(int arg) throws android.os.RemoteException; public void functionB(java.lang.String arg) throws android.os.RemoteException; /** * Default implementation for IDemoAidlInterface. */ public static class Default implements com.example.serverdemo.IDemoAidlInterface { @Override public void functionA(int arg) throws android.os.RemoteException { } @Override public void functionB(java.lang.String arg) throws android.os.RemoteException { } @Override public android.os.IBinder asBinder() {return null;} } /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.serverdemo.IDemoAidlInterface {static final int TRANSACTION_functionA = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_functionB = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); private static final java.lang.String DESCRIPTOR = "com.example.serverdemo.IDemoAidlInterface"; /** * Construct the stub at attach it to the interface. */ public Stub() {this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.serverdemo.IDemoAidlInterface interface, * generating a proxy if needed. */ public static com.example.serverdemo.IDemoAidlInterface asInterface(android.os.IBinder obj) {if ((obj == null)) {return null;} android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.example.serverdemo.IDemoAidlInterface))) {return ((com.example.serverdemo.IDemoAidlInterface) iin); } return new com.example.serverdemo.IDemoAidlInterface.Stub.Proxy(obj); } public static boolean setDefaultImpl(com.example.serverdemo.IDemoAidlInterface impl) { // Only one user of this interface can use this function // at a time. This is a heuristic to detect if two different // users in the same process use this function. if (Stub.Proxy.sDefaultImpl != null) {throw new IllegalStateException("setDefaultImpl() called twice"); } if (impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static com.example.serverdemo.IDemoAidlInterface getDefaultImpl() {return Stub.Proxy.sDefaultImpl;} @Override public android.os.IBinder asBinder() {return this;} @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: {reply.writeString(descriptor); return true; } case TRANSACTION_functionA: {data.enforceInterface(descriptor); int _arg0; _arg0 = data.readInt(); this.functionA(_arg0); reply.writeNoException(); return true; } case TRANSACTION_functionB: {data.enforceInterface(descriptor); java.lang.String _arg0; _arg0 = data.readString(); this.functionB(_arg0); reply.writeNoException(); return true; } default: {return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements com.example.serverdemo.IDemoAidlInterface { public static com.example.serverdemo.IDemoAidlInterface sDefaultImpl; private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) {mRemote = remote;} @Override public android.os.IBinder asBinder() {return mRemote;} public java.lang.String getInterfaceDescriptor() {return DESCRIPTOR;} @Override public void functionA(int arg) throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try {_data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(arg); boolean _status = mRemote.transact(Stub.TRANSACTION_functionA, _data, _reply, 0); if (!_status && getDefaultImpl() != null) {getDefaultImpl().functionA(arg); return; } _reply.readException();} finally {_reply.recycle(); _data.recycle();} } @Override public void functionB(java.lang.String arg) throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try {_data.writeInterfaceToken(DESCRIPTOR); _data.writeString(arg); boolean _status = mRemote.transact(Stub.TRANSACTION_functionB, _data, _reply, 0); if (!_status && getDefaultImpl() != null) {getDefaultImpl().functionB(arg); return; } _reply.readException();} finally {_reply.recycle(); _data.recycle();} } } } }
通过 Binder 进行过程通信的要害,在于主动生成的 xxx.java 文件,而非 xxx.aidl 文件,后者只是为了简化开发者编写生成前者的操作。
在文件编写生成实现后,在 Android 中应用 AIDL 进行近程调用的要害动作为以下三个:
- client 端绑定 server 端服务
- client 端获取 server 端 IBinder 对象
- client 端近程调用 server 端接口
client 端绑定 server 端服务
client 端获取 server 端 IBinder 对象
com.example.serverdemo.IDemoAidlInterface.Stub#asInterface
如果客户端与服务端处于 同过程:
return ((com.example.serverdemo.IDemoAidlInterface) iin);
如果客户端与服务端处于 异过程:
return new com.example.serverdemo.IDemoAidlInterface.Stub.Proxy(obj);
client 端近程调用 server 端接口
参考与举荐
http://gityuan.com/2015/10/31…