基於Binder機制之AIDL原理分析

上一篇完成了兩個項目間的AIDL跨進程通訊demo(這個demo是兩個應用之間的通訊,如果是一個項目之間的通訊就更簡單了,反正就三要素:溝通C-S的橋樑——AIDL文件,客戶端,服務端都放到一個項目就行了),沒有分析任何原理,下面來分析AIDL是如何進行跨進程通訊的:
在進行AIDL原理分析之前,先回憶一下Android跨進程通訊總共有幾種方式:

  1. 文件
  2. AIDL(基於Binder)
  3. Messenger(基於Binder)
  4. Content Provider(基於Binder)
  5. Socket
  6. Binder

至於說如何選擇這幾種通訊方式?

《Android開發藝術》中說的很是清晰:在這裏插入圖片描述
下面來看看AIDL到底做了什麼:
所有資料都告訴我們AIDL是基於Binder機制實現跨進程通訊,顯然又得學學Binder是個什麼玩意,但是飯要一口口吃,路要一步步走,這裏我們再次完全拋開Binder機制,先弄明白AIDL爲我們做了什麼工作。
大家都知道在使用AIDL機制實現跨進程的時候,我們只是生成了一個aidl文件,copy到客戶端和服務端,客戶端就能BindService對應的服務端進行通信,顯然重點都在編譯生成的這個aidl文件中!!看源碼

package com.testaidl;
public interface IMyAidl extends android.os.IInterface{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.testaidl.IMyAidl {。。。}
public void addPerson(com.testaidl.model.Person person) throws android.os.RemoteException;
public java.util.List<com.testaidl.model.Person> getPersonList() throws android.os.RemoteException;

一、可以看到,在第一步、第二步,會生成接口IMyAidl,繼承IInterface,IInterface是進程間通訊定義的通用接口,同時IMyAidl包含我們定義的兩個方法
二、IMyAidl中包含Stub,這是一個Binder,同時也實現了IMyAidl接口
三、重點就在Stub上,先看源碼

/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.testaidl.IMyAidl {
private static final java.lang.String DESCRIPTOR = "com.testaidl.IMyAidl";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.testaidl.IMyAidl interface,
 * generating a proxy if needed.
 */
public static com.testaidl.IMyAidl asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.testaidl.IMyAidl))) {
return ((com.testaidl.IMyAidl)iin);
}
return new com.testaidl.IMyAidl.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_basicTypes:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0!=data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
case TRANSACTION_addPerson:
{
data.enforceInterface(DESCRIPTOR);
com.testaidl.model.Person _arg0;
if ((0!=data.readInt())) {
_arg0 = com.testaidl.model.Person.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addPerson(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getPersonList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.testaidl.model.Person> _result = this.getPersonList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}

代碼有點多,這個類的作用:
1、將一個Binder與當前IMyAidl接口綁定(在Stub構造器中,this.attachInterface(this, DESCRIPTOR);)
2、將Ibinder轉換爲IMyAidl接口(asInterface函數中轉換和創建代理,返回給客戶端使用),不在同一個進程時就創建代理
3、onTransact函數,是Binder處理事情的關鍵方法,根據傳入的code,調用本地/服務端的不同方法

下面看看代理 Proxy

private static class Proxy implements com.testaidl.IMyAidl{
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;
}
/**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean)?(1):(0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void addPerson(com.testaidl.model.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.testaidl.model.Person> getPersonList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.testaidl.model.Person> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.testaidl.model.Person.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}

Proxy主要就是處理下數據,調用實際的Binder來處理

總結:

IInterface文件:aidl定義的方法、Stub
Stub:是一個Binder,同時實現了IInterface接口

  1. 將Binder轉換成IInterface(asInterface方法)
  2. 處理調度的onTransact
  3. Proxy,一個IInterface類型的代理,接口定義方法的僞實現,實現調用的是Binder
    也就是說,AIDL幫我們生成了Binder和跨平臺轉化類Stub,客戶端拿到代理Proxy,調用Binder—通知服務端–服務端調用真正的方法執行
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章