九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
android的init過程分析
http://blog.csdn.net/tommy_wxie/article/details/7532628

前言

Android系統(tǒng)是運作在linux kernal上的,因此它的啟動過程也遵循linux的啟動過程,當linux內(nèi)核啟動之后,運行的第一個進程是init,這個進程是一個守護進程,它的生命周期貫穿整個linux 內(nèi)核運行的始終, linux中所有其他的進程的共同始祖均為init進程。當然為了啟動并運行整個android系統(tǒng),google實現(xiàn)了自己的init進程,下面主要分析init進程都做了些什么?

1.首先,init是一個守護進程,為了防止init的子進程成為僵尸進程(zombie process),需要init在子進程在結(jié)束時獲取子進程的結(jié)束碼,通過結(jié)束碼將程序表中的子進程移除,防止成為僵尸進程的子進程占用程序表的空間,當程序表的空間達到上限時,則系統(tǒng)就不能再啟動新的進程了,那么就會引起很嚴重的系統(tǒng)問題。
    在linux當中,父程序是通過捕捉SIGCHLD信號來得知子進程結(jié)束的情況的;由于系統(tǒng)默認在子進程暫停時也會發(fā)送信號SIGCHLD,init需要忽略子進程在暫停時發(fā)出的SIGCHLD信號,因此將act.sa_flags 置為SA_NOCLDSTOP,該標志位的含義是就是要求系統(tǒng)在子進程暫停時不發(fā)送SIGCHLD信號。具體的代碼如下所示:
    struct sigaction act;
    ………………
    act.sa_handler = sigchld_handler;
    act.sa_flags = SA_NOCLDSTOP;
    act.sa_mask = 0;
    act.sa_restorer = NULL;
    sigaction(SIGCHLD, &act, 0);

2.創(chuàng)建文件系統(tǒng)目錄并掛載相關(guān)的文件系統(tǒng)

    /* clear the umask */
    umask(0);

        /* Get the basic filesystem setup we need put
         * together in the initramdisk on / and then we'll
         * let the rc file figure out the rest.
         */
    mkdir("/dev", 0755);
    mkdir("/proc", 0755);
    mkdir("/sys", 0755);

    mount("tmpfs", "/dev", "tmpfs", 0, "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);

2.1 清除屏蔽字(file mode creation mask),保證新建的目錄的訪問權(quán)限不受屏蔽字影響.

2.2 在init初始化過程中,Android分別掛載了tmpfs,devpts,proc,sysfs 4類文件系統(tǒng)

2.2.1 tmpfs文件系統(tǒng)
    tmpfs是一種虛擬內(nèi)存文件系統(tǒng),因此它會將所有的文件存儲在虛擬內(nèi)存中,并且tmpfs下的所有內(nèi)容均為臨時性的內(nèi)容,如果你將tmpfs文件系統(tǒng)卸載后,那么其下的所有的內(nèi)容將不復(fù)存在。
    tmpfs有些像虛擬磁盤(ramdisk),但不是一回事。說其像虛擬磁盤,是因為它
可以使用你的RAM,但它也可以使用你的交換分區(qū)。傳統(tǒng)的虛擬磁盤是一個塊設(shè)
備,而且需要一個mkfs之類的命令格式化它才能使用。tmpfs是一個獨立的文件系
統(tǒng),不是塊設(shè)備,只要掛接,立即就可以使用。
    tmpfs的大下是不確定的,它最初只有很小的空間,但隨著文件的復(fù)制和創(chuàng)建,
它的大小就會不斷變化,換句話說,它會根據(jù)你的實際需要而改變大??;tmpfs的速
度非常驚人,畢竟它是駐留在RAM中的,即使用了交換分區(qū),性能仍然非常卓越;
由于tmpfs是駐留在RAM的,因此它的內(nèi)容是不持久的,斷電后,tmpfs的內(nèi)容就消失
了,這也是被稱作tmpfs的根本原因。
    關(guān)于tmpfs文件系統(tǒng)請參考linux內(nèi)核文檔:
    kernel/Documentation/filesystems/tmpfs.txt

2.2.2 devpts文件系統(tǒng)    
    devpts文件系統(tǒng)為偽終端提供了一個標準接口,它的標準掛接點是/dev/pts。只要
pty的主復(fù)合設(shè)備/dev/ptmx被打開,就會在/dev/pts下動態(tài)的創(chuàng)建一個新的pty設(shè)備文
件。
2.2.3 proc文件系統(tǒng)
    proc文件系統(tǒng)是一個非常重要的虛擬文件系統(tǒng),它可以看作是內(nèi)核內(nèi)部數(shù)據(jù)結(jié)構(gòu)的接口,通過它我們可以獲得系統(tǒng)的信息,同時也能夠在運行時修改特定的內(nèi)核參數(shù)。
    在proc文件系統(tǒng)中,你可以修改內(nèi)核的參數(shù),是不是很強大?怎么修改呢?你只需要echo一個新的值到對應(yīng)的文件中即可,但是如果在修改過程中發(fā)生錯誤的話,那么你將別無選擇,只能重啟設(shè)備。
    
    關(guān)于tmpfs文件系統(tǒng)請參考linux內(nèi)核文檔:
    kernel/Documentation/filesystems/proc.txt
2.2.4 sysfs文件系統(tǒng)
    與proc文件系統(tǒng)類似,sysfs文件系統(tǒng)也是一個不占有任何磁盤空間的虛擬文件系
統(tǒng)。它通常被掛接在/sys目錄下。sysfs文件系統(tǒng)是Linux2.6內(nèi)核引入的,它把連接在系
統(tǒng)上的設(shè)備和總線組織成為一個分級的文件,使得它們可以在用戶空間存取。

3.屏蔽標準的輸入輸出,即標準的輸入輸出定向到NULL設(shè)備。
    這一步是通過調(diào)用函數(shù)open_devnull_stdio實現(xiàn)的,下面我們研究一下open_devnull_stdio的函數(shù)實現(xiàn)
void open_devnull_stdio(void)
{
    int fd;
    static const char *name = "/dev/__null__";
//創(chuàng)建一個字符專用文件(character special  file) /dev/__null__ 
    if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
//獲取/dev/__null__的文件描述符,并輸出該文件
        fd = open(name, O_RDWR);
        unlink(name);
//將與進程相關(guān)的標準輸入(0),標準輸出(1),標準錯誤輸出(2),均定向到NULL設(shè)備
        if (fd >= 0) {
            dup2(fd, 0);
            dup2(fd, 1);
            dup2(fd, 2);
            if (fd > 2) {
                close(fd);
            }
            return;
        }
    }

    exit(1);
}
 這里解釋一下
            dup2(fd, 0);
            dup2(fd, 1);
            dup2(fd, 2);
過程:
首先說明以下dup2的作用,這個函數(shù)主要是復(fù)制一個函數(shù)的描述符,一般用于重定向進程的stdin,stdout,stderr。它的原型如下:
int dup2(int oldfd, int newfd);
            dup2(fd, 0);
            dup2(fd, 1);
            dup2(fd, 2);
這三次調(diào)用一次將依次代表stdin,stdout,stderr的描述符0,1,2,重定向到dev/null,通過這種方式達到屏蔽標準輸入輸出的作用。
4. 初始化內(nèi)核log系統(tǒng)
    這個過程對應(yīng)的源碼為:
log_init();
這個函數(shù)詳細實現(xiàn)為
void log_init(void)
{
    static const char *name = "/dev/__kmsg__";
    if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
        log_fd = open(name, O_WRONLY);
//當進程在進行exec系統(tǒng)調(diào)用時,要確保log_fd是關(guān)閉的(通過FD_CLOEXEC標志位來設(shè)置).
        fcntl(log_fd, F_SETFD, FD_CLOEXEC);
        unlink(name);
    }
}
有上述實現(xiàn)看出內(nèi)核的log輸出是通過文件描述符log_fd寫入的,那到底寫入到什么設(shè)備呢?/dev/kmsg,這個設(shè)備則會把它收到的任何寫入都作為printk的輸出。printk函數(shù)是內(nèi)核中運行的向控制臺輸出顯示的函數(shù)。


5.解析init.rc

5.1 Android init language

    Android init language包含四種類型語句:Actions, Commands, Services, Options。
它的主要語法風格為:
    1.每一個語句占據(jù)一行,所有關(guān)鍵字通過空格來分割。
    2.c語言風格的反斜杠(/)將被轉(zhuǎn)義為插入一個空格;
    3.如果一個關(guān)鍵字含有一個或多個空格,那么怎么保證關(guān)鍵字完整呢?可以使用雙引號來確定關(guān)鍵字的范圍。
    4.用于行尾的反斜杠表示續(xù)行符。
    5.Actions和Services聲明一個字段(section),緊隨其后的Commands和Options均屬于這個字段,在第一個字段之前的Commands和Options的沒有意義。
    6.Actions和Services有獨一無二的名字,如果Actions和Services的名字有重名,那么將被視作錯誤。

5.1.1 Actions
    Actions其實就是一組被命名的Commands序列。當滿足觸發(fā)器的事件發(fā)生時,這個action就會被置于一個隊列中,這個隊列存放著將要被執(zhí)行的action。其格式如下:
    on <trigger>
          <command>
          <command>
          <command>
    on是Actions的關(guān)鍵字,它表明下面的序列是Actions序列。

5.1.2 Services
    Services是有init進程啟動的或者重新啟動的程序。其格式如下:
    service <name> <pathname> [ <argument> ]*
          <option>
          <option>

5.1.3 Options
    Options是Services的修飾符,由它來指定何時并且如何啟動Services程序。

5.1.4 Commands
    Commands即是在滿足triger條件后,Actions中執(zhí)行的內(nèi)容。

Options和Commands的取值在這里就不描述里,有興趣請參考system/core/rootdir/init.rc

5.2 init.rc解析過程
    我們繼續(xù)回到init.c的main函數(shù)中,看init.rc的解析過程。init文件有兩個init.rc和init.hardware.rc。

    init_parse_config_file("/init.rc");//解析init.rc

    /* pull the kernel commandline and ramdisk properties file in */
    import_kernel_cmdline(0);//從/proc/cmdline讀取內(nèi)核啟動參數(shù),并保存到相應(yīng)的變量中

    get_hardware_name(hardware, &revision);//從/proc/cpuinfo中獲取硬件信息
    snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
    init_parse_config_file(tmp);//解析硬件相關(guān)的init信息

    著重介紹一下init_parse_config_file過程,這個函數(shù)負責init文件的解析。

    1.首先判斷關(guān)鍵字,只能有兩種可能on或者service,通過關(guān)鍵字來判定section范圍;
    2.根據(jù)Actions和Services的格式對section進行逐行解析;
    3.將解析出的內(nèi)容存放到雙向循環(huán)鏈表中。

    解析過程中的雙向循環(huán)鏈表的使用,android用到了一個非常巧妙的鏈表實現(xiàn)方法,一般情況下如果鏈表的節(jié)點是一個單獨的數(shù)據(jù)結(jié)構(gòu)的話,那么針對不同的數(shù)據(jù)結(jié)構(gòu),都需要定義不同鏈表操作。
    而在初始化過程中使用到的鏈表則解決了這個問題,它將鏈表的節(jié)點定義為了一個非常精簡的結(jié)構(gòu),只包含前向和后向指針,那么在定義不同的數(shù)據(jù)結(jié)構(gòu)時,只需要將鏈表節(jié)點嵌入到數(shù)據(jù)結(jié)構(gòu)中即可。
    例如,鏈表節(jié)點定義如下,
    struct listnode
    {
        struct listnode *next;
        struct listnode *prev;
    };

    數(shù)據(jù)結(jié)構(gòu)的定義如下,拿Action的數(shù)據(jù)結(jié)構(gòu)為例,

    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;
        struct command *current;
    };

    這樣的話,所有的鏈表的基本操作,例如插入,刪除等只會針對listnode進行操作,而不是針對特定的數(shù)據(jù)結(jié)構(gòu),如action進行操作,那么在多個數(shù)據(jù)結(jié)構(gòu)使用雙向鏈表時,鏈表的實現(xiàn)得到了統(tǒng)一,即精簡了代碼,又提高了效率。
    但是這樣的鏈表實現(xiàn),存在一個問題,鏈表節(jié)點listnode中只有前向和后向指針,并且前向和后向指針均指向listnode,那么我們通過什么方式來訪問數(shù)據(jù)結(jié)構(gòu)action的內(nèi)容呢?
    在這里引入了一個宏offsetof,我們man一下這個宏的的定義,發(fā)現(xiàn)這個宏是結(jié)構(gòu)體中成員變量的偏移量。這下大家心里是不是已經(jīng)意識到怎么訪問數(shù)據(jù)結(jié)構(gòu)action了吧,對!就是計算鏈表節(jié)點在數(shù)據(jù)結(jié)構(gòu)中的偏移量,來計算數(shù)據(jù)結(jié)構(gòu)實例的地址。

    Android的init過程是通過下面的宏定義來實現(xiàn)的,
#define node_to_item(node, container, member) /
    (container *) (((char*) (node)) - offsetof(container, member))

    小結(jié)一下這種鏈表的優(yōu)點:(1)所有鏈表基本操作都是基于listnode指針的,因此添加類型時,不需要重復(fù)寫鏈表基本操作函數(shù)(2)一個container數(shù)據(jù)結(jié)構(gòu)可以含有多個listnode成員,這樣就可以同時掛到多個不同的鏈表中。

5.3 Actions待執(zhí)行隊列
    當解析完所有的init.rc內(nèi)容之后,在執(zhí)行這些action之前,需要按順序?qū)⑵渲糜谝粋€待執(zhí)行隊列中,如
        action_for_each_trigger("early-init", action_add_queue_tail);

    還有一些沒有在init.rc中定義的action,相比init.rc,這些action的共同點是沒有參數(shù),如
    queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");


    下面我們分析一下init中的Actions待執(zhí)行隊列的順序以及功能


    action_for_each_trigger("early-init", action_add_queue_tail);
    queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");

    queue_builtin_action(property_init_action, "property_init");
    queue_builtin_action(keychord_init_action, "keychord_init");
    queue_builtin_action(console_init_action, "console_init");
    queue_builtin_action(set_init_properties_action, "set_init_properties");

        /* execute all the boot actions to get us started */
    action_for_each_trigger("init", action_add_queue_tail);
    action_for_each_trigger("early-fs", action_add_queue_tail);
    action_for_each_trigger("fs", action_add_queue_tail);
    action_for_each_trigger("post-fs", action_add_queue_tail);

    queue_builtin_action(property_service_init_action, "property_service_init");
    queue_builtin_action(signal_init_action, "signal_init");
    queue_builtin_action(check_startup_action, "check_startup");

    /* execute all the boot actions to get us started */
    action_for_each_trigger("early-boot", action_add_queue_tail);
    action_for_each_trigger("boot", action_add_queue_tail);

        /* run all property triggers based on current state of the properties */
    queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");


#if BOOTCHART
    queue_builtin_action(bootchart_init_action, "bootchart_init");
#endif    

5.3.1 early-init
    查看init.rc中的相應(yīng)字符段為
    start ueventd
    這個action主要目的是通過early-init啟動ueventd服務(wù),這個服務(wù)負責uevent(user space event)的處理,uevent是內(nèi)核向用戶空間發(fā)出的一個時間通知,使應(yīng)用程序能夠有機會對該event做出反應(yīng)。

5.3.2 wait_for_coldboot_done
    android 冷過程結(jié)束后會生成dev/.coldboot_done文件,wait_for_coldboot_done這個action會等待dev/.coldboot_done文件的生成,等待時長為5s。當然這個action不會阻塞android的冷啟動過程,它會沒查詢一次就會休眠0.1s,直到冷啟動結(jié)束。

5.3.3 property_init
    幾種特殊的屬性:
    1.ro.屬性,它表示只讀屬性,它一旦被設(shè)置就不能被修改;
    2.net.屬性,顧名思義,就是與網(wǎng)絡(luò)相關(guān)的屬性,net.屬性中有一個特殊的屬性:net.change,它記錄了每一次最新設(shè)置和更新的net.屬性,也就是每次設(shè)置和更新net.屬性時則會自動的更新net.change屬性,net.change屬性的value就是這個被設(shè)置或者更新的net屬性的name。例如我們更新了屬性net.bt.name的值,由于net有屬性發(fā)生了變化,那么屬性服務(wù)就會自動更新net.change,將其值設(shè)置為net.bt.name。
    3.persist.屬性,以文件的形式保存在/data/property路徑下。persist.屬性由于將其保存在了用戶空間中,所以在property_init中是不能對其更新的,只能將其更新過程交給用戶來處理。
    4.ctl.屬性,雖然是以屬性的形式來進行設(shè)置,其實它的目的是為了啟動或關(guān)閉它指定的service
    初始化android的屬性系統(tǒng),整個的過程分為下面2步
    1.初始化屬性區(qū)域(property area),主要工作是將屬性設(shè)備節(jié)點/dev/properties映射到內(nèi)存空間上,將整個的屬性內(nèi)容作為共享內(nèi)存來處理,這個共享內(nèi)存就是屬性區(qū)域,當前android中使用全局變量__system_property_area__來標記屬性區(qū)域。
    2.加載并設(shè)置/default.prop中定義的屬性,default.prop中主要是一些“ro.”只讀屬性。

5.3.4 keychord_init
    這個東東不是太理解,目前的所有service均未用到這個機制。

5.3.5 console_init
    1.如果/proc/cmdline指定了控制臺終端,那么優(yōu)先使用這個控制臺,如果沒有指定,那么將使用默認控制臺終端/dev/console。
    2.加載開機圖片,參考load_565rle_image函數(shù)
    a,通過ioctl函數(shù)修改dev/tty0(即終端控制臺)為圖像顯示模式;
    b,嘗試打開/initlogo.rle,如果失敗,那么將dev/tty0恢復(fù)為文本顯示模式,則開機時顯示"ANDROID"文字;
    c,如果打開/initlogo.rle成功,那么init將會打開Framebuffer,下面我們分析一下這個過程
        //logo.c
        static int fb_open(struct FB *fb)
        {
            //打開Framebuffer對應(yīng)的設(shè)備文件/dev/graphics/fb0    
            fb->fd = open("/dev/graphics/fb0", O_RDWR);
            if (fb->fd < 0)
            return -1;
            //通過ioctl函數(shù)獲得Framebuffer相關(guān)信息
            //FBIOGET_FSCREENINFO對應(yīng)的是Framebuffer的固定信息
            //FBIOGET_VSCREENINFO對應(yīng)的是Framebuffer的可變信息    
            if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0)
            goto fail;
            if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0)
            goto fail;
            //由于Framebuffer是可以被用戶直接讀寫的,所以需要將/dev/graphics/fb0映射到用戶空間的內(nèi)存區(qū)。
            fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE, 
                    MAP_SHARED, fb->fd, 0);
            if (fb->bits == MAP_FAILED)
            goto fail;

            return 0;

        fail:
            close(fb->fd);
            return -1;
        }
        d,將initlogo.rle數(shù)據(jù)寫到Framebuffer中。

    目前android默認是沒有initlogo.rle,如果想自己添加開機圖片的話,具體過程請參考http://www.cnmsdn.com/html/201005/1274855679ID5109.html

5.3.6 set_init_properties
    設(shè)置與硬件載頻相關(guān)的只讀屬性。

5.3.7 init
    執(zhí)行init.rc中init action字段中定義的處理。init.rc中的actions就不再一一分析了,有興趣或者有時間在分析。

5.3.8 property_service_init
    1.讀取/system/build.prop,/system/default.prop, /data/local.prop以及/data/property/下的屬性并將其設(shè)置;
    2.創(chuàng)建一個服務(wù)器端UNIX Domain Socket,它的socket文件路徑為/dev/socket/property_service,這個socket監(jiān)聽來自客戶端的屬性修改請求.

5.3.9 signal_init
    1.
    2.通過socketpair創(chuàng)建一對已連接的socket,將生成的兩個socket設(shè)置為O_NONBLOCK模式,也就是將對socket句柄的讀寫操作設(shè)置為非阻塞模式。


5.3.10 check_startup
    確保5.3.8中屬性設(shè)置socket文件描述符和signal_init中signal socket文件描述符,如果兩個有其一不存在,那么將退出系統(tǒng)。

5.3.11 boot
    boot action主要由兩部分組成,
    1. 還是一些配置性的工作,例如基本的網(wǎng)絡(luò)配置;ActivityManagerService中用到的進程管理和資源回收時,需要用到的優(yōu)先級變量的設(shè)置等。
    2. 啟動所有init.rc聲明的未指定class的service;
    具體的command為 class_start default。
    在解析init.rc時,如果service未指定class選項的話,那么會給它的classname默認的指定為“default”,而目前的init.rc中的所有的service均未指定class選項,所以命令“class_start default”將按順序啟動所有的service。
    也可以為需要一起啟動,一起關(guān)閉的services指定一個相同的class,那么就可以對這些service進行統(tǒng)一處理了。
    還需注意:如果service中定義了disabled選項,那么不能通過class_start來啟動它,只能顯示的一個一個的啟動。被disabled修飾的service一般是在

5.3.12 queue_propety_triggers
    根據(jù)init.rc中action指定的property值與屬性中的值比較,如果相等則執(zhí)行對應(yīng)的command。例如
    on property:ro.secure=0
        start console
    如果當前ro.secure的值為0,那么啟動console服務(wù)

5.3.13 bootchart_init
    Bootchart 能夠?qū)ο到y(tǒng)的性能進行分析,并生成系統(tǒng)啟動過程的圖表,以便為你提供有價值的參考信息。綜合所得的信息,你就可以進行相應(yīng)的改進,從而加快你的 Linux 系統(tǒng)啟動過程。
    如果設(shè)置了Bootchart,則該過程初始化Bootchart。

5.4 init輪詢過程
    以上部分將所有需要操作的action均放在了action待執(zhí)行隊列中,那么init進程將要進入一個死循環(huán)過程,整個android的將會運行在這個生命周期內(nèi)。

    1.執(zhí)行action待執(zhí)行隊列中的所有command;
    2.重啟所有需要重啟的service;
    3.注冊屬性設(shè)置property_set_fd,信號signal處理signal_recv_fd,keychord keychord_fd三個文件描述符的為輪詢對象。
    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;
        }
    
    有以上代碼可見,init進程將三個描述符均定義為了POLLIN事件響應(yīng),當描述符有可讀數(shù)據(jù)時,對于socket描述符,有連接請求時ufds就會收到POLLIN事件。

    
    4.下面分別對這3個文件描述符的輪詢過程作簡單的介紹
        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();
            }
        }
    上面的代碼為輪詢的總體體現(xiàn),當有POLLIN事件發(fā)生時,相應(yīng)的ufds[i].revents就會被置為POLLIN,然后執(zhí)行各自的handler
    A,property_set_fd
    收到屬性設(shè)置的socket請求之后,設(shè)置相關(guān)屬性。             

    B,signal_recv_fd
    當有子進程終止時,也就是service終止時,內(nèi)核會給init發(fā)送SIGCHLD,此時調(diào)用注冊的handler函數(shù)
    static void sigchld_handler(int s)
    {
        write(signal_fd, &s, 1);
    }
        這個handler函數(shù)是向其中的一個socket signal_fd寫入數(shù)據(jù),由于signal_init過程中初始化了一對已連接的socket signal_fd和signal_recv_fd,因此此時signal_recv_fd會收到向signal_fd寫入的數(shù)據(jù),然后查詢那個service終止,然后根據(jù)該service的屬性來作相關(guān)的操作,是重啟還是結(jié)束進行資源回收。

    C,keychord_fd
    目前的init過程中沒有service執(zhí)行keychord機制。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android研究-初始化程序init和初始化配置文件init.rc
為Android應(yīng)用程序讀取/dev下設(shè)備而提權(quán)(二)
Android init進程啟動過程分析
Android init 進程 init.rc init.*.rc
深入淺出
Android 初始化語言(Android init Language翻譯)
更多類似文章 >>
生活服務(wù)
熱點新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服