Android系統的文件節點都使用SELinux管理權限,前面介紹的init進程第一階段初始化建立的文件節點,以及屬性初始化過程建立的文件節點,是在加載sepolicy以前已經被建立了,在加載完sepolicy以後,須要從新設置相關的屬性。代碼3-13所示是根據file_contexts[1]文件的內容設置相應文件節點的上下文。數組
restorecon("/dev"); restorecon("/dev/socket"); restorecon("/dev/__properties__"); restorecon("/property_contexts"); restorecon_recursive("/sys");
代碼 3-13 main()-設置SELinux訪問權限socket
接下來建立套接字,以便init進程在收到子進程終止的SIGCHLD信號時調用相應的handler。函數
epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (epoll_fd == -1) { ERROR("epoll_create1 failed: %s\n", strerror(errno)); exit(1); } signal_handler_init();
代碼 3-14 main()-建立epoll和套接字rest
代碼3-14中,首先調用epoll_create1()函數建立epoll的句柄,通知內核開始監聽文件描述符(file description,fd)。epoll_create1()函數建立成功時也會佔用一個文件描述符,EPOLL_CLOEXE參數的做用是通知內核在使用完該文件描述符後須要關閉,以避免文件描述符資源耗盡,緊接着調用signal_handler_init()函數建立套接字,安裝信號處理器,並將套接字描述符註冊到epoll中,如代碼3-15所示。code
void signal_handler_init() { // Create a signalling mechanism for SIGCHLD. int s[2]; if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) { (1) ERROR("socketpair failed: %s\n", strerror(errno)); exit(1); } signal_write_fd = s[0]; signal_read_fd = s[1]; // Write to signal_write_fd if we catch SIGCHLD. struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = SIGCHLD_handler; act.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &act, 0); (2) register_epoll_handler(signal_read_fd, handle_signal); (3) }
代碼 3-15 建立套接字,監聽SIGCHLD事件進程
(1)調用socketpair()函數建立一對已經鏈接的非阻塞套接字,套接字描述符存儲在二元數組s[2]中。這對套接字能夠進行雙工通訊,每個描述符既能夠讀也能夠寫。init進程使用s[0]做爲輸入端,s[1]做爲輸出端。事件
(2)安裝子進程信號處理器。Linux進程經過互相發送/接收消息來實現進程間的通訊,這些消息被稱爲「信號」。每一個進程在處理其它進程發送的信號時,都要註冊信號處理器。當進程的運行狀態改變或終止時,就會產生某種信號,init進程是全部進程的父進程,當其子進程終止產生SIGCHLD信號時,init進程須要調用信號安裝函數sigaction()並經過參數傳遞sigaction結構體配置,完成信號處理器的安裝。此處sigaction結構體的sa_flags設置爲SA_NOCLDSTOP,表示僅當進程終止時才接收SIGCHLD信號。當發生SIGCHLD信號時,調用此處的handler,即SIGCHLD_handler,實質是對套拼字signal_write_fd(s[0])執行寫操做。ip
(3)將signal_read_fd(s[1])描述符和相應的handler註冊到epoll中,當SIGCHLD信號產生時,signal_write_fd會被寫入1,因爲socketpair的綁定關係,這將觸發信號對應的signal_read_fd收到數據,epoll監聽到變化,調用此處註冊的handler處理子進程的終止。資源
上述init進程調用signal_handler_init()函數後的處理過程能夠用圖3-7總結,即一旦收到子進程終止觸發的SIGCHLD信號後,將利用信號處理器SIGCHLD_handler向signal_write_fd寫入信息,epoll句柄監聽到signal_read_fd接收到信息,將調用handle_signal處理。關於子進程處理的更詳細內容,咱們將在後面「進程的終止和重啓」章節中進得講解。it
圖 3-7 main()-signal_handler_init()函數處理子進程終止的過程
前面咱們已經講解了init進程如何初始化屬性,在Android系統中,對屬性的修改只能在init進程中進行,其它進程對屬性只有讀的權限,必須經過向init進程發送修改請求,由init接收請求後進行處理,接下來將進一步講解這方面的內容。
[1] file_contexts的內容參考system/sepolicy/file_contexts。