Android中的binder機(jī)制詳解
Binder做為Android中核心機(jī)制,對(duì)于理解Android系統(tǒng)是必不可少的,關(guān)于binder的文章也有很多,但是每次看總感覺看的不是很懂,到底什么才是binder機(jī)制?為什么要使用binder機(jī)制?binder機(jī)制又是怎樣運(yùn)行的呢?這些問題只是了解binder機(jī)制是不夠的,需要從Android的整體系統(tǒng)出發(fā)來分析,在我找了很多資料后,真正的弄懂了binder機(jī)制,相信看完這篇文章大家也可以弄懂binder機(jī)制。
1、Binder是什么?要理解binder,先要知道IPC,Inter-process communication ,也就是進(jìn)程中相互通信,Binder是Android提供的一套進(jìn)程間相互通信框架。用來多進(jìn)程間發(fā)送消息,同步和共享內(nèi)存。已有的進(jìn)程間通信方式有一下幾種:
1、Files 文件系統(tǒng)(包括內(nèi)存映射) 2、Sockets 3、Pipes 管道 4、共享內(nèi)存 5、Intents, ContentProviders, Messenger 6、BinderAndroid系統(tǒng)中的Binder框架圖如下:
拿Activity舉例從上圖可以看出來:Activity是由ActivityManager來控制的,而ActivityManager其實(shí)是通過Binder獲取ActivityManagerService服務(wù)來控制Activity的,并且ActivityManager是Android系統(tǒng)FrameWork層的,和應(yīng)用中的activity不是同一個(gè)進(jìn)程。重點(diǎn):
1、Binder是Android提供的一套進(jìn)程間通信框架。
2、系統(tǒng)服務(wù)ActivityManagerService,LocationManagerService,等都是在單獨(dú)進(jìn)程中的,使用binder和應(yīng)用進(jìn)行通信。
2、Android系統(tǒng)框架如上圖,Android系統(tǒng)分成三層。最上層是application應(yīng)用層,第二層是Framework層,第三層是native層。 由下圖可知幾點(diǎn):1、Android中的應(yīng)用層和系統(tǒng)服務(wù)層不在同一個(gè)進(jìn)程,系統(tǒng)服務(wù)在單獨(dú)的進(jìn)程中。
2、Android中不同應(yīng)用屬于不同的進(jìn)程中。
Android應(yīng)用和系統(tǒng)services運(yùn)行在不同進(jìn)程中是為了安全,穩(wěn)定,以及內(nèi)存管理的原因,但是應(yīng)用和系統(tǒng)服務(wù)需要通信和分享數(shù)據(jù)。
優(yōu)點(diǎn)
安全性:每個(gè)進(jìn)程都單獨(dú)運(yùn)行的,可以保證應(yīng)用層對(duì)系統(tǒng)層的隔離。
穩(wěn)定性:如果某個(gè)進(jìn)程崩潰了不會(huì)導(dǎo)致其他進(jìn)程崩潰。
內(nèi)存分配:如果某個(gè)進(jìn)程以及不需要了可以從內(nèi)存中移除,并且回收相應(yīng)的內(nèi)存。
3、Binder通信client請(qǐng)求service服務(wù),比如說Activity請(qǐng)求Activity ManagerService服務(wù),由于Activity和ActivityManagerService是在兩個(gè)不同的進(jìn)程中的,那么下圖是一個(gè)很直觀的請(qǐng)求過程。
但是注意,一個(gè)進(jìn)程是不能直接直接操作另一個(gè)進(jìn)程的,比如說讀取另一個(gè)進(jìn)程的數(shù)據(jù),或者往另一個(gè)進(jìn)程的內(nèi)存空間寫數(shù)據(jù),進(jìn)程之間的通信要通過內(nèi)核進(jìn)程才可以,因此這里就要使用到進(jìn)程通信工具Binder了如下圖:
Binder driver通過/dev/binder /dev/binder 提供了 open, release release, poll poll, mmap mmap, flush flush, and ioctl等操作的接口api。這樣進(jìn)程A和進(jìn)程B就可以通過內(nèi)核進(jìn)程進(jìn)行通信了。進(jìn)程中大部分的通信都是通過ioctl(binderFd, BINDER_WRITE_READ, &bwd)來進(jìn)行的。bwd 的定義如下:
struct binder_write_read { signed long write_size;/* bytes to write */ signed long write_consumed; /* bytes consumed by driver */ unsigned long write_buffer; signed long read_size; /* bytes to read */ signed long read_consumed; /* bytes consumed by driver */ unsigned long read_buffer; };
但是上面還有個(gè)問題就是client和service要直接和binder driver打交道,但是實(shí)際上client和service并不想知道binder相關(guān)協(xié)議,所以進(jìn)一步client通過添加proxy代理,service通過添加stub來進(jìn)一步處理與binder的交互。
這樣的好處是client和service都可以不用直接去和binder打交道。上面的圖好像已經(jīng)很完善了,但是Android系統(tǒng)更進(jìn)一步封裝,不讓client知道Binder的存在,Android系統(tǒng)提供了Manager來管理client。如下圖:
這樣client只需要交給manager來管理就好了,根本就不用關(guān)心進(jìn)程通信相關(guān)的事,關(guān)于manager其實(shí)是很熟悉的,比如說activity的就是由ActivityManager來控制的,ActivityManager是通過Binder獲取ActivityManagerService來控制activity的。這樣就不用我們自己來使用Binder來ActivityManagerService通信了。更進(jìn)一步,client是如何具體獲取到哪個(gè)service的呢?如下圖所示:
在service和binder之間還有一個(gè)contextManager,也就是serviceManager,每一個(gè)service要先往serviceManager里面進(jìn)行注冊(cè),注冊(cè)完成之后由serviceManager統(tǒng)一管理。 在Android studio中可以通過adb指定打印出當(dāng)前已經(jīng)注冊(cè)過serviceManager的service。
$ adb shell service list Found 71 services: 0 sip: [android.net.sip.ISipService] 1 phone: [com.android.internal.telephony.ITelephony] … 20 location: [android.location.ILocationManager] … 55 activity: [android.app.IActivityManager] 56 package: [android.content.pm.IPackageManager] … 67 SurfaceFlinger: [android.ui.ISurfaceComposer] 68 media.camera: [android.hardware.ICameraService] 69 media.player: [android.media.IMediaPlayerService] 70 media.audio_flinger: [android.media.IAudioFlinger]
下圖是一次更加完整的client和service的通信流程:
在看Binder框架之前,先來看一下,從client發(fā)出請(qǐng)求service的完整的流程。
獲取服務(wù)過程:
第一步:client要請(qǐng)求服務(wù),比如說在activity中調(diào)用context.getSystemService()方法,這個(gè)時(shí)候serviceManager就會(huì)使用getService(name),然后就會(huì)調(diào)用到native層中的ServiceManagerNative類中的getService(name)方法。
第二步:ServiceManagerNative會(huì)通過Binder發(fā)送一條SVG_MGR_GET_SERVICE的指令,然后通過svcmgr_handler()調(diào)用do_find_service()方法去svc_list中查找到相關(guān)的service。
第三步:查找到相應(yīng)的服務(wù)后就會(huì)通過Binder將服務(wù)傳給ServiceManagerNative,然后傳給serviceManager,最后client就可以使用了。
注意: 服務(wù)實(shí)在svclist中保存的,svclist是一個(gè)鏈表,因此客戶端調(diào)用的服務(wù)必須要先注冊(cè)到svclist中。
注冊(cè)服務(wù)過程:
第一步: service通過調(diào)用serviceManager中的addService方法,然后調(diào)用ServiceManagerNative類中的addservice(name)方法。
第二步: ServiceManagerNative會(huì)通過Binder發(fā)送一條SVG_MGR_ADD_SERVICE的指令,然后通過svcmgr_handler()調(diào)用do_add_service()方法往svc_list中添加相應(yīng)的service。
重點(diǎn):所有的服務(wù)都要先注冊(cè)到svc_list中才能被client調(diào)用到。svc_list以linkedlist的形式保存這些服務(wù)。
Binder結(jié)構(gòu)設(shè)計(jì) 要了解binder的結(jié)構(gòu)設(shè)計(jì),就要了解Android的體系結(jié)構(gòu),Android是分成application層,framework層native層,以及內(nèi)核層,Binder設(shè)計(jì)在每一層上都有不同的抽象。如下圖:
由上圖可知Binder的整體設(shè)計(jì)總共有四層:1、Java層AIDL。
2、Framework層, Android.os.Binder 。
framework層中最重要的數(shù)據(jù)結(jié)構(gòu)是transaction,有一下幾個(gè)默認(rèn)的:
3、Native 層: libBinder.cpp
在native層主要是libBinder
4、內(nèi)核層 內(nèi)核層的通信都是通過ioctl來進(jìn)行的,client打開一個(gè)ioctl,進(jìn)入到輪詢隊(duì)列,一直阻塞直到時(shí)間到或者有消息。
1、代理模式(Proxy Pattern ) 在Android中client不是直接去和binder打交道,client直接和Manager交互,而manager和managerProxy交互,也就是說client是通過managerProxy去和binder進(jìn)行交互的。同時(shí)service也不是直接和binder交互,而是通過stub去和binder交互。如下圖。
2、Bridge Pattern 如下圖,應(yīng)用層也就是Java層要使用MediaPlayer,就要調(diào)用native層中的MediaPlayer.cpp,但是MediaPlay.java不是直接去跟JNI打交道,而是通過與MediaPlayerSevice通信,從而經(jīng)過Binder返回的。
Binder IPC 是基于內(nèi)存映射(mmap)來實(shí)現(xiàn)的,但是 mmap() 通常是用在有物理介質(zhì)的文件系統(tǒng)上的。
比如進(jìn)程中的用戶區(qū)域是不能直接和物理設(shè)備打交道的,如果想要把磁盤上的數(shù)據(jù)讀取到進(jìn)程的用戶區(qū)域,需要兩次拷貝(磁盤-->內(nèi)核空間-->用戶空間);通常在這種場景下 mmap() 就能發(fā)揮作用,通過在物理介質(zhì)和用戶空間之間建立映射,減少數(shù)據(jù)的拷貝次數(shù),用內(nèi)存讀寫取代I/O讀寫,提高文件讀取效率。
而 Binder 并不存在物理介質(zhì),因此 Binder 驅(qū)動(dòng)使用 mmap() 并不是為了在物理介質(zhì)和用戶空間之間建立映射,而是用來在內(nèi)核空間創(chuàng)建數(shù)據(jù)接收的緩存空間。
一次完整的 Binder IPC 通信過程通常是這樣:
首先 Binder 驅(qū)動(dòng)在內(nèi)核空間創(chuàng)建一個(gè)數(shù)據(jù)接收緩存區(qū); 接著在內(nèi)核空間開辟一塊內(nèi)核緩存區(qū),建立內(nèi)核緩存區(qū)和內(nèi)核中數(shù)據(jù)接收緩存區(qū)之間的映射關(guān)系,以及內(nèi)核中數(shù)據(jù)接收緩存區(qū)和接收進(jìn)程用戶空間地址的映射關(guān)系; 發(fā)送方進(jìn)程通過系統(tǒng)調(diào)用 copyfromuser() 將數(shù)據(jù) copy 到內(nèi)核中的內(nèi)核緩存區(qū),由于內(nèi)核緩存區(qū)和接收進(jìn)程的用戶空間存在內(nèi)存映射,因此也就相當(dāng)于把數(shù)據(jù)發(fā)送到了接收進(jìn)程的用戶空間,這樣便完成了一次進(jìn)程間的通信。 如下圖:
1、rts.lab.asu.edu/web_438/pro…
2、rts.lab.asu.edu/web_438/pro…
以上就是Android中的binder機(jī)制詳解的詳細(xì)內(nèi)容,更多關(guān)于Android binder的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. asp中response.write("中文")或者js中文亂碼問題2. CSS hack用法案例詳解3. ASP.NET Core實(shí)現(xiàn)中間件的幾種方式4. JSP servlet實(shí)現(xiàn)文件上傳下載和刪除5. 詳解盒子端CSS動(dòng)畫性能提升6. css代碼優(yōu)化的12個(gè)技巧7. 詳解瀏覽器的緩存機(jī)制8. CSS3中Transition屬性詳解以及示例分享9. 怎樣打開XML文件?xml文件如何打開?10. 怎樣才能用js生成xmldom對(duì)象,并且在firefox中也實(shí)現(xiàn)xml數(shù)據(jù)島?
