屬性被大量使用在Android系統中,用來記錄系統設定或進程之間的資訊交換。屬性是在整個系統中全域可見的。每個進程可以get/set屬性,每個屬性都有一個名稱和值,他們都是字串格式。
在系統初始化時,Android將分配一個共用記憶體區來儲存的屬性。這些是由“init”守護進程完成的,其原始碼位於:device/system /init。“init”守護進程將啟動一個屬性服務。屬性服務在“init”守護進程中運行。每一個用戶端想要設定屬性時,必須串連屬性服務,再向其發送資訊。屬性服務將會在共用記憶體區中修改和建立屬性。任何用戶端想獲得屬性資訊,可以從共用記憶體直接讀取。這提高了讀取效能。
用戶端應用程式可以調用libcutils中的API函數以GET/SET屬性資訊。libcutils的原始碼位於:device/libs/cutils。API函數是:
int property_get(const char *key, char *value, const char *default_value);
int property_set(const char *key, const char *value);
而libcutils又調用libc中的 __system_property_xxx 函數獲得共用記憶體中的屬性。libc的原始碼位於:device/system/bionic。
屬性服務調用libc中的__system_property_init函數來初始化屬性系統的共用記憶體。當啟動屬性服務時,將從以下檔案中載入預設屬性:
/ default.prop
/system/build.prop
/system/default.prop
/data/local.prop
屬性將會以上述順序載入。後載入的屬性將覆蓋原先的值。這些屬性載入之後,最後載入的屬性會被保持在/data/property中。
特別屬性
如果屬性名稱以“ro.”開頭,那麼這個屬性被視為唯讀屬性。一旦設定,屬性值不能改變。
如果屬性名稱以“persist.”開頭,當設定這個屬性時,其值也將寫入/data/property。
如果屬性名稱以“net.”開頭,當設定這個屬性時,“net.change”屬性將會自動化佈建,以加入到最後修改的屬性名稱。(這是很巧妙的。 netresolve模組的使用這個屬性來追蹤在net.*屬性上的任何變化。)
屬性“ ctrl.start ”和“ ctrl.stop ”是用來啟動和停止服務。每一項服務必須在/init.rc中定義.系統啟動時,與init守護進程將解析init.rc和啟動屬性服務。一旦收到設定“ ctrl.start ”屬性的請求,屬性服務將使用該屬性值作為服務名找到該服務,啟動該服務。這項服務的啟動結果將會放入“ init.svc.<服務名>“屬性中。用戶端應用程式可以輪詢那個屬性值,以確定結果。
Android toolbox程式
Android toolbox程式提供了兩個工具: setprop和getprop擷取和設定屬性。其使用方法:
getprop <屬性名稱>
setprop <屬性名稱><<屬性值>
Java
在Java應用程式可以使用System.getProperty()和System.setProperty()函數擷取和設定屬性。
Action
預設情況下,設定屬性只會使"init"精靈寫入共用記憶體,它不會執行任何指令碼或二進位程式。但是,您可以將您的想要的實現的操作與init.rc中某個屬性的變化相關聯.例如,在預設的init.rc中有:
# adbd on at boot in emulator
on property:ro.kernel.qemu=1
start adbd
on property:persist.service.adb.enable=1
start adbd
on property:persist.service.adb.enable=0
stop adbd
這樣,如果你設定persist.service.adb.enable為1 ,"init"精靈就知道需要採取行動:開啟adbd服務。
文章中提到的共用記憶體就是Android特有的共用方式:ashmem
Ashmem 是一個匿名共用記憶體(Anonymous SHared MEMory)系統,該系統增加了介面因此進程間可以共用具名記憶體塊。舉一個例子,系統可以利用Ashmem儲存表徵圖,當繪製使用者介面的時候多個進程也可以訪問。Ashmem優於傳統Linux共用記憶體表現在當共用記憶體塊不再被用的時候,它為Kernel提供一種回收這些共用記憶體塊的手段。如果一個程式嘗試訪問Kernel釋放的一個共用記憶體塊,它將會收到一個錯誤提示,然後重新分配記憶體並重載資料。
android下propt怎麼通過init進程傳遞和glibc庫函數的添加
adb shell
# printenv
# getprop 擷取所有java層propt
# setprop wifi.interface eth0 設定"wifi.interface"對應的數值為eth0
環境變數ANDROID_PROPERTY_WORKSPACE=9,32768
所以fd=9,大小size=32768
system/init/init.c=>main()進程將調用
=>property_init
=>init_property_area
void property_init(void)
{
//ashmem_area - android shared memory area是android共用內容存的一種方式
//開啟ashmem裝置,申請一段size大小的kernel空間記憶體,不去釋放,以便供所有使用者空間進程共用.
//核心驅動位於linux/mm/ashmem.c檔案[luther.gliethttp].
init_property_area();
//#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
//從ramdisk中讀取default.prop檔案,將檔案中的所有java環境中使用到的propt釋放到
//這個共用記憶體中.
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
}
當然init程式在後邊仍然可以調用property_set()來設定新的propt,比如:property_set("ro.hardware", hardware);
ok,這個公用使用者空間程式共用的核心空間記憶體地區ashmem已經申請成功,並且填入了所有我們需要的資料,不論是從ramdisk解壓出來的
default.prop檔案直接讀出的propt,還是手工調用property_set()設定的propt,都已經放入了記憶體中.
接下來init繼續運行,註冊環境變數ANDROID_PROPERTY_WORKSPACE:
=>service_start
=>
get_property_workspace(&fd, &sz);
//從init進程的空閑fdt中dup一個閒置fd,比如閒置fd=9
//執行一次dup,那麼開啟init的引用計數就會加1,這樣保證不被無故釋放[luther.gliethttp].
sprintf(tmp, "%d,%d", dup(fd), sz);//比如ANDROID_PROPERTY_WORKSPACE=9,32768
add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);//添加環境變數 "ANDROID_PROPERTY_WORKSPACE"
//其實是放到一個static const char *ENV[32];中,調用service_start()函數時ENV將作為參數傳遞給
//execve(svc->args[0], (char**) svc->args, (char**) ENV);傳遞給service系統服務進程.
bionic/arch-arm/bionic/crtbegin_dynamic.S
bionic/arch-arm/bionic/crtbegin_static.S
_start:
mov r0, sp
mov r1, #0
adr r2, 0f
adr r3, 1f
b __libc_init //glibc庫初始化
0: b main
1: .long __PREINIT_ARRAY__
.long __INIT_ARRAY__
.long __FINI_ARRAY__
.long __CTOR_LIST__
...
使用adb pull init .從emulator模擬器導處init進程,進行如下反組譯碼:
luther@gliethttp:~$ arm-linux-objdump -DS init |more
init: file format elf32-littlearm
Disassembly of section .text:
000080a0 <.text>:
80a0: e1a0000d mov r0, sp
80a4: e3a01000 mov r1, #0 ; 0x0
80a8: e28f2004 add r2, pc, #4 ; 0x4
80ac: e28f3004 add r3, pc, #4 ; 0x4
80b0: ea004ab3 b 0x1ab84 //可以看到這個就是b __libc_init
80b4: ea004ab5 b 0x1ab90 //可以看到這個就是b main
80b8: 0001f000 andeq pc, r1, r0
80bc: 0001f008 andeq pc, r1, r8
80c0: 0001f014 andeq pc, r1, r4, lsl r0
80c4: 0001f01c andeq pc, r1, ip, lsl r0
所以arm-linux-gcc就是按上面的方式對init進程進行link連結的[luther.gliethttp].
bionic/bionic/libc_init_dynamic.c
bionic/bionic/libc_init_static.c
=>__libc_init
bionic/bionic/libc_init_common.c
=>__libc_init_common
=>__system_properties_init
=>__system_property_area__
int __system_properties_init(void)
{
...
env = getenv("ANDROID_PROPERTY_WORKSPACE");
...
pa = mmap(0, sz, PROT_READ, MAP_SHARED, fd, 0);
...
__system_property_area__ = pa;
...
return 0;
}
好了,經過上面glibc庫的初始化之後,所有應用程式都可以通過編譯到glibc庫中自訂的property_get庫函數
操作__system_property_area__了,比如:wpa_supplicant使用者應用應用程式調用wifi_connect_to_supplicant()
=>property_get("wifi.interface", iface, "sta");來獲得ashmem中與"wifi.interface"匹配的propt[luther.gliethttp].
本部落格摘自CSDN網友 http://blog.csdn.net/sustzombie/archive/2010/10/23/5960488.aspx ,讀完以後,相信您對Android的屬性系統有了一定的認識