Android IPC之AIDL原始碼探索(三)細得跟沙一樣,你還不來看!

語言: CN / TW / HK

一、簡介

這將是一個圍繞AIDL的系列文章,內容含AIDL簡單使用、進階使用、AIDL原始碼探索,希望從簡單開始再到複雜,在這個過程中使大家既能掌握AIDL的使用方法和需要注意的細節,同時也能通過對AIDL原始碼的探索,使各位理解AIDL的處理原理。這篇文章為第三篇,會在前兩篇的基礎上,根據例子中的AIDL介面,深入原始碼探索AIDL的實現原理。 - Android IPC之AIDL使用(一) - Android IPC之AIDL使用(二) - Android IPC之AIDL原始碼探索(三) 文章詞彙解釋: - AS:AndroidStudio開發工具 - AIDL檔案:指在aidl目錄下建立的aidl介面 - AIDL類:指由aidl檔案Build生成的類

二、AIDL檔案結構

先回顧一下,前兩篇文章中定義的AIDL檔案。 ```java interface MyAIDLInterface { /* * Demonstrates some basic types that you can use as parameters * and return values in AIDL. / void commonMethod();

void setStringText(String text);

void setObjectMethodIn(in MethodObject o);
void setObjectMethodOut(out MethodObject o);
void setObjectMethodInout(inout MethodObject o);

MethodObject getObjectMethod();

void register(CallBackAIDLInterface aidl);
void unregister(CallBackAIDLInterface aidl);

} 為了全面瞭解AIDL對不同型別函式的處理邏輯,這裡定義了8個函式,register()和unregister()情況一樣,所以總體有7種不同型別。現在去看AIDL類,真正的幕後黑手,類內容有些長,你可能會反感,但相信我你需要耐心的瀏覽一下。java public interface MyAIDLInterface extends android.os.IInterface { / Default implementation for MyAIDLInterface. */ public static class Default implements com.zhukai.aidlservice.MyAIDLInterface { / * Demonstrates some basic types that you can use as parameters * and return values in AIDL. / @Override public void commonMethod() throws android.os.RemoteException { } @Override public void setStringText(java.lang.String text) throws android.os.RemoteException { } @Override public void setObjectMethodIn(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException { } @Override public void setObjectMethodOut(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException { } @Override public void setObjectMethodInout(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException { } @Override public com.zhukai.aidlservice.MethodObject getObjectMethod() throws android.os.RemoteException { return null; } @Override public void register(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException { } @Override public void unregister(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException { } @Override public android.os.IBinder asBinder() { return null; } } / Local-side IPC implementation stub class. / public static abstract class Stub extends android.os.Binder implements com.zhukai.aidlservice.MyAIDLInterface { private static final java.lang.String DESCRIPTOR = "com.zhukai.aidlservice.MyAIDLInterface"; / Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } / * Cast an IBinder object into an com.zhukai.aidlservice.MyAIDLInterface interface, * generating a proxy if needed. / public static com.zhukai.aidlservice.MyAIDLInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.zhukai.aidlservice.MyAIDLInterface))) { return ((com.zhukai.aidlservice.MyAIDLInterface)iin); } return new com.zhukai.aidlservice.MyAIDLInterface.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 { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_commonMethod: { data.enforceInterface(descriptor); this.commonMethod(); reply.writeNoException(); return true; } case TRANSACTION_setStringText: { data.enforceInterface(descriptor); java.lang.String _arg0; _arg0 = data.readString(); this.setStringText(_arg0); reply.writeNoException(); return true; } case TRANSACTION_setObjectMethodIn: { data.enforceInterface(descriptor); com.zhukai.aidlservice.MethodObject _arg0; if ((0!=data.readInt())) { _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.setObjectMethodIn(_arg0); reply.writeNoException(); return true; } case TRANSACTION_setObjectMethodOut: { data.enforceInterface(descriptor); com.zhukai.aidlservice.MethodObject _arg0; _arg0 = new com.zhukai.aidlservice.MethodObject(); this.setObjectMethodOut(_arg0); reply.writeNoException(); if ((_arg0!=null)) { reply.writeInt(1); _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_setObjectMethodInout: { data.enforceInterface(descriptor); com.zhukai.aidlservice.MethodObject _arg0; if ((0!=data.readInt())) { _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.setObjectMethodInout(_arg0); reply.writeNoException(); if ((_arg0!=null)) { reply.writeInt(1); _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_getObjectMethod: { data.enforceInterface(descriptor); com.zhukai.aidlservice.MethodObject _result = this.getObjectMethod(); reply.writeNoException(); if ((_result!=null)) { reply.writeInt(1); _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_register: { data.enforceInterface(descriptor); com.zhukai.aidlservice.CallBackAIDLInterface _arg0; _arg0 = com.zhukai.aidlservice.CallBackAIDLInterface.Stub.asInterface(data.readStrongBinder()); this.register(_arg0); reply.writeNoException(); return true; } case TRANSACTION_unregister: { data.enforceInterface(descriptor); com.zhukai.aidlservice.CallBackAIDLInterface _arg0; _arg0 = com.zhukai.aidlservice.CallBackAIDLInterface.Stub.asInterface(data.readStrongBinder()); this.unregister(_arg0); reply.writeNoException(); return true; } default: { return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements com.zhukai.aidlservice.MyAIDLInterface { 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 commonMethod() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); boolean _status = mRemote.transact(Stub.TRANSACTION_commonMethod, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().commonMethod(); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void setStringText(java.lang.String text) 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.writeString(text); boolean _status = mRemote.transact(Stub.TRANSACTION_setStringText, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().setStringText(text); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void setObjectMethodIn(com.zhukai.aidlservice.MethodObject o) 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 ((o!=null)) { _data.writeInt(1); o.writeToParcel(_data, 0); } else { _data.writeInt(0); } boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodIn, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().setObjectMethodIn(o); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void setObjectMethodOut(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodOut, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().setObjectMethodOut(o); return; } _reply.readException(); if ((0!=_reply.readInt())) { o.readFromParcel(_reply); } } finally { _reply.recycle(); _data.recycle(); } } @Override public void setObjectMethodInout(com.zhukai.aidlservice.MethodObject o) 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 ((o!=null)) { _data.writeInt(1); o.writeToParcel(_data, 0); } else { _data.writeInt(0); } boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodInout, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().setObjectMethodInout(o); return; } _reply.readException(); if ((0!=_reply.readInt())) { o.readFromParcel(_reply); } } finally { _reply.recycle(); _data.recycle(); } } @Override public com.zhukai.aidlservice.MethodObject getObjectMethod() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); com.zhukai.aidlservice.MethodObject _result; try { _data.writeInterfaceToken(DESCRIPTOR); boolean _status = mRemote.transact(Stub.TRANSACTION_getObjectMethod, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getObjectMethod(); } _reply.readException(); if ((0!=_reply.readInt())) { _result = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(_reply); } else { _result = null; } } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void register(com.zhukai.aidlservice.CallBackAIDLInterface aidl) 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.writeStrongBinder((((aidl!=null))?(aidl.asBinder()):(null))); boolean _status = mRemote.transact(Stub.TRANSACTION_register, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().register(aidl); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void unregister(com.zhukai.aidlservice.CallBackAIDLInterface aidl) 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.writeStrongBinder((((aidl!=null))?(aidl.asBinder()):(null))); boolean _status = mRemote.transact(Stub.TRANSACTION_unregister, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().unregister(aidl); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } public static com.zhukai.aidlservice.MyAIDLInterface sDefaultImpl; } static final int TRANSACTION_commonMethod = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_setStringText = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_setObjectMethodIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); static final int TRANSACTION_setObjectMethodOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); static final int TRANSACTION_setObjectMethodInout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4); static final int TRANSACTION_getObjectMethod = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5); static final int TRANSACTION_register = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6); static final int TRANSACTION_unregister = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7); public static boolean setDefaultImpl(com.zhukai.aidlservice.MyAIDLInterface impl) { // Only one user of this interface can use this function // at a time. This is a heuristic to detect if two different // users in the same process use this function. if (Stub.Proxy.sDefaultImpl != null) { throw new IllegalStateException("setDefaultImpl() called twice"); } if (impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static com.zhukai.aidlservice.MyAIDLInterface getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } /* * Demonstrates some basic types that you can use as parameters * and return values in AIDL. / public void commonMethod() throws android.os.RemoteException; public void setStringText(java.lang.String text) throws android.os.RemoteException; public void setObjectMethodIn(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException; public void setObjectMethodOut(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException; public void setObjectMethodInout(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException; public com.zhukai.aidlservice.MethodObject getObjectMethod() throws android.os.RemoteException; public void register(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException; public void unregister(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException; } ``` 看到這裡,我深怕勸退了很多小夥伴,這個類也太長了,但是我相信看到這裡的你還是對這個類有了一點印象,現在只需要我們整理一下思路,先弄清楚類的結構,然後再以實際使用作為入口去追蹤,一切都會雲開霧散!下面我會把程式碼極簡化,讓大家看清類的整體結構。

java public interface MyAIDLInterface extends android.os.IInterface { //預設的實現類 public static class Default implements com.zhukai.aidlservice.MyAIDLInterface { ... //省略了繼承實現的函式 } //服務端的Binder物件 public static abstract class Stub extends android.os.Binder implements com.zhukai.aidlservice.MyAIDLInterface { ... //省略了內容 //客戶端代理物件 private static class Proxy implements com.zhukai.aidlservice.MyAIDLInterface { } ... //省略了內容 } //AIDL檔案中定義的所有函式 public void commonMethod() throws android.os.RemoteException; public void setStringText(java.lang.String text) throws android.os.RemoteException; public void setObjectMethodIn(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException; public void setObjectMethodOut(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException; public void setObjectMethodInout(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException; public com.zhukai.aidlservice.MethodObject getObjectMethod() throws android.os.RemoteException; public void register(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException; public void unregister(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException; } 現在這個類結構就簡單清晰多了,AS根據我們定義的AIDL檔案,構建了最外層MyAIDLInterface類,包含了所有AIDL檔案中定義的函式。再在內部構建了3個實現類Default、Stub、Proxy(Stub內部類),Default就很好理解了,一個預設實現類;Stub、Proxy(Stub內部類)可以說是整個AIDL類中最重要的兩個類,Stub是服務端的,所以它同時還繼承了Binder類(Binder類實現了IBinde介面),Proxy是客戶端的。弄清楚了結構,現在就可以回到使用,通過使用的流程來追蹤內部實現邏輯。

三、原始碼追蹤

1.服務端建立Binder物件

應該還記得在服務端Service中,onBind方法返回了Stub物件。 ```java @Nullable @Override public IBinder onBind(Intent intent) { return stub; }

MyAIDLInterface.Stub stub = new MyAIDLInterface.Stub() {...} 這裡需要看一下Stub物件建立時做了什麼。java private static final java.lang.String DESCRIPTOR = "com.zhukai.aidlservice.MyAIDLInterface"; /* Construct the stub at attach it to the interface. /

private IInterface mOwner; private String mDescriptor;

public Stub() { this.attachInterface(this, DESCRIPTOR);//呼叫了Binder的函式 }

public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) { mOwner = owner;//Stub物件 mDescriptor = descriptor;//描述符 } ``` 通過呼叫父類Binder的attachInterface()函式,把自己和一段描述符繫結在了Binder物件中。這樣在onBind()函式中返回的Binder物件就攜帶了Stub物件和一段描述符,這個描述符就是自己完整的類名。

這個Binder物件最終被返回到哪兒去了呢?會不會是繫結Service的地方,那就去看客戶端。

2.客戶端獲取操作物件

```java private void bind() { Intent intent = new Intent(); intent.setAction("com.zhukai.aidlservice.startService"); intent.setComponent(new ComponentName("com.zhukai.aidlservice","com.zhukai.aidlservice.MyService")); bindService(intent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { myAIDLInterface = MyAIDLInterface.Stub.asInterface(service);//核心方法 ... }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        myAIDLInterface = null;
    }
}, Service.BIND_AUTO_CREATE);

} ``` 在客戶端繫結方法中,ServiceConnection介面的onServiceConnected回撥方法返回了一個IBinder物件,這個IBinder物件,就是剛剛服務端Service中返回的Binder物件。這裡需要注意,根據Binder機制特性,如果我們繫結的服務沒有另起程序,那這個Binder物件和服務端是同一個;另起程序了,這個Binder物件就只是服務端返回Binder物件的一個BinderProxy代理物件。現在Binder已經從服務端傳遞到了客戶端,再看客戶端後續操作。

接著呼叫MyAIDLInterface.Stub.asInterface(service)函式傳入Binder物件,這是一個專門獲取客戶端操作物件的函式。 ```java

//描述符就是AIDL類的完整類名 private static final java.lang.String DESCRIPTOR = "com.zhukai.aidlservice.MyAIDLInterface";

/* * Cast an IBinder object into an com.zhukai.aidlservice.MyAIDLInterface interface, * generating a proxy if needed. / public static com.zhukai.aidlservice.MyAIDLInterface asInterface(android.os.IBinder obj) { if ((obj==null)) {//判空 return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);//核心 if (((iin!=null)&&(iin instanceof com.zhukai.aidlservice.MyAIDLInterface))) { return ((com.zhukai.aidlservice.MyAIDLInterface)iin); } return new com.zhukai.aidlservice.MyAIDLInterface.Stub.Proxy(obj); } 在函式內,先判斷了Binder是否為null,緊接著呼叫Binder物件的queryLocalInterface()函式,傳入了客戶端的描述符DESCRIPTOR。java public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) { if (mDescriptor != null && mDescriptor.equals(descriptor)) {//和Binder快取的描述符做比較 return mOwner; } return null; } ``` 因為Binder物件的不同,在這個函式中就會出現兩種情況,如果這個Binder物件和服務端是同一個,在服務端是有綁定了描述符(mDescriptor)和Stub物件(mOwner)的,再同傳入的客戶端的描述符比較相等,那就會返回繫結的服務端Stub物件。如果這個Binder對像是代理物件,那這個mDescriptor肯定是null,那就直接返回null。

執行跳出這個方法回到asInterface()函式中。 java public static com.zhukai.aidlservice.MyAIDLInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.zhukai.aidlservice.MyAIDLInterface))) {//不為null且型別匹配 return ((com.zhukai.aidlservice.MyAIDLInterface)iin);//把Stub物件轉換成實現的AIDL類 型別 } //否則返回代理物件,傳入了Binder代理物件。 return new com.zhukai.aidlservice.MyAIDLInterface.Stub.Proxy(obj); } 如果iin物件是服務端Stub物件,就直接轉換成AIDL類型別返回,為null,就會傳入Binder代理物件建立Proxy代理物件返回。反正,最終客戶端會拿到一個AIDL類物件,是受Binder物件的不同,返回物件有差異。本篇文章重點是圍繞Service另起程序的情況,也就是Binder為代理物件,那麼此方法將執行到最後一步,返回Proxy代理物件。因為服務端Service是在同一程序的情況下,客戶端拿到的是服務端Stub物件,就不存在IPC了,也就沒有往後分析的必要。

3.各型別函式內部實現分析

客戶端拿到Proxy代理物件,就可以呼叫所有函式與服務端進行通訊。 ```java if (null != myAIDLInterface){ myAIDLInterface.commonMethod(); myAIDLInterface.setStringText("test"); myAIDLInterface.setObjectMethodIn(new MethodObject()); myAIDLInterface.setObjectMethodInout(new MethodObject()); myAIDLInterface.setObjectMethodInout(new MethodObject()); myAIDLInterface.getObjectMethod(); myAIDLInterface.register(callBackAIDLInterface); myAIDLInterface.unregister(callBackAIDLInterface); }

CallBackAIDLInterface callBackAIDLInterface = new CallBackAIDLInterface.Stub() { @Override public void callBack() throws RemoteException {

}

}; ```

commonMethod()

點選進入commonMethod()函式,確是MyAIDLInterface介面的commonMethod()函式,但是因為myAIDLInterface物件實際是Proxy類物件,所以實際上是Proxy類中的實現方法,看下具體實現。 java @Override public void commonMethod() throws android.os.RemoteException { //序列化操作物件Parcel準備 android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR);//寫入描述符 boolean _status = mRemote.transact(Stub.TRANSACTION_commonMethod, _data, _reply, 0);//通過Binder呼叫服務端onTransact()函式,客戶端進入阻塞狀態。 if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通訊失敗,反之成功。 getDefaultImpl().commonMethod();//呼叫預設實現 return; } _reply.readException();//讀取服務端執行是否有異常 } finally {//釋放序列化操作物件 _reply.recycle(); _data.recycle(); } } 因為是IPC的過程,所以傳輸資料都需要進行序列化,所以開始建立了兩個序列化操作物件(_data,_reply)。 然後寫入了一段描述符,接著就直接呼叫了mRemote的transact()函式,傳入了一個標識(Stub.TRANSACTION_commonMethod)和兩個序列化物件(_data,_reply)以及一個int(flags)值。這個標識就是用於區分函式的,稱它為函式標識吧。 java static final int TRANSACTION_commonMethod = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_setStringText = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_setObjectMethodIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); static final int TRANSACTION_setObjectMethodOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); static final int TRANSACTION_setObjectMethodInout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4); static final int TRANSACTION_getObjectMethod = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5); static final int TRANSACTION_register = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6); static final int TRANSACTION_unregister = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7); mRemote就是初始化Proxy物件時傳入的Binder物件;忘記了可以回顧一下前面asInterface()函式的分析。執行到mRemote.transact()這一步其實就堵塞了,Binder機制會通知服務端Stub物件中的onTransact()函式(mRemote.transact()->服務端Binder.onTransact()->Stub類中重寫的onTransact()),現在我們去Stub類中onTransact()函式看下做了什麼。 java @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_commonMethod: { data.enforceInterface(descriptor); this.commonMethod(); reply.writeNoException(); return true; } case TRANSACTION_setStringText: { data.enforceInterface(descriptor); java.lang.String _arg0; _arg0 = data.readString(); this.setStringText(_arg0); reply.writeNoException(); return true; } case TRANSACTION_setObjectMethodIn: { data.enforceInterface(descriptor); com.zhukai.aidlservice.MethodObject _arg0; if ((0!=data.readInt())) { _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.setObjectMethodIn(_arg0); reply.writeNoException(); return true; } case TRANSACTION_setObjectMethodOut: { data.enforceInterface(descriptor); com.zhukai.aidlservice.MethodObject _arg0; _arg0 = new com.zhukai.aidlservice.MethodObject(); this.setObjectMethodOut(_arg0); reply.writeNoException(); if ((_arg0!=null)) { reply.writeInt(1); _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_setObjectMethodInout: { data.enforceInterface(descriptor); com.zhukai.aidlservice.MethodObject _arg0; if ((0!=data.readInt())) { _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.setObjectMethodInout(_arg0); reply.writeNoException(); if ((_arg0!=null)) { reply.writeInt(1); _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_getObjectMethod: { data.enforceInterface(descriptor); com.zhukai.aidlservice.MethodObject _result = this.getObjectMethod(); reply.writeNoException(); if ((_result!=null)) { reply.writeInt(1); _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_register: { data.enforceInterface(descriptor); com.zhukai.aidlservice.CallBackAIDLInterface _arg0; _arg0 = com.zhukai.aidlservice.CallBackAIDLInterface.Stub.asInterface(data.readStrongBinder()); this.register(_arg0); reply.writeNoException(); return true; } case TRANSACTION_unregister: { data.enforceInterface(descriptor); com.zhukai.aidlservice.CallBackAIDLInterface _arg0; _arg0 = com.zhukai.aidlservice.CallBackAIDLInterface.Stub.asInterface(data.readStrongBinder()); this.unregister(_arg0); reply.writeNoException(); return true; } default: { return super.onTransact(code, data, reply, flags); } } } 整體看下來,是通過不同的函式標識做了不同的邏輯處理。分析commonMethod()函式,根據函式標識判斷是TRANSACTION_commonMethod分支。 java case TRANSACTION_commonMethod: { data.enforceInterface(descriptor);//對描述符進行了校驗 this.commonMethod();//呼叫了自己的commonMethod()函式,也就是服務端Stub物件的commonMethod()函式。 reply.writeNoException();//寫入無異常 return true; } 首先對描述符進行了校驗,再呼叫了this.commonMethod()函式。這個this就是Stub物件,既呼叫了服務端Stub物件的commonMethod()函式。後面再寫入無異常,返回true代表執行成功。服務端執行完畢,客戶端阻塞恢復執行繼續執行下面程式碼。 java if (!_status && getDefaultImpl() != null) { getDefaultImpl().commonMethod(); return; } _reply.readException(); 失敗了一般也是不會有設定預設實現,所以後續就是執行讀取服務端寫入的異常,進行異常檢測,如果服務端寫入了異常,那客戶端將丟擲異常。感興趣可以點入原始碼檢視一下。這樣一次完整的通訊就完成了。

注:分析完commonMethod()函式,我們對AIDL基本的通訊邏輯已經清楚了,後續不同型別函式實現只是在處理細節上有所差異,差異都是存在客戶端Proxy實現函式和服務端Stub類onTransact()函式中。故後續只分析這兩個函式即可,並且直接把客服端和服務端兩個函式放在一起,便於直觀。

setStringText(String text)

```java //客戶端Proxy類 @Override public void setStringText(java.lang.String text) throws android.os.RemoteException { //序列化操作物件Parcel準備 android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR);//寫入描述符 _data.writeString(text);//寫入傳入的資料 boolean _status = mRemote.transact(Stub.TRANSACTION_setStringText, _data, _reply, 0);//通過Binder呼叫服務端onTransact()函式,客戶端進入阻塞狀態。 if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通訊失敗,反之成功。 getDefaultImpl().setStringText(text);//呼叫預設實現 return; } _reply.readException();//讀取服務端執行是否有異常 } finally {//釋放序列化操作物件 _reply.recycle(); _data.recycle(); } }

//服務端Stub類 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case TRANSACTION_setStringText: { data.enforceInterface(descriptor);//對描述符進行了校驗 java.lang.String _arg0; _arg0 = data.readString();//讀取客戶端寫入的資料 this.setStringText(_arg0);//呼叫自己的函式,並傳入讀取的資料 reply.writeNoException();//寫入無異常 return true; } } } ``` 差異主要是客戶端多了一步寫入資料,服務端相應的就多了一步讀取資料。

void setObjectMethodIn(in MethodObject o)

```java //客戶端Proxy類 @Override public void setObjectMethodIn(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException { //序列化操作物件Parcel準備 android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR);//寫入描述符 if ((o!=null)) {//資料物件不為null _data.writeInt(1);//寫入1,表示序列化物件不為null o.writeToParcel(_data, 0);//寫入序列化物件 } else { _data.writeInt(0);//寫入0,表示序列化資料物件為null } boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodIn, _data, _reply, 0);//通過Binder呼叫服務端onTransact()函式,客戶端進入阻塞狀態。 if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通訊失敗,反之成功。 getDefaultImpl().setObjectMethodIn(o);//呼叫預設實現 return; } _reply.readException();//讀取服務端執行是否有異常 } finally {//釋放序列化操作物件 _reply.recycle(); _data.recycle(); } }

//服務端Stub類 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case TRANSACTION_setObjectMethodIn: { data.enforceInterface(descriptor);//對描述符進行了校驗 com.zhukai.aidlservice.MethodObject _arg0; if ((0!=data.readInt())) {//客戶端有寫入0或1,非0代表序列化物件不為null _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data);//進行反序列化 } else { _arg0 = null; } this.setObjectMethodIn(_arg0);//呼叫自己的函式,傳入資料物件。 reply.writeNoException();//寫入無異常 return true; } } } ``` setObjectMethodIn()函式引數是一個物件型別,並在AIDL檔案中進行了in修飾字首修飾,引數的資料物件只能從客戶端傳入服務端,所以在邏輯上只在客戶端進行了序列化,在服務端進行反序列化,服務端的修改並不能影響到客戶端。

setObjectMethodOut(out MethodObject o)

```java //客戶端Proxy類 @Override public void setObjectMethodOut(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException { //序列化操作物件Parcel準備 android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR);//寫入描述符 boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodOut, _data, _reply, 0);//通過Binder呼叫服務端onTransact()函式,客戶端進入阻塞狀態。 if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通訊失敗,反之成功。 getDefaultImpl().setObjectMethodOut(o);//呼叫預設實現 return; } _reply.readException();//讀取服務端執行是否有異常 if ((0!=_reply.readInt())) {//服務端有寫入0或1,非0代表序列化物件不為null o.readFromParcel(_reply);//反序列化修改引數中資料物件o的資料 } } finally {//釋放序列化操作物件 _reply.recycle(); _data.recycle(); } }

//服務端Stub類 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case TRANSACTION_setObjectMethodOut: { data.enforceInterface(descriptor);//對描述符進行了校驗 com.zhukai.aidlservice.MethodObject _arg0; _arg0 = new com.zhukai.aidlservice.MethodObject();//建立一個數據物件 this.setObjectMethodOut(_arg0);//呼叫自己的函式,傳入剛剛建立的物件。 reply.writeNoException();//寫入無異常 if ((_arg0!=null)) {//資料物件不為null reply.writeInt(1);//寫入1,表示序列化資料物件不為null _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);//寫入序列化物件 } else { reply.writeInt(0);//寫入0,表示序列化資料物件為null } return true; } } } ``` setObjectMethodOut()函式引數也是一個物件型別,並在AIDL檔案中進行了out修飾字首修飾,客戶端引數資料物件無法傳輸到服務端,所以在客戶端呼叫mRemote.transact()函式之前,並沒有進行序列化寫入操作;但是因為服務端的修改是可以影響到客戶端的,所以在服務端的處理上直接建立了一個數據物件,並呼叫函式時傳入,使服務端進行操作,在方法執行完後,又進行了序列化寫入操作。當服務端無異常執行完成後,客戶端阻塞停止,反而客戶端通過反序列化對原本傳入的資料物件進行了資料修改。

setObjectMethodInout(inout MethodObject o)

java 客戶端Proxy類 @Override public void setObjectMethodInout(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException { //序列化操作類物件Pracel準備 android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR);//寫入描述符 if ((o!=null)) {//資料物件不為null _data.writeInt(1);//寫入1,表示序列化資料物件不為null o.writeToParcel(_data, 0);//寫入序列化物件 } else { _data.writeInt(0);//寫入0,表示序列化資料物件為null } boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodInout, _data, _reply, 0);//通過Binder呼叫服務端onTransact()函式,客戶端進入阻塞狀態。 if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通訊失敗,反之成功。 getDefaultImpl().setObjectMethodInout(o);//呼叫預設實現 return; } _reply.readException();//讀取服務端執行是否有異常 if ((0!=_reply.readInt())) {//服務端有寫入0或1,非0代表序列化物件不為null o.readFromParcel(_reply);//反序列化修改引數中資料物件o的資料 } } finally {//釋放序列化操作物件 _reply.recycle(); _data.recycle(); } } //服務端Stub類 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case TRANSACTION_setObjectMethodInout: { data.enforceInterface(descriptor);//對描述符進行了校驗 com.zhukai.aidlservice.MethodObject _arg0; if ((0!=data.readInt())) {//客戶端有寫入0或1,非0代表序列化物件不為null _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data);//進行反序列化 } else { _arg0 = null; } this.setObjectMethodInout(_arg0);//呼叫自己的函式,傳入剛剛的資料物件。 reply.writeNoException();//寫入無異常 if ((_arg0!=null)) {//資料物件不為null reply.writeInt(1);//寫入1,表示序列化資料物件不為null _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);//寫入序列化物件 } else { reply.writeInt(0);//寫入0,表示序列化資料物件為null } return true; } } } setObjectMethodInout()函式引數同樣是一個物件型別,並在AIDL檔案中進行了inout修飾字首修飾,引數的資料物件既能傳輸到服務端,同時服務端對資料物件的修改也能同步到客戶端,所以在邏輯處理上客服端在呼叫mRemote.transact()函式之前,進行了序列化處理,在服務端進行了反序列化處理。服務端在呼叫自己函式時傳入了這個反序列化得來的資料物件,同時函式執行完又將這個資料物件再進行序列化;等到服務端執行完畢後,客戶端阻塞停止,客戶端也進行一次反序列化,修改了引數傳入的資料物件資料。整體上就是前面兩個函式的邏輯結合,在客服端到服務端一次序列化和反序列化操作,從服務端回到客戶端也是一次序列化和反序列化操作。

MethodObject getObjectMethod()

前面函式都是沒有帶返回值的,這個函式是無參帶返回值。 java //客戶端Proxy類 @Override public com.zhukai.aidlservice.MethodObject getObjectMethod() throws android.os.RemoteException { //序列化操作物件Parcel準備 android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); com.zhukai.aidlservice.MethodObject _result; try { _data.writeInterfaceToken(DESCRIPTOR);//寫入描述符 boolean _status = mRemote.transact(Stub.TRANSACTION_getObjectMethod, _data, _reply, 0);//通過Binder呼叫服務端onTransact()函式,客戶端進入阻塞狀態 if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通訊失敗,反之成功。 return getDefaultImpl().getObjectMethod();//呼叫預設實現 } _reply.readException();//讀取服務端執行是否有異常 if ((0!=_reply.readInt())) {//服務端有寫入0或1,非0代表序列化物件不為null _result = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(_reply);//進行反序列化 } else { _result = null; } } finally {//釋放序列化操作物件 _reply.recycle(); _data.recycle(); } return _result;//返回資料物件 } //服務端Stub類 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case TRANSACTION_getObjectMethod: { data.enforceInterface(descriptor);//進行描述符校驗 com.zhukai.aidlservice.MethodObject _result = this.getObjectMethod();//呼叫自己的函式活的資料物件。 reply.writeNoException();//寫入無異常 if ((_result!=null)) {//資料物件不為null reply.writeInt(1);//寫入1,標識序列化資料物件不為null _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);//進行序列化操作 } else { reply.writeInt(0);//寫入0,標識序列化資料物件為null } return true; } } } MethodObject getObjectMethod()和setObjectMethodOut(out MethodObject o)函式在邏輯上有些相似,差異是客戶端在對服務端寫入的序列化物件進行反序列化處理時,因為setObjectMethodOut(out MethodObject o)函式原本引數中就有一個數據物件,所以直接呼叫了資料物件的readFromParcel()函式,通過反序列化修改了資料物件的資料;而MethodObject getObjectMethod()函式,則是要通過呼叫createFromParcel()函式,反序列化重新建立一個物件。但兩者在實現效果上都是一樣的。

register(CallBackAIDLInterface aidl)

java //客戶端Proxy類 @Override public void register(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException { //序列化操作物件Parcel準備 android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR);//寫入操作符 _data.writeStrongBinder((((aidl!=null))?(aidl.asBinder()):(null)));//寫入AIDl類的Binder物件 boolean _status = mRemote.transact(Stub.TRANSACTION_register, _data, _reply, 0);//通過Binder呼叫服務端onTransact()函式,客戶端進入阻塞狀態 if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通訊失敗,反之成功。 getDefaultImpl().register(aidl);//呼叫預設實現 return; } _reply.readException();//讀取服務端操作有無異常 } finally {//釋放序列化操作物件 _reply.recycle(); _data.recycle(); } } //服務端Stub類 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case TRANSACTION_register: { data.enforceInterface(descriptor);//對描述符進行校驗 com.zhukai.aidlservice.CallBackAIDLInterface _arg0; //讀取客戶端傳入的Binder物件並通過Stub.asInterface()函式獲取了Proxy代理物件 _arg0 = com.zhukai.aidlservice.CallBackAIDLInterface.Stub.asInterface(data.readStrongBinder()); this.register(_arg0);//呼叫自己的方法,傳入代理物件 reply.writeNoException();//寫入無異常 return true; } } } register(CallBackAIDLInterface aidl)函式引數是AIDL類型別,在實際的邏輯中並不是傳入的本身,而是傳入了自己的Binder物件(既客戶端建立的Stub物件的Binder物件,此時客戶端在角色上變成了服務端)。服務端讀取了傳入的Binder物件後,通過Stub.asInterface(data.readStrongBinder())函式完成了Proxy代理物件的獲取(此時服務端在角色上變成了客戶端),再呼叫自己的函式,把這個代理物件給服務端使用。

unregister(CallBackAIDLInterface aidl)函式不需要做額外的講解,跟register(CallBackAIDLInterface aidl)是一樣的。

四、總結

看完這個系列,希望能讓大家對AIDL有一個較深入的理解,篇幅較長,十分感謝大家能耐心看完!歡迎關注點贊,繼續閱讀AIDL系列文章,後續將努力學習輸出更高質量文章。