AndroidInitProcess分析心得(3)

一路跑下來, 我們可以發現終於看到我們想看的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.

 

 

You May Also Like