最近添加一些預設的屬性設定,原代碼已有的架構是載入到android屬性系統中,所以看了一下android屬性系統是怎麼回事。
公司原有的架構是這麼一回事:添加屬性到一個xls檔案中,用python讀取xls檔案,寫為一個文字檔,將文字檔copy到手機中的/system/flex目錄下,這個目錄原先是不存在的,具體怎麼操作的,以後再說。假設這個建立的屬性檔案叫my.prop。代碼中載入這個屬性檔案,然後就是和其他屬性一般操作這些自訂的屬性了。
android系統預設檔案定義在/bionic/include/sys/_system_properties.h檔案中,如下:
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
目前後兩個檔案是沒有的。
除了這些檔案(加上my.prop),還有一些零星的定義,主要是通過方法定義的,例如/init.rc中有部分,init.c中main()中定義有部分等等。
android初始化從init.c的main()函數開始:
有這麼幾句:
property_init();
property_set_fd = start_property_service();
ufds[1].fd = property_set_fd;
ufds[1].events = POLLIN;
for(;;) {
int nr, i, timeout = -1;
for (i = 0; i < fd_count; i++)
ufds[i].revents = 0;
drain_action_queue();
restart_processes();
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
#if BOOTCHART
if (bootchart_count > 0) {
if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
timeout = BOOTCHART_POLLING_MS;
if (bootchart_step() < 0 || --bootchart_count == 0) {
bootchart_finish();
bootchart_count = 0;
}
}
#endif
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
if (ufds[2].revents == POLLIN) {
/* we got a SIGCHLD - reap and restart as needed */
read(signal_recv_fd, tmp, sizeof(tmp));
while (!wait_for_one_process(0))
;
continue;
}
if (ufds[0].revents == POLLIN)
handle_device_fd(device_fd);
if (ufds[1].revents == POLLIN)
handle_property_set_fd(property_set_fd);
if (ufds[3].revents == POLLIN)
handle_keychord(keychord_fd);
}
property_init()代碼(位於/system/core/init/property_service.c)如下:
void property_init(void)
{
init_property_area();
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
}
第一行分配了property記憶體空間,這裡很有趣啊,不知道他具體怎麼整的,空間大小用的數值是32768,PROP_NAME_MAX=32, PROP_VALUE_NAME=92,我如果這樣算的,32768/(8*(32+92))=33,很明顯不止33條記錄。望有研究的朋友給個提示。
分配的空間用__system_property_area__指向的。其他地方要用。
第二行載入了/default.prop這個屬性檔案,不知道原作者是基於什麼樣的考慮將幾個檔案分開載入。
看main()函數中的第二行 property_set_fd = start_property_service();
int start_property_service(void)
{
int fd;
//Load my FLEX property
load_properties_from_file("/system/flex/my.prop");
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
if(fd < 0) return -1;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
listen(fd, 8);
return fd;
}
載入其餘幾個屬性檔案。 load_persistent_properties();載入/data/property目錄下的屬性。
main中的其餘部分主要用於檢測是否有新的設定,有的時候進入設定流程,鑒權失敗會提示相關的異常,這裡疑惑就是新的設定是怎麼進入的。流程是怎麼走的。求解。。。
以上部分是為開機部分的載入內容。應用上主要集中在兩個部分:
c/c++層次上主要在/system/core/libcutil/properties.c,提供了property_set(),property_get(),property_list()等函數,對應的提供了幾個shell工具,就是在adb shell中可以直接調用,可以查看/system/bin目錄下有getprop,setprop,工具,事實上,init.rc也用到了這些工具。例如:
setprop ro.FOREGROUND_APP_ADJ 0
setprop ro.VISIBLE_APP_ADJ 1
setprop ro.SECONDARY_SERVER_ADJ 2
setprop ro.BACKUP_APP_ADJ 2
setprop ro.HOME_APP_ADJ 4
setprop ro.HIDDEN_APP_MIN_ADJ 7
setprop ro.CONTENT_PROVIDER_ADJ 14
setprop ro.EMPTY_APP_ADJ 15
setprop wifi.interface eth0
setprop ro.opengles.version 131072
這裡提供一個listprop的工具,顯示當前所有的property name-value對,已經測試過可行:
建立一個目錄,包含兩個檔案:Android.mk和list_property.c檔案
Android.mk檔案如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= list_property.c
LOCAL_SHARED_LIBRARIES := /
libcutils /
libutils /
LOCAL_MODULE:= listprop
include $(BUILD_EXECUTABLE)
include $(call all-makefiles-under,$(LOCAL_PATH))
list_property.c如下:
#include <cutils/properties.h>
#include <stdio.h>
void print_prop(const char* key,const char* value,void* cookie)
{
printf("key=%s,/tvalue=%s/n",key,value);
}
int main()
{
property_list(print_prop,NULL);
return 0;
}
確保Android.mk被編譯進去就行了。
Java層次上的應用主要在SystemProperties.java這個類中,無非是get/set方法。
11:10:37 2011-01-08