編輯:關於Android編程
Binder機制是一種C/S結構,主要包括三部分,分別為Client、Server、ServiceManager。ServiceManager是谷歌設計的,它是一段簡潔的C代碼(位置在native/cmds/servicemanager/service_manager.c),主要是方便集中管理系統中的各種服務,也方便Client和Server查詢系統中的服務信息。
我們首先來看一個跟ServiceManager很大關聯的類,它就是IServiceManager類:
該類包括四個方法,名字就不重復了,通過這些方法可以注冊服務、查詢服務信息等,另外它還有一個enum枚舉,enum包含與方法相對應的四個常量。查看源碼我們可知enum常量的值為1,2,3,4。
GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION,
};
其中IBinder::FIRST_CALL_TRANSACTION的值為1,這裡的取值是很重要的,因為他們分別對應ServiceManager(service_manager.c)中的enum常量:
enum {
SVC_MGR_GET_SERVICE = 1,
SVC_MGR_CHECK_SERVICE,
SVC_MGR_ADD_SERVICE,
SVC_MGR_LIST_SERVICES,
};
該enum在native/cmds/servicemanager/binder.h位置,service_manager.c程序引用了binder.h。這樣C/S實現IServiceManager接口後,如果C/S傳遞GET_SERVICE_TRANSACTION參數,ServiceManager(service_manager.c)就能對應SVC_MGR_GET_SERVICE處理了,其他類似。
之所以開頭就講IServiceManager類,是因為我覺得從宏觀上對C/S和ServiceManager的關系有一個大概的印象很重要,如下圖所示:
如何看到這裡你在好奇使用的是什麼軟件畫圖的,我鄭重的推薦一下Gliffy畫圖軟件,而且它有chrome插件,相比viso等軟件更輕、更簡單。
在上圖IServiceManager和ServiceManager之間什麼都沒有畫,那他們是如何通信的呢?其實他們是通過一種叫Binder設備進行通信的,這也是今天的主題,如果不了解設備的概念,建議查看linux的相關知識。我們將Binder設備加入可得到下圖:
從上圖我們知道了IServiceManager和ServiceManager可以通過Binder通信,但是還沒有和C/S關聯,我們加上C/S後來看看效果圖,如下所示:
因為Client與binder通信在java層涉及的層次太多,我們主要分析Server與Binder的通信。
main_mediaserver作為Server端,肯定會與mediaplayerservice關聯,defaultServiceManager方法可以獲得BpServiceManager對象,這樣通過該對象就能與binder設備通信。MediaPlayerService::instantiate()這句很重要,是main_mediaserver和mediaplayerservice關聯的橋梁,該方法的具體代碼如下:
voidMediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"),new MediaPlayerService());
}
我們看出instantiate方法的作用是將MediaPlayerService注冊到ServiceManager中,這裡又出現了defaultServiceManager方法,說明注冊服務也是通過BpServiceManager來執行的。
回到main_mediaserver我們找不到defaultServiceManager方法,但是我們可以找到如下聲明:
#include
從上面代碼我們只能看出gDefaultServiceManager是IServiceManager類,而不能確定它就是BpServiceManager類。我們繼續跟蹤,首先關注ProcessState類,它是一個記錄進程狀態的類。之前的圖中我們在Server和BpServiceManager之間添加的就是ProcessState,不記得可以回頭看一下,之所以放在這麼重要的位置,那是因為Binder設備的操作都是跟進程關聯的,一個進程共享一個Binder設備。我們來看看ProcessState::self()->getContextObject(NULL)具體內容:
我們跟進getStrongProxyForHandle(0)(位置在native/libs/binder/ProcessState.cpp),內容如下:
由上面的代碼我們知道getStrongProxyForHandle(0)返回的是BpBinder,所以defaultServiceManager()方法可以簡化為
gDefaultServiceManager= interface_cast
interface_cast在IServiceManager類中沒有定義,它是在父類頭文件IInterface.h中定義的,它是一個模板方法,位置在native/include/binder/IInterface.h中,如下所示:
上述代碼中的INTERFACE模板類為IServiceManager,這是在defaultServiceManager()方法中傳入的,所以gDefaultServiceManager =IServiceManager::asInterface(new BpBinder(0))。這樣我們跟蹤IServiceManager的asInterface()方法,但是在IServiceManager中沒有找到該方法,我們繼續在父類IInterface.cpp中找,我們可以找到如下代碼:
我們進一步簡化gDefaultServiceManager= new BpServiceManager(new BpBinder(0)),其實BpServiceManager沒有什麼特別的意義,它都是通過BpBinder去通信的,它的意義是就在於保存BpBinder對象以供MediaPlayerService調用。BpServiceManager中的成員變量mRemote就是用來保存BpBinder對象的,mRemote變量定義在BpRefbase類中,繼承關系如下:
階段總結,我們可以知道defaultServiceManager()方法得到是BpServcieManager對象,並且BpServiceManager對象中的變量mRemote保存了BpBinder對象。
回顧之前的main_mediasever.cpp類,我們知道MediaPlayerService服務是通過MediaPlayerService::instantiate()這句代碼將自己注冊到ServerManager,我們再回顧一下具體顯示的代碼:
voidMediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"),new MediaPlayerService());
}
之前我們分析過defaultServiceManager方法得到的是BpServiceManager,我們就以MediaPlayerService的addService過程為例分析一下《BpServiceManager到Binder設備的過程》。
我們進入BpServiceManager的addService方法看看,位置在native/libs/binder/IServiceManager.cpp,實現代碼如下:注意data.writeStrongBinder(service)這句代碼,service就是MediaPlayerService::instantiate方法中new的MediaPlayerService對象。感興趣話可以追蹤writeStrongBinder方法的實現,它的主要作用就是將MediaPlayerService對象保存在Parcel對象中並通過binder設備傳遞給ServerManager ,這樣以後就可以通過該對象與ServiceManager和Client通信了。
remote()方法就是獲得mRemote對象,調用BpBinder的transact方法就能與Binder設備通信了,我們進入transact方法看一下:
IPCThreadState是什麼呢?之前我們介紹過ProcessState類,我們知道ProcessState類是記錄進程的狀態,IPCThreadState跟ProcessState有很大的關系,從字面意思來講,IPCThreadState就是IPC有關線程的狀態,也就是一個進程可能同時存在好多線程與外界的進程通過IPC通信,用圖描述如下:
我們進入IPCThreadState(位置在native/libs/binder/IPCThreadState.cpp)的transact方法中看看:
代碼中的writeTransactionData方法,主要是將數據寫入Pacel緩存中,方便進行比較等操作,但是真正的傳遞數據是在waitForResponse方法中,代碼如下:
注意talkWithDriver方法,我們再進入該方法中看看:
注意mProcess變量,由之前IPCThreadState和ProcessState關系圖我們知道該mProcess變量就是指向ProcessState對象,所以mProcess->mDriverFD指向的就是進程中唯一的Binder設備,這樣就可以將數據寫入Binder設備來傳遞數據。
ServiceManager處理Binder數據的過程
開頭我們就說了ServiceManager其實是一段C程序,那我們看看service_manager.c的代碼(位置在native/cmds/servicemanager/service_manager.c):
其中bs = binder_open(128*1024)就是打開binder設備,第一感覺就是128*1024的size是不是太小了,驅動相關的朋友有知道的請不吝賜教。我們關注後面的binder_loop方法,它就是負責操作binder設備,定義在native/cmds/servicemanager/binder.c
從代碼的內容可以看出該方法裡面包含了一個死循環,這樣一旦service_manager.c程序運行後,該程序就開始監聽binder設備的數據了。binder_write_read結構體是用來在binder設備傳遞數據的,如果需要了解更詳細的信息請參考其它資料。通過ioctl方法可以獲得binder設備中的數據,那有事怎麼解析的呢?我們看看binder_parse方法的代碼:
從代碼中可以看出,binder.c會根據ptr的指針所指類型進行不同的響應。
以我們之前的分析經驗可以知道操作binder設備主要跟進程的ProcessState和IPCThreadState類有關,我們跟蹤IPCThreadState::self()->joinThreadPool()看看:
注意該方法中的talkWithDriver帶的參數是false,當Server端是注冊服務或初始化時傳遞的參數是false,我們現在分析的是Server端接收數據,所以我們分析getAndExecuteCommand方法,跟蹤進去看看:
這裡也看到talkWithDriver,而且默認傳遞的參數是true,不信的話可以去IPCThreadState.h頭文件看看,位置在native/include/binder/IPCThreadState.h。
有之前《BpServiceManager到Binder設備的過程》的最後一步talkWithDriver方法的分析,我們知道talkWithDriver方法會與binder設備打交道,通過ioctl方法傳遞數據,並將binder數據緩存到Parcel對象,那我們現在分析一下Server如何處理從Binder設備讀取的數據吧。首先從緩存Parcel中讀取數據:
cmd =mIn.readInt32()
此時的cmd的類型就是BR_TRANSACTION了,然後我們進入executeCommand方法看看,代碼太長我們截取主要部分:關鍵就是sp
voidMediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"),new MediaPlayerService());
}
我們傳遞進去的是MediaPlayerService對象,並通過後續BpServiceManager中的writeStrongBinder將MediaPlayerService打包成Parcel傳遞給ServiceManager的。但是即便這樣,MediaPlayerService跟BBinder又有什麼關系呢?我們來看一下MediaPlayerService的繼承關系:很激動,我們發現MediaPlayerService繼承BBinder,那tr.cookie就是指向MediaPlayerService對象了。有了MediaPlayerService對象後,Server(main_mediaserver.cpp)就能調用MediaPlayerService的transact方法做出響應了,transact的具體實現我們就不分析了。
雖然我們知道了MediaPlayerService通過binder_transaction_data.cookie域傳遞,但是我們對Server和ServcieManager之間數據的傳遞沒有一個很直觀的印象,我相信你看完之後會有一個更深的理解。我們在這裡引用侯亮的圖片簡單說明一下:
我們簡單分析一下紅線表示的流程,當我們在Server端(即圖片中的發起端進程)需要向ServerManager(目標端進程)注冊服務時,在驅動層會創建實體樹的根binder_node,將Server端的MediaPlayerService對象保存到cookie域,只有被其他進程調用時才會創建引用樹的根binder_ref。當目標端進程需要用到Server端MediaPlayerService服務時,直接在驅動層訪問binder_node的cookie域就能拿到MediaPlayerServcie對象了,再通過transact方法傳遞數據。
很多人在用刷機精靈最新版時,除了看到很多確實可以用到的功能,也發現了一個根本沒想過會去用也並不了解的功能,那就是adb命令工具。如果你在刷機過程中有點閱歷,
anddroid studio的內存修改昨天有位朋友問到了下面的一個問題這個判斷為android studio的分配的內存不夠用。據我的了解造成這個的原因主要有以下幾個方
項目介紹 因為要參加某信息安全比賽,選擇了安卓apk的行為分析與評估的課題,所以首先需要了解安卓程序是怎樣編寫和運行的。我們的第一個任務就是寫出一個多人通信的app。
1、Context說明 Context是一個用於訪問全局信息的接口,如應用程序的資源(如圖片,字符串等),一些常用的組件繼承自Context,如Activity和Serv
status_t AudioSystem::setStreamVolum