一路跑下來, 我們可以發現終於看到我們想看的command元素了, 原來在每一個act元素中還有一串由act元素所帶的comand建立的cmdlinked list, 每一個comand元素會有一個func的functionpointer. 這個function pointer就是由kw_func macro所指定的.
[cpp]
//system\core\init\init_parser.c
#define kw_func(kw) (keyword_info[kw].func)
//system\core\init\init_parser.c
#define kw_func(kw) (keyword_info[kw].func)
由這個macro可以知道, 其所指定的function就看kw_func macro所帶的參數kw經由keyword_infomapping table去指定的.
回到執行流程的execute_one_command函數繼續分析, 由上面的一些細節可以對於cur_command所帶的function跟keyword_info mapping table中所記錄的function有關.Example:
[cpp]
//system\core\rootdir\init.rc
write /proc/sys/kernel/panic_on_oops 1
//system\core\rootdir\init.rc
write /proc/sys/kernel/panic_on_oops 1
會經由keyword_info mapping table中的
[cpp] view plaincopyprint?KEYWORD(write, COMMAND, 2, do_write)
KEYWORD(write, COMMAND, 2, do_write)
呼叫到
[cpp]
\\system\core\init\builtins.c
int do_write(int nargs, char **args)
{
const char *path = args[1];
const char *value = args[2];
char prop_val[PROP_VALUE_MAX];
int ret;
ret = expand_props(prop_val, value, sizeof(prop_val));
if (ret) {
ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
return -EINVAL;
}
return write_file(path, prop_val);
}
\\system\core\init\builtins.c
int do_write(int nargs, char **args)
{
const char *path = args[1];
const char *value = args[2];
char prop_val[PROP_VALUE_MAX];
int ret;
ret = expand_props(prop_val, value, sizeof(prop_val));
if (ret) {
ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
return -EINVAL;
}
return write_file(path, prop_val);
}
建立filesystem path node
Init process是android的一個啟動的process,在initprocess一啟動就會開始建構一些file system.
[cpp]
//system\core\init\init.c
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
//system\core\init\init.c
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
首先先建構出三個目錄, dev, proc, sys, 期三個目錄所放的檔案個不同.
/dev
在Linux下, 任何的周邊裝置都是以檔案的形態存在這目錄下. 要控制周邊裝置只要針對這目錄下的檔案路徑作檔案讀寫就行了.
/proc
本身是一個virtual file system, 裡面放置的檔案資料都會存在記憶體當中, 也就是說只有裝置在執行時, 這目錄下才會有檔案出現..
/sys
本身是一個virtual file system, 跟/proc放置的檔案不一樣, 放的都是跟核心有關的資料或是核心偵測到的硬體裝置資訊..
之後會發現就在這三個主要的目錄下掛載其他目錄,和建構子目錄.
監控系統屬性變化跟事件
Init process所監控的對象有property, signal, keychord. Init process一啟動時便會針對這三個對像作initialize的動作.
[cpp]
// system\core\init\init.c
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(property_service_init_action, "property_service_init");
queue_builtin_action(signal_init_action, "signal_init");
// system\core\init\init.c
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(property_service_init_action, "property_service_init");
queue_builtin_action(signal_init_action, "signal_init");
queue_builtin_action函數只是將第一個函數封裝成一個command, 然後在利用command組成一個act的資料元素, 之後在將這個act新增到action_list中, 之後再經由action_add_queue_tail將此新的act資料元素送進actionqueue中. 其command所帶的函數會在前面所討論的execute_one_command函數呼叫到.
由於三個對像初始化的型為大同小異, 這裡就舉property來說明initial其間做哪些行為.
[cpp]
// system\core\init\init.c
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.
*/
start_property_service();
return 0;
}
//system\core\init\property_service.c
void start_property_service(void)
{
int fd;
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
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;
}
// system\core\init\init.c
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.
*/
start_property_service();
return 0;
}
//system\core\init\property_service.c
void start_property_service(void)
{
int fd;
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
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;
}
一開始就會下載property設定檔, 這些檔案存放的路徑定義在_system_properties.h
[cpp]
// bionic\libc\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"
// bionic\libc\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"
所有的android系統所吃的設定檔一開機就會從這些檔案去讀取. 至於propertyconfig file如何去編輯, 這不在這裡的範圍. 所以就不在這分析.下載完所有的property的設定值之後就開啟socket去等待變化. 並把filedescriptor傳給global 變數property_set_fd.
一旦初始化之後, 就開始進入監控流程.
[cpp]
//system\core\init\init.c
int main(int argc, char **argv)
{
//...
for(;;) {
// 執行action list 中的act的command.
// 檢查是否有service需要重新啟動
(1)
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;
}
//....
(2)
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
(3)
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents == POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
//....
}
}
}
return 0;
}
//system\core\init\init.c
int main(int argc, char **argv)
{
//...
for(;;) {
// 執行action list 中的act的command.
// 檢查是否有service需要重新啟動
(1)
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;
}
//....
(2)
nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
(3)
for (i = 0; i < fd_count; i++) {
if (ufds[i].revents == POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
//....
}
}
}
return 0;
}
(1) 註冊pollfd 結構, 其中get_property_set_fd 函數所取得的值就是之前在initial時期所開啟socket的 filedescriptor.
(2) 開始進入polling監控變化. 一有變化才會繼續第三步, 否則跳過接著下一次polling監控.
(3) 一有變化就開始比對所註冊的filedescriptor, 之前有提到目前android(4.2)監控的對象有三個. 最後進入handlefunction.