碼個蛋(codeegg) 第 936 次推文
作者:Hanking
連結:https://juejin.im/post/5e89f717f265da47e6491496
Binder做為Android中核心機制,對於理解Android系統是必不可少的,關於binder的文章也有很多,但是每次看總感覺看的不是很懂,到底什麼才是binder機制?為什麼要使用binder機制?binder機制又是怎樣運行的呢?這些問題只是了解binder機制是不夠的,需要從Android的整體系統出發來分析,在我找了很多資料後,真正的弄懂了binder機制,相信看完這篇文章大家也可以弄懂binder機制。
要理解binder,先要知道IPC,Inter-process communication ,也就是進程中相互通信,Binder是Android提供的一套進程間相互通信框架。用來多進程間發送消息,同步和共享內存。已有的進程間通信方式有一下幾種:
1、Files 文件系統(包括內存映射)
2、Sockets
3、Pipes 管道
4、共享內存
5、Intents, ContentProviders, Messenger
6、Binder
Android系統中的Binder框架圖如下:
拿Activity舉例從上圖可以看出來:Activity是由ActivityManager來控制的,而ActivityManager其實是通過Binder獲取ActivityManagerService服務來控制Activity的,並且ActivityManager是Android系統FrameWork層的,和應用中的activity不是同一個進程。
重點:
1、Binder是Android提供的一套進程間通信框架。
2、系統服務ActivityManagerService,LocationManagerService,等都是在單獨進程中的,使用binder和應用進行通信。
如上圖,Android系統分成三層。最上層是application應用層,第二層是Framework層,第三層是native層。由下圖可知幾點:
1、Android中的應用層和系統服務層不在同一個進程,系統服務在單獨的進程中。
2、Android中不同應用屬於不同的進程中。
Android應用和系統services運行在不同進程中是為了安全,穩定,以及內存管理的原因,但是應用和系統服務需要通信和分享數據。
優點
安全性:每個進程都單獨運行的,可以保證應用層對系統層的隔離。
穩定性:如果某個進程崩潰了不會導致其他進程崩潰。
內存分配:如果某個進程以及不需要了可以從內存中移除,並且回收相應的內存。
client請求service服務,比如說Activity請求Activity ManagerService服務,由於Activity和ActivityManagerService是在兩個不同的進程中的,那麼下圖是一個很直觀的請求過程。
但是注意,一個進程是不能直接直接操作另一個進程的,比如說讀取另一個進程的數據,或者往另一個進程的內存空間寫數據,進程之間的通信要通過內核進程才可以,因此這裡就要使用到進程通信工具Binder了如下圖:
Binder driver通過/dev/binder
/dev/binder 提供了 open, release release, poll poll, mmap mmap, flush flush, and ioctl 等操作的接口api。這樣進程A和進程B就可以通過內核進程進行通信了。
進程中大部分的通信都是通過ioctl(binderFd, BINDER_WRITE_READ, &bwd)來進行的。bwd 的定義如下:
struct binder_write_read { signed long write_size; signed long write_consumed; unsigned long write_buffer; signed long read_size; signed long read_consumed; unsigned long read_buffer;};
但是上面還有個問題就是client和service要直接和binder driver打交道,但是實際上client和service並不想知道binder相關協議,所以進一步client通過添加proxy代理,service通過添加stub來進一步處理與binder的交互。
這樣的好處是client和service都可以不用直接去和binder打交道。上面的圖好像已經很完善了,但是Android系統更進一步封裝,不讓client知道Binder的存在,Android系統提供了Manager來管理client。如下圖:
這樣client只需要交給manager來管理就好了,根本就不用關心進程通信相關的事,關於manager其實是很熟悉的,比如說activity的就是由ActivityManager來控制的,ActivityManager是通過Binder獲取ActivityManagerService來控制activity的。這樣就不用我們自己來使用Binder來ActivityManagerService通信了。
更進一步,client是如何具體獲取到哪個service的呢?如下圖所示:
在service和binder之間還有一個contextManager,也就是serviceManager,每一個service要先往serviceManager裡面進行註冊,註冊完成之後由serviceManager統一管理。在Android studio中可以通過adb指定列印出當前已經註冊過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發出請求service的完整的流程。
獲取服務過程:
第一步:client要請求服務,比如說在activity中調用context.getSystemService()方法,這個時候serviceManager就會使用getService(name),然後就會調用到native層中的ServiceManagerNative類中的getService(name)方法。
第二步:ServiceManagerNative會通過Binder發送一條SVG_MGR_GET_SERVICE的指令,然後通過svcmgr_handler()調用do_find_service()方法去svc_list中查找到相關的service。
第三步:查找到相應的服務後就會通過Binder將服務傳給ServiceManagerNative,然後傳給serviceManager,最後client就可以使用了。
注意: 服務實在svclist中保存的,svclist是一個鍊表,因此客戶端調用的服務必須要先註冊到svclist中。
註冊服務過程:
第一步: service通過調用serviceManager中的addService方法,然後調用ServiceManagerNative類中的addservice(name)方法。
第二步: ServiceManagerNative會通過Binder發送一條SVG_MGR_ADD_SERVICE的指令,然後通過svcmgr_handler()調用do_add_service()方法往svc_list中添加相應的service。
重點:所有的服務都要先註冊到svc_list中才能被client調用到。svc_list以linkedlist的形式保存這些服務。
Binder結構設計要了解binder的結構設計,就要了解Android的體系結構,Android是分成application層,framework層native層,以及內核層,Binder設計在每一層上都有不同的抽象。如下圖:
由上圖可知Binder的整體設計總共有四層:
1、Java層AIDL。
2、Framework層, Android.os.Binder 。
framework層中最重要的數據結構是transaction,有一下幾個默認的:
3、Native 層: libBinder.cpp
在native層主要是libBinder
4、內核層內核層的通信都是通過ioctl來進行的,client打開一個ioctl,進入到輪詢隊列,一直阻塞直到時間到或者有消息。
1、代理模式(Proxy Pattern )在Android中client不是直接去和binder打交道,client直接和Manager交互,而manager和managerProxy交互,也就是說client是通過managerProxy去和binder進行交互的。同時service也不是直接和binder交互,而是通過stub去和binder交互。如下圖。
2、Bridge Pattern如下圖,應用層也就是Java層要使用MediaPlayer,就要調用native層中的MediaPlayer.cpp,但是MediaPlay.java不是直接去跟JNI打交道,而是通過與MediaPlayerSevice通信,從而經過Binder返回的。
今天的文章就到這裡了,圖還是挺多的,有沒有覺得好理解多了?相關文章:
今日問題:
Binder理解得怎麼樣啦?
專屬升級社區:《疫魔無情碼個蛋有愛,招聘社區助大家找到更心怡的工作》