Binder机制 - AIDL

前言

在我们应用开发过程中常见的binder跨进程,除了通过跨进程调用系统服务外,就是通过AIDL实现两个应用进程间的跨进程调用了。本文写在对AIDL实现跨进程通信的原理的讲解之前,先简单介绍一下AIDL在binder跨进程通信过程中做了什么,起到什么作用。熟悉了这个结构,在后续文章涉及AIDL时就可以一句带过了。

aidl生成类展示

创建aidl文件

AIDL 复制代码
// ITestService.aidl
package com.lingchen.test.ipc;
interface ITestService {
    String getName();

    int getProcessId();
}

编译后生成aidl对应接口代码展示:

Java 复制代码
package com.lingchen.test.ipc;
public interface ITestService extends android.os.IInterface
{
  public static class Default implements com.lingchen.test.ipc.ITestService
  {
    @Override public java.lang.String getName() throws android.os.RemoteException
    {
      return null;
    }
    @Override public int getProcessId() throws android.os.RemoteException
    {
      return 0;
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  public static abstract class Stub extends android.os.Binder implements com.lingchen.test.ipc.ITestService
  {
    private static final java.lang.String DESCRIPTOR = "com.lingchen.test.ipc.ITestService";
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    public static com.lingchen.test.ipc.ITestService asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.lingchen.test.ipc.ITestService))) {
        return ((com.lingchen.test.ipc.ITestService)iin);
      }
      return new com.lingchen.test.ipc.ITestService.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_getName:
        {
          data.enforceInterface(descriptor);
          java.lang.String _result = this.getName();
          reply.writeNoException();
          reply.writeString(_result);
          return true;
        }
        case TRANSACTION_getProcessId:
        {
          data.enforceInterface(descriptor);
          int _result = this.getProcessId();
          reply.writeNoException();
          reply.writeInt(_result);
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.lingchen.test.ipc.ITestService
    {
      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 java.lang.String getName() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.lang.String _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getName();
          }
          _reply.readException();
          _result = _reply.readString();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public int getProcessId() 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);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getProcessId, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getProcessId();
          }
          _reply.readException();
          _result = _reply.readInt();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      public static com.lingchen.test.ipc.ITestService sDefaultImpl;
    }
    static final int TRANSACTION_getName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getProcessId = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    public static boolean setDefaultImpl(com.lingchen.test.ipc.ITestService impl) {
      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.lingchen.test.ipc.ITestService getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  public java.lang.String getName() throws android.os.RemoteException;
  public int getProcessId() throws android.os.RemoteException;
}

解释

客户端

Java 复制代码
// 使用
// asInterface得到的是一个代理类Proxy
mService = ITestService.Stub.asInterface(service);
String name = mService.getName();
Java 复制代码
// AIDL
    public static com.lingchen.test.ipc.ITestService asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.lingchen.test.ipc.ITestService))) {
        return ((com.lingchen.test.ipc.ITestService)iin);
      }
      return new com.lingchen.test.ipc.ITestService.Stub.Proxy(obj);
    }

在客户端可以通过调用 asInterface 可以获得Proxy代理对象,这里的service是在客户端本地代表对端server的binder引用。

asInterface的实现就是创建一个Proxy代理对象。

Java 复制代码
    private static class Proxy implements com.lingchen.test.ipc.ITestService
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }

Proxy是实现了ITestService接口的代理类,它持有代表对端的IBinder对象。

Java 复制代码
// Proxy
      @Override public java.lang.String getName() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.lang.String _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getName();
          }
          _reply.readException();
          _result = _reply.readString();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }

当我们在客户端通过Proxy代理调用接口提供的方法时,Proxy代理会帮调用者做一些组织数据等的动作,然后调用mRemote.transact携带着数据发起binder通信。

服务端

Java 复制代码
public class TestBinder extends ITestService.Stub {
    @Override
    public String getName() throws RemoteException {
        ...
    }

    @Override
    public int getProcessId() throws RemoteException {
        ...
    }
}

通过继承 ITestService.Stub 成为binder服务端,并具体实现ITestService接口方法。

Java 复制代码
  public static abstract class Stub extends android.os.Binder implements com.lingchen.test.ipc.ITestService
  {
    @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_getName:
        {
          data.enforceInterface(descriptor);
          // 调用实现
          java.lang.String _result = this.getName();
          reply.writeNoException();
          reply.writeString(_result);
          return true;
        }
        case TRANSACTION_getProcessId:
        {
          data.enforceInterface(descriptor);
          // 调用实现
          int _result = this.getProcessId();
          reply.writeNoException();
          reply.writeInt(_result);
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }

服务端接收到请求后会触发 onTransact 处理,在onTransact中对数据进行解析并调用实现类的具体方法去做具体实现。

使用过程

简单画了个草图:

  1. client端通过asInterface获取到代理类Proxy
  2. 通过Proxy代理对象调用其实现的跨进程接口方法发起binder通信
    • Proxy代理方法中帮助调用者做了数据封装动作
    • Proxy持有代表对端的IBinder对象mRemote,通过mRemote发起实际的binder通信
  3. server端接收到通信,触发onTransact方法做具体响应
    • onTransact方法在aidl生成类的Stub中
    • Stub是Binder实现类,服务端通过继承Stub成为binder服务端
    • onTransact方法对远程调用的处理是1处理传入的数据2调用this(binder服务实现类)实现的对应的ipc接口方法做具体处理。

对于使用者,在客户端只需要asInterface获取到代理类,直接调用目标方法;在服务端只需要继承Stub成为binder服务端,实现IPC接口要实现的方法即可。而其中的客户端封装数据,调用binder.transact,服务端onTransact响应binder通信,解析数据,回调server具体实现方法,这些繁琐且固定的动作都由AIDL生成类固定封装好了,调用者不需要关心,方便了使用。

相关推荐
阿巴斯甜14 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker14 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952715 小时前
Andorid Google 登录接入文档
android
黄林晴16 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android