本文主要來分析一下AIDL實現原理,在Android進程間通信AIDL(一)學習如何使用AIDL時,在Client端用到了IRemoteService這么一個類,廢話不多說,直接貼代碼
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\Android\\demo\\AIDLDemo\\app\\src\\main\\aidl\\com\\zx\\aidl\\demo\\IRemoteService.aidl
*/
package com.zx.aidl.demo;
public interface IRemoteService extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder
implements com.zx.aidl.demo.IRemoteService {
private static final java.lang.String DESCRIPTOR = "com.zx.aidl.demo.IRemoteService";
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.zx.aidl.demo.IRemoteService interface,
* generating a proxy if needed.
*/
public static com.zx.aidl.demo.IRemoteService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.zx.aidl.demo.IRemoteService))) {
return ((com.zx.aidl.demo.IRemoteService) iin);
}
return new com.zx.aidl.demo.IRemoteService.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 {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_addPerson: {
data.enforceInterface(DESCRIPTOR);
com.zx.aidl.demo.Person _arg0;
if ((0 != data.readInt())) {
_arg0 = com.zx.aidl.demo.Person.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addPerson(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getPersons: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.zx.aidl.demo.Person> _result = this.getPersons();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.zx.aidl.demo.IRemoteService {
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 addPerson(com.zx.aidl.demo.Person person)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((person != null)) {
_data.writeInt(1);
person.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override public java.util.List<com.zx.aidl.demo.Person> getPersons()
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.zx.aidl.demo.Person> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getPersons, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.zx.aidl.demo.Person.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getPersons = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public void addPerson(com.zx.aidl.demo.Person person) throws android.os.RemoteException;
public java.util.List<com.zx.aidl.demo.Person> getPersons() throws android.os.RemoteException;
}
接下來我們一步一步分析上面代碼,首先看下它的注釋:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\Android\\demo\\AIDLDemo\\app\\src\\main\\aidl\\com\\zx\\aidl\\demo\\IRemoteService.aidl
*/
IRemoteService.java文件是SDK根據IRemoteService.aidl自動為我們生成的一個Java文件,并且不允許修改,那SDK為什么要為我們生成這個文件呢?首先我們知道ADIL進程間通信其實本質就是Binder機制,既然能讓客戶端訪問服務端,服務端就得公布其接口和方法供客戶端調用,IRemoteService正是充當了該角色,這里是SDK為了我們開發更簡單方便,自動生成了這么一個類,當然我們也可以自己手動去實現它。仔細查看這個接口,發現其結構其實很簡單,一個靜態內部抽象類和倆方法,我們來重點分析下內部抽象類Stub,主要來分析下它的幾個重要方法
- asInterface(android.os.IBinder obj)
這個方法其實是將Binder對象轉換成IRemoteService接口
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.zx.aidl.demo.IRemoteService))) {
return ((com.zx.aidl.demo.IRemoteService) iin);
}
return new com.zx.aidl.demo.IRemoteService.Stub.Proxy(obj);
首先它會通過傳入的binder對象參數去查詢本地是否有該接口,其實也是判斷是否是本地通信,如果是,直接返回該接口,查詢的時候會傳入DESCRIPTOR這么一個參數,這個參數其實是Binder的唯一標識,一般都采用類名,如果不是本地通信,會返回Proxy這么一個對象,并且將傳入了Binder對象作為參數,因為我們主要分析的是進程間通信,所以分析第二種情況,我們去看下Proxy這個類到底是什么鬼?
private static class Proxy implements com.zx.aidl.demo.IRemoteService {
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 addPerson(com.zx.aidl.demo.Person person)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((person != null)) {
_data.writeInt(1);
person.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override public java.util.List<com.zx.aidl.demo.Person> getPersons()
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.zx.aidl.demo.Person> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getPersons, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.zx.aidl.demo.Person.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getPersons = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
Proxy是Stub的一個靜態內部類,從字面意思就知道它其實是一個代理類,那它到底代理的是誰?顯然Proxy內部持有了一個 Ibinder 變量,所以它其實Binder的代理,其實也就是Stub的代理對象,Proxy也實現了IRemoteService接口以及addPerson和getPersons方法,我們這里選擇getPersons這個方法來分析,看它內部到底做了那些操作,為什么不用addPerson呢,沒什么原因,因為原理都一樣,就隨便拿一個方法來分析
@Override public java.util.List<com.zx.aidl.demo.Person> getPersons()
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.zx.aidl.demo.Person> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getPersons, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.zx.aidl.demo.Person.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
從 asInterface(android.os.IBinder obj) 這個方法我們知道,其實在Client端拿到的是Proxy這個對象,所以它的addPerson和getPersons方法其實是運行在Client端的,首先會創建倆個Parcel參數,輸入新參數_data和_reply,同時創建了一個List返回對象_result,接下來主要分為三個步驟:
- 將方法參數信息寫入_data中
- 調用transact方法像服務端發起RPC(Remote Procedure Cal)遠程調用請求,同時掛起客戶端線程,等待服務端的onTransact方法返回結果
- 從_reply中拿到結果并返回然后喚醒客戶端線程
這里說下第二步,transact方法時在底層執行的,所以我們這里不用去深究方法里到底做了什么,只需要知道該方方法向服務端的發送了一個請求,然后服務端會執行它的onTransact方法,那么onTransact到底在什么地方,其實就是Stub類里面的onTransact方法,接下來我們去看下Stub類里面的onTransact方法具體實現
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply,
int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_addPerson: {
data.enforceInterface(DESCRIPTOR);
com.zx.aidl.demo.Person _arg0;
if ((0 != data.readInt())) {
_arg0 = com.zx.aidl.demo.Person.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addPerson(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getPersons: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.zx.aidl.demo.Person> _result = this.getPersons();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
首先會根據code去判斷客戶端請求目標方法,這里的code就是我們在上面transact方法中傳入的Stub.TRANSACTION_getPersons,所以我們直接去看相對應的方法處理
data.enforceInterface(DESCRIPTOR);
java.util.List<com.zx.aidl.demo.Person> _result = this.getPersons();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
首先它會去調用自身的getPersons方法,其實就是我們在Service里實現的getPersons方法
private IRemoteService.Stub binder = new IRemoteService.Stub() {
@Override public void addPerson(Person person) throws RemoteException {
persons.add(person);
}
@Override public List<Person> getPersons() throws RemoteException {
return persons;
}
};
然后將結果寫入reply中返回給我們的客戶端,需要注意的是,最后方法返回值是true,如果返回false的話,客戶端會請求失敗,到這里我們整個流程分析就已經結束,接下來我們做一個總結,先上個圖
- 客戶端通過asInterface(android.os.IBinder obj)得到代理對象Proxy
- 客戶端調用Proxy的getPersons方法,該方法內執行transact方法向服務端 發送遠程調用請求,并掛起客戶端線程
- 服務端得到請求后執行onTransact方法,調用自身的getPersons方法拿到結果,將結果返回給客戶端,喚醒客戶端線程