一、Android4.4屬性系統(tǒng)系列文章
Android4.4屬性系統(tǒng)-初始化
Android4.4屬性系統(tǒng)-系統(tǒng)服務(wù)
Android4.4屬性系統(tǒng)-內(nèi)存空間共享
Android4.4屬性系統(tǒng)-屬性獲取
Android4.4屬性系統(tǒng)-屬性設(shè)置
二、寫在前面-如何閱讀本系列文章
本系列文章大部分是對源碼的解析和注釋,所以讀起來枯燥無味,并且雜亂,這是閱讀系統(tǒng)源碼無法避免的,如果你有條件,可以點(diǎn)擊下載Android4.4源碼,閱讀源碼可以使用eclise,AndroidStudio,vim等。
文章的章節(jié)安卓是按照代碼模塊區(qū)分的,例如init進(jìn)程代碼,libcutils代碼是按章節(jié)來區(qū)分,但不同模塊的代碼之間是有關(guān)聯(lián)的,閱讀時(shí)需要經(jīng)常跳轉(zhuǎn),通過搜索功能進(jìn)行頁內(nèi)搜索即可
三、安卓屬性系統(tǒng)介紹
Android 里有很多屬性(property),每個(gè)屬性都有一個(gè)名字和值,他們都是字符串格式。這些屬性定義了 Android 系統(tǒng)的一些公共系統(tǒng)屬性。
在Android平臺中,為了讓運(yùn)行中的所有進(jìn)程共享系統(tǒng)運(yùn)行時(shí)所需要的各種設(shè)置值,系統(tǒng)開辟了屬性存儲區(qū)域,并提供了訪問該區(qū)域的API。屬性由鍵(key)與值(value)構(gòu)成,其表現(xiàn)形式為“鍵=值”。
在訪問屬性值時(shí),添加了訪問權(quán)限控制,增強(qiáng)了訪問的安全性。系統(tǒng)中所有運(yùn)行中的進(jìn)程都可以訪問屬性值,但僅有init進(jìn)程才能修改屬性值。其他進(jìn)程修改屬性值時(shí),必須向init進(jìn)程提出請求,最終由init進(jìn)程負(fù)責(zé)修改屬性值。在此過程中,init進(jìn)程會(huì)先檢查各屬性的訪問權(quán)限,而后再修改屬性值。
當(dāng)屬性值更改后,若定義在init.rc文件中的某個(gè)特定條件得到滿足,則與此條件相匹配的動(dòng)作就會(huì)發(fā)生,每個(gè)動(dòng)作都有一個(gè)觸發(fā)器,決定動(dòng)作的執(zhí)行時(shí)間,記錄在“on property”關(guān)鍵字后的命令即被執(zhí)行。
3.1屬性系統(tǒng)工作框架

從圖中我們可以看出Android屬性系統(tǒng)由有三個(gè)進(jìn)程,一組屬性文件和一塊共享內(nèi)存組成。這塊共享內(nèi)存保存著系統(tǒng)中所有的屬性記錄,只有Property service能寫這塊共享內(nèi)存,并且Property service負(fù)責(zé)將屬性文件中的屬性記錄加載到共享內(nèi)存中。
**屬性讀取進(jìn)程**(property consumer)把這塊共享內(nèi)存映射到自己的進(jìn)程空間,然后直接讀取它。**屬性設(shè)置進(jìn)程**(property setter)也加載這塊共享到他的進(jìn)程空間,但是他不能直接寫這塊共享內(nèi)存。當(dāng)他需要增加或者修改屬性的時(shí)候,通過Unix Socket發(fā)生屬性給Property service,Property service將代表設(shè)置進(jìn)程寫入共享內(nèi)存和屬性文件。
Property service運(yùn)行于**init進(jìn)程**中。init進(jìn)程首先創(chuàng)建一塊共享內(nèi)存,并把他的句柄fd存放在這塊內(nèi)存中,**init進(jìn)程通過mmap帶MAP_SHARE標(biāo)志的系統(tǒng)調(diào)用,把這塊內(nèi)存映射到他的虛擬空間中,最終這塊內(nèi)存所有的更新將會(huì)被所有映射這塊共享內(nèi)存的進(jìn)程看到**。共享內(nèi)存句柄fd和共享內(nèi)存大小存儲在系統(tǒng)環(huán)境變量“ANDROID_PROPERTY_WORKSPACE”中,所有的進(jìn)程包括屬性設(shè)置進(jìn)程和屬性讀取進(jìn)程都將通過這個(gè)系統(tǒng)環(huán)境變量獲得共享內(nèi)存的句柄fd和大小,然后把這塊內(nèi)存映射到他們自己的虛擬空間。共享內(nèi)存布局如下:

當(dāng)前,屬性不能被刪除。也就是說一旦屬性被創(chuàng)建,將不可以被刪除,但是它們可以被修改
四、屬性系統(tǒng)的優(yōu)點(diǎn)
屬性系統(tǒng)有一下四個(gè)優(yōu)點(diǎn)
- 全局性:只要擁有對應(yīng)的權(quán)限,就可以同步獲取和修改
- 廣泛的可訪問性:在Java層,native層,shell層都可以獲取和修改
- 初始化早:屬性服務(wù)實(shí)在 init 進(jìn)程中啟動(dòng)的
- 使用簡單:主要就兩個(gè)方法 set 和 get
但是只能支持有限的類型:string、int、long、boolean
五、屬性系統(tǒng)的初始化和啟動(dòng)過程
屬性服務(wù)的是從init進(jìn)程中啟動(dòng),init 進(jìn)程(源碼位于/system/core/init/init.c)主要完成:
- 解析 init.rc 文件并執(zhí)行相應(yīng)動(dòng)作和服務(wù)
- 生成設(shè)備驅(qū)動(dòng)節(jié)點(diǎn)
- 處理子進(jìn)程終止
- 提供屬性服務(wù)
先上圖熟悉流程:

5.1 init進(jìn)程初始化property_service
init進(jìn)程是安卓系統(tǒng)第一個(gè)進(jìn)程,由它執(zhí)行系統(tǒng)的初始化過程,屬性服務(wù)也是由它開始初始化的
system/core/init/init.h
init.h是init.c的頭文件,它定義了兩個(gè)重要的結(jié)構(gòu)體:command和action
#include <cutils/list.h>
struct command
{
/* list of commands in an action */
struct listnode clist; //listnode結(jié)構(gòu)體定義在list.h
//command 結(jié)構(gòu)體中的func指向一個(gè)函數(shù),該函數(shù)在后續(xù)init 進(jìn)程調(diào)用execute_one_command 時(shí)會(huì)被調(diào)用
int (*func)(int nargs, char **args);
int nargs;
char *args[1];
};
struct action {
/* node in list of all actions */
struct listnode alist;
/* node in the queue of pending actions */
struct listnode qlist;
/* node in list of actions for a trigger */
struct listnode tlist;
unsigned hash;
const char *name;
struct listnode commands; //listnode結(jié)構(gòu)體定義在list.h
struct command *current;
};
system/core/init/init.c
init.c是init進(jìn)程的源文件,找到入口main()函數(shù)
//引入property相關(guān)的頭文件
#include <sys/system_properties.h>
#include "property_service.h"
static int property_triggers_enabled = 0;
static struct action *cur_action = NULL;
static struct command *cur_command = NULL;
static struct listnode *command_queue = NULL;
int main(int argc, char **argv)
{
int property_set_fd_init = 0;
//1-property初始化,位于property_service.c
property_init();
//2-這些目錄必須在初始策略加載之前創(chuàng)建,因此需要將其安全上下文恢復(fù)到正確的值。這必須在由ueventd填充/dev之前發(fā)生。
restorecon("/dev");
restorecon("/dev/socket");
restorecon("/dev/__properties__");
restorecon_recursive("/sys");
is_charger = !strcmp(bootmode, "charger");
INFO("property init\n");
//3-如果不是充電狀態(tài),加載默認(rèn)properties
if (!is_charger)
property_load_boot_defaults();
// queue_builtin_action()將 property_init_action函數(shù)放入特定的列表中
queue_builtin_action(property_service_init_action, "property_service_init");
/* run all property triggers based on current state of the properties */
queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
//進(jìn)入for循環(huán),
for(;;) {
int nr, i, timeout = -1;
execute_one_command();//execute_one_command 函數(shù)從 action_queue 隊(duì)列中獲取 action 并執(zhí)行
restart_processes();
if (!property_set_fd_init && get_property_set_fd() > 0) {
ufds[fd_count].fd = get_property_set_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
property_set_fd_init = 1;
}
if (!signal_fd_init && get_signal_fd() > 0) {
ufds[fd_count].fd = get_signal_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
signal_fd_init = 1;
}
if (!keychord_fd_init && get_keychord_fd() > 0) {
ufds[fd_count].fd = get_keychord_fd();
ufds[fd_count].events = POLLIN;
ufds[fd_count].revents = 0;
fd_count++;
keychord_fd_init = 1;
}
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
if (!action_queue_empty() || cur_action)
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;
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents == POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
else if (ufds[i].fd == get_keychord_fd())
handle_keychord();
else if (ufds[i].fd == get_signal_fd())
handle_signal();
}
}
}
}
//property發(fā)生改變
void property_changed(const char *name, const char *value)
{
if (property_triggers_enabled)
queue_property_triggers(name, value);
}
static int queue_property_triggers_action(int nargs, char **args)
{
queue_all_property_triggers(); //位于init_parser.c
/* enable property triggers */
property_triggers_enabled = 1;
return 0;
}
//從action隊(duì)列中讀取action并執(zhí)行
void execute_one_command(void)
{
int ret;
//判斷是獲取一個(gè)新的 action 還是繼續(xù)執(zhí)行 action 的 commands 列表中的下一個(gè) command
if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
//對于Android屬性系統(tǒng),是一個(gè)新的action,cur_action==NULL,cur_command==NULL
//從 action_queue 中 獲 取 action 并 賦 值 給 cur_action,定義在init_parser.c中
cur_action = action_remove_queue_head();
cur_command = NULL;
if (!cur_action)
return;
INFO("processing action %p (%s)\n", cur_action, cur_action->name);
//從 cur_action 中的 commands 節(jié)點(diǎn)中獲取第一個(gè) command 賦值給 cur_command
cur_command = get_first_command(cur_action);
} else {
cur_command = get_next_command(cur_action, cur_command);
}
if (!cur_command)
return;
//對于 Android 屬性系統(tǒng),action 的 commands 節(jié)點(diǎn)只有一個(gè) command,調(diào)用
//command中 func 成員所指向的函數(shù),此處調(diào)用 property_service_init_action函數(shù)
ret = cur_command->func(cur_command->nargs, cur_command->args);
INFO("command '%s' r=%d\n", cur_command->args[0], ret);
}
//從指定action結(jié)體中,獲取commands鏈表的第一個(gè)節(jié)點(diǎn)
static struct command *get_first_command(struct action *act)
{
struct listnode *node;
node = list_head(&act->commands);
if (!node || list_empty(&act->commands))
return NULL;
return node_to_item(node, struct command, clist);
}
//Android屬性服務(wù)初始化函數(shù)
static int property_service_init_action(int nargs, char **args)
{
/* read any property files on system or data and
* fire up the property service. This must happen
* after the ro.foo properties are set above so
* that /data/local.prop cannot interfere with them.
*/
//該方法開始讀取系統(tǒng)中所有的property文件或者數(shù)據(jù),并啟動(dòng)Property服務(wù),但是這
//必須在ro.foo的屬性被設(shè)置之后,這樣/data/local.prop就不會(huì)干擾它們
start_property_service(); //定義在property_service.c中
return 0;
}
5.2 property_service.c解析
system/core/init/property_service.c
#include "property_service.h"
#include <sys/socket.h>
#include <sys/_system_properties.h>
#define PERSISTENT_PROPERTY_DIR "/data/property"
//標(biāo)識persistent proerties是否加載完成
static int persistent_properties_loaded = 0;
//標(biāo)識property初始化是否完成
static int property_area_inited = 0;
typedef struct {
size_t size; //共享內(nèi)存空間大小
int fd; //句柄
} workspace;
//property初始化
void property_init(void)
{
init_property_area();
}
/*init_property_area 初始化共享內(nèi)存空間。在 Android 系統(tǒng)中,所有的進(jìn)程是共享
*系統(tǒng)屬性值的,Android 系統(tǒng)提供了一個(gè)名為屬性的保存空間,在共享內(nèi)存區(qū)域中
*(ASHMEM),創(chuàng)建并初始化屬性域*/
static workspace pa_workspace;
static int init_property_area(void)
{
if (property_area_inited) //只能初始化一次
return -1;
//初始化共享內(nèi)存區(qū)域,位于system_properties.c
if(__system_property_area_init())
return -1;
//初始化工作空間,大小初始化為0
if(init_workspace(&pa_workspace, 0))
return -1;
fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
property_area_inited = 1; //設(shè)置初始化完成標(biāo)志
return 0;
}
//初始化工作空間,workspace在該文件中被定義,參數(shù)<工作空間,空間大小>
static int init_workspace(workspace *w, size_t size)
{
void *data;
//#define PROP_FILENAME "/dev/__properties__" 定義在_system_properties.h
int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW); //打開內(nèi)存映射文件
if (fd < 0)
return -1;
w->size = size; //設(shè)置空間大小
w->fd = fd; //設(shè)置文件句柄,fd 為/dev/__properties__文件句柄
return 0;
}
void property_load_boot_defaults(void)
{
//從文件中加載,PROP_PATH_RAMDISK_DEFAULT=“/defalult.prop”
//定義在_system_properties.h文件中
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
}
/*
default.prop 文件中的內(nèi)容是在 Android系統(tǒng)編譯時(shí)寫入到 boot.img 中的,而每次
開機(jī),boot.img 會(huì)進(jìn)行解壓,所以想要修改該文件中的內(nèi)容可以重新編譯系統(tǒng),或
者修改 boot.img 文件,在/build/core/main.mk 文件中定義了不同屬性的值,
ADDITIONAL_DEFAULT_PROPERTIES 變量值就是需要寫入到 default.prop 文件中
的內(nèi)容
build/core/main.mk部分內(nèi)容如下:
# Target is secure in user builds.
ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=1
# Disallow mock locations by default for user builds
ADDITIONAL_DEFAULT_PROPERTIES += ro.allow.mock.location=0
default.prop文件內(nèi)容一般如下 :
shell@sp9820w_poc_780:/ $ cat default.prop
#
# ADDITIONAL_DEFAULT_PROPERTIES
#
ro.secure=1
ro.allow.mock.location=0
ro.debuggable=1
camera.disable_zsl_mode=1
persist.sys.usb.config=mtp,adb
*/
//從指定文件中加載屬性
static void load_properties_from_file(const char *fn)
{
char *data;
unsigned sz;
//打開文件,讀取內(nèi)容
data = read_file(fn, &sz);
if(data != 0) {
//打開成功,加載property
load_properties(data);
//關(guān)閉文件
free(data);
}
}
//解析property數(shù)據(jù),逐行解析
static void load_properties(char *data)
{
char *key, *value, *eol, *sol, *tmp;
sol = data; //sol指向文件開始
//char *strchr(const char *str, int c)返回在字符串 str 中第一次出現(xiàn)字符 c 的位置,實(shí)現(xiàn)逐行讀取
while((eol = strchr(sol, '\n'))) { //返回?fù)Q行符的指針
key = sol; //key表示行首的指針
*eol++ = 0; //相關(guān)于*eol=0; eol++; '\n'替換為0,此時(shí)eol為下一行的行首指針
sol = eol; //賦值給sol
value = strchr(key, '='); //截取一行中'='前面的字符,value指向'='
if(value == 0) continue; //如果=前面為空,跳過
*value++ = 0; //’=‘替換為0,value指向原'='后面的內(nèi)容,即實(shí)際的value字節(jié)地址
while(isspace(*key)) key++; //去掉一行前面的空格
if(*key == '#') continue; //如果是'#'開頭,表示注釋,跳過
tmp = value - 2; //value-2為key的末尾地址
while((tmp > key) && isspace(*tmp)) *tmp-- = 0; //判斷key末尾是否有空白符,如果有替換為0
while(isspace(*value)) value++; //判斷value起始內(nèi)容中是否有空白符,如果有替換為0
tmp = eol - 2; //判斷value末尾內(nèi)容中是否有空白符,如果有替換為0
while((tmp > value) && isspace(*tmp)) *tmp-- = 0;
//設(shè)置屬性,關(guān)鍵調(diào)用,該方法本章不再繼續(xù)深究
property_set(key, value);
}
}
//啟動(dòng)屬性服務(wù)
void start_property_service(void)
{
int fd;
//1.加載/system/build.prop
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
//2.加載 /system/default.prop
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
//3.加載override props
load_override_properties();
/* 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;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
listen(fd, 8);
property_set_fd = fd;
}
5.3 system_properties.c解析
屬性存儲在混合(trie)字典樹 /(binary)二叉樹結(jié)構(gòu)中。每個(gè)屬性的名稱都以'.'分隔,字符和標(biāo)記放在一起成為一個(gè)特里結(jié)構(gòu)。 特里結(jié)構(gòu)的每個(gè)級別的兄弟姐妹都存儲在一個(gè)二叉樹。例如,“ro.secure”=“1”可以存儲如下:

特里結(jié)構(gòu)的根結(jié)點(diǎn)是空的,后面第二個(gè)節(jié)點(diǎn)為ro,ro結(jié)點(diǎn)是一個(gè)二叉樹的根結(jié)點(diǎn),它的左孩子為net,右孩子為sys。ro的后驅(qū)結(jié)點(diǎn)為secure,它也是一個(gè)二駐樹的根結(jié)點(diǎn),左孩子為com,右孩子為prop,值為1。這樣把prop前面的串起來就是ro.secure=1。
bionic/libc/include/sys/system_properties.h
typedef struct prop_info prop_info;
//prop key和value的最大長度
#define PROP_NAME_MAX 32
#define PROP_VALUE_MAX 92
bionic/libc/include/sys/_system_properties.h
#define PROP_AREA_MAGIC 0x504f5250
#define PROP_AREA_VERSION 0xfc6ed0ab
#define PROP_AREA_VERSION_COMPAT 0x45434f76
#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"
#define PROP_PATH_FACTORY "/factory/factory.prop"
//定義映射內(nèi)存空間的大小128K
#define PA_SIZE (128 * 1024)
//prop service的名稱
#define PROP_SERVICE_NAME "property_service"
//prop內(nèi)存映射文件
#define PROP_FILENAME "/dev/__properties__"
bionic/libc/bionic/system_properties.c
static char property_filename[PATH_MAX] = PROP_FILENAME;
//property共享內(nèi)存結(jié)構(gòu)體
struct prop_area {
unsigned bytes_used; //已使用的字節(jié)數(shù)
unsigned volatile serial; //serial 表示整個(gè) prop_area 被修改的次數(shù),包括
新增加的
unsigned magic;
unsigned version;
unsigned reserved[28];
char data[0]; //實(shí)際的共享內(nèi)存區(qū)域
};
//定義全局變量
typedef struct prop_area prop_area;
//property info結(jié)構(gòu)體
struct prop_info {
//prop_info 中的 serial,其高8 位表示該 prop_info 中 name 的長度,而低 24 位表示該 prop_info 被更新的次數(shù)
unsigned volatile serial;
char value[PROP_VALUE_MAX];
char name[0];
};
//定義全局變量
typedef struct prop_info prop_info;
//初始化共享內(nèi)存
int __system_property_area_init()
{
return map_prop_area_rw();
}
//初始化可讀寫的共享內(nèi)存區(qū)域
static int map_prop_area_rw()
{
prop_area *pa; //prop_area結(jié)構(gòu)體定義在該文件中
int fd;
int ret;
/* dev is a tmpfs that we can use to carve a shared workspace
* out of, so let's do that...
*/
//dev是一個(gè)臨時(shí)文件系統(tǒng),我們可以用來定制共享工作區(qū)
fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
if (fd < 0) {
if (errno == EACCES) {
/* for consistency with the case where the process has already
* mapped the page in and segfaults when trying to write to it
*/
abort();
}
return -1;
}
//fcntl 根據(jù)文件描述詞來操作文件特性,給 init_workspace 中創(chuàng)建的文件描述符設(shè)置文件描述符標(biāo)記
ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
if (ret < 0)
goto out;
if (ftruncate(fd, PA_SIZE) < 0)
goto out;
pa_size = PA_SIZE; //設(shè)置映射內(nèi)存空間大小
pa_data_size = pa_size - sizeof(prop_area); //數(shù)據(jù)空間大小=總空間-prop_area結(jié)構(gòu)體占用的空間
compat_mode = false;
/*映射為共享內(nèi)存,mmap將一個(gè)文件或者其它對象映射進(jìn)內(nèi)存
*這里是關(guān)鍵的部分,關(guān)于mmap可以參考(https://blog.csdn.net/yangle4695/article/details/52139585)
*/
/*參數(shù)<映射的內(nèi)存起始地址為NULL=0,映射大小,可讀|可寫,
*MAP_SHARED :對映射區(qū)域的寫入數(shù)據(jù)會(huì)復(fù)制回文件內(nèi), 而且允許其他映射該文件的進(jìn)程共享
* fd文件描述符, offset:表示被映射對象(即文件)從那里開始對映,通常都是用0>
* 返回被映射區(qū)的指針pa
*/
pa = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(pa == MAP_FAILED)
goto out;
memset(pa, 0, pa_size); //初始化映射內(nèi)存區(qū)域?yàn)?0
pa->magic = PROP_AREA_MAGIC;
pa->version = PROP_AREA_VERSION;
/* reserve root node */
pa->bytes_used = sizeof(prop_bt);
/* plug into the lib property services */
//將 pa 賦值給__system_property_area__
__system_property_area__ = pa;
close(fd);
return 0;
out:
close(fd);
return -1;
}
//查詢prop
const prop_info *__system_property_find(const char *name)
{
if (__predict_false(compat_mode)) {
return __system_property_find_compat(name);
}
return find_property(root_node(), name, strlen(name), NULL, 0, false);
}
//前面介紹過了,屬性的存儲結(jié)構(gòu)為特里結(jié)構(gòu)+二叉樹結(jié)構(gòu),所以查找屬性其實(shí)就是
//特里結(jié)構(gòu)+二叉樹結(jié)構(gòu)的遍歷
static const prop_info *find_property(prop_bt *trie, const char *name,
uint8_t namelen, const char *value, uint8_t valuelen,
bool alloc_if_needed)
{
const char *remaining_name = name;
while (true) {
char *sep = strchr(remaining_name, '.');
bool want_subtree = (sep != NULL);
uint8_t substr_size;
prop_bt *root;
if (want_subtree) {
substr_size = sep - remaining_name;
} else {
substr_size = strlen(remaining_name);
}
if (!substr_size)
return NULL;
if (trie->children) {
root = to_prop_obj(trie->children);
} else if (alloc_if_needed) {
root = new_prop_bt(remaining_name, substr_size, &trie->children);
} else {
root = NULL;
}
if (!root)
return NULL;
trie = find_prop_bt(root, remaining_name, substr_size, alloc_if_needed);
if (!trie)
return NULL;
if (!want_subtree)
break;
remaining_name = sep + 1;
}
if (trie->prop) {
return to_prop_obj(trie->prop);
} else if (alloc_if_needed) {
return new_prop_info(name, namelen, value, valuelen, &trie->prop);
} else {
return NULL;
}
}

5.4 init_parser.c解析
system/core/init/init_parser.c
static list_declare(service_list);
static list_declare(action_list); //聲明action list
static list_declare(action_queue);
//參數(shù)<函數(shù)指針,函數(shù)指針指向函數(shù)的參數(shù)>
void queue_builtin_action(int (*func)(int nargs, char **args), char *name)
{
struct action *act; //定義在init.h中
struct command *cmd; //定義在init.h中
act = calloc(1, sizeof(*act)); //act分配內(nèi)存
act->name = name; //Android 系統(tǒng)屬性服務(wù)來說,該值為 property_service_init
list_init(&act->commands); //初始化,將 listnode 的 next 和 prev 都指向自
身
list_init(&act->qlist); //初始化qlist
cmd = calloc(1, sizeof(*cmd)); //cmd分配內(nèi)存
cmd->func = func; //設(shè)置函數(shù)指針,對于屬性服務(wù)為property_service_init_action函數(shù)
cmd->args[0] = name; //args 表示函數(shù)運(yùn)行的參數(shù)值,此處只有一個(gè)name參數(shù)
list_add_tail(&act->commands, &cmd->clist); //在action的commands鏈表的尾部添加節(jié)點(diǎn)cmd->clist
//action_list尾部添加節(jié)點(diǎn)act->alist
list_add_tail(&action_list, &act->alist);
//
action_add_queue_tail(act);
}
void action_add_queue_tail(struct action *act)
{
if (list_empty(&act->qlist)) { //如果鏈表為空則添加
list_add_tail(&action_queue, &act->qlist);
}
}
//從action_queue獲取頭節(jié)點(diǎn),并刪除頭結(jié)點(diǎn)
struct action *action_remove_queue_head(void)
{
if (list_empty(&action_queue)) {
return 0;
} else {
struct listnode *node = list_head(&action_queue);
struct action *act = node_to_item(node, struct action, qlist);
list_remove(node);
list_init(node);
return act;
}
}
queue_builtin_action方法執(zhí)行完后,action 和 command 結(jié)構(gòu)體以及 action_list 和 action_queue 的關(guān)系如下圖(queue_builtin_action 在 此 處 并 不 是 最 后 一 次 被 調(diào) 用 , 因 此 action_list 以 及action_queue 和 action 之間用虛點(diǎn)線表示,action_list 和 action_queue 之前還有其他的 action結(jié)構(gòu)體變量)

5.5 cutils庫解析
目錄位置system/core/libcutils,是一些c的函數(shù)工具庫,現(xiàn)在介紹一些涉及到的文件
system/core/include/cutils/list.h
//可構(gòu)成雙向鏈表
struct listnode
{
struct listnode *next;
struct listnode *prev;
};
//宏定義,聲明并初始化鏈表
#define list_declare(name) \
struct listnode name = { \
.next = &name, \
.prev = &name, \
}
system/core/libcutils/list.c
#include <cutils/list.h>
//初始化鏈表
void list_init(struct listnode *node)
{
node->next = node;
node->prev = node;
}
//末尾添加節(jié)點(diǎn)
void list_add_tail(struct listnode *head, struct listnode *item)
{
item->next = head;
item->prev = head->prev;
head->prev->next = item;
head->prev = item;
}
//移除節(jié)點(diǎn)
void list_remove(struct listnode *item)
{
item->next->prev = item->prev;
item->prev->next = item->next;
}
六、參考
Android屬性系統(tǒng)
Linux 內(nèi)存映射函數(shù) mmap
trie
Linux 內(nèi)存映射函數(shù) mmap()函數(shù)詳解
Android屬性系統(tǒng)