android進(jìn)程間通信一般用到三種:
1.system property 系統(tǒng)屬性呐萌,可以對整個(gè)系統(tǒng)全局共享望门,所以可以達(dá)到進(jìn)程間共享的目的
2.socket通信宪肖,很多framework 框架層與system之間通信用這個(gè)抠忘,比如vold與mountservice杜秸、NetworkManagementService與netd解幼、NsdService與netd抑党。系統(tǒng)framework 框架層有實(shí)現(xiàn)了NativeDaemonConnector供大家調(diào)用。
3.AIDL撵摆、鼎鼎大名的AIDL底靠,Android Interface definition language的縮寫,是android最常用的進(jìn)程間通信方式特铝,從android 系統(tǒng)中可以找到很多這樣的例子暑中。他的優(yōu)點(diǎn)很多壹瘟,比如可定義接口,只要按照標(biāo)準(zhǔn)鳄逾,可以很容易的用自定義接口實(shí)現(xiàn)進(jìn)程間通信稻轨,傳輸參數(shù)不受限制,這是上面兩種不具備的優(yōu)勢雕凹。
當(dāng)然肯定很多朋友會(huì)說還有廣播啊殴俱,廣播也能實(shí)現(xiàn)進(jìn)程間的通信,但是他只能局限在框架層和應(yīng)用枚抵。無法與中間件實(shí)現(xiàn)廣播通信线欲。
1.屬性鍵值對
今天我們介紹第一種,最簡單也很實(shí)用的進(jìn)程間通信方式汽摹。這些屬性可能是有些資源的使用狀態(tài)李丰,進(jìn)程的執(zhí)行狀態(tài),系統(tǒng)的特有屬性逼泣。趴泌。。
屬性系統(tǒng)是android的一個(gè)重要特性拉庶。每個(gè)屬性是一個(gè)鍵值對(key/value pair)踱讨,其類型都是字符串。但給它的缺點(diǎn)也很明顯砍的,只能傳輸簡單的參數(shù)。
可以通過命令adb shell :
getprop查看android設(shè)備上所有屬性狀態(tài)值莺治±希或者使用setprop設(shè)置某個(gè)屬性的狀態(tài)。
特別屬性 :
如果屬性名稱以“ro.”開頭谣旁,那么這個(gè)屬性被視為只讀屬性床佳。一旦設(shè)置,屬性值不能改變榄审。
如果屬性名稱以“persist.”開頭砌们,當(dāng)設(shè)置這個(gè)屬性時(shí),其值也將寫入/data/property搁进。
如果屬性名稱以“net.”開頭浪感,當(dāng)設(shè)置這個(gè)屬性時(shí),“net.change”屬性將會(huì)自動(dòng)設(shè)置饼问,以加入到最后修改的屬性名影兽。
(這是很巧妙的。 netresolve模塊的使用這個(gè)屬性來追蹤在net.*屬性上的任何變化莱革。)
屬性“ ctrl.start ”和“ ctrl.stop ”是用來啟動(dòng)和停止服務(wù)峻堰。每一項(xiàng)服務(wù)必須在/init.rc中定義.系統(tǒng)啟動(dòng)時(shí)讹开,與init守護(hù)進(jìn)程將解析init.rc和啟動(dòng)屬性服務(wù)。一旦收到設(shè)置“ ctrl.start ”屬性的請求捐名,屬性服務(wù)將使用該屬性值作為服務(wù)名找到該服務(wù)旦万,啟動(dòng)該服務(wù)。這項(xiàng)服務(wù)的啟動(dòng)結(jié)果將會(huì)放入“ init.svc.<服務(wù)名>“屬性中镶蹋〕伤遥客戶端應(yīng)用程序可以輪詢那個(gè)屬性值,以確定結(jié)果梅忌。開機(jī)動(dòng)畫就是這么實(shí)現(xiàn)的狰腌。
2.framework訪問系統(tǒng) 屬性
framework通過SystemProperties接口操作系統(tǒng)屬性,所以在java層大家都可以使用該類來獲取或者設(shè)置系統(tǒng)屬性牧氮。SystemProperties通過JNI調(diào)用訪問系統(tǒng)屬性琼腔。
代碼路徑frameworks\base\core\java\android\os\ SystemProperties.java:
public class SystemProperties {
//JNI
private static native String native_get(String key, String def);
privatestaticnativevoidnative_set(String key, String def);
public static String get(String key, String def) {
?return native_get(key, def);?
}
public static void set(String key, String val) {
?native_set(key, val);?
}?
}
Jni代碼位置:
\frameworks\base\core\jni\android_os_SystemProperties.cpp
實(shí)現(xiàn)是在\bionic\libc\bionic\system_properties.c中:
int __system_property_get(constchar*name,char*value) {
//數(shù)據(jù)已經(jīng)存儲在內(nèi)存中__system_property_area__ 等待讀取完返回
const prop_info *pi = __system_property_find(name);
return __system_property_read(pi,0, value);?
}
進(jìn)程啟動(dòng)后數(shù)據(jù)已經(jīng)將系統(tǒng)屬性數(shù)據(jù)讀取到相應(yīng)的共享內(nèi)存中,保存在全局變量__system_property_area__踱葛;
進(jìn)程之間都是獨(dú)立的丹莲,系統(tǒng)屬性數(shù)據(jù)是如何讀取到當(dāng)前進(jìn)程空間中的呢?后續(xù)介紹尸诽。
設(shè)置屬性異步socket通信:
int __system_property_set(constchar*key,constchar*value) {
? ?msg.cmd = PROP_MSG_SETPROP;?
? strlcpy(msg.name, key,sizeofmsg.name);?
? strlcpy(msg.value, value,sizeofmsg.value);?
? err = send_prop_msg(&msg);
?}
static int send_prop_msg(prop_msg *msg) {
? ?//sokcet 通信 /dev/socket/property_service
? ?s = socket(AF_LOCAL, SOCK_STREAM,0);?
? ?connect(s, (structsockaddr *) &addr, alen)?
? ?send(s, msg,sizeof(prop_msg),0)
? ? close(s);
}
通過socket向property_service發(fā)送消息甥材,property_service運(yùn)行在哪里呢?
3.Property Service創(chuàng)建服務(wù)端socket
Property Service在init進(jìn)程中性含,init進(jìn)程啟動(dòng)監(jiān)聽過程中:\system\core\init\Init.c
Property Service 是運(yùn)行在init守護(hù)進(jìn)程中洲赵。
先看看Property Service接收到消息后的處理。
4. Property Service 監(jiān)聽socket處理
Property Service監(jiān)聽socket消息的處理過程:
通過設(shè)置系統(tǒng)屬性啟動(dòng)/關(guān)閉Service:
權(quán)限判斷:
所以如果想要應(yīng)用有權(quán)限啟動(dòng)/關(guān)閉某Native Service:
需要具有system/root權(quán)限,找到對應(yīng)應(yīng)用uid gid商蕴,將應(yīng)用名稱加入到control_perms列表中
處理消息 可以通過設(shè)置系統(tǒng)屬性 改變服務(wù)的執(zhí)行狀態(tài) start/stop:
連著前面就是ctr.start和ctr.stop系統(tǒng)屬性:用來啟動(dòng)和停止服務(wù)的叠萍。
例如:
// start boot animation
property_set("ctl.start", "bootanim");
在init.rc中表明服務(wù)是否在開機(jī)時(shí)啟動(dòng):
service adbd /sbin/adbd
classcore
disabled//不自動(dòng)啟動(dòng)
啟動(dòng)服務(wù)的時(shí)候會(huì)判斷:
修改系統(tǒng)屬性值:
看這個(gè)修改系統(tǒng)屬性權(quán)限表,配置系統(tǒng)權(quán)限可以查看system/core/include/private/android_filesystem_config.h:
指定了特定的用戶有用修改 帶有某些前綴的系統(tǒng)屬性值绪商。
到這里基本就是Property對外的基本工作流程苛谷,Property Service內(nèi)部具體如何實(shí)現(xiàn),操作運(yùn)行格郁,
跨進(jìn)程空想內(nèi)存等問題仍未清除是如何處理的腹殿。
5. 屬性系統(tǒng)設(shè)計(jì)
Property Service運(yùn)行在init進(jìn)程中,開機(jī)從屬性文件中加載到共享內(nèi)存中例书;設(shè)置系統(tǒng)屬性通過socket與Property Service通信锣尉。
Property Consumer進(jìn)程將存儲系統(tǒng)屬性值的共享內(nèi)存,加載到當(dāng)前進(jìn)程虛擬空間中决采,實(shí)現(xiàn)對系統(tǒng)屬性值的讀取悟耘。
Property Setter進(jìn)程修改系統(tǒng)屬性,通過socket向Property Service發(fā)送消息织狐,更改系統(tǒng)屬性值暂幼。
6. 屬性系統(tǒng)實(shí)現(xiàn)
屬性系統(tǒng)設(shè)計(jì)的關(guān)鍵就是:跨進(jìn)程共享內(nèi)存的實(shí)現(xiàn)筏勒。
下面將看看屬性系統(tǒng)實(shí)現(xiàn)具體過程:
Init進(jìn)程執(zhí)行:
初始化Property Service:\system\core\init\property_service.c
初始化共享內(nèi)存空間:
__system_property_area__:
每個(gè)進(jìn)程都會(huì)使用此變量,指向系統(tǒng)屬性共享內(nèi)存區(qū)域旺嬉,訪問系統(tǒng)屬性管行,很重要。
位于:\bionic\libc\bionic\system_properties.c中邪媳,屬于bionic庫捐顷。后面將介紹各進(jìn)程如何加載共享內(nèi)存。
將文件作為共享內(nèi)存映射到進(jìn)程空間內(nèi)存使用:
加載系統(tǒng)屬性默認(rèn)數(shù)據(jù)文件:
加上上面所述:Property Service Socket資源的創(chuàng)建雨效,來監(jiān)聽socket通信連接設(shè)置系統(tǒng)屬性迅涮,
在Init進(jìn)程中Property Service完成了初始化。
將得到該內(nèi)存區(qū)域數(shù)據(jù)結(jié)構(gòu):
7. 進(jìn)程共享系統(tǒng)屬性內(nèi)存空間實(shí)現(xiàn)
Property Service運(yùn)行于init進(jìn)程中徽龟,將文件映射為創(chuàng)建一塊共享內(nèi)存空間叮姑,但在整個(gè)系統(tǒng)中,
其他進(jìn)程也能夠讀取這塊內(nèi)存映射到當(dāng)前進(jìn)程空間中据悔,是如何實(shí)現(xiàn)的呢传透?
Service進(jìn)程啟動(dòng):將共享內(nèi)存空間fd size作為環(huán)境變量傳遞給新創(chuàng)建進(jìn)程
共享內(nèi)存空間fd size作為環(huán)境變量傳遞給新創(chuàng)建進(jìn)程后,將在何處使用呢极颓?
將系統(tǒng)屬性內(nèi)存空間映射到當(dāng)前進(jìn)程虛擬空間:
進(jìn)程在啟動(dòng)時(shí)朱盐,會(huì)加載動(dòng)態(tài)庫bionic libc庫:
\bionic\libc\bionic\libc_init_dynamic.c中:
void __attribute__((constructor)) __libc_preinit(void);
根據(jù)GCC的constructor/destructor屬性:
給一個(gè)函數(shù)賦予constructor或destructor,其中constructor在main開始運(yùn)行之前被調(diào)用菠隆,
destructor在main函數(shù)結(jié)束后被調(diào)用兵琳。如果有多個(gè)constructor或destructor,可以給每個(gè)constructor
或destructor賦予優(yōu)先級骇径,對于constructor闰围,優(yōu)先級數(shù)值越小,運(yùn)行越早既峡。destructor則相反。
多個(gè)constructor需要加優(yōu)先級:
__libc_preinit在bionic libc庫加載的時(shí)候會(huì)被調(diào)用: