android init進程分析 ueventd

來源:互聯網
上載者:User

android init進程分析 ueventd

(懶人最近想起我還有csdn好久沒打理了,這個android init躺在我的草稿箱中快5年了,稍微改改發出來吧)

ueventd主要是負責裝置節點的建立、許可權設定等一些列工作。服務通過使用uevent,監控驅動發送的訊息,做進一步處理。
ueventd實際和init是同一個binary,只是走了不同分支,可參看前一部分。

ueventd的整體代碼比較簡單,主要是三部分:

解析ueventd.rc 初始化裝置資訊 迴圈polling uevent訊息

主函數及相關功能如下如下:

int ueventd_main(int argc, char **argv){ // 和init一樣,沒有std輸入輸出    open_devnull_stdio();    // 初始化kernel log,讓ueventd的log,通過kernel printk的log輸出到串口中    klog_init(); //解析和處理ueventd的rc檔案    import_kernel_cmdline(0, import_kernel_nv);    get_hardware_name(hardware, &revision);    ueventd_parse_config_file(/ueventd.rc);    snprintf(tmp, sizeof(tmp), /ueventd.%s.rc, hardware);    ueventd_parse_config_file(tmp); // 裝置初始化    device_init(); // polling uevent訊息,對裝置進行管理    ufd.events = POLLIN;    ufd.fd = get_device_fd();    while(1) {        ufd.revents = 0;        nr = poll(&ufd, 1, -1);        if (nr <= 0)            continue;        if (ufd.revents == POLLIN)               handle_device_fd(); // polling到訊息,處理event訊息    }}

處理和解析ueventd.rc
這部分相比init.rc來說,巨簡單,沒什麼特別的。主要是通過rc檔案,來控制目錄節點的許可權。如:

 

/dev/ttyUSB2       0666   radio   radio/dev/ts0710mux*           0640   radio      radio/dev/ppp                  0666   radio      vpn# sysfs properties/sys/devices/virtual/input/input*   enable      0666  system   system/sys/devices/virtual/input/input*   poll_delay  0666  system   system
詳情應該不需要展開,基本都能瞭解。

 

 

裝置初始化
kernel在載入裝置時,會通過socket發送uevent事件給userspace, 在init裡,通過接受這些uevent事件,來建立裝置的節點。主要函數是device_init()

初始化函數為device_init,如下

 

void device_init(void){    suseconds_t t0, t1;    struct stat info;    int fd;    sehandle = NULL;    if (is_selinux_enabled() > 0) {        sehandle = selinux_android_file_context_handle();    }    /* is 256K enough? udev uses 16MB! */    device_fd = uevent_open_socket(256*1024, true);    if(device_fd < 0)        return;    fcntl(device_fd, F_SETFD, FD_CLOEXEC);    fcntl(device_fd, F_SETFL, O_NONBLOCK);    if (stat(coldboot_done, &info) < 0) {        t0 = get_usecs();        coldboot(/sys/class);        coldboot(/sys/block);        coldboot(/sys/devices);        t1 = get_usecs();        fd = open(coldboot_done, O_WRONLY|O_CREAT, 0000);        close(fd);        log_event_print(coldboot %ld uS, ((long) (t1 - t0)));    } else {        log_event_print(skipping coldboot, already done);    }}

 

 

open_uevent_socket();
這是開啟uevent的socket。這裡的uevent是用到netlink中的核心事件向使用者態通知(NETLINK_KOBJECT_UEVENT)功能,是核心和使用者態進行雙向資料轉送的非常好的方式,除了eventd外,netd和vold也是使用uevent的。
初始化函數中,比較要注意的coldboot這個函數,字面意思是冷啟動,它的作用是,對那些在uventd啟動前,已經add上的驅動,再重新操作一下,讓他們再發一次event訊息,上層號針對性處理。
這裡對 /sys/class,/sys/block和/sys/devices下的裝置遍曆一遍:

 

static void do_coldboot(DIR *d){    struct dirent *de;    int dfd, fd;    dfd = dirfd(d);    fd = openat(dfd, uevent, O_WRONLY);    if(fd >= 0) {        write(fd, add, 4);        close(fd);        handle_device_fd();    }    while((de = readdir(d))) {        DIR *d2;        if(de->d_type != DT_DIR || de->d_name[0] == '.')            continue;        fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);        if(fd < 0)            continue;        d2 = fdopendir(fd);        if(d2 == 0)            close(fd);        else {            do_coldboot(d2);            closedir(d2);        }    }}
write(fd, add , 4)啟用核心,重發add事件的uevent,handle_device_fd();針對event訊息,做響應的處理。

 

 

uevent訊息處理

初始化好了之後,daemon程式只要polling新的event事件即可,polling到了,就調用handle_device_fd();來處理,可以看看這個函數:

void handle_device_fd(){    char msg[UEVENT_MSG_LEN+2];    int n;    while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {        if(n >= UEVENT_MSG_LEN)   /* overflow -- discard */            continue;        msg[n] = '';        msg[n+1] = '';        struct uevent uevent;        parse_event(msg, &uevent);        handle_device_event(&uevent);        handle_firmware_event(&uevent);    }}

功能就是接受核心發的event訊息,然後parser此訊息,處理對應的訊息事件。

這裡:

static void handle_device_event(struct uevent *uevent){    if (!strcmp(uevent->action,add) || !strcmp(uevent->action, change))        fixup_sys_perms(uevent->path);    if (!strncmp(uevent->subsystem, block, 5)) {        handle_block_device_event(uevent);    } else if (!strncmp(uevent->subsystem, platform, 8)) {        handle_platform_device_event(uevent);    } else {        handle_generic_device_event(uevent);    }}

主要功能,就是根據發過來的uevent,建立/刪除裝置節點,同時以ueventd.rc中描述的使用權限設定更新一些節點許可權。

 

static void handle_firmware_event(struct uevent *uevent){    pid_t pid;    int ret;    if(strcmp(uevent->subsystem, firmware))        return;    if(strcmp(uevent->action, add))        return;    /* we fork, to avoid making large memory allocations in init proper */    pid = fork();    if (!pid) {        process_firmware_event(uevent);        exit(EXIT_SUCCESS);    }}
如果有副處理器, 還要下載副處理器的firmware,這裡是處理副處理器要下載firmware的指令,fork一個子進程處理。



 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.