Android 与linux一样使用设备驱动来访问硬件设备,设备节点文件是设备驱动的逻辑文件,应用程序使用设备节点文件来访问设备驱动程序,linux使用mknod来创建设备节点文件,Android 有自己法子。

Android 使用Init 进程来创建设备节点文件,分两种情况:静态节点文件和动态节点文件,以应对已经定义好的冷插拔和系统运行起来后插入的热插拔设备。

若要添加新的用户定义的新设备需要在此结构体中添加相应信息。

init 首先调用device_init() 函数,创建一个socket 来接收uevent,再通过cold_boot() 调用do_coldboot()对内核启动时注册到/sys下的驱动程序进行冷插拔处理,do_coldboot会启动uevent,在handler_device_fd()中接收uevent信息,并写入到uevent struct 中,调用handle_device_event()创建节点文件,先创建所有的子目录,然后调用make_device()创建节点文件。

init 对于热插拔的动态设备,使用事件处理循环来完成,使用poll()监听来自驱动程序的uevent, 然后调用handle_device_fd()创建设备节点。

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

init.c中

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


我们再来看看handle_device_fd(),该函数定义在devices.c中

1. void handle_device_fd(int
2. { 
3.         ... 
4.         handle_device_event(&uevent); 
5.         handle_firmware_event(&uevent); 
6.     } 
7. } 
 
 而handle_device_event定义如下:
 
1. static void handle_device_event(struct
2. { 
3.     ... 
4. if(!strcmp(uevent->action, "add")) { 
5.         make_device(devpath, block, uevent->major, uevent->minor); 
6. return; 
7.     } 
8.     ... 
9. } 
 
 make_device定义如下:
 
1. static void make_device(const char *path, int block, int major, int
2. { 
3.     ... 
4.     mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR); 
5.     dev = (major << 8) | minor; 
6.     ... 
7.     setegid(gid); 
8.     mknod(path, mode, dev); 
9.     chown(path, uid, -1); 
10.     setegid(AID_ROOT); 
11. } 
 
 我们看看get_device_perm如下实现:
 
1. static mode_t get_device_perm(const char
2. { 
3.     mode_t perm; 
4.  
5. if
6. return
7. else if
8. return
9. else
10. struct
11. struct
12. struct
13.  
14. /* Check partners list. */
15.         list_for_each(node, &devperms_partners) { 
16. struct
17.             dp = &perm_node->dp; 
18.  
19. if
20. if
21. continue; 
22. else
23. if
24. continue; 
25.             } 
26. /* Found perm in partner list. */
27.             *uid = dp->uid; 
28.             *gid = dp->gid; 
29. return
30.         } 
31. /* Default if nothing found. */
32.         *uid = 0; 
33.         *gid = 0; 
34. return
35.     } 
36. }


我们最后可以看到在devperms中定义了要生成的设备节点:

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

 


在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)对设备节点进行删除。