0%

手写AIDL


Android中使用多进程可以分配更多的内存,内存空间隔离,Android系统是用户空间+内核空间,用户程序崩溃了系统内核程序也不受影响,其中Server、Client、ServiceManager 运行于用户空间,Binder驱动运行于内核空间。Android的多进程通信就是采用Binder实现的。

Binder驱动建立了内核缓存区和内核数据接收缓存区的映射关系,以及内核数据接收缓存区和接收进程用户空间地址的映射关系,内核缓存区和接收进程的用户空间地址存在内存映射,发送方进程将数据复制到内核缓存区,相当于把数据发送到了接收进程的用户空间。

为了更了解Android进程间的通信机制,理解AIDL的原理,利用binder实现进程间的通信,记录一次手写AIDL的过程


定义一个bean类Book,实现序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class Book implements Parcelable {

private String name;
private int type;

public Book(String name, int type) {
this.name = name;
this.type = type;
}

protected Book(Parcel in) {
this.name = in.readString();
this.type = in.readInt();
}

public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}

@Override
public Book[] newArray(int size) {
return new Book[size];
}
};

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(type);
}

@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", type=" + type +
'}';
}
}

定义操作接口类IBookManager继承IInterface,定义数据操作的方法

1
2
3
4
5
6
public interface IBookManager extends IInterface {

void addBook(Book book) throws RemoteException;

List<Book> getBookList() throws RemoteException;
}

定义抽象类Stub继承Binder类和IBookManager接口

  1. 实现onTransact方法,获取传入的参数,调用IBookManager接口的方法,这里暂不实现IBookManager的方法
  2. 返回IBookManager对象,需传入binder对象,如果与这个传入的binder对象在同一进程调用queryLocalInterface返回,否则把Binder传入Proxy对象返回一个远程的代理对象
  3. 返回Binder对象(自身)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    public abstract class Stub extends Binder implements IBookManager {

    private static final String DESCRIPTOR = "com.enjoy.binder.common.IBookManager";

    public Stub() {
    this.attachInterface(this, DESCRIPTOR);
    }

    public static IBookManager asInterface(IBinder binder) {
    if ((binder == null)) {
    return null;
    }
    // 先查找本地接口对象,如果同一个进程直接返回
    IInterface iin = binder.queryLocalInterface(DESCRIPTOR);
    if ((iin != null) && (iin instanceof IBookManager)) {
    return (IBookManager) iin;
    }
    // 传入binder对象,返回一个远程的代理对象
    return new Proxy(binder);
    }

    // 返回自身对象
    @Override
    public IBinder asBinder() {
    return this;
    }

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    switch (code) {
    case INTERFACE_TRANSACTION:
    reply.writeString(DESCRIPTOR);
    return true;
    // 添加书,调用addBook接口
    case TRANSACTION_addBook:
    data.enforceInterface(DESCRIPTOR);
    // 获取传入的book对象
    Book arg0 = null;
    if ((0 != data.readInt())) {
    arg0 = Book.CREATOR.createFromParcel(data);
    }
    this.addBook(arg0);
    reply.writeNoException();
    return true;
    // 获取书的列表,调用getBookList接口
    case TRANSACTION_getBookList:
    data.enforceInterface(DESCRIPTOR);
    List<Book> result = this.getBookList();
    reply.writeNoException();
    reply.writeTypedList(result);
    return true;
    }
    return super.onTransact(code, data, reply, flags);
    }

    static final int TRANSACTION_addBook = IBinder.FIRST_CALL_TRANSACTION;
    static final int TRANSACTION_getBookList = IBinder.FIRST_CALL_TRANSACTION + 1;
    }
    定义一个代理类实现IBookManager接口,调用Stub类传入的Binder对象通过Stub类的onTransact方法进行数据操作
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    public class Proxy implements IBookManager {

    private static final String DESCRIPTOR = "com.enjoy.binder.common.IBookManager";

    private IBinder mRemote;
    // 保存Stub类传入的Binder对象
    public Proxy(IBinder remote) {
    mRemote = remote;
    }

    // 实现跨进程数据传输,调Binder对象的onTransact方法
    @Override
    public void addBook(Book book) throws RemoteException {
    Parcel data = Parcel.obtain(); // 跨进程传输数据对象
    Parcel reply = Parcel.obtain(); // 跨进程传输返回结果
    try {
    data.writeInterfaceToken(DESCRIPTOR);
    if ((book != null)) {
    data.writeInt(1);
    book.writeToParcel(data, 0);
    } else {
    data.writeInt(0);
    }
    // 调Stub的onTransact方法进行Stub.TRANSACTION_addBook处理,远端返回
    mRemote.transact(Stub.TRANSACTION_addBook, data, reply, 0);
    reply.readException();
    } finally {
    reply.recycle();
    data.recycle();
    }
    }

    // 实现跨进程数据传输,调Binder对象的onTransact方法
    @Override
    public List<Book> getBookList() throws RemoteException {
    Parcel data = Parcel.obtain(); // 跨进程传输数据对象
    Parcel reply = Parcel.obtain(); // 跨进程传输返回结果
    List<Book> result;
    try {
    data.writeInterfaceToken(DESCRIPTOR);
    // 调Stub的onTransact方法进行Stub.TRANSACTION_getBookList处理,远端返回
    mRemote.transact(Stub.TRANSACTION_getBookList, data, reply, 0);
    reply.readException();
    result = reply.createTypedArrayList(Book.CREATOR);
    } finally {
    reply.recycle();
    data.recycle();
    }
    return result;
    }

    // 返回Stub类传入的Binder对象
    @Override
    public IBinder asBinder() {
    return mRemote;
    }
    }
    定义一个工作在独立进程的远程服务类,定义数据源,创建Binder对象,实现数据操作接口IBookManager内addBook方法和getBookList方法的具体业务逻辑,并返回创建的Binder对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class RemoteService extends Service {

    private ArrayList<Book> books; // 定义数据源

    // 服务绑定后返回Binder对象
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
    books = new ArrayList<>();
    Log.e("RemoteService", "success onBind");
    return iBinder;
    }

    // 创建一个Binder对象,实现IBookManager的数据操作方法,Stub类的对象在远端进程(独立进程)初始化
    private IBinder iBinder = new Stub() {
    @Override
    public void addBook(Book book) throws RemoteException {
    books.add(book);
    }

    @Override
    public List<Book> getBookList() throws RemoteException {
    return books;
    }
    };
    }
    在AndroidManifest中声明该服务在对立进程
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <service
    android:name=".server.RemoteService"
    android:exported="true"
    android:process=":remote">
    <intent-filter>
    <action android:name="com.enjoy.binder" />
    <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    </service>
    在主进程Activity中绑定远端服务进程,并通过binder对象调用数据操作方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    public class ClientActivity extends AppCompatActivity {

    private IBookManager iBookManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);
    // 绑定远端服务进程
    Intent intent = new Intent(this, RemoteService.class);
    intent.setAction("com.enjoy.binder");
    bindService(intent, connection, Context.BIND_AUTO_CREATE);
    // 点击,通过binder对象(远程代理对象)调用数据操作方法
    findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    try {
    iBookManager.addBook(new Book("数据结构与算法", 3));
    List<Book> books = iBookManager.getBookList();
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }
    });
    }

    private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    Log.e("ClientActivity", "onServiceConnected: success");
    iBookManager = Stub.asInterface(service);// Binder对象(远程代理对象)
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
    Log.e("ClientActivity", "onServiceDisconnected: success");
    iBookManager = null;
    }
    };
    }
    最后总结一下:
  4. Stub继承binder实现服务接口,onTransact根据code调服务接口
  5. Activity绑定远程服务,连接回调中获取Stub.asInterface,区分是否同一进程返回代理对象,如果是返回本地接口,否则返回远程服务onBinder返回的IBinder代理对象
  6. 代理类实现服务接口,数据打包,检查token,跨进程调transact序列化发送data和获取返回reply,客户端线程挂起
  7. 服务端实例化Stub并实现服务接口接收客户端请求并响应