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

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