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

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

对于冷插拔设备,init 进程事先获取等待冷插拔处理的驱动程序,事先定义好个驱动的设备节点文件(在android_source_code/system/core/init/devices.c中),在struct perms_devices[ ] 列出了设备节点的名称。访问权限,用户ID,组ID,若要添加新的用户定义的新设备需要在此结构体中添加相应信息。

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

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

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

而handle_device_event定义如下:

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

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

  1. static struct 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)对设备节点进行删除。

Android如何生成设备节点相关推荐

  1. linux设备和驱动注册,Linux驱动第五篇-----驱动注册和生成设备节点

    加载驱动的指令是:insmod xx.ko 查看驱动的指令是: lsmod 卸载驱动的指令是:rmmod xx 在include/linux/platform_device.h这个文件中定义了平台驱动 ...

  2. Linux驱动(11)--生成设备节点

    生成设备节点 1. 生成设备节点 1.1 杂项设备 1.2 注册文件 1.3 生成设备节点源代码 1.4 生成设备节点步骤 1.5 需要注意的问题 2. 调用设备节点 1. 生成设备节点 1.1 杂项 ...

  3. Linux字符驱动中动态分配设备号与动态生成设备节点

    在编写Linux内核驱动程序的时候,如果不动态生成设备号的话,需要自己手动分配设备号,有可能你分配的设备号会与已有设备号相同而产生冲突.因此推荐自动分配设备号.使用下面的函数: int alloc_c ...

  4. 九、linux设备节点注册

    临时占位,还没弄好,后期再修改 一.杂项设备 杂项设备可以说是对一部分字符设备的封装,还有一部分不好归类驱动也归到杂项设备. 为什么会引入杂项设备?         • 第一.节省主设备号       ...

  5. linux字符驱动之自动创建设备节点

    上一节中,我们是手工创建设备节点,大家肯定也会觉得这样做太麻烦了. 上一节文章链接:https://blog.csdn.net/qq_37659294/article/details/10430270 ...

  6. 驱动中动态创建设备号、设备节点

    在Linux驱动(三)字符设备驱动框架中,我们简要介绍了如何编写一个简单的驱动框架,并总结了步骤 1.生成设备号 2.向内核注册该设备号 3.初始化设备对象,完成操作方法集 4.向内核注册该设备对象 ...

  7. linux生成驱动编译的头文件,嵌入式Linux字符设备驱动——5生成字符设备节点

    嵌入式Linux字符设备驱动开发流程--以LED为例 前言 留空 头文件 #include 查看系统设备类 ls /sys/class 设备类结构体 文件(路径):include/linux/devi ...

  8. linux下usb设备节点名不固定,解决Linux下USB设备节点ttyUSB名不固定的问题,生成固定USB转串口设备节点...

    解决Linux下USB设备节点ttyUSB名不固定的问题,生成固定USB转串口设备节点 2018-09-19 http://blog.sina.com.cn/s/blog_8b58097f0102wx ...

  9. I.MX6 Android 设备节点权限

    /*********************************************************************************** I.MX6 Android 设 ...

最新文章

  1. 网易有道词典笔 —— 73 岁“人类高质量”奶奶梅耶马斯克的中文学习之选
  2. 基于vue-cli配置移动端自适应
  3. Java——遍历List过程中添加和删除元素的问题(亲测第二种)
  4. 能源感知型云计算的快速摘要
  5. 喜欢 TypeScript 的人,一点都不比 Python 少
  6. 并发编程之线程安全性
  7. mysql用正则表达式定位符_MYSQL使用正则表达式过滤数据
  8. 单调栈-leetcode-739. 每日温度
  9. 学生学籍管理系统_登陆界面设计
  10. 微软小娜 服务器连不上,win10小娜提示“无法获取你感兴趣的信息,因为你处于离线状态”的解决方法...
  11. 题解 luoguP3513 【[POI2011]KON-Conspiracy】
  12. javaweb项目通过natapp实现项目让外网访问
  13. 光电自动避障小车_智能化搬运的实现 AGV小车无人搬运车
  14. 宝塔绑定域名访问不了_建站系列教程(二)--本地局域网访问和域名解析
  15. 【ENSP模拟器】路由基础(HCNP)——A与B互ping的问题
  16. Python源码剖析2-字符串对象PyStringObject
  17. ImageLoader源码解析(一)
  18. 魏文王问扁鹊的注释_魏文王问扁鹊的典故故事介绍
  19. Vue实现移动端开屏广告+滑动登录
  20. 为什么智能手机的电池这么不耐用?

热门文章

  1. QMdiArea中多个小窗口如何自动调整大小以挤满整个窗口界面?(tile/cascade)
  2. C语言学习11:strlen()函数详解
  3. 各种插值法的python实现
  4. Flink并行度与slot之间的关系
  5. 软考笔记第五天之系统安全分析与设计
  6. 使用sklear.metrics计算precision等指标
  7. JS javascript 睡眠
  8. 2年多的时间,我在便利蜂便利店消费了4千多块
  9. 免费地图下载流量如何领取?
  10. 2021年中国工业软件行业发展现状分析,行业国产化程度亟待提升「图」