这是一系列的 Binder 文章,会从内核层到 Framework 层,再到使用层,深入浅出,介绍整个 Binder 的规划。详见《图解 Binder:概述》。

本文基于 Android platform 分支 android-13.0.0_r1 和内核分支 common-android13-5.15 解析。

一些要害代码的链接,可能会由于源码的变动,发生位置偏移、丢失等现象。能够搜索函数名,从头进行定位。

AIDL(Android Interface Definition Language)是一种支持跨进程通讯 (IPC) 的接口界说言语。在 Android 系统中,各个进程一般运用 Binder 通讯。Android 供给的 AIDL 也是基于 Binder 的。经过 AIDL,咱们能够使用其他进程的 Service,调用其他进程的函数。

AIDL 的效果,其实便是为开发者生成两个类:Stub 和 Proxy。这两个类都是一些模板代码,主要目的除了减轻开发者的工作量以外,也是为了隐藏跨进程通讯 (IPC) 的各种细节在这两个类中,使得开发者只需求重视完成详细的服务逻辑,而无需关怀底层通讯的细节。

Stub 一般用于服务端,Proxy 一般用于客户端。

AIDL 的运用

要在 Java 中运用 AIDL,咱们需求履行以下步骤:

  1. 无论是客户端,仍是服务端,都要界说 AIDL 接口:创立一个后缀为 .aidl 的文件,并在其中界说一个接口。接口中能够声明需求跨进程调用的函数。例如,创立一个名为 IExampleService.aidl 的文件,其内容如下:

    package com.example;
    interface IExampleService {
          String getMessage();
    }
    
  2. 编译生成代码:编译项目时,AIDL 编译器会主动为界说的 AIDL 接口生成对应的 Java 文件:IExampleService.java。生成的文件里包含了 IExampleService 接口、Stub 类和 Proxy 类。

  3. 在服务端里供给一个 Service,由 Service 供给 Binder 实体:Stub 类承继自 Binder,这意味它本身便是个 Binder 实体,但是它是个抽象类,不供给 getMessage() 的完成。所以,需求咱们承继 Stub,然后完成 getMessage()。最终,再创立一个 ExampleService(承继自 Service 类),然后在它的 onBind 里,回来咱们的 Binder 实体。

    package com.example;
    public class ExampleService extends Service {
        private final IExampleService.Stub mBinder = new IExampleService.Stub() {
            @Override
            public String getMessage() {
                return "Hello from ExampleService!";
            }
        };
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    }
    

    当然,不要忘了在服务端的 AndroidManifest.xml 中注册服务:

    <service android:name=".ExampleService"
        android:exported="true"
        android:enabled="true">
        <intent-filter>
            <action android:name="com.example.IExampleService"/>
        </intent-filter>
    </service>
    
  4. 客户端经过 AIDL ,调用服务端里的 getMessage():

    先在客户端进程中,bindService() 绑定服务端的 ExampleService 服务。例如:

    private IExampleService mExampleService;
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            mExampleService = IExampleService.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName className) {
            mExampleService = null;
        }
    };
    void bindService() {
        Intent intent = new Intent("com.example.IExampleService");
        intent.setPackage("com.example");
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }
    void unbindService() {
        if (mExampleService != null) {
            unbindService(mConnection);
            mExampleService = null;
        }
    }
    

    这样,在客户端进程能够经过 AIDL 生成的 Proxy 的 getMessage(),调用服务端的 getMessage():

    try {
        String message = mExampleService.getMessage();
    } catch (RemoteException e) {
        e.printStackTrace();
    }
    

Stub 和 Proxy

在 AIDL 主动生成的 IExampleService.java里,最要害的是 Stub 和 Proxy。它们之间的关系如下图:

图解 Binder:AIDL

Proxy 一般用于客户端,最要害的是它的 getMessage() :

public String getMessage() throws android.os.RemoteException {
    // _data 是写缓冲区
    android.os.Parcel _data = android.os.Parcel.obtain();
    // _reply 是读缓冲区
    android.os.Parcel _reply = android.os.Parcel.obtain();
    String _result;
    try {
        _data.writeInterfaceToken(DESCRIPTOR);
        // TRANSACTION_getMessage 是函数索引
        // mRemote 是 BinderProxy 的实例
        boolean _status = mRemote.transact(Stub.TRANSACTION_getMessage, _data, _reply, 0);
        if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getMessage();
        }
        _reply.readException();
        // 从读缓冲区读取长途调用的成果
        _result = _reply.readString();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
    return _result;
}

Stub 一般用于服务端。Stub 承继自 Binder,代表它便是一个 Binder 实体。它是一个抽象类,不会完成 getMessage(),交给子类去完成。咱们需求留意一下它的 onTransact():

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
    String descriptor = DESCRIPTOR;
    switch (code) {
        case INTERFACE_TRANSACTION: {
            reply.writeString(descriptor);
            return true;
        }
        // 目标函数的索引
        case TRANSACTION_getMessage: {
            data.enforceInterface(descriptor);
            // 调用 getMessage()
            String _result = this.getMessage();
            reply.writeNoException();
            // 回来成果给客户端
            reply.writeString(_result);
            return true;
        }
        default: {
            return super.onTransact(code, data, reply, flags);
        }
    }
}

在一次 getMessage() 的跨进程调用里,它们的效果如下:

图解 Binder:AIDL

transact()

transact() 会向 Binder 驱动建议业务,大致的调用链路是:

BinderProxy.java

└─transact()

└──transactNative()

└───android_util_Binder.cpp.cpp

└────android_os_BinderProxy_transact()

└─────BpBinder.cpp

└──────transact()

└───────IPCThreadState.cpp

└────────self()

└─────────transact()

└──────────writeTransactionData()

└──────────waitForResponse()

└───────────talkWithDriver()

└────────────ioctl.cpp

└─────────────ioctl()

注意:从 transact() 到 ioctl() ,这个过程都是同步调用。即当咱们经过 AIDL 调用长途服务时,客户端会等待服务端完成处理并回来成果。整个过程中,客户端线程会堵塞,直到收到来自服务端的回应。所以,咱们千万别在主线程建议调用。

onTransact()

服务端的 Binder 线程池的线程接收到 BR_TRANSACTION 音讯后,会一路调用到 onTransact():

IPCThreadState.cpp

└─executeCommand() // 读取服务端的读缓冲区数据,处理 BR_TRANSACTION 音讯

└──Binder.cpp

└───BBinder::transact() // 根据业务数据里的函数索引、参数,完成函数调用。

└────JavaBBinder.cpp(承继自 BBinder)

└─────onTransact()

└──────Binder.java

└───────execTransact()

└────────execTransactInternal()

└─────────onTransact() // Stub 会覆盖父类的 onTransact()

BpBinder 与 BinderProxy、BBinder 与 Binder

transact() 和 onTransact() 的调用链路里出现了 BpBinder、BinderProxy、BBinder(JavaBBinder)和 Binder。

在 Binder 业务一文,已经提到过,BBinder 即 Binder 实体,而 BpBinder 即 Binder 署理,持有着 Binder 引证。它们两个都是 C++ 里的类。

而 Binder、BinderProxy 则是它们的 Java 层表明。如下图:

图解 Binder:AIDL

使用级服务

服务端供给的 ExampleService 属于使用级服务。在前面的示例中,咱们在客户端里会经过 bindService() 发动它,并在 ServiceConnection 回调里,拿到了所需的 Binder 引证。

使用等级的服务一般不会注册到 ServiceManager,而是由 AMS 进行管理。

当客户端建议 bindService() 调用后,会经过 Binder 调用到 AMS 的 bindServiceLocked(),进行服务的绑定。假如服务还没发动,AMS 会经过 Binder 通讯,告诉服务端创立、发动和绑定服务。服务端履行绑定逻辑后,会传递 Binder 实体给 Binder 驱动,Binder 驱动转化为 Binder 引证后,再传给 AMS。最终由 AMS 转交给客户端,即最终会履行 ServiceConnection 回调的 onServiceConnected()。

图解 Binder:AIDL

  • Binder 实体是服务端里的 IExampleService.Stub mBinder。
  • Binder 引证均是经过 Binder 驱动转化的,上图没有画出 Binder 驱动。

aidl-cpp

C++ 层也能够经过 aidl-cpp 来运用 AIDL。