说起Android的过程间通信,想必大家都会不谋而合的想起Android中的Binder机制。而提起Binder,想必也有不少同学会想起初学Android时被Binder和AIDL摆布的恐惧感。然而作为一个Android开发者,Binder是咱们必须把握的常识。因为它是构架整个Android大厦的钢筋和混凝土,连贯了Android各个系统服务和下层利用。只有理解了Binder机制能力更加深刻的了解Android开发和Android Framework。这也是为什么无论是《Android开发艺术摸索》还是《深刻了解Android内核波及思维》这些进阶类书籍把过程间通信和Binder机制放到靠前章节的起因,它太重要了,重要到整个Android Framework都离不开Binder的身影。

本篇文章咱们暂且不去探讨Binder的底层实现,因为就目前而言,笔者把握的水平也不足以去输入Binder实现原理的的内容。因而,为了不误导大家,这里就来写一写Binder的根底用法以及AIDL。尽管对于Binder和AIDL的根底用法网上的内容亘古未有。然而能把Binder和AIDL写的浅显易懂的文章并不多见。也就导致了很多人感觉Binder跟AIDL的应用都很难。

本篇文章,我将通过我本人的学习思路来带大家意识Binder机制和AIDL。

一、过程间通信

在操作系统中,每个过程都有一块独立的内存空间。为了保障程序的的安全性,操作系统都会有一套严格的平安机制来禁止过程间的非法拜访。毕竟,如果你的APP能拜访到别的APP的运行空间,或者别的APP能够轻而易举的拜访到你APP的运行空间,设想一下你是不是解体的心都有了。所以,操作系统层面会对利用过程进行内存隔离,以保障APP的运行平安。然而,很多状况下过程间也是须要互相通信的,例如剪贴板的性能,能够从一个程序中复制信息到另一个程序。这就是过程间通信诞生的背景。

狭义的讲,过程间通信(Inter-process communication,简称IPC)是指运行在不同过程中的若干线程间的数据交换。

操作系统中常见的过程间通信形式有共享内存、管道、UDS以及Binder等。对于这些过程间的通信形式本篇文章咱们不做深究,理解即可。

  • 共享内存(Shared Memory) 共享内存形式实现过程间通信依附的是申请一块内存区域,让后将这块内存映射到过程空间中,这样两个过程都能够间接拜访这块内存。在进行过程间通信时,两个过程能够利用这块内存空间进行数据交换。通过这样的形式,缩小了数据的赋值操作,因而共享内存实现过程间通信在速度上有显著劣势。
  • 管道(Pipe) 管道也是操作系统中常见的一种过程间通信形式,Windows零碎过程间的通信依赖于此中形式实现。在进行过程间通信时,会在两个过程间建设一根领有读(read)写(write)性能的管道,一个过程写数据,另一个过程能够读取数据,从而实现过程间通信问题。
  • UDS(UNIX Domain Socket) UDS也被称为IPC Socket,但它有别于network 的Socket。UDS的外部实现不依赖于TCP/IP协定,而是基于本机的“安全可靠操作”实现。UDS这种过程间通信形式在Android中用到的也是比拟多的。
  • Binder Binder是Android中独有的一种过程间通信形式。它底层依附mmap,只须要一次数据拷贝,把一块物理内存同时映射到内核和指标过程的用户空间。

本篇文章,咱们重点就是理解如何应用Binder实现过程间通信。Binder仅仅从名字来看就给人一种很神秘的感觉,就因为这个名字可能就会吓走不少初学者。但其实Binder自身并没有很神秘,它仅仅是Android零碎提供给开发者的一种过程间通信形式。

而从上述几种过程间通信形式来看,无论是哪种过程间通信,都是须要一个过程提供数据,一个过程获取数据。因而,咱们能够把提供数据的一端称为服务端,把获取数据的一端称为客户端。从这个角度来看Binder是不是就有点相似于HTTP协定了?所以,你齐全能够把Binder当成是一种HTTP协定,客户端通过Binder来获取服务端的数据。意识到这一点,再看Binder的应用就会简略多了。

二、应用Binder实现过程间通信

应用Binder实现过程间通信其实非常简单。咱们举一个查问问题的例子,服务端提供依据学生姓名查问学生问题的接口,客户端连贯服务端通过学生姓名来查问问题,而客户端与服务端的媒介就是Binder。

1.服务端的实现

服务端天然是要提供服务的,因而就须要咱们开启一个Service期待客户端的连贯。对于Android的Service这里就不必多说了吧,咱们实现一个GradeService并继承Service,来提供问题查问接口。代码如下:

public class GradeService extends Service {    public static final int REQUEST_CODE=1000;    private final Binder mBinder = new Binder() {        @Override        protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {            if (code == REQUEST_CODE) {                String name = data.readString();                // 依据姓名查问学生问题并将问题写入到返回数据                int studentGrade = getStudentGrade(name);                if (reply != null)                    reply.writeInt(studentGrade);                return true;            }            return super.onTransact(code, data, reply, flags);        }        // 依据姓名查问学生问题        public int getStudentGrade(String name) {                     return StudentMap.getStudentGrade(name);        }    };    @Nullable    @Override    public IBinder onBind(Intent intent) {        return mBinder;    }}

因为咱们要实现的是跨过程通信,因而,咱们将这个服务端的Service设置到近程过程中,在AndroidManifest文件中如下:

<service    android:name="com.zhpan.sample.binder.server.GradeService"    android:process=":server">    <intent-filter>        <action android:name="android.intent.action.server.gradeservice" />    </intent-filter></service>

就这样,一个近程的,提供问题查问的服务就实现了。

2.客户端的实现

客户端自然而然的是要连贯服务端过程问题查问。因而,咱们在客户端的Activity中取绑定GradeService进行问题查问。代码如下:

public class BinderActivity extends AppCompatActivity {    // 近程服务的Binder代理    private IBinder mRemoteBinder;    private final ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {            // 获取近程服务的Binder代理            mRemoteBinder = iBinder;        }        @Override        public void onServiceDisconnected(ComponentName componentName) {            mRemoteBinder = null;        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_binder);        // 绑定服务        findViewById(R.id.btn_bind_service).setOnClickListener(view -> bindGradeService());        // 查问学生问题        findViewById(R.id.btn_find_grade).setOnClickListener(view -> getStudentGrade("Anna"));    }    // 绑定近程服务    private void bindGradeService() {        String action = "android.intent.action.server.gradeservice";        Intent intent = new Intent(action);        intent.setPackage(getPackageName());        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);    }    // 从近程服务查问学生问题    private int getStudentGrade(String name) {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        int grade = 0;        data.writeString(name);        try {            if (mRemoteBinder == null) {                throw new IllegalStateException("Need Bind Remote Server...");            }            mRemoteBinder.transact(REQUEST_CODE, data, reply, 0);            grade = reply.readInt();        } catch (RemoteException e) {            e.printStackTrace();        }        return grade;    }

客户端的代码就是通过绑定近程服务,而后获取到服务的Binder代理,来查问学生问题。可见,应用Binder实现过程间通信是非常简单的,能够说简略的有点出乎所料。那咱们之前写的AIDL是什么呢?AIDL生成的那一堆是什么玩意儿?咱们且往下看。

三、代理模式优化Binder应用

尽管上一章中的代码曾经非常简单了,然而还是有能够优化的空间。咱们能够通过设计模式来进行优化,让代码更加简洁。

首先须要定义一个接口查问问题的接口IGradeInterface,代码如下:

public interface IGradeInterface {    // 查问问题接口    int getStudentGrade(String name);}

1.服务端代码优化

接着,对服务端的代码进行优化。咱们实现一个自定义的GradeBinder,并实现上述接口,代码如下:

public class GradeBinder extends Binder implements IGradeInterface {    @Override    public int getStudentGrade(String name) {        return StudentMap.getStudentGrade(name);    }    @Override    protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {        if (code == REQUEST_CODE) {            String name = data.readString();            int studentGrade = getStudentGrade(name);            if (reply != null)                reply.writeInt(studentGrade);            return true;        }        return super.onTransact(code, data, reply, flags);    }}

上述代码将查问问题的相干逻辑从Service搬到了GradeBinder中。因而,此时Service中只须要在onBind的时候返回GradeBinder的实例即可。代码如下:

public class GradeService extends Service {    public static final int REQUEST_CODE=1000;    @Nullable    @Override    public IBinder onBind(Intent intent) {        return new GradeBinder();    }}

2.客户端代码优化

客户端优化的思路是在连贯到近程服务时候实例化一个代理类,代理类持有Binder,让代理类行使Binder的权力。首先来看代理类的代码实现:

public class BinderProxy implements IGradeInterface {    // 被代理的Binder    private final IBinder mBinder;    // 私有化构造方法    private BinderProxy(IBinder binder) {        mBinder = binder;    }    // 通过Binde读取问题    @Override    public int getStudentGrade(String name) {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        int grade = 0;        data.writeString(name);        try {            if (mBinder == null) {                throw new IllegalStateException("Need Bind Remote Server...");            }            mBinder.transact(REQUEST_CODE, data, reply, 0);            grade = reply.readInt();        } catch (RemoteException e) {            e.printStackTrace();        }        return grade;    }            // 实例化Binder代理类的对象    public static IGradeInterface asInterface(IBinder iBinder) {        if (iBinder == null) {            return null;        }                 if (iBinder instanceof IGradeInterface) {            LogUtils.e("以后过程");            // 如果是同一个过程的申请,则间接返回Binder            return (IGradeInterface) iBinder;        } else {            LogUtils.e("近程过程");            // 如果是跨过程查问则返回Binder的代理对象            return new BinderProxy(iBinder);        }    }}

BinderProxy类的构造方法被设置成了private。同时提供了一个asInterface办法中,这个办法通过判断Binder是不是IGradeInterface类型从而确定是不是跨过程的通信。如果不是跨过程通信,则返回以后这个Binder,否则就返回Binder的这个代理类。

接下来客户端连贯上近程服务的时候应用BinderProxy获取Binder或者BinderProxy实例。代码如下:

public class BinderProxyActivity extends BaseViewBindingActivity<ActivityBinderBinding> {    // 此处可能是BinderProxy也可能是GradeBinder    private IGradeInterface mBinderProxy;    private final ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {            // 连贯服务胜利,依据是否跨过程获取BinderProxy或者GradeBinder实例            mBinderProxy = BinderProxy.asInterface(iBinder);        }        @Override        public void onServiceDisconnected(ComponentName componentName) {            mBinderProxy = null;        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        binding.btnBindService.setOnClickListener(view -> bindGradeService());          // 查问学生问题点击事件,通过mBinderProxy查问问题        binding.btnFindGrade.setOnClickListener(view -> ToastUtils.showShort("Anna grade is " + mBinderProxy.getStudentGrade("Anna")));    }    // 绑定服务    private void bindGradeService() {        String action = "android.intent.action.server.gradeservice";        Intent intent = new Intent(action);        intent.setPackage(getPackageName());        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);    }}

能够看到,此时的代码相比第一章的代码整洁了不少。然而,代码写起来仿佛还没有第一章中的不便。次要是因为要咱们减少一个IGradeInterface接口,还要自定义一个GradeBinder,同时,还须要写代理类的相干代码,感觉十分繁琐。那么有没有方法让代码简洁,写起来还不繁琐呢?答案是必定的,应用AIDL就能够实现。

四、AIDL

AIDL是Android Interface Description Languaged 简写。用于刻画客户端/服务端通信接口的一种描述语言。提起AIDL置信很多人都会感觉头大,定义一个AIDL接口,生成了那么多不知所云的代码,看起来几乎就是劫难。先别放心,如果你看懂了第三章的内容,那么其实你曾经齐全把握了AIDL。没错,说白了AIDL生成的那一坨代码其实就是咱们第三章中写的代码。即AIDL的原理其实就是应用了代理模式对Binder的应用进行了优化,应用AIDL保障了代码的整洁,同时也省去了本人编写繁琐的代理类相干代码。

对于AIDL的应用就非常简单了。

1.创立AIDL接口

首先,在要创立AIDL的目录上右键->New->AIDL->AIDl File 来创立一个AIDL文件,如下图所示:

创立一个名为IGradeService的AIDL文件,并增加一个getStudentGrade的办法。代码如下:

// IGradeService.aidlpackage com.zhpan.sample.binder.aidl;// Declare any non-default types here with import statementsinterface IGradeService {    /**     * Demonstrates some basic types that you can use as parameters     * and return values in AIDL.     */    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,            double aDouble, String aString);    int getStudentGrade(String name);}

接着Rebuild一下我的项目后IDE就会主动生成AIDL的代码了。

2.AIDL生成的代码

在我的项目的build目录下com.zhpan.sample.binder.aidl包中会看到主动生成的一个名为IGradeService的接口,代码如下:

// 这个接口相当于上一章中的IGradeInterface接口public interface IGradeService extends android.os.IInterface {    ...    // Stub是一个Binder,相当于上一章中的GradeBinder  public static abstract class Stub extends android.os.Binder      implements com.zhpan.sample.binder.aidl.IGradeService {    private static final java.lang.String DESCRIPTOR = "com.zhpan.sample.binder.aidl.IGradeService";    public Stub() {      this.attachInterface(this, DESCRIPTOR);    }    public static IGradeService asInterface(android.os.IBinder obj) {            if ((obj == null)) {        return null;      }      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);      if (((iin != null) && (iin instanceof com.zhpan.sample.binder.aidl.IGradeService))) {        // 如果是以后过程则间接返回以后Binder对象        return ((com.zhpan.sample.binder.aidl.IGradeService) iin);      }      // 跨过程则返回Binder的代理对象      return new com.zhpan.sample.binder.aidl.IGradeService.Stub.Proxy(obj);    }    @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_basicTypes: {          data.enforceInterface(descriptor);          int _arg0;          _arg0 = data.readInt();          long _arg1;          _arg1 = data.readLong();          boolean _arg2;          _arg2 = (0 != data.readInt());          float _arg3;          _arg3 = data.readFloat();          double _arg4;          _arg4 = data.readDouble();          java.lang.String _arg5;          _arg5 = data.readString();          this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);          reply.writeNoException();          return true;        }        case TRANSACTION_getStudentGrade: {          data.enforceInterface(descriptor);          java.lang.String _arg0;          _arg0 = data.readString();          int _result = this.getStudentGrade(_arg0);          reply.writeNoException();          reply.writeInt(_result);          return true;        }        default: {          return super.onTransact(code, data, reply, flags);        }      }    }    // Binder的代理类,相当于上一章中的BinderProxy    private static class Proxy implements com.zhpan.sample.binder.aidl.IGradeService {      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 basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,          double aDouble, java.lang.String aString) 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(anInt);          _data.writeLong(aLong);          _data.writeInt(((aBoolean) ? (1) : (0)));          _data.writeFloat(aFloat);          _data.writeDouble(aDouble);          _data.writeString(aString);          boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);          if (!_status && getDefaultImpl() != null) {            getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString);            return;          }          _reply.readException();        } finally {          _reply.recycle();          _data.recycle();        }      }      @Override public int getStudentGrade(java.lang.String name)          throws android.os.RemoteException {        android.os.Parcel _data = android.os.Parcel.obtain();        android.os.Parcel _reply = android.os.Parcel.obtain();        int _result;        try {          _data.writeInterfaceToken(DESCRIPTOR);          _data.writeString(name);          boolean _status = mRemote.transact(Stub.TRANSACTION_getStudentGrade, _data, _reply, 0);          if (!_status && getDefaultImpl() != null) {            return getDefaultImpl().getStudentGrade(name);          }          _reply.readException();          _result = _reply.readInt();        } finally {          _reply.recycle();          _data.recycle();        }        return _result;      }      public static com.zhpan.sample.binder.aidl.IGradeService sDefaultImpl;    }    static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);    static final int TRANSACTION_getStudentGrade = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);    public static boolean setDefaultImpl(com.zhpan.sample.binder.aidl.IGradeService impl) {      if (Stub.Proxy.sDefaultImpl == null && impl != null) {        Stub.Proxy.sDefaultImpl = impl;        return true;      }      return false;    }    public static com.zhpan.sample.binder.aidl.IGradeService getDefaultImpl() {      return Stub.Proxy.sDefaultImpl;    }  }  /**   * Demonstrates some basic types that you can use as parameters   * and return values in AIDL.   */  public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble,      java.lang.String aString) throws android.os.RemoteException;  public int getStudentGrade(java.lang.String name) throws android.os.RemoteException;}

瞥一眼代码会发现IGradeService接口中有一个名为Stub的外部类,它继承了Binder,并实现了IGradeService接口,并且它的外部有一个asInterface的办法,这个办法与咱们上一章BinderProxy中的asInterface统一,只是写的地位不同而已。另外在Stub的onTranscation办法的TRANSACTION\_getStudentGrade条件中的代码与GradeBinder的onTranscation办法代码是一样的。

接着,Stub类中还有一个名为Proxy的外部类。Proxy类与上一章的BinderProxy绝对应。能够看到Proxy类的构造方法并没有修饰符,而BinderProxy的构造方法被申明成了private,都能够避免内部通过构造方法区实例化代理类的对象。Proxy的getStudentGrade办法与BinderProxy中的getStudentGrade一样,通过Binder去读取服务端的写入数据。

3.AIDL客户端

应用AIDL的客户端实现简直与第三章中的代码统一。只不过是在连贯到服务端后通过IGradeService.Stub下的asInterface办法来获取Binder或者Binder的代理对象。代码如下:

public class AidlActivity extends BaseViewBindingActivity<ActivityBinderBinding> {    private IGradeService mBinderProxy;    private final ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {            // 连贯服务后,依据是否跨过程获取Binder或者Binder的代理对象            mBinderProxy = IGradeService.Stub.asInterface(iBinder);        }        @Override        public void onServiceDisconnected(ComponentName componentName) {            mBinderProxy = null;        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        binding.btnBindService.setOnClickListener(view -> bindGradeService());          // 查问学生问题        binding.btnFindGrade.setOnClickListener(view -> getStudentGrade("Anna"));    }      // 绑定服务    private void bindGradeService() {        String action = "android.intent.action.server.aidl.gradeservice";        Intent intent = new Intent(action);        intent.setPackage(getPackageName());        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);    }      // 查问问题    private void getStudentGrade(String name) {        int grade = 0;        try {            grade = mBinderProxy.getStudentGrade(name);        } catch (RemoteException e) {            e.printStackTrace();        }        ToastUtils.showShort("Anna grade is " + grade);    }}

到这里,对于AIDL的介绍就完结了。有没有惊奇的发现AIDL原来这么简略!

五、总结

本篇文章次要带大家意识了过程间通信和Binder与AIDL的应用。通过本篇文章的学习能够发现Binder与AIDL其实是非常简单的。理解了Binder之后,咱们就能够去更加深刻的学习Android Framework层的常识了。

视频
无所不能的Binder底层原理解析
过程间通信原理

原文: https://juejin.cn/post/6994057245113729038