仿寫系統AIDL框架 學習Binder機制
目的:通過仿寫AIDL加深對Android應用層和Framework層中應用的Binder機制的理解。
AIDL(Android接口定義語言)是一種框架,對Binder的封裝。幫助我們方便的去使用Binder。如果直接用Binder需要寫很多代碼,採用AIDL可能只需要幾行。就能完成跨進程通訊。
代碼地址:https://github.com/itlgc/Android-Binder-Custom
Binder是什麼?
從IPC角度: Binder是Android中的一種跨進程通信方式。
從Android Driver層:Binder還可以理解爲一種虛擬的物理設備,它的設備驅動是/dev/binder。
從Android Native層:Binder是創建Service Manager以及BpBinder/BBinder模型,搭建與binder驅動的橋樑。
從Android Framework層:Binder是各種Manager(ActivityManager、WindowManager等)和相應xxxManagerService的橋樑。
從Android 應用層:Binder是客戶端和服務端進行通信的媒介,當bindService的時候,服務端會返回一個包含了服務端業務調用的 Binder對象,通過這個Binder對象,客戶端就可以獲取服務端提供的服務或者數據,這裏的服務包括普通服務和基於AIDL的服務。
Binder四個重要對象
IBinder
一個接口,代表跨進程通訊的能力,只要實現這個接口就能具備跨進程通訊的能力。
IInterface
代表Service這一方能提供什麼能力,即提供了哪些方法。
Binder
實現了IBinder。
Stub
使用AIDL時候,工具會給我們生成一個靜態內部類Stub,這個類extends Binder 以及 implements IInterface。 這個類也是個抽象類,具體內部實現需要我們自己去實現。
部分代碼實現
仿寫AIDL框架來模擬在Client端添加對象,Server端將對象保存到容器中,同時提供給Client端查詢的方法。
在Client通過連接Server端服務來獲取到代理
/**定義接口服務*/
public interface IPersonManager extends IInterface {
void addPerson(Person person);
List<Person> getPersonList();
}
//服務連接
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//獲取到Server端提供的功能的代理接口
iPersonManager = BinderStub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
//Client端觸發功能
btnBinder.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//通過AIDL實現調用到Server端方法
iPersonManager.addPerson(new Person("name" + i, i++));
//.....省略部分代碼.....
Log.e("TAG:" + TAG,"客戶端mPersonList.size(): "+iPersonManager.getPersonList().size() + "*");
}
});
/**
* 通過queryLocalInterface方法,查找本地Binder對象
* 如果返回的就是PersonManger,說明client和server處於同一個進程,直接返回
* 如果不是,則返回給一個代理對象
*
* @param iBinder Binder驅動傳來的IBinder對象
*/
public static IPersonManager asInterface(IBinder iBinder) {
if (iBinder == null) {
return null;
}
IInterface iInterface = iBinder.queryLocalInterface(DESCRIPTOR);
if (iInterface instanceof IPersonManager) {
Log.d("TAG:","asInterface: client和server處於同一個進程,直接返回" );
return (IPersonManager) iInterface;
}
Log.d("TAG:","asInterface: client和server處於不同進程,返回代理對象" );
return new CustomProxy(iBinder);
}
CustomProxy : 作爲Binder機制的發送端
public class CustomProxy implements IPersonManager {
private IBinder mIBinder;
public CustomProxy(IBinder iBinder) {
this.mIBinder = iBinder;
}
/**
* 1、首先通過Parcel將數據序列化,
* 2、然後調用 remote.transact()將方法code,和data傳輸過去,
* 對應的會回調在在Server中的onTransact()中
* @param person
*/
@Override
public void addPerson(Person person) {
Parcel data = Parcel.obtain();
Parcel replay = Parcel.obtain();
try {
data.writeInterfaceToken(BinderStub.DESCRIPTOR);
if (person != null) {
data.writeInt(1);
person.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
/**
* 通過transact()方法將上述數據發送到Binder驅動
* 參數1:目標方法標識符,(Client進程和Server進程自身約定)
* 參數2:上述的Parcel對象
* 參數3:結果回覆
*/
mIBinder.transact(BinderStub.ADD_PERSON, data, replay, 0);
//在發送數據後,Client進程的該線程會暫時被掛起
replay.readException();
}catch (RemoteException e){
e.printStackTrace();
}finally {
data.recycle();
replay.recycle();
}
}
@Override
public List<Person> getPersonList() {
//....省略
}
// 3. Binder驅動根據代理對象 找到對應的真身Binder對象所在的Server進程(系統自動執行)
// 4. Binder驅動把數據發送到Server進程中,並通知Server進程執行解包(系統自動執行)
@Override
public IBinder asBinder() {
return null;
}
}
BinderStub: 作爲Binder的接收端
public abstract class BinderStub extends Binder implements IPersonManager {
//Binder唯一標識 自定義
public static final String DESCRIPTOR = "com.it.binder.IPersonManager";
// 方法標識
public static final int GET_PERSON = IBinder.FIRST_CALL_TRANSACTION;
public static final int ADD_PERSON = IBinder.FIRST_CALL_TRANSACTION + 1;
//......省略部分代碼.....
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,
int flags) throws RemoteException {
// 1. 收到Binder驅動通知後,Server 進程通過回調Binder對象onTransact()進行數據解包 & 調用目標方法
// code即在transact()中約定的目標方法的標識符
switch (code) {
case INTERFACE_TRANSACTION:
return true;
case GET_PERSON:
data.enforceInterface(DESCRIPTOR);
List<Person> personList = this.getPersonList();
if (reply != null) {
reply.writeNoException();
reply.writeTypedList(personList);
}
return true;
case ADD_PERSON:
// 解包Parcel中的數據
data.enforceInterface(DESCRIPTOR);
Person person = null;
// 解析目標方法對象的標識符
if (data.readInt() != 0) {
person = Person.CREATOR.createFromParcel(data);
}
this.addPerson(person);
// 將結果寫入到reply
if (reply != null)
reply.writeNoException();
return true;
}
// 2. 將結算結果返回 到Binder驅動
return super.onTransact(code, data, reply, flags);
}
}
mStub對象,也就是Server中的Binder實體對象,在這裏做Server端操作。
public class ServerService extends Service {
public static final String TAG = ServerService.class.getSimpleName();
private List<Person> mPersonList = new ArrayList<>();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mStub;
}
private IBinder mStub = new BinderStub() {
@Override
public void addPerson(Person person) {
if (person == null) {
Log.e("TAG:"+TAG, "null obj");
person = new Person();
}
mPersonList.add(person);
Log.e("TAG:"+TAG, "服務端mPersonList.size(): "+mPersonList.size());
}
@Override
public List<Person> getPersonList() {
return mPersonList;
}
};
}