「Android」Binder机制入门学习笔记

Binder是什么

  • Binder是一种过程通信机制
  • Binder是一个虚构物理设施驱动
  • Binder是一个可能发动通信的类

为什么须要多过程

  • 晋升稳定性
    每个过程相互独立,子过程解体不会影响主过程的稳定性(微信小程序、插件化插件...)
  • 冲破内存限度
    虚拟机对每个过程限度了内存大小,让某些组件运行在独立过程中,能够升高OOM的产生概率,也能够升高被零碎杀死的概率(加载图片…)
  • 业务须要
    某些通信或服务过程须要保活,插件化接入插件开发须要(音讯推送过程...)

为什么应用Binder

Linux现有IPC机制

在学习Binder机制前,先简略说说Linux现有的所有过程间IPC机制:

  1. 管道:在创立时调配一个page大小的内存,缓存区大小比拟无限
  2. 音讯队列:信息复制两次,额定的CPU耗费;不适合频繁或信息量大的通信
  3. 共享内存:毋庸复制,共享缓冲区间接付附加到过程虚拟地址空间,速度快;但过程间的同步问题操作系统无奈实现,必须各过程利用同步工具解决
  4. 套接字:作为更通用的接口,传输效率低,次要用于不通机器或跨网络的通信
  5. 信号量:常作为一种锁机制,避免某过程正在访问共享资源时,其余过程也拜访该资源。因而,次要作为过程间以及同一过程内不同线程之间的同步伎俩
  6. 信号:不适用于信息替换,更实用于过程中断管制,比方非法内存拜访,杀死某个过程等

比照

  1. 从性能的角度 数据拷贝次数:Binder数据拷贝只须要一次,而管道、音讯队列、Socket都须要2次,但共享内存形式一次内存拷贝都不须要。从性能角度看,Binder性能仅次于共享内存。
  2. 从稳定性的角度Binder是基于C/S架构的,Client端有什么需要,间接发送给Server端去实现,架构清晰清朗,Server端与Client端绝对独立,稳定性较好;而共享内存实现形式简单,没有客户与服务端之别, 须要充分考虑到拜访临界资源的并发同步问题,否则可能会呈现死锁等问题。从稳定性角度看,Binder架构优于共享内存。
  3. 传统Linux IPC的接管方无奈取得对方过程牢靠的UID/PID,从而无奈甄别对方身份,平安保护措施齐全由下层协定来确保;Android为每个装置好的应用程序调配了本人的UID,故过程的UID是甄别过程身份的重要标记,后面提到C/S架构,Android零碎中对外只裸露Client端,Client端将工作发送给Server端,Server端会依据权限控制策略,判断UID/PID是否满足拜访权限。从安全性角度看,Binder架构优于传统IPC。
  4. 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进行近程调用的要害动作为以下三个:

  1. client端绑定server端服务
  2. client端获取server端IBinder对象
  3. 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...