Android應用程序是由Activity励堡、Service饺汹、BroadcastReceiver和ContentProvider四大組件構成的临谱,這些組件有可能運行在同一個進程中碗誉,也有可能運行在不同的進程中,同時Android系統(tǒng)提供的一些服務組件瞒滴,如Activity管理服務ActivityManagerService和Package管理服務PackageManagerService都運行在系統(tǒng)進程system中曲梗,這些運行在不同進程中的應用程序組件和系統(tǒng)服務組件大部分時候都是采用Android系統(tǒng)開發(fā)的一套名為Binder進程間通信機制實現(xiàn)通信赞警。
Binder通信機制與傳統(tǒng)的進程間通信機制相比,其在進程間傳輸數(shù)據(jù)時虏两,只需要執(zhí)行一次拷貝操作愧旦,因此它不僅提高了效率,而且節(jié)省了內存空間定罢。
在Binder通信機制中笤虫,提供服務的進程稱為Server進程,訪問服務的進程稱為Client進程祖凫。Server進程中可以同時運行多個Service組件來給Client進程提供服務琼蚯,Service組件也稱為Service本地對象,Client進程也可以同時向多個Service組件請求服務惠况,每一個請求在Client進程中都對應有一個Client組件遭庶,也稱為Service代理對象,Client進程正是靠這些Client組件向運行在Server進程中的Service組件發(fā)起通信請求售滤。
Server進程和Client進程的通信依靠運行在內核空間的驅動程序來進行罚拟,Binder驅動程序向用戶空間暴露了一個設備文件/dev/binder使得應用程序進程可以間接地通過它來建立通信通道。Service組件在啟動時會將自己注冊到運行在servicemanager進程中Service Manger組件中完箩,Client組件可通過Service Manager組件找到Service組件赐俗,所以Service Manager組件是Binder進程間通信機制的上下文管理者,同時Service Manager組件也是通過Binder進程間通信機制與普通Server進程和Client進程實現(xiàn)通信的弊知,只不過它是一個特殊的Service組件阻逮,下圖展示了Server進程、Client進程秩彤、Service Manager組件以及Binder驅動程序之間的關系:
大體介紹完Binder進程間通信的概念后叔扼,接下來簡單描述一下Binder進程間通信流程的整體實現(xiàn)流程。Binder進程間通信依靠內核層的Binder驅動程序以及用戶層的Binder進程間通信庫來完成漫雷,其中用戶層的Binder進程間通信庫包括C/C++層的Binder接口與Java層中的Binder接口瓜富,而Java層中的Binder接口正是通過JNI方法來調用C/C++層的Binder接口以提供進程間通信能力。
Binder驅動程序中定義了很多基礎數(shù)據(jù)結構降盹,主要包括以下重要的數(shù)據(jù)結構:
1与柑、 binder_node Binder實體對象,代表內核中的Service組件
2蓄坏、 binder_ref Binder引用對象价捧,代表內核中的Client組件
3、 binder_proc 代表使用Binder進程間通信機制的進程
4涡戳、 binder_thread 代表Binder線程
5结蟋、 binder_transaction 代表進程間通信過程的事務
6、 binder_work 代表待處理的工作項
7渔彰、 binder_transaction_data 代表進程間通信所傳輸?shù)臄?shù)據(jù)
8嵌屎、 binder_buffer 代表內核緩沖區(qū)
……
Binder進程間通信庫C/C++層接口的基礎數(shù)據(jù)結構主要如下:
1推正、IBinder Binder基礎接口,BBinder和BpBinder均繼承它
2宝惰、BnInterface Binder本地對象舔稀,代表C/C++層中的Service組件
3、BpInterface Binder代理對象掌测,代表C/C++層中的Client組件
4、BBinder 為Binder本地對象提供進程間通信接口
5产园、BpBinder 為Binder代理對象提供進程間通信接口
6汞斧、IInterface Service組件接口,描述Service組件提供的功能接口
7什燕、IPCThreadState BBinder與BpBinder通過其與Binder驅動程序交互
8粘勒、ProcessState 使用Binder進程間通信機制的進程通過其初始化Binder設備
……
Binder進程間通信庫Java層接口的基礎數(shù)據(jù)結構主要如下:
1、IBinder Binder基礎接口屎即,Binder和BinderProxy均實現(xiàn)該接口
2庙睡、Binder Java服務,代表Jave層中的Service組件
3技俐、BinderProxy Java服務代理對象乘陪,為Java層中的Client組件提供進程間通信的能力
4、IInterface Service組件接口雕擂,描述Service組件提供的功能接口
……
下圖為Binder驅動程序與C/C++層進程間通信庫的交互圖:
在Binder驅動程序中啡邑,每個Service組件使用binder_node實體對象表示,而Client組件使用binder_ref引用對象表示井赌,驅動程序會為采用了Binder進程間通信的進程生成一個binder_proc對象代表其進程谤逼,并為進程的用戶空間地址映射內核空間地址,同時在binder_proc中通過user_buffer_offset字段保存進程用戶空間地址與驅動程序為其分配的內核空間地址的差值仇穗。binder_proc中維護有一個binder_node實體對象的紅黑樹管理其進程中的Service組件流部,同樣采用紅黑樹管理進程中的Client組件對應的binder_ref引用對象。binder_node中使用hash列表管理其被哪些binder_ref對象引用,相應的binder_ref中存在一個hash列表結點表示其引用了哪個binder_node實體對象纹坐,所以可由binder_ref引用對象查到到binder_node實體對象枝冀,進而再由binder_node實體對象中指向用戶層中Service組件的地址字段找到Service組件以請求其服務,binder_node與binder_ref中的proc字段指向其所屬于的binder_proc恰画。
Server進程中的Service組件需要繼承自BnInterface模板類宾茂,BnInterface模板類繼承了Service組件接口模板,Service組件需要實現(xiàn)Service組件接口中的方法以對外提供服務能力拴还,BBinder類為Binder本地對象提供了與Binder驅動程序通信的接口跨晴,而BnInterface模板類繼承自BBinder,所以Service組件可通過Binder驅動程序間接與Client組件進行通信片林。
Client進程中的Client組件需要繼承自BpInterface模板類端盆,BpInterface模板類繼承了模板Service組件接口以及BpRefBase怀骤,BpRefBase中持有一個BpBinder,BpBinder為Binder代理對象提供了與Binder驅動程序通信的接口焕妙,所以Client組件可通過Binder驅動程序間接與Service組件進行通信蒋伦。
當Server進程通過Service Manager注冊Service組件時,驅動程序便為Server進程創(chuàng)建一個binder_node實體對象焚鹊,同時為Service Manager創(chuàng)建一個binder_ref引用對象引用該binder_node實體對象痕届,Service Manager會將該binder_ref引用對象的句柄值以及注冊Service組件時傳入的服務名進行關聯(lián)后存在內部的服務列表中。當Client進程通過Service Manager獲取Service組件對應的服務時末患,Service Manager會通過其內部的服務列表得到Service組件關聯(lián)的binder_ref引用對象的句柄值研叫,驅動程序根據(jù)該句柄值可找到Service組件對應的binder_node對象,然后再為Client進程生成一個binder_ref對象引用該binder_node對象璧针,Client進程在得到binder_ref對象的句柄值后嚷炉,便可創(chuàng)建一個BpBinder對象,進而由BpBinder對象創(chuàng)建Binder代理對象探橱,也即Client組件申屹。
BBinder與BpBinder是通過IPCThreadState實現(xiàn)和Binder驅動程序通信的,IPCThreadState既負責實現(xiàn)Service組件與Client組件向驅動程序發(fā)送通信信息隧膏,也負責接收處理來自驅動程序返回的通信信息哗讥。因為采用Binder進程間通信的進程雙方都有一個線程池,所以線程池中的每個線程都有其對應的IPCThreadState對象私植,通過IPCThreadState對象的transact函數(shù)即可向binder驅動程序發(fā)送通信數(shù)據(jù)忌栅。Client進程通過IPCThreadState將通信數(shù)據(jù)封裝為binder_transaction_data,并進一步封裝到binder_write_read結構體中的輸出緩沖區(qū)后通過BINDER_WRITE_READ這條IO控制命令發(fā)送給Binder驅動程序。由于BpBinder對象持有Client組件的句柄值曲稼,所以可由該句柄值找到對應的binder_ref引用對象索绪,進而找到binder_node實體對象,從而知道該通信請求是發(fā)送給哪個Server進程的贫悄。Binder驅動程序收到該IO命令后瑞驱,會將來自用戶空間的通信數(shù)據(jù)拷貝到Server進程的內核空間中的binder_buffer緩沖區(qū)中,并生成一個binder_transaction事務窄坦,事務中保存了binder_buffer唤反,然后將這個事務添加到Server進程或Server進程的binder線程的待處理工作項列表中,并喚醒Server進程或Server 進程的binder線程處理該工作項鸭津,驅動程序會根據(jù)binder_proc中的user_buffer_offset字段將內核binder_buffer緩沖區(qū)轉換為用戶空間緩沖區(qū)彤侍,并封裝為binder_transaction_data后,進一步封裝到binder_writer_read的輸入緩沖區(qū)后交由Server進程處理逆趋,Server進程處理完通信請求后盏阶,同樣通過BINDER_WRITE_READ IO控制命令將通信結果數(shù)據(jù)發(fā)送給Binder驅動程序,驅動程序可由binder_transaction事務找到發(fā)起請求的Client進程闻书,然后通過IPCThreadState對象將通信結果數(shù)據(jù)返回給Client進程名斟。
當進程向驅動程序發(fā)送通信請求時脑慧,其需要通過一個命令協(xié)議代碼表明其請求類型,同樣當驅動程序向進程發(fā)送返回結果時砰盐,也需要通過一個返回協(xié)議代碼表明其返回結果的類型闷袒,命令協(xié)議代碼與返回協(xié)議代碼都是由通信協(xié)議代碼和通信數(shù)據(jù)構成,命令協(xié)議代碼的通信協(xié)議代碼都以BC_開頭岩梳,返回協(xié)議代碼的通信協(xié)議代碼均以BR_開頭囊骤,例如BC_TRANSATION即代表通常的Binder通信請求,其通信數(shù)據(jù)通過binder_transaction_data表示冀值,BR_REPLY代表驅動程序向源進程轉發(fā)目標進程返回給源進程的數(shù)據(jù)淘捡,其通信數(shù)據(jù)也采用binder_transaction_data表示。其他的命令協(xié)議代碼還有諸如BC_INCREFS池摧、BC_DECREFS、BC_ACQUIRE激况、BC_RELEASE用于增減Binder引用對象的強弱引用計數(shù)作彤、BC_REQUEST_DEATH_NOTIFICATION用于注冊死亡接收通知等等。其他的返回協(xié)議代碼還有諸如BR_INCREFS乌逐、BR_DECREFS竭讳、BR_AQUIRE、BR_RELEASE用于增減Binder本地對象強弱引用計數(shù)浙踢、BR_DEAD_BINDER用于通知Client組件Service組件已經死亡等等绢慢。
下圖是Binder通訊庫為Java層提供的Binder接口與C/C++層接口的關系圖
在Java層中,Server進程中的Service組件稱為Java服務洛波,而Client進程中的Client組件稱為Java服務代理對象胰舆,從上圖可看到Java服務繼承自Java層的Binder類,Java層的Binder對象持有一個JavaBBinderHolder對象蹬挤,而JavaBBinderHolder對象又持有一個JavaBBinder對象缚窿,JavaBBinder繼承自BBinder,所以JavaBBinder對象即為Java服務在C/C++層中對應的Binder本地對象。Java服務代理對象持有一個BinderProxy對象焰扳,BinderProxy對象又持有一個BpBinder倦零,從而Java服務代理對象可由BinderProxy對象調用BpBinder對象實現(xiàn)向Java服務對象發(fā)起通信請求。
當通過Java層的Service Manager注冊Java服務時吨悍,在new Java服務時扫茅,服務繼承自的Java層的Binder類的構造函數(shù)中會通過JNI調用初始化接口,初始化接口內部會創(chuàng)建JavaBBinderHolder對象育瓜,并將該對象保存到Java層Binder對象的mObject字段中葫隙,JavaBBinderHolder對象內部也會持有Java層Binder對象,同時JavaBBinderHolder內部還持有一個mBinder字段用于保存JavaBBinder對象爆雹,JavaBBinder內部存在指向Java層Binder對象地址的字段表明其引用了Java層的哪個服務停蕉。注冊服務的過程中愕鼓,會獲取該JavaBBinder本地對象進行注冊,如果獲取該JavaBBinder對象的時候該對象還未創(chuàng)建慧起,則會先進行創(chuàng)建菇晃,剩下的注冊流程即轉到C/C++層中的注冊流程
當通過Java層的Service Manager獲取Java服務時,會從Service Manager中得到Java服務對應的Binder實體對象所對應的Binder引用對象的句柄值蚓挤,得到該句柄值后磺送,便可創(chuàng)建一個BpBinder對象,進而創(chuàng)建BinderProxy對象灿意,有了BinderProxy對象即可創(chuàng)建Java服務代理對象估灿。獲得了Java服務代理對象后,即可通過Java服務代理對象向Java服務發(fā)起請求缤剧,請求流程最終會交由到C/C++層中的BBinder本地對象與BpBinder對象進行處理馅袁。