標(biāo)簽:
androidsystempropertyit |
分類: programming |
Android為了儲存關(guān)于全局系統(tǒng)設(shè)置的信息,使用了一個(gè)系統(tǒng)屬性公共緩沖區(qū),這個(gè)緩沖區(qū)的內(nèi)容是(屬性,值)對的列表,對外提供get和set服務(wù)??梢哉f,屬性區(qū)域相當(dāng)于一般應(yīng)用的配置文件。本文不說有哪些具體屬性,而是描述一下這個(gè)屬性系統(tǒng)的實(shí)現(xiàn)。
屬性系統(tǒng)首先得有個(gè)固定地址空間,這是初始化的任務(wù),初始化工作的最佳位置是在init進(jìn)程。在init進(jìn)程里,init_property_area函數(shù)調(diào)用init_workspace完成屬性空間的分配:
fd = ashmem_create_region ("system_properties", size);
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED , fd, 0);
隨后,
pa = pa_workspace.data;
__system_property_area__ = pa;
最后一句的__system_property_area__就是屬性空間的入口地址。
屬性的服務(wù)函數(shù)(get和set)是由bionic下system_properties.c文件提供的,即它是android的libc庫的一部分。以get操作為例:
init使用的property_get是個(gè)包裝函數(shù),其實(shí)現(xiàn)是調(diào)用__system_property_find函數(shù),后者是要找到所找屬性的入口。
這得遍歷屬性緩沖區(qū)的結(jié)構(gòu)。這個(gè)緩沖區(qū)包括兩個(gè)部分:目錄和內(nèi)容。目錄項(xiàng)目的結(jié)構(gòu)是:
struct prop_area {
unsigned volatile count;
unsigned volatile serial;
unsigned magic;
unsigned version;
unsigned reserved[4];
unsigned toc[1];
};
具體屬性的結(jié)構(gòu)是:
struct prop_info {
char name[PROP_NAME_MAX];
unsigned volatile serial;
char value[PROP_VALUE_MAX];
};
find函數(shù)的主要內(nèi)容:
prop_area *pa = __system_property_area__;
unsigned count = pa->count;
unsigned *toc = pa->toc;
unsigned len = strlen(name);
while(count--) {
unsigned entry = *toc++;
if(TOC_NAME_LEN(entry) != len) continue;
pi = TOC_TO_INFO(pa, entry);
if(memcmp(name, pi->name, len)) continue;
return pi;
}
count是總共的屬性數(shù)目,toc是屬性目錄的入口地址。以上循環(huán)中,entry是屬性的偏移量,是個(gè)32位的整數(shù),其高位字節(jié)存儲的是屬性名的長度,后24位存儲的是屬性在緩沖區(qū)里的偏移量。TOC_NAME_LEN就是取得目錄項(xiàng)的高8位,而TOC_TO_INFO則是取得后24位,然后再加上屬性緩沖區(qū)的入口地址,就得到具體屬性的入口地址,然后再把類型轉(zhuǎn)換為prop_info的指針,然后返回這個(gè)值。
還有個(gè)問題:系統(tǒng)屬性的客戶是如何獲知__system_property_area__的位置呢?這些客戶通過連接C庫而能調(diào)用系統(tǒng)屬性的各個(gè)API,但并不能自動獲知系統(tǒng)屬性緩沖區(qū)的地址,這個(gè)地址在每個(gè)客戶進(jìn)程裝載時(shí),都初始化為0。進(jìn)程之間可以共享代碼,但并不自動共享數(shù)據(jù),除非程序做些特殊的處理,比如使用共享內(nèi)存。此處利用了二進(jìn)制文件(可執(zhí)行文件或者庫)的init段,即把一些必須的初始化代碼,比如C++對象的構(gòu)造函數(shù),放在這個(gè)init段里,每次動態(tài)連接或裝載二進(jìn)制文件時(shí),就首先執(zhí)行這個(gè)初始化段。
gcc提供了constructor屬性來指示把代碼放在init段里。system_properties的緩沖區(qū)地址,是在bionic libC庫的init段里被確定的。文件libc_init_dynamic.c的__libc_prenit函數(shù)調(diào)用了__libc_init_common,后者又調(diào)用了__system_properties_init,最后這個(gè)函數(shù)確定__system_property_area__的地址。而函數(shù)__libc_prenit被給予屬性constructor:
void __attribute__((constructor)) __libc_prenit(void);
這樣在bionic libc動態(tài)庫被裝載時(shí),系統(tǒng)屬性緩沖區(qū)地址就被確定了,后續(xù)的API調(diào)用就能找對位置了。
屬性系統(tǒng)首先得有個(gè)固定地址空間,這是初始化的任務(wù),初始化工作的最佳位置是在init進(jìn)程。在init進(jìn)程里,init_property_area函數(shù)調(diào)用init_workspace完成屬性空間的分配:
fd = ashmem_create_region ("system_properties", size);
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED , fd, 0);
隨后,
pa = pa_workspace.data;
__system_property_area__ = pa;
最后一句的__system_property_area__就是屬性空間的入口地址。
屬性的服務(wù)函數(shù)(get和set)是由bionic下system_properties.c文件提供的,即它是android的libc庫的一部分。以get操作為例:
init使用的property_get是個(gè)包裝函數(shù),其實(shí)現(xiàn)是調(diào)用__system_property_find函數(shù),后者是要找到所找屬性的入口。
這得遍歷屬性緩沖區(qū)的結(jié)構(gòu)。這個(gè)緩沖區(qū)包括兩個(gè)部分:目錄和內(nèi)容。目錄項(xiàng)目的結(jié)構(gòu)是:
struct prop_area {
unsigned volatile count;
unsigned volatile serial;
unsigned magic;
unsigned version;
unsigned reserved[4];
unsigned toc[1];
};
具體屬性的結(jié)構(gòu)是:
struct prop_info {
char name[PROP_NAME_MAX];
unsigned volatile serial;
char value[PROP_VALUE_MAX];
};
find函數(shù)的主要內(nèi)容:
prop_area *pa = __system_property_area__;
unsigned count = pa->count;
unsigned *toc = pa->toc;
unsigned len = strlen(name);
while(count--) {
unsigned entry = *toc++;
if(TOC_NAME_LEN(entry) != len) continue;
pi = TOC_TO_INFO(pa, entry);
if(memcmp(name, pi->name, len)) continue;
return pi;
}
count是總共的屬性數(shù)目,toc是屬性目錄的入口地址。以上循環(huán)中,entry是屬性的偏移量,是個(gè)32位的整數(shù),其高位字節(jié)存儲的是屬性名的長度,后24位存儲的是屬性在緩沖區(qū)里的偏移量。TOC_NAME_LEN就是取得目錄項(xiàng)的高8位,而TOC_TO_INFO則是取得后24位,然后再加上屬性緩沖區(qū)的入口地址,就得到具體屬性的入口地址,然后再把類型轉(zhuǎn)換為prop_info的指針,然后返回這個(gè)值。
還有個(gè)問題:系統(tǒng)屬性的客戶是如何獲知__system_property_area__的位置呢?這些客戶通過連接C庫而能調(diào)用系統(tǒng)屬性的各個(gè)API,但并不能自動獲知系統(tǒng)屬性緩沖區(qū)的地址,這個(gè)地址在每個(gè)客戶進(jìn)程裝載時(shí),都初始化為0。進(jìn)程之間可以共享代碼,但并不自動共享數(shù)據(jù),除非程序做些特殊的處理,比如使用共享內(nèi)存。此處利用了二進(jìn)制文件(可執(zhí)行文件或者庫)的init段,即把一些必須的初始化代碼,比如C++對象的構(gòu)造函數(shù),放在這個(gè)init段里,每次動態(tài)連接或裝載二進(jìn)制文件時(shí),就首先執(zhí)行這個(gè)初始化段。
gcc提供了constructor屬性來指示把代碼放在init段里。system_properties的緩沖區(qū)地址,是在bionic libC庫的init段里被確定的。文件libc_init_dynamic.c的__libc_prenit函數(shù)調(diào)用了__libc_init_common,后者又調(diào)用了__system_properties_init,最后這個(gè)函數(shù)確定__system_property_area__的地址。而函數(shù)__libc_prenit被給予屬性constructor:
void __attribute__((constructor)) __libc_prenit(void);
這樣在bionic libc動態(tài)庫被裝載時(shí),系統(tǒng)屬性緩沖區(qū)地址就被確定了,后續(xù)的API調(diào)用就能找對位置了。
注:結(jié)合源代碼看了這部分,看了還是不理解,先放在這里,說不定再回頭看,就能理解了
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
