Android中的binder機(jī)制詳解
前言
Binder做為Android中核心機(jī)制,對于理解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、Binder
Android系統(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)用層對系統(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請求service服務(wù),比如說Activity請求Activity ManagerService服務(wù),由于Activity和ActivityManagerService是在兩個(gè)不同的進(jìn)程中的,那么下圖是一個(gè)很直觀的請求過程。
但是注意,一個(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)行注冊,注冊完成之后由serviceManager統(tǒng)一管理。 在Android studio中可以通過adb指定打印出當(dāng)前已經(jīng)注冊過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的通信流程:
4、Binder框架
在看Binder框架之前,先來看一下,從client發(fā)出請求service的完整的流程。
獲取服務(wù)過程:
第一步:client要請求服務(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ù)必須要先注冊到svclist中。
注冊服務(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ù)都要先注冊到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í)間到或者有消息。
5、Binder中使用的設(shè)計(jì)模式
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返回的。
6、Binder與內(nèi)存映射mmap
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)程間的通信。 如下圖:
參考文獻(xià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的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android實(shí)現(xiàn)環(huán)信修改頭像和昵稱
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)環(huán)信修改頭像和昵稱,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02Android UI使用HorizontalListView實(shí)現(xiàn)水平滑動(dòng)
這篇文章主要為大家詳細(xì)介紹了Android UI使用HorizontalListView實(shí)現(xiàn)水平滑動(dòng)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01Android數(shù)據(jù)加密之異或加密算法的實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄狝ndroid數(shù)據(jù)加密之異或加密算法的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-10-10Android 斷點(diǎn)續(xù)傳原理以及實(shí)現(xiàn)
這篇文章主要介紹了Android 斷點(diǎn)續(xù)傳原理以及實(shí)現(xiàn)的相關(guān)資料,這里對斷點(diǎn)續(xù)傳原理進(jìn)行了詳細(xì)介紹,需要的朋友可以參考下2016-12-12Android獲取系統(tǒng)儲存以及內(nèi)存信息的方法(一)
這篇文章主要為大家詳細(xì)介紹了Android獲取系統(tǒng)儲存以及內(nèi)存信息的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Android中LeakCanary檢測內(nèi)存泄漏的方法
本篇文章主要介紹了Android中LeakCanary檢測內(nèi)存泄漏的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09