1. 程式人生 > >Android如何生成裝置節點

Android如何生成裝置節點

在Android中,由於沒有mdev和udev,所以它沒有辦法動態的生成裝置節點,那麼它是如何做的呢?

我們可以在system/core/init/下的init.c和devices.c中找到答案:

init.c中

  1. int main(int argc, char **argv) 
  2.     ... 
  3.         /* Get the basic filesystem setup we need put 
  4.          * together in the initramdisk on / and then we'll 
  5.          * let the rc file figure out the rest.
     
  6.          */
  7.     mkdir("/dev", 0755); 
  8.     mkdir("/proc", 0755); 
  9.     mkdir("/sys", 0755); 
  10.     mount("tmpfs""/dev""tmpfs", 0, "mode=0755"); 
  11.     mkdir("/dev/pts", 0755); 
  12.     mkdir("/dev/socket", 0755); 
  13.     mount("devpts""/dev/pts""devpts", 0, NULL); 
  14.     mount("proc""/proc""proc", 0, NULL); 
  15.     mount("sysfs""/sys"
    "sysfs", 0, NULL); 
  16.    for(;;) { 
  17.        ... 
  18.         if (ufds[0].revents == POLLIN) 
  19. handle_device_fd(device_fd); 
  20.         if (ufds[1].revents == POLLIN) 
  21.             handle_property_set_fd(property_set_fd); 
  22.         if (ufds[3].revents == POLLIN) 
  23.             handle_keychord(keychord_fd); 
  24.     } 
  25.     return
     0; 

我們再來看看handle_device_fd(),該函式定義在devices.c中

  1. void handle_device_fd(int fd) 
  2.         ... 
  3. handle_device_event(&uevent); 
  4.         handle_firmware_event(&uevent); 
  5.     } 

而handle_device_event定義如下:

  1. staticvoid handle_device_event(struct uevent *uevent) 
  2.     ... 
  3.     if(!strcmp(uevent->action, "add")) { 
  4. make_device(devpath, block, uevent->major, uevent->minor); 
  5.         return
  6.     } 
  7.     ... 

make_device定義如下:

  1. staticvoid make_device(constchar *path, int block, int major, int minor) 
  2.     ... 
  3. mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR); 
  4.     dev = (major << 8) | minor; 
  5.     ... 
  6.     setegid(gid); 
  7. mknod(path, mode, dev); 
  8.     chown(path, uid, -1); 
  9.     setegid(AID_ROOT); 

我們看看get_device_perm如下實現:

  1. static mode_t get_device_perm(constchar *path, unsigned *uid, unsigned *gid) 
  2.     mode_t perm; 
  3.     if (get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) { 
  4.         return perm; 
  5.     } elseif (get_device_perm_inner(devperms, path, uid, gid, &perm) == 0) { 
  6.         return perm; 
  7.     } else { 
  8.         struct listnode *node; 
  9.         struct perm_node *perm_node; 
  10.         struct perms_ *dp; 
  11.         /* Check partners list. */
  12.         list_for_each(node, &devperms_partners) { 
  13.             perm_node = node_to_item(node, struct perm_node, plist); 
  14.             dp = &perm_node->dp; 
  15.             if (dp->prefix) { 
  16.                 if (strncmp(path, dp->name, strlen(dp->name))) 
  17.                     continue
  18.             } else { 
  19.                 if (strcmp(path, dp->name)) 
  20.                     continue
  21.             } 
  22.             /* Found perm in partner list. */
  23.             *uid = dp->uid; 
  24.             *gid = dp->gid; 
  25.             return dp->perm; 
  26.         } 
  27.         /* Default if nothing found. */
  28.         *uid = 0; 
  29.         *gid = 0; 
  30.         return 0600; 
  31.     } 

我們最後可以看到在devperms中定義了要生成的裝置節點:

  1. staticstruct perms_ devperms[] = { 
  2.     { "/dev/null",          0666,   AID_ROOT,       AID_ROOT,       0 }, 
  3.     { "/dev/zero",          0666,   AID_ROOT,       AID_ROOT,       0 }, 
  4.     { "/dev/full",          0666,   AID_ROOT,       AID_ROOT,       0 }, 
  5.     { "/dev/ptmx",          0666,   AID_ROOT,       AID_ROOT,       0 }, 
  6.     { "/dev/tty",           0666,   AID_ROOT,       AID_ROOT,       0 }, 
  7.     { "/dev/random",        0666,   AID_ROOT,       AID_ROOT,       0 }, 
  8.     { "/dev/urandom",       0666,   AID_ROOT,       AID_ROOT,       0 }, 
  9.     { "/dev/ashmem",        0666,   AID_ROOT,       AID_ROOT,       0 }, 
  10.     { "/dev/binder",        0666,   AID_ROOT,       AID_ROOT,       0 }, 
  11.         /* logger should be world writable (for logging) but not readable */
  12.     { "/dev/log/",          0662,   AID_ROOT,       AID_LOG,        1 }, 
  13.     /* the msm hw3d client device node is world writable/readable. */
  14.     { "/dev/msm_hw3dc",     0666,   AID_ROOT,       AID_ROOT,       0 }, 
  15.     /* gpu driver for adreno200 is globally accessible */
  16.     { "/dev/kgsl",          0666,   AID_ROOT,       AID_ROOT,       0 }, 
  17.         /* these should not be world writable */
  18.     { "/dev/diag",          0660,   AID_RADIO,      AID_RADIO,        0 }, 
  19.     { "/dev/diag_arm9",     0660,   AID_RADIO,      AID_RADIO,        0 }, 
  20.     { "/dev/android_adb",   0660,   AID_ADB,        AID_ADB,        0 }, 
  21.     { "/dev/android_adb_enable",   0660,   AID_ADB,        AID_ADB,        0 }, 
  22.     { "/dev/ttyMSM0",       0600,   AID_BLUETOOTH,  AID_BLUETOOTH,  0 }, 
  23.     { "/dev/ttyHS0",        0600,   AID_BLUETOOTH,  AID_BLUETOOTH,  0 }, 
  24.     { "/dev/uinput",        0660,   AID_SYSTEM,     AID_BLUETOOTH,  0 }, 
  25.     { "/dev/alarm",         0664,   AID_SYSTEM,     AID_RADIO,      0 }, 
  26.     { "/dev/tty0",          0660,   AID_ROOT,       AID_SYSTEM,     0 }, 
  27.     { "/dev/graphics/",     0660,   AID_ROOT,       AID_GRAPHICS,   1 }, 
  28.     { "/dev/msm_hw3dm",     0660,   AID_SYSTEM,     AID_GRAPHICS,   0 }, 
  29.     { "/dev/input/",        0660,   AID_ROOT,       AID_INPUT,      1 }, 
  30.     { "/dev/eac",           0660,   AID_ROOT,       AID_AUDIO,      0 }, 
  31.     { "/dev/cam",           0660,   AID_ROOT,       AID_CAMERA,     0 }, 
  32.     { "/dev/pmem",          0660,   AID_SYSTEM,     AID_GRAPHICS,   0 }, 
  33.     { "/dev/pmem_adsp",     0660,   AID_SYSTEM,     AID_AUDIO,      1 }, 
  34.     { "/dev/pmem_camera",   0660,   AID_SYSTEM,     AID_CAMERA,     1 }, 
  35.     { "/dev/oncrpc/",       0660,   AID_ROOT,       AID_SYSTEM,     1 }, 
  36.     { "/dev/adsp/",         0660,   AID_SYSTEM,     AID_AUDIO,      1 }, 
  37.     { "/dev/snd/",          0660,   AID_SYSTEM,     AID_AUDIO,      1 }, 
  38.     { "/dev/mt9t013",       0660,   AID_SYSTEM,     AID_SYSTEM,     0 }, 
  39.     { "/dev/msm_camera/",   0660,   AID_SYSTEM,     AID_SYSTEM,     1 }, 
  40.     { "/dev/akm8976_daemon",0640,   AID_COMPASS,    AID_SYSTEM,     0 }, 
  41.     { "/dev/akm8976_aot",   0640,   AID_COMPASS,    AID_SYSTEM,     0 }, 
  42.     { "/dev/akm8973_daemon",0640,   AID_COMPASS,    AID_SYSTEM,     0 }, 
  43.     { "/dev/akm8973_aot",   0640,   AID_COMPASS,    AID_SYSTEM,     0 }, 
  44.     { "/dev/bma150",        0640,   AID_COMPASS,    AID_SYSTEM,     0 }, 
  45.     { "/dev/cm3602",        0640,   AID_COMPASS,    AID_SYSTEM,     0 }, 
  46.     { "/dev/akm8976_pffd",  0640,   AID_COMPASS,    AID_SYSTEM,     0 }, 
  47.     { "/dev/lightsensor",   0640,   AID_SYSTEM,     AID_SYSTEM,     0 }, 
  48.     { "/dev/msm_pcm_out",   0660,   AID_SYSTEM,     AID_AUDIO,      1 }, 
  49.     { "/dev/msm_pcm_in",    0660,   AID_SYSTEM,     AID_AUDIO,      1 }, 
  50.     { "/dev/msm_pcm_ctl",   0660,   AID_SYSTEM,     AID_AUDIO,      1 }, 
  51.     { "/dev/msm_snd",       0660,   AID_SYSTEM,     AID_AUDIO,      1 }, 
  52.     { "/dev/msm_mp3",       0660,   AID_SYSTEM,     AID_AUDIO,      1 }, 
  53.     { "/dev/audience_a1026", 0660,   AID_SYSTEM,     AID_AUDIO,      1 }, 
  54.     { "/dev/tpa2018d1",     0660,   AID_SYSTEM,     AID_AUDIO,      1 }, 
  55.     { "/dev/msm_audpre",    0660,   AID_SYSTEM,     AID_AUDIO,      0 }, 
  56.     { "/dev/msm_audio_ctl", 0660,   AID_SYSTEM,     AID_AUDIO,      0 }, 
  57.     { "/dev/htc-acoustic",  0660,   AID_SYSTEM,     AID_AUDIO,      0 }, 
  58.     { "/dev/vdec",          0660,   AID_SYSTEM,     AID_AUDIO,      0 }, 
  59.     { "/dev/q6venc",        0660,   AID_SYSTEM,     AID_AUDIO,      0 }, 
  60.     { "/dev/snd/dsp",       0660,   AID_SYSTEM,     AID_AUDIO,      0 }, 
  61.     { "/dev/snd/dsp1",      0660,   AID_SYSTEM,     AID_AUDIO,      0 }, 
  62.     { "/dev/snd/mixer",     0660,   AID_SYSTEM,     AID_AUDIO,      0 }, 
  63.     { "/dev/smd0",          0640,   AID_RADIO,      AID_RADIO,      0 }, 
  64.     { "/dev/qemu_trace",    0666,   AID_SYSTEM,     AID_SYSTEM,     0 }, 
  65.     { "/dev/qmi",           0640,   AID_RADIO,      AID_RADIO,      0 }, 
  66.     { "/dev/qmi0",          0640,   AID_RADIO,      AID_RADIO,      0 }, 
  67.     { "/dev/qmi1",          0640,   AID_RADIO,      AID_RADIO,      0 }, 
  68.     { "/dev/qmi2",          0640,   AID_RADIO,      AID_RADIO,      0 }, 
  69.         /* CDMA radio interface MUX */
  70.     { "/dev/ts0710mux",     0640,   AID_RADIO,      AID_RADIO,      1 }, 
  71.     { "/dev/ppp",           0660,   AID_RADIO,      AID_VPN,        0 }, 
  72.     { "/dev/tun",           0640,   AID_VPN,        AID_VPN,        0 }, 
  73.     { NULL, 0, 0, 0, 0 }, 
  74. }; 

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

if (ufds[0].revents == POLLIN)

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)對裝置節點進行刪除。