生活随笔
收集整理的這篇文章主要介紹了
两种AIDL用法分析(原)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? ? ? 我們在前面介紹了關于AIDL的兩種用法,第一種用法主要用在應用層中(
應用層的AIDL調用
),第二種用法主要用在framework中(
Framework中的AIDL調用
)。但是這兩種用法中都提到了Stub、asInterface等關鍵字,在這一節中我們主要針對AIDL內部機制的分析來深入理解AIDL調用的過程。
? ? ? ? 為了便于分析,我們還拿第一節中我們自己搭建的例子去分析。
? ? ? ? 當時我們在Eclipse Android工程的Java包目錄中建立了一個擴展名為aidl的文件(IMyService.aidl),并寫下需要的接口。Eclipse會在gen目錄下生成一個IMyService.Java的文件。
一、整體結構
? ? ? ? 我們打開IMyService.Java文件查看,發現他的結構是這樣的:
[java]?view plaincopy
public?interface?IMyService?extends?android.os.IInterface?{?? ?????? ????public?static?abstract?class?Stub?extends?android.os.Binder?implements?aidl.pac.IMyService?{?? ????????public?Stub()?{?? ????????}?? ?????????? ????????public?static?aidl.pac.IMyService?asInterface(android.os.IBinder?obj)?{?? ????????}?? ????????public?android.os.IBinder?asBinder()?{?? ????????}?? ?????????? ????????public?boolean?onTransact(int?code,?android.os.Parcel?data,????android.os.Parcel?reply,?int?flags)?? ????????????????throws?android.os.RemoteException?{?? ????????}?? ?????????? ????????private?static?class?Proxy?implements?aidl.pac.IMyService?{?? ????????????private?android.os.IBinder?mRemote;?? ?????????????? ????????????Proxy(android.os.IBinder?remote)?{?? ????????????}?? ????????????public?android.os.IBinder?asBinder()?{?? ????????????}?? ????????????public?java.lang.String?getInterfaceDescriptor()?{?? ????????????}?? ?????????????? ????????????public?java.lang.String?getValue()?? ????????????????????throws?android.os.RemoteException?{?? ????????}?? ?????????? ????????static?final?int?TRANSACTION_getValue?=?(android.os.IBinder.FIRST_CALL_TRANSACTION?+?0);?? ????}?? ????public?java.lang.String?getValue()?throws?android.os.RemoteException;?? }??
? ? ? ? 下面是一個結構圖:? ? ? ? ? ? ? 整體上來看,IMyService.java文件中的IMyService類有一個Stub的內部類,還有一個getValue方法。這個方法就是我們在aidl中定義的方法。同時我們看到,生成的IMyService繼承自IInterface,說明這也是一個接口,并沒有對getValue進行實現。
? ? ? ? 對于getValue這個方法,當我們在服務端的內部類中繼承了IMyService.Stub抽象類以后,就需要對未曾實現的getValue方法進行定義。
? ? ? ? 再來看IMyService的內部類Stub。這個內部類是一個實現了IMyService接口的Binder抽象類。內部有3個方法asInterface、asBinder、onTransact,還有一個內部類Proxy。
二、得到的遠端Service對象
? ? ? ? 現在我們來看一下客戶端當初得到的服務端對象的情況,當我們連接上服務端后,會被動調用onServiceConnected方法:
[java]?view plaincopy
public?void?onServiceConnected(ComponentName?name,?IBinder?service)?{?? ????mIMyService?=?IMyService.Stub.asInterface(service);?? }??
? ? ? ? 在這里得到的service對象其實就是MyServiceImpl對象,他是實現了IMyService.Stub具體接口的IBinder。再來看一下asInterface:
[java]?view plaincopy
public?static?aidl.pac.IMyService?asInterface(android.os.IBinder?obj)?{?? ?????? ????return?new?aidl.pac.IMyService.Stub.Proxy(obj);?? }??
? ? ? ? 可以看出,onServiceConnected參數是遠程服務端的IBinder對象,返回值是IMyService.Stub.Proxy(obj),這里的Proxy是Stub的內部類:
[java]?view plaincopy
private?static?class?Proxy?implements?aidl.pac.IMyService?{}??
? ? ? ? 內部除了構造方法以外,只有getValue方法:
[java]?view plaincopy
?? public?java.lang.String?getValue()????throws?android.os.RemoteException?{?? ????_data.writeInterfaceToken(DESCRIPTOR);?? ?????? ????mRemote.transact(Stub.TRANSACTION_getValue,?_data,?_reply,0);?? ????_reply.readException();?? ????_result?=?_reply.readString();?? ????return?_result;?? }??
? ? ? ? 到這里我們看到,Proxy內部確實擁有服務端的各個方法,但
這些方法并不是真實的實現,而只是通過mRemote.transact傳輸出去
。
? ? ? ? 也就是說,
在客戶端通過mIMyService = IMyService.Stub.asInterface(service)得到的就是Proxy對象,可以通過這個對象間接的調用服務端的各個方法,而具體調用過程就是經過mRemote.transact傳輸給真正的Service(也就是MyService.MyServiceImpl類)
。
? ? ? ? 那么,具體來說,我們是如何通過這個代理對象調用到真實的getValue呢?
三、如何通過代理對象調用遠端Service方法
? ? ? ? 在代理類的getValue方法中看到,他是調用了mRemote.transact的方法。
? ? ? ? 而mRemote.transact的方法通過底層的Binder通訊,將數據傳輸給服務端進程,并調用服務端的onTransact方法:
[java]?view plaincopy
public?boolean?onTransact(int?code,?android.os.Parcel?data,????android.os.Parcel?reply,?int?flags){?? ????switch?(code)?{?? ?????????? ????????case?TRANSACTION_getValue:?{?? ????????????data.enforceInterface(DESCRIPTOR);?? ????????????java.lang.String?_result?=?this.getValue();?? ????????????reply.writeNoException();?? ????????????reply.writeString(_result);?? ????????????return?true;?? ????????}?? ????}?? ????return?super.onTransact(code,?data,?reply,?flags);?? }??
? ? ? ? 因為當初得到的遠程服務對象是MyServiceImpl的對象,因此這里的this就指向了MyServiceImpl類。
因此getValue方法就進入到了MyServiceImpl的內部,也就是遠程服務端的內部。由此完成了一次完整的調用過程。
四、AIDL總結 ? ?
? ? ? ? 1、AIDL要是實現的最終目標是
跨進程訪問
,簡單的說就是得到另一個進程的對象,并調用其方法。
? ? ? ? 2、AIDL與接口類似,
本質屬性都是一個Interface
(AIDL文件是IInterface,而Interface是繼承自Interface的),而且都只定義了抽象方法,沒有具體的實現,需要子類去實現。
? ? ? ? 3、與接口不同的是:
由AIDL生成的stub類本質上是一個Binder
!這個類所生成的對象有兩種方式可以傳遞給另外一個進程:
? ? ? ? ? ? ? ? 3.a、一種是通過bindService的方式,綁定一個服務,而在綁定后,服務將會返回給客戶端一個Binder的對象,此時可以把繼承自stub的Binder傳遞給客戶端。
? ? ? ? ? ? ? ? 3.b、另外一種就是把繼承自stub的類提升為系統服務,此時,我們通過ServiceManager去得到當前的系統服務,ServiceManager就會把目標Service的Binder對象傳遞給客戶端。
? ? ? ? 4、經過上面兩種方法得到的Binder對象,就像得到了本地的某個對象一樣,可以調用其遠程的方法。
原文地址:?http://blog.csdn.net/u010961631/article/details/12082161
總結
以上是生活随笔為你收集整理的两种AIDL用法分析(原)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。