1. 程式人生 > >Linux裝置節點建立》使用者空間ueventd建立裝置節點規則

Linux裝置節點建立》使用者空間ueventd建立裝置節點規則

說明:本文基於Android2.3和Linux2.6,其餘版本僅供參考。

一、devfs、udev和sysfs是什麼關係?

linux2.6之前使用devfs裝置檔案系統,它存在與核心空間;

linux2.6之後使用udev裝置檔案系統,它存在與使用者空間、但嚴重依賴與sysfs檔案系統。

二、Android(使用linux2.6以後的裝置節點建立策略)裝置節點的建立

  在Android中,沒有獨立的類似於udev或者mdev的使用者程式,這個功能整合到了init中做了。程式碼見:system/core/init/init.c檔案,如下:

  1. if (ufds[0].revents == POLLIN)  
  2.   handle_device_fd(device_fd);  

其中handle_device_fd(device_fd)函式在system/core/init/devices.c中實現,引數device_fd 由函式device_init()->open_uevent_socket()->socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)函式呼叫返回。

函式handle_device_fd(device_fd)中,根據傳進來的device_fd引數,呼叫recv(fd, msg, UEVENT_MSG_LEN, 0)函式,將核心探測到的裝置並通過NETLINK機制傳過來的socket描述符轉化成訊息。接著呼叫parse_event(msg, &uevent);函式將訊息翻譯成uevent事件,並將改事件傳遞給handle_device_event(&uevent)函式。

handle_device_event(&uevent)函式中,依據引數uevent->subsystem型別建立dev下的相應目錄,如:/dev/graphics。緊接著根據uevent->action是"add"還是"remove"來實現裝置節點的建立與刪除。如果uevent->action是"add",則呼叫make_device(devpath, block, uevent->major, uevent->minor)函式生成裝置節點。如果uevent->action是"remove",則呼叫unlink(devpath)對裝置節點進行刪除。

三、下邊看看Android的ueventd程序

說明:其配置檔案uevent.rc不起實際作用,只是對建立的裝置節點檔案屬性做設定。

1.system/core/init/ueventd.c

  1. int ueventd_main(int argc, char **argv){  
  2.   device_init();  
  3.   /* 
  4.   system/core/init/device.c 
  5.   void device_init(void){ 
  6.     device_fd = uevent_open_socket(64*1024, true); 
  7.     coldboot("/sys/class"); 
  8.     coldboot("/sys/block"); 
  9.     coldboot("/sys/devices"); 
  10.   } 
  11.   */
  12.   ufd.events = POLLIN;  
  13.   ufd.fd = get_device_fd();  
  14.   while(1) {  
  15.     ufd.revents = 0;  
  16.     nr = poll(&ufd, 1, -1);  
  17.     if (nr <= 0)  
  18.       continue;  
  19.     if (ufd.revents == POLLIN)  
  20.       handle_device_fd();  
  21.   }       
  22. }  

2.system/core/init/device.c

注意:只有主次裝置號的事件才會建立裝置節點

  1. void handle_device_fd(){  
  2.   while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {  
  3.     handle_device_event(&uevent);  
  4.   }  
  5. }  
  6. staticvoid handle_device_event(struct uevent *uevent){  
  7.   if (!strcmp(uevent->action,"add"))  
  8.     fixup_sys_perms(uevent->path);  
  9.   /* if it's not a /dev device, nothing else to do */
  10.   if((uevent->major < 0) || (uevent->minor < 0)){//只有主次裝置號的事件才會建立裝置節點
  11.     //ERROR("TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0\n");//add by tankai
  12.     return;  
  13.   }  
  14.   if(!strncmp(uevent->subsystem, "block", 5)) {  
  15.     block = 1;  
  16.     base = "/dev/block/";  
  17.     mkdir(base, 0755);  
  18.     if (!strncmp(uevent->path, "/devices/platform/", 18))  
  19.       links = parse_platform_block_device(uevent);  
  20.   } else {  
  21.     block = 0;  
  22.     /* this should probably be configurable somehow */
  23.     if (!strncmp(uevent->subsystem, "usb", 3)) {  
  24.       if (!strcmp(uevent->subsystem, "usb")) {  
  25.         /* This imitates the file system that would be created 
  26.         * if we were using devfs instead. 
  27.         * Minors are broken up into groups of 128, starting at "001" 
  28.         */
  29.         int bus_id = uevent->minor / 128 + 1;  
  30.         int device_id = uevent->minor % 128 + 1;  
  31.         /* build directories */
  32.         mkdir("/dev/bus", 0755);  
  33.         mkdir("/dev/bus/usb", 0755);  
  34.         snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id);  
  35.         mkdir(devpath, 0755);  
  36.         snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id);  
  37.         devpath_ready = 1;  
  38.       } else {  
  39.         /* ignore other USB events */
  40.         return;  
  41.       }  
  42.     } elseif (!strncmp(uevent->subsystem, "graphics", 8)) {  
  43.       base = "/dev/graphics/";  
  44.       mkdir(base, 0755);  
  45.     } elseif (!strncmp(uevent->subsystem, "oncrpc", 6)) {  
  46.       base = "/dev/oncrpc/";  
  47.       mkdir(base, 0755);  
  48.     } elseif (!strncmp(uevent->subsystem, "adsp", 4)) {  
  49.       base = "/dev/adsp/";  
  50.       mkdir(base, 0755);  
  51.     } elseif (!strncmp(uevent->subsystem, "msm_camera", 10)) {  
  52.       base = "/dev/msm_camera/";  
  53.       mkdir(base, 0755);  
  54.     } elseif(!strncmp(uevent->subsystem, "input", 5)) {  
  55.       base = "/dev/input/";  
  56.       mkdir(base, 0755);  
  57.     } elseif(!strncmp(uevent->subsystem, "mtd", 3)) {  
  58.       base = "/dev/mtd/";  
  59.       mkdir(base, 0755);  
  60.     } elseif(!strncmp(uevent->subsystem, "sound", 5)) {  
  61.       base = "/dev/snd/";  
  62.       mkdir(base, 0755);  
  63.     } elseif(!strncmp(uevent->subsystem, "misc", 4) &&  
  64.                     !strncmp(name, "log_", 4)) {  
  65.       base = "/dev/log/";  
  66.       mkdir(base, 0755);  
  67.       name += 4;  
  68.     } else
  69.       base = "/dev/";  
  70.   }  
  71.   if (!devpath_ready)  
  72.     snprintf(devpath, sizeof(devpath), "%s%s", base, name);  
  73.   if(!strcmp(uevent->action, "add")) {  
  74.     //ERROR("TK------_>>>>>>>>>make_devices\n");//add by tankai
  75.     make_device(devpath, uevent->path, block, uevent->major, uevent->minor);  
  76.     if (links) {  
  77.       for (i = 0; links[i]; i++)  
  78.         make_link(devpath, links[i]);  
  79.     }  
  80.   }  
  81. }  
  82. staticvoid make_device(constchar *path,  
  83.                         constchar *upath,  
  84.                         int block, int major, int minor)  
  85. {  
  86.   mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);  
  87.   setegid(gid);  
  88.   mknod(path, mode, dev);  
  89.   chown(path, uid, -1);  
  90.   setegid(AID_ROOT);