圖解Android中的binder機制

前言

Binder作爲Android中核心機制,對於理解Android系統是必不可少的,關於binder的文章也有不少,可是每次看總感受看的不是很懂,到底什麼纔是binder機制?爲何要使用binder機制?binder機制又是怎樣運行的呢?這些問題只是瞭解binder機制是不夠的,須要從Android的總體系統出發來分析,在我找了不少資料後,真正的弄懂了binder機制,相信看完這篇文章你們也能夠弄懂binder機制。java

一、Binder是什麼?

要理解binder,先要知道IPC,Inter-process communication ,也就是進程中相互通訊,Binder是Android提供的一套進程間相互通訊框架。用來多進程間發送消息,同步和共享內存。已有的進程間通訊方式有一下幾種: android

在這裏插入圖片描述
一、Files 文件系統(包括內存映射) 二、Sockets 三、Pipes 管道 四、共享內存 五、Intents, ContentProviders, Messenger 六、Binder

Android系統中的Binder框架圖以下: web

在這裏插入圖片描述
拿Activity舉例從上圖能夠看出來:Activity是由ActivityManager來控制的,而ActivityManager實際上是經過Binder獲取ActivityManagerService服務來控制Activity的,而且ActivityManager是Android系統FrameWork層的,和應用中的activity不是同一個進程。

重點shell

一、Binder是Android提供的一套進程間通訊框架。設計模式

二、系統服務ActivityManagerService,LocationManagerService,等都是在單獨進程中的,使用binder和應用進行通訊。api

二、Android系統框架

在這裏插入圖片描述
如上圖,Android系統分紅三層。最上層是application應用層,第二層是Framework層,第三層是native層。 由下圖可知幾點:

一、Android中的應用層和系統服務層不在同一個進程,系統服務在單獨的進程中。緩存

二、Android中不一樣應用屬於不一樣的進程中。安全

Android應用和系統services運行在不一樣進程中是爲了安全,穩定,以及內存管理的緣由,可是應用和系統服務須要通訊和分享數據。數據結構

優勢app

安全性:每一個進程都單獨運行的,能夠保證應用層對系統層的隔離。

穩定性:若是某個進程崩潰了不會致使其餘進程崩潰。

內存分配:若是某個進程以及不須要了能夠從內存中移除,而且回收相應的內存。

三、Binder通訊

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;/* 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;
   };
複製代碼

可是上面還有個問題就是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框架

在看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的總體設計總共有四層:

一、Java層AIDL。

二、Framework層, Android.os.Binder 。

framework層中最重要的數據結構是transaction,有一下幾個默認的:

在這裏插入圖片描述

三、Native 層: libBinder.cpp

在native層主要是libBinder

在這裏插入圖片描述
四、內核層 內核層的通訊都是經過ioctl來進行的,client打開一個ioctl,進入到輪詢隊列,一直阻塞直到時間到或者有消息。

在這裏插入圖片描述

五、Binder中使用的設計模式

一、代理模式(Proxy Pattern ) 在Android中client不是直接去和binder打交道,client直接和Manager交互,而manager和managerProxy交互,也就是說client是經過managerProxy去和binder進行交互的。同時service也不是直接和binder交互,而是經過stub去和binder交互。以下圖。

在這裏插入圖片描述
二、Bridge Pattern 以下圖,應用層也就是Java層要使用MediaPlayer,就要調用native層中的MediaPlayer.cpp,可是MediaPlay.java不是直接去跟JNI打交道,而是經過與MediaPlayerSevice通訊,從而通過Binder返回的。
在這裏插入圖片描述

六、Binder與內存映射mmap

Binder IPC 是基於內存映射(mmap)來實現的,可是 mmap() 一般是用在有物理介質的文件系統上的。

好比進程中的用戶區域是不能直接和物理設備打交道的,若是想要把磁盤上的數據讀取到進程的用戶區域,須要兩次拷貝(磁盤-->內核空間-->用戶空間);一般在這種場景下 mmap() 就能發揮做用,經過在物理介質和用戶空間之間創建映射,減小數據的拷貝次數,用內存讀寫取代I/O讀寫,提升文件讀取效率。

而 Binder 並不存在物理介質,所以 Binder 驅動使用 mmap() 並非爲了在物理介質和用戶空間之間創建映射,而是用來在內核空間建立數據接收的緩存空間。

一次完整的 Binder IPC 通訊過程一般是這樣:

首先 Binder 驅動在內核空間建立一個數據接收緩存區; 接着在內核空間開闢一塊內核緩存區,創建內核緩存區和內核中數據接收緩存區之間的映射關係,以及內核中數據接收緩存區和接收進程用戶空間地址的映射關係; 發送方進程經過系統調用 copyfromuser() 將數據 copy 到內核中的內核緩存區,因爲內核緩存區和接收進程的用戶空間存在內存映射,所以也就至關於把數據發送到了接收進程的用戶空間,這樣便完成了一次進程間的通訊。 以下圖:

在這裏插入圖片描述

參考文獻

一、rts.lab.asu.edu/web_438/pro…

二、rts.lab.asu.edu/web_438/pro…

相關文章
相關標籤/搜索