繼上一篇AIDL的簡單介紹,相信應該對AIDL有一個大體的瞭解,那麼這一篇咱們來深刻探討一下AIDL爲何可以完成這個跨進程操做,這其中是否隱藏着一些鮮爲人知的祕密,讓咱們跟着筆者的思路,慢慢撥開籠罩在AIDL上的謎團。java
先用上圖總體描述這個AIDL從客戶端(Client)發起請求至服務端(Server)相應的工做流程,咱們能夠看出總體的核心就是Binderandroid
用於將服務端的Binder對象轉換成客戶端所需的AIDL接口類型的對象,這種轉換過程是區分進程的【若是客戶端和服務端位於同一進程,那麼此方法返回的就是服務端的Stub對象自己,不然返回的是系統封裝後的Stub.proxy對象】iphone
private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IDemandManager demandManager = IDemandManager.Stub.asInterface(service); } };
在ServiceConnection
綁定服務的方法裏,咱們經過IDemandManager.Stub.asInterface(service)
方法得到IDemandManager
對象,咱們跟着asInterface
步伐看看裏面有什麼名堂。
PS : onServiceConnected
方法的(IBinder)service參數在ActivityThread建立,他們之間還會扯出ActivityManagerService,ManagerService等,有興趣的能夠經過Activity 的啓動過程加深功力,深刻了解。ide
從上圖的類結構圖中咱們能夠看出,這個IDemandManager.aidl文件經過編譯成爲一個接口類,而這個類最核心的成員是Stub類和Stub的內部代理類Proxy。
順着asInterface
方法,結合上面對該方法的描述,能夠看出經過DESCRIPTOR
標識判斷
若是是同一進程,那麼就返回Stub對象自己(obj.queryLocalInterface(DESCRIPTOR)
),不然若是是跨進程則返回Stub的代理內部類Proxy。
也就是說這個asInterface
方法返回的是一個遠程接口具有的能力(有什麼方法能夠調用),在咱們項目裏,asInterface
的能力就是get/setDemand和註冊/解綁監聽接口。工具
緊接着asInterface
,咱們看到一個簡潔的方法asBinder
this
顧名思義,asBinder用於返回當前Binder對象。spa
//Stub @Override public android.os.IBinder asBinder() { return this; }
//Proxy private android.os.IBinder mRemote; @Override public android.os.IBinder asBinder() { return mRemote; }
根據代碼咱們能夠追溯到,proxy的這個mRemote就是綁定服務(bindService)時候
由IDemandManager.Stub.asInterface(binder);
傳入的IBinder
對象。.net
這個Binder對象具備跨進程能力,在Stub類裏面(也就是本進程)直接就是Binder本地對象,在Proxy類裏面返回的是遠程代理對象(Binder代理對象)。[因此跨進程的謎團,會隨着對Binder的分析和研究,逐漸變得清晰起來。]線程
由於咱們這個編譯生成的IDemandManager
接口繼承了android.os.IInterface
接口,因此咱們先分析IInterface
接口。代理
public interface IDemandManager extends android.os.IInterface
而這個IInterface
接口就只聲明瞭一個方法,可是Stub和Proxy都分別間接的實現了該接口。
/** * Base class for Binder interfaces. When defining a new interface, * you must derive it from IInterface. */ public interface IInterface { /** * Retrieve the Binder object associated with this interface. * You must use this instead of a plain cast, so that proxy objects * can return the correct result. */ public IBinder asBinder(); }
Binder接口的基類。 定義新接口時,
你必須實現IInterface接口。檢索與此界面關聯的Binder對象。
你必須使用它而不是一個簡單的轉換
這樣代理對象才能夠返回正確的結果。
從上面的系統註釋中咱們能夠理解出:
IInterface
Binder
表達出這個能力。
private static final java.lang.String DESCRIPTOR = "qdx.aidlserver.IDemandManager";//系統生成的
Binder的惟一標識,通常用當前Binder的類名錶示。
咱們發現IDemandManager
接口,實際上並無太多複雜的方法,看完了asInterface
和asBinder
方法,咱們再來分析onTransact
方法。
onTransact
方法運行在服務端中的Binder線程池中
客戶端發起跨進程請求時,遠程請求會經過系統底層封裝後交給此方法來處理。
若是此方法返回false,那麼客戶端的請求就會失敗。
也就是說,這個onTransact
方法就是服務端處理的核心,接收到客戶端的請求,而且經過客戶端攜帶的參數,執行完服務端的方法,返回結果。下面經過系統生成的代碼,咱們簡要的分析一下onTransact
方法裏咱們項目寫的setDemandIn
和setDemandOut
方法。
case TRANSACTION_setDemandIn: { data.enforceInterface(DESCRIPTOR); qdx.aidlserver.MessageBean _arg0; if ((0 != data.readInt())) { _arg0 = qdx.aidlserver.MessageBean.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.setDemandIn(_arg0); reply.writeNoException(); return true; } case TRANSACTION_setDemandOut: { data.enforceInterface(DESCRIPTOR); qdx.aidlserver.MessageBean _arg0; _arg0 = new qdx.aidlserver.MessageBean(); this.setDemandOut(_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; }
此段代碼並無多少玄機,就是負責數據的讀寫,以及結果的返回。
可是有一個知識點能夠在此驗證,就是定向tag的做用,上面的方法定向tag分別是in和out,上篇文章介紹定向tag的做用就是跨進程中數據的流向,setDemandIn
方法中咱們能夠看到咱們讀取了客戶端傳遞過來的數據參數data,即客戶端->服務端。out方法能夠同理自行分析。AIDL中的in,out,inout分析
分析完了Stub,就剩下Stub的內部代理類Proxy
驚奇的發現Proxy類主要是用來方法調用,也就是用來客戶端的跨進程調用。
transact
方法運行在客戶端,首先它建立該方法所須要的輸入型Parcel對象_data、輸出型Parcel對象_reply;
接着調用綁定服務傳來的IBinder對象的transact方法來發起遠程過程調用(RPC)請求,同時當前線程掛起;
而後服務端的onTransact
方法會被調用,直到RPC過程返回後,當前線程繼續執行,並從_reply中取出RPC過程的返回結果,也就是返回_reply中的數據。
咱們看到得到Parcel
的方法爲Parcel.obtain()
,按照套路這個應該就是從Parcel
池中獲取該對象,減小建立對象的開支,跟進方法咱們能夠看得的確是建立了一個POOL_SIZE
爲6的池用來獲取Parcel
對象。
因此在跨進程通信中Parcel是通信的基本單元,傳遞載體。
而這個transact
方法是一個本地方法,在native層中實現,功力不足,點到爲止。
分析到了這裏,感受頓悟了許多,再一次引用開頭概述的圖片來看大概,總體的思路便浮在腦海中。so 噠死內~
經過對AIDL的分析,咱們發現原來這一切圍繞着Binder有序的展開
AIDL經過Stub類用來接收並處理數據,Proxy代理類用來發送數據,而這兩個類也只是經過對Binder的處理和調用,下一篇咱們將深刻摸清這個Binder究竟爲什麼物,可以輕鬆遊走於跨進程之中。
因此所謂的服務端和客戶端,咱們拆開看以後發現原來竟是不一樣類的處理
Stub充當服務端角色,持有Binder實體(本地對象)。
Proxy代理類充當客戶端角色,持有Binder引用(句柄)。
並且所謂的服務端和客戶端都是相對而言的,服務端不只能夠接收和處理消息,並且能夠定時往客戶端發送數據,與此同時服務端使用Proxy類跨進程調用,至關於充當了」Client」。
而且有一點要理解是,跨進程通信的時候,傳遞的數據對象並非從進程A原本來本的發給進程B。庫克說要送你蘋果,而你收到的iphone X就真的是美國生產的嗎?不,它也多是made in China.
終上所述,AIDl這個工具就已經分析結束,若是文中有不足之處還望指出。若是有什麼更好的看法也能夠留言,最終的目標都是共同進步。有興趣的能夠繼續看Android Binder之應用層總結與分析。
AIDL文章借鑑(上)
AIDL文章借鑑(下) 最後感謝《Android 開發藝術探索》專業的分析。