




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
【移動應(yīng)用開發(fā)技術(shù)】Binder的示例分析
在下給大家分享一下Binder的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!1、為什么是Binder?1.1傳統(tǒng)IPC機(jī)制的缺點(diǎn)大家都知道Android系統(tǒng)是基于Linux內(nèi)核實(shí)現(xiàn)的,Linux已經(jīng)提供了多種進(jìn)程間通信機(jī)制,比如:管道、消息隊列、共享內(nèi)存和套接字(Socket)等等,為什么還要再實(shí)現(xiàn)一套IPC機(jī)制呢?主要是基于兩方面的原因:1.1.1性能角度管道、消息隊列、Socket實(shí)現(xiàn)一次進(jìn)程通信都需要2次內(nèi)存拷貝,效率太低;共享內(nèi)存雖然不需要拷貝內(nèi)存,但管理復(fù)雜;Binder只需要一次內(nèi)存拷貝,從性能角度來看,低于共享內(nèi)存方式,優(yōu)于其它方式。1.1.2安全性考慮傳統(tǒng)的IPC機(jī)制沒有安全措施,接收方無法獲得對方可靠的進(jìn)程ID或用戶ID,完全靠上層的協(xié)議來保護(hù),比如Socket通信的IP地址是客戶端填入的,很可能被惡意程序篡改。Android作為面向終端用戶的開源平臺,應(yīng)用市場中有海量的應(yīng)用供用戶選擇,因此安全性極為重要。Android系統(tǒng)為每個已安裝的App都分配了用戶ID(UID),UID是鑒別進(jìn)程身份的重要標(biāo)識,通過UID可以進(jìn)行一系列的權(quán)限校驗(yàn)。另一方面
,傳統(tǒng)IPC的接入點(diǎn)是開放的,任何程序都可以根據(jù)協(xié)議進(jìn)行訪問,無法阻止惡意程序的訪問,Android需要一種基于C/S架構(gòu)的IPC機(jī)制,Server端需要能夠?qū)lient的請求進(jìn)行身份校驗(yàn),來保證數(shù)據(jù)的安全性。1.2Linux的一些基本知識要知道Binder是如何只用一次內(nèi)存拷貝即實(shí)現(xiàn)跨進(jìn)程通信的,首先需要弄清楚為什么傳統(tǒng)IPC機(jī)制為什么需要兩次內(nèi)存拷貝,這就需要先了解一些操作系統(tǒng)的基礎(chǔ)知識。1.2.1進(jìn)程隔離先來看一下維基百科對“進(jìn)程隔離”的定義:進(jìn)程隔離是為保護(hù)操作系統(tǒng)中進(jìn)程互不干擾而設(shè)計的一組不同硬件和軟件的技術(shù)。這個技術(shù)是為了避免進(jìn)程A寫入進(jìn)程B的情況發(fā)生。
進(jìn)程的隔離實(shí)現(xiàn),使用了虛擬地址空間。進(jìn)程A的虛擬地址和進(jìn)程B的虛擬地址不同,這樣就防止進(jìn)程A將數(shù)據(jù)信息寫入進(jìn)程B。也就是說,進(jìn)程之間的數(shù)據(jù)是不共享的,A進(jìn)程無法直接訪問B進(jìn)程的數(shù)據(jù),以此來保證數(shù)據(jù)的安全性。在進(jìn)程隔離的操作系統(tǒng)中,進(jìn)程之間的交互必須通過IPC機(jī)制。進(jìn)程隔離的實(shí)現(xiàn)使用了虛擬地址空間,什么是虛擬地址空間呢?首先需要了解操作系統(tǒng)中的虛擬內(nèi)存概念,它是一種提高編程效率和提高物理內(nèi)存利用效率的一種技術(shù)。簡單來說,就是應(yīng)用程序看到了都一片連續(xù)完整的內(nèi)存地址空間,而實(shí)際上這些地壇空間是映射到碎片化的物理內(nèi)存中的,這個映射的過程對應(yīng)用程序來說是透明的。這個概念很重要,對于虛擬內(nèi)存更深入的理解可以參考這篇文章:Linux
虛擬內(nèi)存和物理內(nèi)存的理解1.2.2進(jìn)程空間:用戶空間/內(nèi)核空間現(xiàn)在的操作系統(tǒng)都采用虛擬內(nèi)存,對32位的操作系統(tǒng)而言,尋址空間是2的32次方,即4G。操作系統(tǒng)的核心是內(nèi)核,內(nèi)核擁有對底層設(shè)備的所有訪問權(quán)限,因此需要和普通的應(yīng)用程序獨(dú)立開來,用戶進(jìn)程不能直接訪問內(nèi)核進(jìn)程。操作系統(tǒng)從邏輯上把虛擬地址空間劃分為用戶空間(User
Space)和內(nèi)核空間(Kernel
Space)。在32位的Linux操作系統(tǒng)中,將高位的1GB字節(jié)供內(nèi)核使用,稱之為內(nèi)核空間;剩下的3GB字節(jié)供用戶進(jìn)程使用,稱之為用戶空間。1.2.3系統(tǒng)調(diào)用:用戶態(tài)/內(nèi)核態(tài)因?yàn)橛脩艨臻g的權(quán)限低于內(nèi)核空間,不可避免用戶空間需要訪問內(nèi)核空間的資源,比如讀寫文件和網(wǎng)絡(luò)訪問,如何實(shí)現(xiàn)呢?唯一的方式就是通過操作系統(tǒng)提供的系統(tǒng)調(diào)用接口,通過系統(tǒng)調(diào)用接口,用戶程序可以在內(nèi)核的控制下實(shí)現(xiàn)對內(nèi)核資源的有限訪問,這樣既能滿足應(yīng)用程序的資源請求,也能保障系統(tǒng)安全和穩(wěn)定。當(dāng)用戶進(jìn)程執(zhí)行自己的代碼時,進(jìn)程當(dāng)前就處于用戶運(yùn)行態(tài)(用戶態(tài)),此時處理器執(zhí)行用戶代碼,權(quán)限較低;當(dāng)用戶進(jìn)程通過系統(tǒng)調(diào)用執(zhí)行內(nèi)核代碼時,進(jìn)程就暫時進(jìn)入了內(nèi)核運(yùn)行態(tài)(內(nèi)核態(tài)),此時處理器權(quán)限***,可以執(zhí)行特權(quán)指令。1.2.4內(nèi)核模塊/驅(qū)動前面說了用戶空間可以通過系統(tǒng)調(diào)用訪問內(nèi)核空間,那用戶空間之間(進(jìn)程間)怎么通信呢?傳統(tǒng)的IPC機(jī)制都是通過內(nèi)核來支持的,Binder也一樣,有一個運(yùn)行在內(nèi)核中的Binder驅(qū)動程序負(fù)責(zé)進(jìn)程之間Binder的通信。驅(qū)動程序一般指的是設(shè)備驅(qū)動程序(DeviceDriver),是一種可以使計算機(jī)和設(shè)備通信的特殊程序。相當(dāng)于硬件的接口,操作系統(tǒng)只有通過這個接口。Binder驅(qū)動是一種虛擬的字符設(shè)備,注冊在/dev/binder中,其定義了一套Binder通信協(xié)議,負(fù)責(zé)建立進(jìn)程間的Binder通信,提供了數(shù)據(jù)包在進(jìn)程之間傳遞的一系列底層支持。應(yīng)用進(jìn)程訪問Binder驅(qū)動也是通過系統(tǒng)調(diào)用實(shí)現(xiàn)的。1.3傳統(tǒng)IPC機(jī)制的通信原理了解了上面的基礎(chǔ)知識后,我們來看看傳統(tǒng)IPC機(jī)制是如何實(shí)現(xiàn),通常是下面兩個步驟(共享內(nèi)存機(jī)制除外):發(fā)送方進(jìn)程通過系統(tǒng)調(diào)用(copy_from_user)將要發(fā)送的數(shù)據(jù)存拷貝到內(nèi)核緩存區(qū)中。接收方開辟一段內(nèi)存空間,內(nèi)核通過系統(tǒng)調(diào)用(copy_to_user)將內(nèi)核緩存區(qū)中的數(shù)據(jù)拷貝到接收方的內(nèi)存緩存區(qū)。這種傳統(tǒng)IPC機(jī)制存在2個問題:需要進(jìn)行2次數(shù)據(jù)拷貝,第1次是從發(fā)送方用戶空間拷貝到內(nèi)核緩存區(qū),第2次是從內(nèi)核緩存區(qū)拷貝到接收方用戶空間。接收方進(jìn)程不知道事先要分配多大的空間來接收數(shù)據(jù),可能存在空間上的浪費(fèi)。2、Binder的基本原理2.1Binder底層原理傳統(tǒng)IPC機(jī)制需要拷貝2次內(nèi)存,Binder是如何只用1次內(nèi)存拷貝就實(shí)現(xiàn)進(jìn)程間通信的呢?前面我們已經(jīng)了解到,Linux是使用的是虛擬內(nèi)存尋址方式,用戶空間的虛擬內(nèi)存地址是映射到物理內(nèi)存中的,對虛擬內(nèi)存的讀寫實(shí)際上是對物理內(nèi)存的讀寫,這個過程就是內(nèi)存映射,這個內(nèi)存映射過程是通過系統(tǒng)調(diào)用mmap()來實(shí)現(xiàn)的。Binder借助了內(nèi)存映射的方法,在內(nèi)核空間和接收方用戶空間的數(shù)據(jù)緩存區(qū)之間做了一層內(nèi)存映射。這樣一來,從發(fā)送方用戶空間拷貝到內(nèi)核空間緩存區(qū)的數(shù)據(jù),就相當(dāng)于直接拷貝到了接收方用戶空間的數(shù)據(jù)緩存區(qū),從而減少了一次數(shù)據(jù)拷貝。2.2Binder通信模型Binder是基于C/S架構(gòu)的,對于通信雙方來說,發(fā)起請求的進(jìn)程屬于Client,接收請求的進(jìn)程屬于Server,由于存在進(jìn)程隔離,雙方不能直接通信,Binder是如何實(shí)現(xiàn)的呢?寫給Android應(yīng)用工程師的Binder
原理剖析中舉的網(wǎng)絡(luò)通信例子很貼切,Binder的通信過程與網(wǎng)絡(luò)請求類似,網(wǎng)絡(luò)通信過程可以簡化為4個角色:Client、Server、DNS服務(wù)器和路由器。一次完整的網(wǎng)絡(luò)通信大體過程如下:a、Client輸入Server的域名b、DNS解析域名通過域名是無法直接找到相應(yīng)Server的,必須先通過DNS服務(wù)器將Server的域名轉(zhuǎn)化為具體的IP地址。c、通過路由器將請求發(fā)送至ServerClient通過DNS服務(wù)器解析到Server的IP地址后,也還不能直接向Server發(fā)起請求,需要經(jīng)過路由器的層層中轉(zhuǎn)才還到達(dá)Server。d、Server返回數(shù)據(jù)Server接收到請求并處理后,再通過路由器將數(shù)據(jù)返回給Client。在Binder機(jī)制中,也定義了4個角色:Client、Server、Binder驅(qū)動和ServiceManager。Binder驅(qū)動:類似網(wǎng)絡(luò)通信中的路由器,負(fù)責(zé)將Client的請求轉(zhuǎn)發(fā)到具體的Server中執(zhí)行,并將Server返回的數(shù)據(jù)傳回給Client。ServiceManager:類似網(wǎng)絡(luò)通信中的DNS服務(wù)器,負(fù)責(zé)將Client請求的Binder描述符轉(zhuǎn)化為具體的Server地址,以便Binder驅(qū)動能夠轉(zhuǎn)發(fā)給具體的Server。Server如需提供Binder服務(wù),需要向ServiceManager注冊。具體的通信過程是這樣的:a、Server向ServiceManager注冊Server通過Binder驅(qū)動向ServiceManager注冊,聲明可以對外提供服務(wù)。ServiceManager中會保留一份映射表:名字為zhangsan的Server對應(yīng)的Binder引用是0x12345。b、Client向ServiceManager請求Server的Binder引用Client想要請求Server的數(shù)據(jù)時,需要先通過Binder驅(qū)動向ServiceManager請求Server的Binder引用:我要向名字為zhangsan的Server通信,請告訴我Server的Binder引用。c、向具體的Server發(fā)送請求Client拿到這個Binder引用后,就可以通過Binder驅(qū)動和Server進(jìn)行通信了。d、Server返回結(jié)果Server響應(yīng)請求后,需要再次通過Binder驅(qū)動將結(jié)果返回給Client。可以看到,Client、Server、ServiceManager之間的通信都是通過Binder驅(qū)動作為橋梁的,可見Binder驅(qū)動的重要性。也許你還有一點(diǎn)疑問,ServiceManager和Binder驅(qū)動屬于兩個不同的進(jìn)程,它們是為Client和Server之間的進(jìn)程間通信服務(wù)的,也就是說Client和Server之間的進(jìn)程間通信依賴ServiceManager和Binder驅(qū)動之間的進(jìn)程間通信,這就像是:“蛋生雞,雞生蛋,但***個蛋得通過一只雞孵出來”。Binder機(jī)制是如何創(chuàng)造***只下蛋的雞呢?當(dāng)Android系統(tǒng)啟動后,會創(chuàng)建一個名稱為servicemanager的進(jìn)程,這個進(jìn)程通過一個約定的命令BINDERSETCONTEXT_MGR向Binder驅(qū)動注冊,申請成為為ServiceManager,Binder驅(qū)動會自動為ServiceManager創(chuàng)建一個Binder實(shí)體(***只下蛋的雞);并且這個Binder實(shí)體的引用在所有的Client中都為0,也就說各個Client通過這個0號引用就可以和ServiceManager進(jìn)行通信。Server通過0號引用向ServiceManager進(jìn)行注冊,Client通過0號引用就可以獲取到要通信的Server的Binder引用。AndroidBinder設(shè)計與實(shí)現(xiàn)-設(shè)計篇中對Client、Server、Binder驅(qū)動和ServiceManager有更詳細(xì)的介紹。2.3Binder的代理機(jī)制通過上面的分析,我們已經(jīng)知道了Binder的基本通信過程:Client向SerivceManger獲取到Server的Binder引用,Client通過Binder引用向Server發(fā)起具體請求。Client通過這個Binder引用具體是如何調(diào)用Server方法的呢?比如一個Server提供add方法,Client實(shí)際請求add的流程是這樣的:Client先通過Binder驅(qū)動向ServiceManager獲取Server的Binder引用,這個引用就是一個Java
Object,這個Object有一個add方法;Cient拿到這個Object后就可以直接請求add方法了。實(shí)際上Client拿到的Object并不是Server真正的Binder實(shí)體,Binder驅(qū)動做了一層對象轉(zhuǎn)換,將這個Object包裝成了一個代理對象ProxyObject,這個ProxyObject和真正的Binder實(shí)體有相同的方法簽名,Client通過這個ProxyObject請求add方法時,Binder驅(qū)動會自動將請求轉(zhuǎn)發(fā)到具體的Binder實(shí)體中執(zhí)行,這就是Binder的代理機(jī)制。由于ProxyObject和真正的Binder實(shí)體有相同的方法簽名,其實(shí)Client并不需要關(guān)心是ProxyObject還是真實(shí)的Object。為了方便描述,下面將Server真正的Binder實(shí)體稱為Binder本地對象;將Client中的Binder引用,即ProxyObject,稱之為Binder代理對象。2.4對Binder概念的重新理解經(jīng)過上面的分析,我們已經(jīng)大體清楚了Binder機(jī)制的基本通信原理,現(xiàn)在回過頭來重新梳理下對Binder機(jī)制的認(rèn)識:總體來說,Binder是基于C/S結(jié)構(gòu)的一種面向?qū)ο蟮腎PC機(jī)制。包含:Client、Server、Binder驅(qū)動和ServiceManager四大組成部分。各組成部分中的Binder含義都有所有不同:對于ClientBinder是Server本地對象的一個引用,這個引用實(shí)際上是一個代理對象,Client通過這個代理對象來間接訪問Server的本地對象;對于ServerBinder是提供具體實(shí)現(xiàn)的本地對象,需向ServiceManager注冊;對于Binder驅(qū)動它是連接Client來Server的橋梁,負(fù)責(zé)將代理對象轉(zhuǎn)化為本地對象,并將Server的執(zhí)行結(jié)果返回給Client。對于ServiceManager它保存了ServerBinder字符名稱和Binder引用的映射,Client通過它來找到Server的Binder引用。Binder驅(qū)動中保留了Binder代理對象和Binder本地對象的具體結(jié)構(gòu),由于我們只關(guān)心Binder的基本通信機(jī)制,底層實(shí)現(xiàn)不做過多介紹,想具體了解的同學(xué)可以參考Android
Binder設(shè)計與實(shí)現(xiàn)-設(shè)計篇。3、通過代碼來理解Binder上面的介紹比較抽象,現(xiàn)在我們通過具體實(shí)例來理解Binder。通過AIDL實(shí)例來了解Binder的用法通過手動編碼實(shí)現(xiàn)ActivityManagerService3.1通過AIDL實(shí)例來了解Binder的用法實(shí)現(xiàn)Binder通信的最常用方法就是通過aidl,aidl接口定義了Client和Server進(jìn)行通信的接口,對aidl不了解的同學(xué)請參考官方文檔Android
接口定義語言(AIDL)。3.1.1與Binder相關(guān)的幾個類的職責(zé)在具體分析之前,我們需要先了解與Binder相關(guān)的幾個類的職責(zé):IBinder跨進(jìn)程通信的Base接口,它聲明了跨進(jìn)程通信需要實(shí)現(xiàn)的一系列抽象方法,實(shí)現(xiàn)了這個接口就說明可以進(jìn)行跨進(jìn)程通信,Client和Server都要實(shí)現(xiàn)此接口。IInterface這也是一個Base接口,用來表示Server提供了哪些能力,是Client和Server通信的協(xié)議。Binder提供Binder服務(wù)的本地對象的基類,它實(shí)現(xiàn)了IBinder接口,所有本地對象都要繼承這個類。BinderProxy在Binder.java這個文件中還定義了一個BinderProxy類,這個類表示Binder代理對象它同樣實(shí)現(xiàn)了IBinder接口,不過它的很多實(shí)現(xiàn)都交由native層處理。Client中拿到的實(shí)際上是這個代理對象。Stub這個類在編譯aidl文件后自動生成,它繼承自Binder,表示它是一個Binder本地對象;它是一個抽象類,實(shí)現(xiàn)了IInterface接口,表明它的子類需要實(shí)現(xiàn)Server將要提供的具體能力(即aidl文件中聲明的方法)。Proxy它實(shí)現(xiàn)了IInterface接口,說明它是Binder通信過程的一部分;它實(shí)現(xiàn)了aidl中聲明的方法,但最終還是交由其中的mRemote成員來處理,說明它是一個代理對象,mRemote成員實(shí)際上就是BinderProxy。3.1.2AIDL實(shí)例首先定義一個aidl文件,這個接口中聲明了一個getPid方法://
IRemoteService.aidl
package
com.rush.demo.aidltest;
interface
IRemoteService
{
int
getPid();
}下面是編譯IRemoteService.aild后生成的java類://
IRemoteService.java
package
com.rush.demo.aidltest;
public
interface
IRemoteService
extends
android.os.IInterface
{
public
static
abstract
class
Stub
extends
android.os.Binder
implements
com.rush.demo.aidltest.IRemoteService
{
//Binder描述符
private
static
final
java.lang.String
DESCRIPTOR
=
"com.rush.demo.aidltest.IRemoteService";
public
Stub()
{
this.attachInterface(this,
DESCRIPTOR);
}
public
static
com.rush.demo.aidltest.IRemoteService
asInterface(android.os.IBinder
obj)
{
if
((obj
==
null))
{
return
null;
}
android.os.IInterface
iin
=
obj.queryLocalInterface(DESCRIPTOR);
if
(((iin
!=
null)
&&
(iin
instanceof
com.rush.demo.aidltest.IRemoteService)))
{
return
((com.rush.demo.aidltest.IRemoteService)
iin);
}
return
new
com.rush.demo.aidltest.IRemoteService.Stub.Proxy(obj);
}
@Override
public
android.os.IBinder
asBinder()
{
return
this;
}
@Override
public
boolean
onTransact(int
code,
android.os.Parcel
data,
android.os.Parcel
reply,
int
flags)
throws
android.os.RemoteException
{
switch
(code)
{
case
INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return
true;
}
case
TRANSACTION_getPid:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String
_arg0;
_arg0
=
data.readString();
int
_result
=
this.getPid(_arg0);
reply.writeNoException();
reply.writeInt(_result);
return
true;
}
}
return
super.onTransact(code,
data,
reply,
flags);
}
private
static
class
Proxy
implements
com.rush.demo.aidltest.IRemoteService
{
private
android.os.IBinder
mRemote;
Proxy(android.os.IBinder
remote)
{
mRemote
=
remote;
}
@Override
public
android.os.IBinder
asBinder()
{
return
mRemote;
}
public
java.lang.String
getInterfaceDescriptor()
{
return
DESCRIPTOR;
}
@Override
public
int
getPid(java.lang.String
name)
throws
android.os.RemoteException
{
android.os.Parcel
_data
=
android.os.Parcel.obtain();
android.os.Parcel
_reply
=
android.os.Parcel.obtain();
int
_result;
try
{
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
mRemote.transact(Stub.TRANSACTION_getPid,
_data,
_reply,
0);
_reply.readException();
_result
=
_reply.readInt();
}
finally
{
_reply.recycle();
_data.recycle();
}
return
_result;
}
static
final
int
TRANSACTION_getPid
=
(android.os.IBinder.FIRST_CALL_TRANSACTION
+
0);
}
public
int
getPid(java.lang.String
name)
throws
android.os.RemoteException;
}這個文件中有3個類:a、IRemoteService繼承至IInterface接口,聲明了IRemoteService.aidl中聲明的getPid方法,它是Client和Service通信的接口。b、IRemoteService.StubIRemoteService的靜態(tài)抽象內(nèi)部類,繼承自Binder,其子類需要實(shí)現(xiàn)IRemoteService接口,表明它是Server的Binder本地對象,需要實(shí)現(xiàn)getPid接口。c、IRemoteService.Stub.ProxyIRemoteService.Stub的靜態(tài)內(nèi)部類,它并沒有繼承自Binder,而是包含了一個IBinder對象,這個對象其實(shí)是BinderProxy,說明它是Server在Client中的本地代理對象。Proxy實(shí)現(xiàn)了getPid接口,將參數(shù)序列化后交由mRemote(BinderProxy)處理,實(shí)際上就是交給Binder驅(qū)動來完成與遠(yuǎn)程Stub的通信。先來看Stub中的asInterface方法,這個方法通常是Client在bindService成功后,由Client來調(diào)用的,作用是將綁定成功后返回的IBinder對象轉(zhuǎn)換為具體的IInterface接口,Client拿到這個IInterface接口后就可以和自由的調(diào)用Server提供的方法了。public
static
com.rush.demo.aidltest.IRemoteService
asInterface(android.os.IBinder
obj)
{
if
((obj
==
null))
{
return
null;
}
android.os.IInterface
iin
=
obj.queryLocalInterface(DESCRIPTOR);
if
(((iin
!=
null)
&&
(iin
instanceof
com.rush.demo.aidltest.IRemoteService)))
{
return
((com.rush.demo.aidltest.IRemoteService)
iin);
}
return
new
com.rush.demo.aidltest.IRemoteService.Stub.Proxy(obj);
}asInterface方法中既可能返回Stub本身的IRemoteService對象,也可能創(chuàng)建一個Proxy對象,這是為什么呢?因?yàn)锽inder雖然是跨進(jìn)程通信機(jī)制,但也可以為本進(jìn)程服務(wù),也就是說Client和Server可能在同一個進(jìn)程,在同一個進(jìn)程就沒必要通過Binder驅(qū)動來中轉(zhuǎn)了,直接訪問就可以了;如果Client和Server在不同的進(jìn)程,就需要通過Binder代理對象來中轉(zhuǎn)。也就是說:Client和Server在同一個進(jìn)程,obj是Binder本地對象(Stub的子類),asInterface方法返回的就是Binder本地對象;Client和Server在不同的進(jìn)程,obj實(shí)際上是Binder代理對象,asInterface返回一個Proxy對象。//Binder.java
/**
*
obj.queryLocalInterface是怎樣去查找是否有本地的IInterface呢,從Binder的代碼中可以看到,只是簡單的比較Binder的描述符和要查找的描述符是否匹配,匹配的話直接返回mOwner,這個mOwner就是Stub構(gòu)造方法中調(diào)用attachInterface方法傳入的this參數(shù)。
*/
public
IInterface
queryLocalInterface(String
descriptor)
{
if
(mDescriptor.equals(descriptor))
{
return
mOwner;
}
return
null;
}
final
class
BinderProxy
implements
IBinder
{
public
IInterface
queryLocalInterface(String
descriptor)
{
return
null;
}
}
public
static
abstract
class
Stub
extends
android.os.Binder
implements
com.rush.demo.aidltest.IRemoteService
{
//
Binder描述符,值為接口類名全稱
private
static
final
java.lang.String
DESCRIPTOR
=
"com.rush.demo.aidltest.IRemoteService";
public
Stub()
{
//向Binder中綁定owner和descriptor
this.attachInterface(this,
DESCRIPTOR);
}
}obj.queryLocalInterface是怎樣去查找是否有本地的IInterface呢,從Binder的代碼中可以看到,只是簡單的比較Binder的描述符和要查找的描述符是否匹配,匹配的話直接返回mOwner,這個mOwner就是Stub構(gòu)造方法中調(diào)用attachInterface方法傳入的this參數(shù)。而BinderProxy的queryLocalInterface方法直接返回null。Client中通過Binder調(diào)用Server方法有兩種場景:1、Client和Server在同一個進(jìn)程Stub.asInterface方法返回的是Stub對象,即Binder本地對象。也就是說和Binder跨進(jìn)程通信無關(guān),直接調(diào)用即可,此時Client調(diào)用方和Server響應(yīng)方在同一個線程中。2、Client和Server在不同的進(jìn)程Stub.asInterface方法返回的是Binder代理對象,需要通過Binder驅(qū)動完成跨進(jìn)程通信。這種場景下,Client調(diào)用方線程會被掛起(Binder也提供了異步的方式,這里不討論),等待Server響應(yīng)后返回數(shù)據(jù)。這里要注意的是,Server的響應(yīng)是在Server進(jìn)程的Binder線程池中處理的,并不是主線程。接下來分析跨進(jìn)程場景下,Client調(diào)用getPid方法的具體流程:1、Client調(diào)用Binder代理對象,Client線程掛起Client中拿到的IRemoteService引用實(shí)際上是Proxy,調(diào)用getPid方法實(shí)際上是調(diào)用Proxy的getPid方法,這個方法只是將參數(shù)序列化后,調(diào)用了mRemote成員的transact方法。Stub類中為IRemoteService中的每個方法定義了方法編號,transact方法中傳入getPid方法的編號。此時Client調(diào)用方線程掛起,等待Server響應(yīng)數(shù)據(jù)。//
Stub.Proxy
public
int
getPid(java.lang.String
name)
throws
android.os.RemoteException
{
...
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
mRemote.transact(Stub.TRANSACTION_getPid,
_data,
_reply,
0);
_reply.readException();
_result
=
_reply.readInt();
...
return
_result;
}2、Binder代理對象將請求派發(fā)給Binder驅(qū)動Proxy中的mRemote成員實(shí)際上是BinderProxy,而BinderProxy中的transact方法最終調(diào)用于transactNative方法,也就是說Client的請求派發(fā)給了Binder驅(qū)動來處理。3、Binder驅(qū)動將請求派發(fā)給ServerBinder驅(qū)動經(jīng)過一系列的處理后,將請求派發(fā)給了Server,即調(diào)用Server本地Binder對象(Stub)的onTransact方法最終在此方法中完成getPid方法的具體調(diào)用。在onTransact方法中,根據(jù)Proxy中調(diào)用transact時傳入的方法編號來區(qū)別具體要處理的方法。//
Stub
public
boolean
onTransact(int
code,
android.os.Parcel
data,
android.os.Parcel
reply,
int
flags)
throws
android.os.RemoteException
{
switch
(code)
{
...
case
TRANSACTION_getPid:
{
data.enforceInterface(DESCRIPTOR);
//獲取方法參數(shù)
java.lang.String
_arg0
=
data.readString();
//調(diào)用getPid方法,這個方法在Stub的子類,即Server中實(shí)現(xiàn)
int
_result
=
this.getPid(_arg0);
reply.writeNoException();
reply.writeInt(_result);
return
true;
}
}
return
super.onTransact(code,
data,
reply,
flags);
}4、喚醒Client線程,返回結(jié)果onTransact處理結(jié)束后,將結(jié)果寫入reply并返回至Binder驅(qū)動,驅(qū)動喚醒掛起的Client線程,并將結(jié)果返回。至此,一次跨進(jìn)程通信完成。3.2手動編碼來實(shí)現(xiàn)ActivityManagerService通過前面的示例我們已經(jīng)知道,aidl文件只是用來定義C/S交互的接口,Android在編譯時會自動生成相應(yīng)的Java類,生成的類中包含了Stub和Proxy靜態(tài)內(nèi)部類,用來封裝數(shù)據(jù)轉(zhuǎn)換的過程,實(shí)際使用時只關(guān)心具體的Java接口類即可。為什么Stub和Proxy是靜態(tài)內(nèi)部類呢?這其實(shí)只是為了將三個類放在一個文件中,提高代碼的聚合性。通過上面的分析,我們其實(shí)完全可以不通過aidl,手動編碼來實(shí)現(xiàn)Binder的通信,下面我們通過編碼來實(shí)現(xiàn)ActivityManagerService。首先定義IActivityManager接口:public
interface
IActivityManager
extends
IInterface
{
//binder描述符
String
DESCRIPTOR
=
"android.app.IActivityManager";
//方法編號
int
TRANSACTION_startActivity
=
IBinder.FIRST_CALL_TRANSACTION
+
0;
//聲明一個啟動activity的方法,為了簡化,這里只傳入intent參數(shù)
int
startActivity(Intent
intent)
throws
RemoteException;
}其次,實(shí)現(xiàn)ActivityManagerService側(cè)的本地Binder對象基類://
名稱隨意,不一致叫Stub
public
abstract
class
ActivityManagerNative
extends
Binder
implements
IActivityManager
{
public
static
IActivityManager
asInterface(IBinder
obj)
{
if
(obj
==
null)
{
return
null;
}
IActivityManager
in
=
(IActivityManager)
obj.queryLocalInterface(IActivityManager.DESCRIPTOR);
if
(in
!=
null)
{
return
in;
}
//代理對象,見下面的代碼
return
new
ActivityManagerProxy(obj);
}
@Override
public
IBinder
asBinder()
{
return
this;
}
@Override
protected
boolean
onTransact(int
code,
Parcel
data,
Parcel
reply,
int
flags)
throws
RemoteException
{
switch
(code)
{
//
獲取binder描述符
case
INTERFACE_TRANSACTION:
reply.writeString(IActivityManager.DESCRIPTOR);
return
true;
//
啟動activity,從data中反序列化出intent參數(shù)后,直接調(diào)用子類startActivity方法啟動activity。
case
IActivityManager.TRANSACTION_startAc
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025煤炭購銷合同范本協(xié)議
- 2025物流包機(jī)運(yùn)輸合同運(yùn)輸合同
- 2024年版房地產(chǎn)稅收優(yōu)惠政策合同
- 2025投資合作合同范本
- 2025年度混凝土澆筑技術(shù)指導(dǎo)和服務(wù)合同3篇
- 2025版智能鎖具研發(fā)生產(chǎn)及銷售合作合同3篇
- 二零二五年度NDA保密協(xié)議促進(jìn)技術(shù)交流與合作3篇
- 二零二五年度商業(yè)空間室內(nèi)外裝修施工合同2篇
- 2024年軟件開發(fā)定制合同格式3篇
- 2025無抵押借款合同范本
- 2024-2030年中國電子級四氟化硅行業(yè)風(fēng)險評估及未來全景深度解析研究報告
- JGJ106-2014建筑基樁檢測技術(shù)規(guī)范
- 中考字音字形練習(xí)題(含答案)-字音字形專項訓(xùn)練
- 四柱萬能液壓機(jī)液壓系統(tǒng) (1)講解
- JTT 1501-2024 潛水作業(yè)現(xiàn)場安全監(jiān)管要求(正式版)
- 家鄉(xiāng)土特產(chǎn)電商營銷策劃方案(2篇)
- CTD申報資料撰寫模板:模塊三之3.2.S.4原料藥的質(zhì)量控制
- 汽車標(biāo)準(zhǔn)-商用車輛前軸總成
- 個人貸款月供款計算表模板
- 先玉335玉米品種介紹課件講解
- (正式版)JTT 1482-2023 道路運(yùn)輸安全監(jiān)督檢查規(guī)范
評論
0/150
提交評論