深入浅出Android底层(六)-Android中的IPC-Binder通信机制-自己实现AIDL

166 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情

前言

上一篇文章我们使用AIDL文件实现了IPC通信,在build的过程中as帮我们生成了很多模板化的代码,今天为了深入理解Binder机制的数据传输,我们自己动手实现一下Binder的通信,把AS帮我们生成的那些代码自己手写出来~

为了深入理解Binder的通信机制,我们还是用Person服务

一、服务端

1.1 定义服务端接口

public interface PersonInterface {

    void addPerson(Person person);

    List<Person> getPersonList();
}

1.2 声明序列化对象

这里声明的对象还是不变

image.png

1.3 定义Binder提供的代理对象

public class Proxy implements PersonInterface {
    private IBinder iBinder;

    public Proxy(IBinder iBinder) {
        this.iBinder = iBinder;
    }

    @Override
    public void addPerson(Person person) {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();

        data.writeInterfaceToken(DESCRIPTOR);
        if (person != null) {
            data.writeInt(1);
            person.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        try {
            iBinder.transact(BinderObj.TRANSACTION_ADDPerson, data, reply, 0);
        } catch (RemoteException e) {
            e.printStackTrace();
        } finally {
            reply.recycle();
            data.recycle();
        }


    }

    @Override
    public List<Person> getPersonList() {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        List<Person> result = null;
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            iBinder.transact(BinderObj.TRANSACTION_GETPerson, data, reply, 0);
            reply.readException();
            result = reply.createTypedArrayList(Person.CREATOR);
        } catch (RemoteException e) {
            e.printStackTrace();
        } finally {
            reply.recycle();
            data.recycle();
        }
        return result;
    }

    @Override
    public IBinder asBinder() {
        return null;
    }
}

这里提供的代理对象主要就是通过Parcel将数据序列化,然后调用remote.transact()将方法的code,以及入参的data传递过去

1.4 自定义Binder

public static PersonInterface asInterface(IBinder iBinder) {
    IInterface iInterface = iBinder.queryLocalInterface(DESCRIPTOR);
    if (null != iInterface && iInterface instanceof PersonInterface) {
        return (PersonInterface) iBinder;
    }
    return new Proxy(iBinder);
}

这里我们的Binder也根据是否在同一进程提供不同的服务端对象

1.5 自定义服务端服务

image.png

1.6 注册服务

<service
    android:name=".MyService"
    android:enabled="true"
    android:exported="true" />

二、客户端使用接口

2.1 复制服务端接口

image.png

客户端需要将服务端提供的接口以及序列化的对象已经Binder代理拷贝到相应包路径下

2.2 使用代理对象

image.png

客户端的使用方法还是和aidl使用的步骤是类似的

总结

image.png

没有使用aidl文件,我们也实现了进程间的IPC通信,而BinderObj文件的实际逻辑也与aidl模板生成的代码逻辑类似.都是在onTransact函数中进行关键数据的传输,另外也提供了代理生成的具体方法

  • 从Server进程来看,Binder是存在的实体对象,client通过transact()函数,经过Binder驱动,最终回调到Binder实体的onTransact()函数中
  • 从Client进程来看,Binder指的是Binder代理对象,时Binder实体对象的一个远程代理,通过Binder驱动与服务端进行交互.