一绊含、緣由
網上有很多關于AIDL原理的講述,但一直有個疑問是binder為什么在service端是stub炊汹,而客戶端拿到就變成BinerProxy躬充?網上講了很多,但一到這個地方就一筆帶過讨便,所以決定自己研究下充甚。
二、首先簡述下AIDL使用流程
1.創(chuàng)建AIDL文件
AIDL文件會在build下生成java文件霸褒。如下:
在service中創(chuàng)建binder伴找,實現stub并在service的onBind()中返回如下:
在另一個進程中綁定
單步調試看下傳過來的binder
可以看到客戶端是BinderProxy類型。
三废菱、分析service綁定流程尋找stub在何處被轉化成了binderProxy
要找到從哪里轉化必須分析service綁定流程技矮,
從bindService函數起
ContextWrapper.java中
我們知道是裝飾模式,實現在ContextImpl.java中
調用bindServiceCommon函數
可以看到這個ActivityManagerNative.getDefault().bindService殊轴,通過代理實際上調用了ActivityManagerService.java的bindService函數
繼續(xù)bindServiceLocked函數衰倦,太長截取關鍵代碼
調用了bringUpServiceLocked函數,繼續(xù)
調用了realStartServiceLodcked函數
調用了scheduleCreateService和requestServiceBindingsLocked旁理,猜想這兩個函數就是創(chuàng)建service和bindservice樊零,成功后肯定回調service的onCreate和onBind。
此處又用到了代理孽文,實際上實現函數在ActivityThread.java中驻襟,我關心的是onBind回調,所以直接看scheduleBindService這個函數
又用了個message芋哭,繼續(xù)
終于找到了沉衣,通過調用service的onBind函數拿到了Binder,此時binder還是stub類楷掉。緊接著通過代理調用了ActivityManagerService的publishService函數厢蒜,看到binder是直接作為參數傳進去的霞势。
參數繼續(xù)傳,繼續(xù)跟蹤
binder沒做處理斑鸦,直接回調了c.conn.connected愕贡。在一開始ContextImpl.java的bindServiceCommon函數中做了一些準備工作,就是創(chuàng)建這個回調類巷屿。此處調用到了
繼續(xù)
繼續(xù)
在doConnected中調用了ServiceConnection類的onServiceConnected函數固以,就是我們在客戶端寫的綁定回調。流程結束嘱巾,不過問題沒解決憨琳,參數binder始終沒變,哪里搗鬼旬昭?
從handleBindService拿到binder開始起篙螟,此時還是服務端service進程,和ActivityManagerService交互问拘,將binder交給了ActivityManagerService,ActivityManagerService又交給客戶端回調onServiceConnected遍略。
剛才分析時遇到ActivityManagerNative.getDefault(),由于也是binder通信骤坐,直接找到了實現ActivityManagerService進行分析绪杏。
這里有兩點:
1.我們寫的service和ActivityManagerService通過binder進行傳輸。
2.傳輸時的又有一個binder作為參數纽绍。這個binder是我們寫的service和client通信用的binder蕾久。
重新分析下ActivityManagerNative.getDefault().publishService( data.token, data.intent, binder);
在ActivityManagerNative定義了Proxy端操作
Parcel類型,通過writeStrongBinder將binder寫入拌夏,分析Parcel.java
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
調到了jni了僧著,在android_os_Parcel.cpp中
ibinderForJavaObject將binder轉化為C++層對應得binder,也就是JavaBBinderHolder障簿,JavaBBinderHolder是個裝飾類霹抛,里面有JavaBBinder,而JavaBBinder繼承BBinder卷谈。最后通過Parcel.java中的writeStrongBinder寫入到binder驅動中杯拐。
writeStrongBinder調用flatten_binder
flatten_binder區(qū)分了情況本地binder將type置為BINDER_TYPE_BINDER
我們當然在研究跨進程的binder,所以此處置為BINDER_TYPE_HANDLE世蔗,并創(chuàng)建了BpBinder類端逼。BpBinder就是BinderProxy在C++層的對應類。分析到此處大致明白污淋,讀取binder的時候肯定是找到BpBinder顶滩,進而找到BinderProxy,返回給了ActivityManagerService寸爆。
看下怎們讀取的
看ActivityManagerService如何拿到傳過來的binder礁鲁,類似
通過readStrongBinder拿到binder盐欺,然后調用了publishService()函數給客戶端〗龃迹看jni對應的函數
此處終于明白了冗美,parcel->readStrongBinder()找到BpBinder,javaObjectForIBinder()返回對應的BinderProxy給ActivityManagerService析二。
如下
之前寫的時候置位了粉洼,是BINDER_TYPE_HANDLE
在getStrongProxyForHandle中判斷BpBinder是否存在,直接找到或創(chuàng)建并返回叶摄。
再看javaObjectForIBinder()
通過對應關系找到BinderProxy属韧,如果找不到就創(chuàng)建BinderProxy,并將BinderProxy和BpBinder建立對應關系蛤吓。gBinderProxyOffsets即jni調用java的BinderProxy類宵喂。如下
所以在ActivityManagerService拿到binder的時候,這個binder已經是BinderProxy会傲,后面給到客戶端回調onServiceConnected函數樊破。
分析完畢。
四唆铐,小結
一開始有這個疑問還是由于對binder的結構了解不深入”蓟總結兩點艾岂。
(1)Binder分為java層Binder和C++層Binder。Android代碼中使用binder的方式很靈活朋其,可以不關心C++層層Binder王浴,直接通過java層Binder封裝使用,即本例討論的AIDL方式梅猿∶ダ保可以在C++直接創(chuàng)建BBbinder和BpBinder來進行通信,比如深入理解android中講到的MediaServer袱蚓。當然也可以一側使用java钞啸,另一側使用C。更直接的可能直接通過ioctl方式直接寫入binder驅動都可能喇潘。不了解binder的結構就發(fā)現各種資料講解的都不一樣体斩,其實只是這幾種使用方式的排列組合。只要了解一點颖低,BinderProxy對應BpBinder絮吵,Binder對應BBinder的關系就不會錯。
(2)系統(tǒng)service都在SystemServer進行注冊忱屑,系統(tǒng)service的binder都是通過SystemServer查找拿到蹬敲。SystemServer負責返回給客戶端代理對象即BinderProxy暇昂。匿名binder,即本例討論的AIDL伴嗡,在和ActivityManagerService傳輸的過程中進行轉化急波。binder作為對象被傳輸,具體就是通過writeStrongBinder和readStrongBinder闹究。