android的Binder通信機制java層淺談

1.Service Manager的Java代理對象

在Java層中,Service Manager的代理對象類型爲ServiceManagerProxy。它繼承並且實現了IServiceManager接口,其中四個成員函數和一個變量如下:
getService、checkService:獲取Java服務代理對象
addService:註冊Java服務
listService:獲取已經註冊的java服務表mRemote:類型爲Ibinder,指向了一個BinderProxy對象。這個對象用來描述Java服務代理對象,內部的成員變量mObject,指向c++層中的一個Binder代理對象。Java服務代理和c++層中的服務代理由此聯繫起來。
在Java層中,Service Manager的代理對象由Service Manager類創建。
其成員函數getIServiceManager,作用就是用來獲取Service Manager的Java遠程接口了,而這個函數又是通過ServiceManagerNative類的成員方法asInterface來獲取Service Manager的Java遠程接口的。
這裏寫圖片描述
從上面代碼可看出在調用asInterface函數之前,首先要通過getContextObject函數來獲得一個BinderProxy對象。
getContextObject是一個JNI方法:
這裏寫圖片描述
第3行調用函數獲得一個句柄爲NULL的Binder代理對象。第4行使用函數javaObjectForIBinde爲這個對象創建一個Java服務代理對象(BinderProxy)。
第3行調用函數獲得一個句柄爲NULL的Binder代理對象。第4行使用函數

javaObjectForIBinde爲這個對象創建一個Java服務代理對象(BinderProxy)。

這裏寫圖片描述
這裏傳進來的參數是一個BpBinder的指針,而BpBinder::checkSubclass繼承於父類IBinder::checkSubclass,它什麼也不做就返回false。於是直接向下執行:

會創建一個Java層的BinderProxy對象

這裏寫圖片描述
17行中,由於這個BpBinder對象是第一創建,它裏面什麼對象也沒有,因此,這裏返回的object爲NULL。繼續執行

最後的代碼如下:

這裏寫圖片描述

小結:整個的過程就是在Java層,我們擁有了一個Service Manager遠程接口ServiceManagerProxy,而這個ServiceManagerProxy對象在JNI層有一個句柄值爲0的BpBinder對象與之通過gBinderProxyOffsets關聯起來。這樣獲取Service Manager的Java遠程接口的過程就完成了。

2Java服務接口的定義

在實現Java服務之前,必須要定義這個Java服務接口。在Android中通過AIDL語言來定義Java服務接口。
首先,以一個硬件訪問服務爲例,其aidl文件如下:
setVal設置變量
getVal獲取變量
文件編譯後會生成一個IFregService.java文件
這裏寫圖片描述

IFregService.java文件展開如下:

這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

總結:

aidl文件編譯之後,就是根據IFregService接口的定義生成相應的Stub和Proxy類,即實現這個FregService的Server必須繼承於這裏的IFregService.Stub類,而這個FregService的遠程接口就是這裏的IFregService.Stub.Proxy對象獲得的IFregService接口。 ##

3Java服務接口的啓動

Java服務和binder服務一樣,同樣需要將自己註冊到Service Manager中,但是由於system和Android進程啓動的時候都會在內部啓動一個線程池,所以運行在裏面的Java服務啓動時,只需要註冊服務,不需要添加線程池。
服務FregService是從IFregService.Stub類繼承來的,是一個實現了IFregService接口的Java服務

定義如下

這裏寫圖片描述
第8行首先創建一個服務FregService,然後接着調用ServiceManager類的靜態成員函數addService來註冊。
首先分析創建過程:new FregService
由於硬件訪問服務FregService繼承了IFregService.Stub類,這個類繼承了Binder類,因此最終創建服務時會調用Binder類的構造函數。
構造函數調用了成員函數init來執行初始化工作,init是一個JNI方法。
這裏寫圖片描述

小結:

註冊Java服務時,並不是真的將Java服務註冊到Service Manager中,而是將它對應的一個類型爲JavaBBinder的本地對象註冊到Service Manager中。當這個JavaBBinder類型的本地對象收到來自client進程的進程間通信請求時,他就需要將這個請求發送給Java服務來處理。 ##

4Java服務代理對象的獲取

ava服務在註冊到Service Manager之後,Android應用程序就可以通過它來獲取一個Java服務的代理對象,通過代理對象,就可以使用相應的Java服務了。
因此,客戶端想要使用服務,首先要獲取Java服務的代理對象,下面分析流程:

客戶端中代碼如下:

這裏寫圖片描述
在第7行①通過ServiceManager類的靜態函數getService獲取名稱爲”freg”的Java服務代理對象;②使用IFregService.Stub類的函數asInterface將其轉化爲實現了服務接口的代理對象。

小結:

經過兩個函數的封裝,getService函數相當於下面語句這就是我們想要獲得的Java服務代理對象了。再獲取了Java代理對象後,就可以調用服務了。Binder機制在提供Java接口時使用了JNI方法封裝c++接口,使用AIDL語言來完成服務的定義,使用全局數據結構將Java服務接口中的各種對象和對應在c++層中的各個對象關聯起來,從而使Android應用可以通過Java語言使用Binder進程間通信。 ##

5實例

Service代碼如下:

這裏寫圖片描述

客戶端的activity代碼如下:

這裏寫圖片描述

aidl文件代碼如下:

這裏寫圖片描述

aidl對應的java文件內容爲:

這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

運行截圖

這裏寫圖片描述

普通服務 和系統服務是有些區別的:

①服務啓動和註冊:系統服務是需要更改Android源碼,將服務添加至systemserver中,並且隨開機啓動;此次實例是將服務編譯好之後把相應的包存放在客戶端功能內,當做一個數據文件來訪問的。
②調用:調用系統服務客戶端需要一個service manager的代理對象,靠它尋找服務的代理對象,並且完成服務;而此實例則是在客戶端內使用包含了這個服務的包以及相應的接口,是對系統服務調用的一個簡化。

Binder機制在java層和C++層的實現的相同點和不同點?

相同點:①這兩層的Binder機制結構是相同的。Java層的Binder機制實際上是對c++層次進行了一個封裝,使用JNI方法,使得Java代碼可以調用c++層中相應的函數。
②僅從使用方式來看兩個層是相同的。都是 首先需要一個Service Manager,隨後定義相關的服務,之後把服務註冊到Service Manager中;客戶端在使用服務時,首先獲得Service Manager的代理對象,之後從中找到相關的服務代理對象,在從這個服務代理對象中找到相關服務函數,調用函數完成Binder通信功能。
不同點:①數據結構:Java層想使用Binder機制就必須使用JNI方法調用C++層中的相應的對象,因此在Java層和c++層中要記錄相對應的對象的地址,把兩者關聯起來,在Java層中就可以完成c++層中的功能
②服務的定義:c++層運行在系統底層,因此服務的定義可以直接寫在頭文件中,隨系統運行。但是Java服務需要使用AIDL語言來定義,才能時Java服務接口有Binder通信能力。
③服務的啓動:c++層的服務需要由服務端自己分配Binder線程池,而Java層的服務隨着system啓動,不需要自己分配。
④服務的調用:c++層:首先獲得service manager的代理對象,通過它獲得一個服務的代理對象,通過服務代理對象完成通信。
Java:首先獲得Java層的service manager的代理對象,再通過JNI方法獲得c++層中Binder代理對象,將他封裝成Java服務的代理對象,返回給調用者,在使用函數的時候通過JNI方法使用c++層的Binder機制,通過Binder機制尋找Java層中相對應的服務。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章