【Binder 机制】AIDL 分析 ( AIDL 通信完整流程梳理 )
文章目錄
- AIDL 跨進(jìn)程通信完整流程梳理
- 1、AIDL 文件編譯
- 2、注冊(cè)服務(wù)
- 3、IMyAidlInterface.Stub.asInterface 方法獲取遠(yuǎn)程服務(wù)
- 4、IMyAidlInterface.Stub.Proxy 代理類
- 5、IMyAidlInterface.Stub.Proxy 代理類方法執(zhí)行
- 6、Binder.transact 方法執(zhí)行
- 7、IMyAidlInterface.Stub.onTransact 方法執(zhí)行
- 8、調(diào)用 Service 中實(shí)現(xiàn)的 IMyAidlInterface.Stub 抽象方法
AIDL 跨進(jìn)程通信完整流程梳理
1、AIDL 文件編譯
AIDL 文件 IMyAidlInterface.aidl 在客戶端和服務(wù)端都有 , 編譯時(shí) , 都會(huì)在 " build\generated\aidl_source_output_dir\debug\out\kim\hsl\aidl_demo " 目錄生成 IMyAidlInterface.java 源文件 ;
這樣在客戶端與服務(wù)器端都可以調(diào)用 IMyAidlInterface.Stub 類的相關(guān)方法 , 主要是 asInterface 方法 , 用于獲取遠(yuǎn)程服務(wù)或代理 ;
2、注冊(cè)服務(wù)
在應(yīng)用中 , 通過(guò)綁定 Service 注冊(cè)服務(wù) ;
// 通過(guò) Action 和 包名 , 綁定遠(yuǎn)程服務(wù)Intent intent = new Intent("android.intent.action.MyService");intent.setPackage("kim.hsl.aidl_demo");bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);3、IMyAidlInterface.Stub.asInterface 方法獲取遠(yuǎn)程服務(wù)
開(kāi)啟一個(gè) ServiceConnection , 在 ServiceConnection 的 onServiceConnected 方法中 ,
調(diào)用 IMyAidlInterface.Stub.asInterface 方法 ,
在 IMyAidlInterface.Stub.asInterface 方法中 , 傳入我們需要的 Service 遠(yuǎn)程服務(wù) ; 這里涉及到跨進(jìn)程調(diào)用 , 拿到的是一個(gè)代理 ;
Stub 中定義了 asInterface 方法 , 該方法的作用是將 android.os.IBinder 對(duì)象轉(zhuǎn)為 AIDL 接口對(duì)象 ; 傳入的 DESCRIPTOR 描述符 , 用于描述用戶想要哪個(gè) Binder , android.os.IBinder 對(duì)象調(diào)用 queryLocalInterface 方法 , 檢查本地服務(wù)是否存在 ;
- 如果可以找到本地服務(wù)對(duì)應(yīng)的接口 , 可以直接返回本地服務(wù) ;
- 如果沒(méi)有找到本地服務(wù) , 就會(huì)返回一個(gè) Stub 代理 ;
詳細(xì)的過(guò)程參考下面的代碼 :
/*** 將IBinder對(duì)象強(qiáng)制轉(zhuǎn)換為kim.hsl.aidl_demo.IMyAidlInterface接口,必要時(shí)生成代理。*/public static kim.hsl.aidl_demo.IMyAidlInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}// 傳入 DESCRIPTOR 描述符 , 用于描述用戶想要哪個(gè) Binder// android.os.IBinder 對(duì)象調(diào)用 queryLocalInterface 方法 , 檢查本地服務(wù)android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);// 如果可以找到本地服務(wù)對(duì)應(yīng)的接口 , 可以直接返回本地服務(wù) if (((iin!=null)&&(iin instanceof kim.hsl.aidl_demo.IMyAidlInterface))) {return ((kim.hsl.aidl_demo.IMyAidlInterface)iin);}// 如果沒(méi)有找到本地服務(wù) , 就會(huì)返回一個(gè) Stub 代理 return new kim.hsl.aidl_demo.IMyAidlInterface.Stub.Proxy(obj);}4、IMyAidlInterface.Stub.Proxy 代理類
上述 IMyAidlInterface.Stub.asInterface 方法 , 最終返回一個(gè)代理 , 代理如下 :
在 IMyAidlInterface.java 中的代理中 , 實(shí)現(xiàn)了 333 個(gè) AIDL 接口方法 ;
private static class Proxy implements kim.hsl.aidl_demo.IMyAidlInterface{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{}/*** in 寫(xiě)入, out 輸出, inout 寫(xiě)入和輸出*/@Override public void addStudent(kim.hsl.aidl_demo.Student student) throws android.os.RemoteException{}/*** 獲取 Student 集合*/@Override public java.util.List<kim.hsl.aidl_demo.Student> getStudents() throws android.os.RemoteException{return _result;}}5、IMyAidlInterface.Stub.Proxy 代理類方法執(zhí)行
在主應(yīng)用中 , 調(diào)用 IMyAidlInterface aidl 也就是 IMyAidlInterface.Stub.asInterface 方法返回的代理對(duì)象的 addStudent 方法 , 分析代理中的該方法 , 首先生成輸入和輸出數(shù)據(jù) , 傳參和反參都會(huì)傳入 mRemote.transact 方法中 , 這是 Binder 的方法 ;
/*** in 寫(xiě)入, out 輸出, inout 寫(xiě)入和輸出*/@Override public void addStudent(kim.hsl.aidl_demo.Student student) throws android.os.RemoteException{// 通過(guò) Parcel 池獲得兩個(gè)對(duì)象 , 分別用于輸入和輸出// 輸入對(duì)象android.os.Parcel _data = android.os.Parcel.obtain();// 輸出對(duì)象android.os.Parcel _reply = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);if ((student!=null)) {_data.writeInt(1);student.writeToParcel(_data, 0);}else {_data.writeInt(0);}// 調(diào)用 Binder 的 transact 方法 boolean _status = mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);if (!_status && getDefaultImpl() != null) {getDefaultImpl().addStudent(student);return;}_reply.readException();if ((0!=_reply.readInt())) {student.readFromParcel(_reply);}}finally {_reply.recycle();_data.recycle();}}6、Binder.transact 方法執(zhí)行
Binder 中的 transact 方法執(zhí)行后 , 會(huì)回調(diào) IMyAidlInterface.java 中的 Stub 內(nèi)部類的 onTransact 方法 ,
Binder 的 transact 方法 ; 進(jìn)入該方法后 , 會(huì)將原來(lái)的線程掛起 , 直到返回 , 原來(lái)的線程才會(huì)繼續(xù)執(zhí)行 , 這里非常容易出現(xiàn) ANR ;
/*** 遠(yuǎn)程對(duì)象的基類,由{@link IBinder}定義的輕量級(jí)遠(yuǎn)程過(guò)程調(diào)用機(jī)制的核心部分。* 此類是IBinder的一個(gè)實(shí)現(xiàn),它提供了此類對(duì)象的標(biāo)準(zhǔn)本地實(shí)現(xiàn)。** <p>大多數(shù)開(kāi)發(fā)人員不會(huì)直接實(shí)現(xiàn)這個(gè)類,* 而是使用<a href=“{@docRoot}guide/components/aidl.html”>aidl</a>工具來(lái)描述所需的接口,* 讓它生成適當(dāng)?shù)腂inder子類。* 然而,您可以直接從Binder派生來(lái)實(shí)現(xiàn)您自己的定制RPC協(xié)議,* 或者直接實(shí)例化一個(gè)原始Binder對(duì)象,將其用作可以跨進(jìn)程共享的令牌。** <p>這個(gè)類只是一個(gè)基本的IPC原語(yǔ);* 它對(duì)應(yīng)用程序的生命周期沒(méi)有影響,并且只有創(chuàng)建它的進(jìn)程繼續(xù)運(yùn)行時(shí)才有效。* 要正確使用此功能,您必須在頂級(jí)應(yīng)用程序組件(a{@link android.app.Service}、* {@link android.app.Activity}或{@link android.content.ContentProvider})* 的上下文中執(zhí)行此操作,該組件應(yīng)保持運(yùn)行。</p>** <p>您必須記住流程可能會(huì)消失的情況,因此需要稍后重新創(chuàng)建新的活頁(yè)夾,* 并在流程再次啟動(dòng)時(shí)重新附加它。* 例如,如果您在{@link android.app.Activity}中使用此函數(shù),* 則您的活動(dòng)的進(jìn)程可能會(huì)在活動(dòng)未啟動(dòng)時(shí)被終止;* 如果以后重新創(chuàng)建活動(dòng),則需要?jiǎng)?chuàng)建新的活頁(yè)夾,* 并再次將其交回正確的位置;* 您需要注意的是,您的流程可能由于其他原因(例如接收廣播)而啟動(dòng),* 這將不涉及重新創(chuàng)建活動(dòng),因此運(yùn)行其代碼以創(chuàng)建新的綁定。</p>** @see IBinder*/ public class Binder implements IBinder {/*** 默認(rèn)實(shí)現(xiàn)回放地塊并調(diào)用onTransact。在遠(yuǎn)程端,transact調(diào)用綁定器來(lái)執(zhí)行IPC。*/public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,int flags) throws RemoteException {if (false) Log.v("Binder", "Transact: " + code + " to " + this);if (data != null) {data.setDataPosition(0);}boolean r = onTransact(code, data, reply, flags);if (reply != null) {reply.setDataPosition(0);}return r;} }7、IMyAidlInterface.Stub.onTransact 方法執(zhí)行
在 IMyAidlInterface.Stub.onTransact 方法中 , 通過(guò)方法對(duì)應(yīng)的 ID 常量值匹配方法 , 在該方法中就會(huì)調(diào)用 IMyAidlInterface.Stub 中沒(méi)有實(shí)現(xiàn)的抽象方法 ;
@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_basicTypes:{return true;}case TRANSACTION_addStudent:{return true;}case TRANSACTION_getStudents:{return true;}default:{return super.onTransact(code, data, reply, flags);}}}8、調(diào)用 Service 中實(shí)現(xiàn)的 IMyAidlInterface.Stub 抽象方法
IMyAidlInterface.Stub 中的抽象方法 , 在 Service 中實(shí)現(xiàn) ;
/*** 創(chuàng)建 IMyAidlInterface.Stub 抽象類子類對(duì)象 , 實(shí)現(xiàn)其中的 3 個(gè)抽象方法* Binder 調(diào)用 transact 方法時(shí) , 會(huì)調(diào)用 IMyAidlInterface.Stub 的 onTransact 方法* 在 IMyAidlInterface.Stub.onTransact 方法中會(huì)調(diào)用下面實(shí)現(xiàn)的抽象方法*/private IMyAidlInterface.Stub stub = new IMyAidlInterface.Stub() {@Overridepublic void basicTypes(int anInt, long aLong,boolean aBoolean, float aFloat, double aDouble,String aString) throws RemoteException {Log.i(TAG, "anInt=" + anInt + " , aLong=" + aLong +" , aBoolean=" + aBoolean + " , aFloat=" + aFloat +" , aDouble=" + aDouble + " , aString=" + aString);}@Overridepublic void addStudent(Student student) throws RemoteException {if (students != null) {students.add(student);}}@Overridepublic List<Student> getStudents() throws RemoteException {return students;}};總結(jié)
以上是生活随笔為你收集整理的【Binder 机制】AIDL 分析 ( AIDL 通信完整流程梳理 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Binder 机制】AIDL 分析 (
- 下一篇: 【错误记录】Windows 系统 bat