Android如何生成设备节点
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中
- int main(int argc, char **argv)
- {
- ...
- /* Get the basic filesystem setup we need put
- * together in the initramdisk on / and then we'll
- * let the rc file figure out the rest.
- */
- mkdir("/dev", 0755);
- mkdir("/proc", 0755);
- mkdir("/sys", 0755);
- mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");
- mkdir("/dev/pts", 0755);
- mkdir("/dev/socket", 0755);
- mount("devpts", "/dev/pts", "devpts", 0, NULL);
- mount("proc", "/proc", "proc", 0, NULL);
- mount("sysfs", "/sys", "sysfs", 0, NULL);
- for(;;) {
- ...
- if (ufds[0].revents == POLLIN)
- handle_device_fd(device_fd);
- if (ufds[1].revents == POLLIN)
- handle_property_set_fd(property_set_fd);
- if (ufds[3].revents == POLLIN)
- handle_keychord(keychord_fd);
- }
- return 0;
- }
我们再来看看handle_device_fd(),该函数定义在devices.c中
- void handle_device_fd(int fd)
- {
- ...
- handle_device_event(&uevent);
- handle_firmware_event(&uevent);
- }
- }
而handle_device_event定义如下:
- static void handle_device_event(struct uevent *uevent)
- {
- ...
- if(!strcmp(uevent->action, "add")) {
- make_device(devpath, block, uevent->major, uevent->minor);
- return;
- }
- ...
- }
make_device定义如下:
- static void make_device(const char *path, int block, int major, int minor)
- {
- ...
- mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
- dev = (major << 8) | minor;
- ...
- setegid(gid);
- mknod(path, mode, dev);
- chown(path, uid, -1);
- setegid(AID_ROOT);
- }
我们看看get_device_perm如下实现:
- static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid)
- {
- mode_t perm;
- if (get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) {
- return perm;
- } else if (get_device_perm_inner(devperms, path, uid, gid, &perm) == 0) {
- return perm;
- } else {
- struct listnode *node;
- struct perm_node *perm_node;
- struct perms_ *dp;
- /* Check partners list. */
- list_for_each(node, &devperms_partners) {
- perm_node = node_to_item(node, struct perm_node, plist);
- dp = &perm_node->dp;
- if (dp->prefix) {
- if (strncmp(path, dp->name, strlen(dp->name)))
- continue;
- } else {
- if (strcmp(path, dp->name))
- continue;
- }
- /* Found perm in partner list. */
- *uid = dp->uid;
- *gid = dp->gid;
- return dp->perm;
- }
- /* Default if nothing found. */
- *uid = 0;
- *gid = 0;
- return 0600;
- }
- }
我们最后可以看到在devperms中定义了要生成的设备节点:
- static struct perms_ devperms[] = {
- { "/dev/null", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/zero", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/full", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/ptmx", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/tty", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/random", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 },
- { "/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 },
- /* logger should be world writable (for logging) but not readable */
- { "/dev/log/", 0662, AID_ROOT, AID_LOG, 1 },
- /* the msm hw3d client device node is world writable/readable. */
- { "/dev/msm_hw3dc", 0666, AID_ROOT, AID_ROOT, 0 },
- /* gpu driver for adreno200 is globally accessible */
- { "/dev/kgsl", 0666, AID_ROOT, AID_ROOT, 0 },
- /* these should not be world writable */
- { "/dev/diag", 0660, AID_RADIO, AID_RADIO, 0 },
- { "/dev/diag_arm9", 0660, AID_RADIO, AID_RADIO, 0 },
- { "/dev/android_adb", 0660, AID_ADB, AID_ADB, 0 },
- { "/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 },
- { "/dev/ttyMSM0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
- { "/dev/ttyHS0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
- { "/dev/uinput", 0660, AID_SYSTEM, AID_BLUETOOTH, 0 },
- { "/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 },
- { "/dev/tty0", 0660, AID_ROOT, AID_SYSTEM, 0 },
- { "/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 },
- { "/dev/msm_hw3dm", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },
- { "/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 },
- { "/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 },
- { "/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 },
- { "/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },
- { "/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 },
- { "/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 },
- { "/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/snd/", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 },
- { "/dev/msm_camera/", 0660, AID_SYSTEM, AID_SYSTEM, 1 },
- { "/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/akm8973_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/akm8973_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/bma150", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/cm3602", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- { "/dev/lightsensor", 0640, AID_SYSTEM, AID_SYSTEM, 0 },
- { "/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/audience_a1026", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/tpa2018d1", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- { "/dev/msm_audpre", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/msm_audio_ctl", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/htc-acoustic", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/vdec", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/q6venc", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/snd/dsp", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/snd/dsp1", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/snd/mixer", 0660, AID_SYSTEM, AID_AUDIO, 0 },
- { "/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 },
- { "/dev/qemu_trace", 0666, AID_SYSTEM, AID_SYSTEM, 0 },
- { "/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 },
- { "/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 },
- { "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 },
- { "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 },
- /* CDMA radio interface MUX */
- { "/dev/ts0710mux", 0640, AID_RADIO, AID_RADIO, 1 },
- { "/dev/ppp", 0660, AID_RADIO, AID_VPN, 0 },
- { "/dev/tun", 0640, AID_VPN, AID_VPN, 0 },
- { NULL, 0, 0, 0, 0 },
- };
在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如何生成设备节点相关推荐
- linux设备和驱动注册,Linux驱动第五篇-----驱动注册和生成设备节点
加载驱动的指令是:insmod xx.ko 查看驱动的指令是: lsmod 卸载驱动的指令是:rmmod xx 在include/linux/platform_device.h这个文件中定义了平台驱动 ...
- Linux驱动(11)--生成设备节点
生成设备节点 1. 生成设备节点 1.1 杂项设备 1.2 注册文件 1.3 生成设备节点源代码 1.4 生成设备节点步骤 1.5 需要注意的问题 2. 调用设备节点 1. 生成设备节点 1.1 杂项 ...
- Linux字符驱动中动态分配设备号与动态生成设备节点
在编写Linux内核驱动程序的时候,如果不动态生成设备号的话,需要自己手动分配设备号,有可能你分配的设备号会与已有设备号相同而产生冲突.因此推荐自动分配设备号.使用下面的函数: int alloc_c ...
- 九、linux设备节点注册
临时占位,还没弄好,后期再修改 一.杂项设备 杂项设备可以说是对一部分字符设备的封装,还有一部分不好归类驱动也归到杂项设备. 为什么会引入杂项设备? • 第一.节省主设备号 ...
- linux字符驱动之自动创建设备节点
上一节中,我们是手工创建设备节点,大家肯定也会觉得这样做太麻烦了. 上一节文章链接:https://blog.csdn.net/qq_37659294/article/details/10430270 ...
- 驱动中动态创建设备号、设备节点
在Linux驱动(三)字符设备驱动框架中,我们简要介绍了如何编写一个简单的驱动框架,并总结了步骤 1.生成设备号 2.向内核注册该设备号 3.初始化设备对象,完成操作方法集 4.向内核注册该设备对象 ...
- linux生成驱动编译的头文件,嵌入式Linux字符设备驱动——5生成字符设备节点
嵌入式Linux字符设备驱动开发流程--以LED为例 前言 留空 头文件 #include 查看系统设备类 ls /sys/class 设备类结构体 文件(路径):include/linux/devi ...
- linux下usb设备节点名不固定,解决Linux下USB设备节点ttyUSB名不固定的问题,生成固定USB转串口设备节点...
解决Linux下USB设备节点ttyUSB名不固定的问题,生成固定USB转串口设备节点 2018-09-19 http://blog.sina.com.cn/s/blog_8b58097f0102wx ...
- I.MX6 Android 设备节点权限
/*********************************************************************************** I.MX6 Android 设 ...
最新文章
- 网易有道词典笔 —— 73 岁“人类高质量”奶奶梅耶马斯克的中文学习之选
- 基于vue-cli配置移动端自适应
- Java——遍历List过程中添加和删除元素的问题(亲测第二种)
- 能源感知型云计算的快速摘要
- 喜欢 TypeScript 的人,一点都不比 Python 少
- 并发编程之线程安全性
- mysql用正则表达式定位符_MYSQL使用正则表达式过滤数据
- 单调栈-leetcode-739. 每日温度
- 学生学籍管理系统_登陆界面设计
- 微软小娜 服务器连不上,win10小娜提示“无法获取你感兴趣的信息,因为你处于离线状态”的解决方法...
- 题解 luoguP3513 【[POI2011]KON-Conspiracy】
- javaweb项目通过natapp实现项目让外网访问
- 光电自动避障小车_智能化搬运的实现 AGV小车无人搬运车
- 宝塔绑定域名访问不了_建站系列教程(二)--本地局域网访问和域名解析
- 【ENSP模拟器】路由基础(HCNP)——A与B互ping的问题
- Python源码剖析2-字符串对象PyStringObject
- ImageLoader源码解析(一)
- 魏文王问扁鹊的注释_魏文王问扁鹊的典故故事介绍
- Vue实现移动端开屏广告+滑动登录
- 为什么智能手机的电池这么不耐用?