Linux设备模型(六) - Android ueventd浅析

在linux2.6之后,udev取代了devfs,但是在android中却没有udev或者mdev[1],而是由ueventd进程实现了类似功能(管理设备节点权限、创建设备节点)。

一,ueventd启动过程

system/core/rootdir/init.rc

on early-init
start ueventd## Daemon processes to be run by init.
##
service ueventd /system/bin/ueventdclass corecriticalseclabel u:r:ueventd:s0shutdown critical

在运行环境中查看命令“/sbin/ueventd”,其实它是"/init"的软链接:

lynkco:/system $ ls -l /system/bin/ueventd
lrwxr-xr-x 1 root shell 4 2009-01-01 00:00 /system/bin/ueventd -> init

在文件init.c的main()函数中有一个巧妙的处理:可以通过判断第一个运行参数来启动不同的进程:

如果执行“./ueventd”,进入第一个条件分支,执行uevent_main()函数;

如果执行“./watchdog”,进入第二个条件分支,执行watchdogd_main()函数;

如果执行"./init",跳过所有分支条件,继续执行main()函数。

system/core/init/init.c :

int main(int argc, char** argv) {if (!strcmp(basename(argv[0]), "ueventd")) {return ueventd_main(argc, argv);}... ...
}

因此,脚本init.rc中的命令“start ueventd”最终执行的是ueventd_main()函数。

二,组成和功能

1,ueventd 的主要组成部分

devices.cpp

devices.h

uevent.h

uevent_listener.cpp

uevent_listener.h

ueventd.cpp

ueventd.h

ueventd_parser.cpp

ueventd_parser.h

2,主要实现的功能

  • 解析ueventd相关rc文件,管理设备节点权限;

  • Cold boot,递归扫描/sys目录,根据uevent文件,静态创建设备节点;

  • Hot plug,获取内核uevent事件,动态创建设备节点。

int ueventd_main(int argc, char** argv) {LOG(INFO) << "ueventd started!";auto ueventd_configuration = GetConfiguration(); //解析ueventd相关rc文件uevent_handlers.emplace_back(std::make_unique<DeviceHandler>(std::move(ueventd_configuration.dev_permissions),std::move(ueventd_configuration.sysfs_permissions),std::move(ueventd_configuration.subsystems), android::fs_mgr::GetBootDevices(), true));uevent_handlers.emplace_back(std::make_unique<FirmwareHandler>(std::move(ueventd_configuration.firmware_directories),std::move(ueventd_configuration.external_firmware_handlers)));if (ueventd_configuration.enable_modalias_handling) {std::vector<std::string> base_paths = {"/odm/lib/modules", "/vendor/lib/modules"};uevent_handlers.emplace_back(std::make_unique<ModaliasHandler>(base_paths));}UeventListener uevent_listener(ueventd_configuration.uevent_socket_rcvbuf_size);if (!android::base::GetBoolProperty(kColdBootDoneProp, false)) {ColdBoot cold_boot(uevent_listener, uevent_handlers,ueventd_configuration.enable_parallel_restorecon);cold_boot.Run(); //静态创建设备节点}for (auto& uevent_handler : uevent_handlers) {uevent_handler->ColdbootDone();}// We use waitpid() in ColdBoot, so we can't ignore SIGCHLD until now.signal(SIGCHLD, SIG_IGN);// Reap and pending children that exited between the last call to waitpid() and setting SIG_IGN// for SIGCHLD above.while (waitpid(-1, nullptr, WNOHANG) > 0) {}// Restore prio before main loopsetpriority(PRIO_PROCESS, 0, 0);uevent_listener.Poll([&uevent_handlers](const Uevent& uevent) {for (auto& uevent_handler : uevent_handlers) {uevent_handler->HandleUevent(uevent); //动态创建设备节点}return ListenerAction::kContinue;});return 0;
}}  // namespace init
}  // namespace android

三,主要功能解析

1,解析ueventd相关rc文件,管理设备节点权限

ueventd_configuration = GetConfiguration();----ParseConfig({"/system/etc/ueventd.rc"});--------parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));------------parser.AddSingleLineParser("uevent_socket_rcvbuf_size", std::bind(ParseUeventSocketRcvbufSizeLine, _1, &ueventd_configuration.uevent_socket_rcvbuf_size));

 这里请注意,GetConfiguration并不创建设备节点,它的作用是提供数据库,当有设备节点生成的时候,eventd会参考这个数据库设置设备节点的权限。

2,Cold boot,递归扫描/sys目录,根据uevent文件,静态创建设备节点

当ueventd启动时,它会遍历所有在/sys注册的设备并将'add'写入它找到的每个'uevent'文件,这会导致内核生成并重新发送所有当前注册设备的uevent消息。这样做是因为当这些设备注册到sysfs时,ueventd根本还没有开始运行,没能接收他们的uevent消息并妥善处理,这样Android系统也是无法正常运行的,所以需要重新生成其uevent以便ueventd对其做处理。这个过程被称为

'冷启动',即cold_boot,cold_boot也是ueventd在开机过程中的最主要的工作。

  • netlink socket的创建

  • uevent的监听与接收

  • uevent的处理

UeventListener(size_t uevent_socket_rcvbuf_size)
----device_fd_.reset(uevent_open_socket(uevent_socket_rcvbuf_size, true)); //netlink socket的创建
----fcntl(device_fd_, F_SETFL, O_NONBLOCK); //设置为非阻塞
ColdBoot cold_boot(uevent_listener, uevent_handlers, ueventd_configuration.enable_parallel_restorecon);
cold_boot.Run();
--------RegenerateUevents(); //it writes 'add' to every 'uevent' file that it finds in `/sys/class`, `/sys/block`, and `/sys/devices`
------------RegenerateUeventsForPath(path, callback)
----------------RegenerateUeventsForDir(d.get(), callback);
--------------------fd = openat(dfd, "uevent", O_WRONLY | O_CLOEXEC); //打开搜索到的uevent节点并写入add,重新触发kernel发送uevent msg
--------------------write(fd, "add\n", 4);
--------------------close(fd);
--------------------result = ReadUevent(&uevent)
------------------------uevent_kernel_multicast_recv(device_fd_, msg, UEVENT_MSG_LEN); //uevent的监听与接收
------------------------ParseEvent(msg, uevent); //解析uevent msg,结果存在uevent结构体中,所有的uevent最后保存在uevent_queue_链表
----------------------------uevent->action = msg;
----------------------------uevent->path = msg;
--------ForkSubProcesses() //fork子进程并行处理保存在uevent_queue_链表中的uevent
------------UeventHandlerMain(unsigned int process_num, unsigned int total_processes)
------------uevent_handler->HandleUevent(uevent); //uevent的处理
----------------DeviceHandler::HandleUevent(const Uevent& uevent)
----------------HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
--------------------MakeDevice(devpath, block, major, minor, links); //创建设备节点
------------------------auto[mode, uid, gid] = GetDevicePermissions(path, links); //在数据库中查找指定的节点权限,如果没有指定就用默认的
------------------------dev_t dev = makedev(major, minor);
--------------------mkdir_recursive(Dirname(link), 0755) //创建目录
------------------------make_dir(path, mode);
----------------------------rc = mkdir(path.c_str(), mode);

3,Hot plug,获取内核uevent事件,动态创建设备节点

uevent_listener.Poll([&uevent_handlers](const Uevent& uevent)
----ufd.fd = device_fd_;
----poll(&ufd, 1, timeout_ms);
----result = ReadUevent(&uevent)
uevent_handler->HandleUevent(uevent);

四,ueventd相关rc文件的规则

system/core/init/init.c/README.ueventd.md文件中有介绍rc文件的规则。

1,ueventd rc文件路径

## Importing configuration files

--------------------------------

Ueventd reads /system/etc/ueventd.rc, all other files are imported via the `import` command, which takes the format of

    import <path>

This command parses an ueventd config file, extending the current configuration.  If _path_ is a

directory, each file in the directory is parsed as a config file. It is not recursive, nested

directories will not be parsed.  Imported files are parsed after the current file has been parsed.

2,/dev规则

The permissions can be modified using a ueventd.rc script and a line that beings with `/dev`. These lines take the format of

    devname mode uid gid [options]

For example

    /dev/null 0666 root root

When `/dev/null` is created, its mode will be set to `0666`, its user to `root` and its group to

`root`.

3,/sys规则

Ueventd by default takes no action for `/sys`, however it can be instructed to set permissions for

certain files in `/sys` when matching uevents are generated. This is done using a ueventd.rc script and a line that begins with `/sys`. These lines take the format of

    nodename attr mode uid gid [options]

For example

    /sys/devices/system/cpu/cpu* cpufreq/scaling_max_freq 0664 system system

When a uevent that matches the pattern `/sys/devices/system/cpu/cpu*` is sent, the matching sysfs attribute, `cpufreq/scaling_max_freq`, will have its mode set to `0664`, its user to to `system` and its group set to `system`.

具体内容请查看README.ueventd.md。

参考链接:

AndroidP之 Ueventd - 简书

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/704351.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTTP 与HTTPS笔记

HTTP 80 HTTP是一个在计算机世界里专门在【两点】之间【传输】文字、图片、音频、视频等【超文本】数据的约定和规范。 HTTP状态码 1xx 提示信息&#xff0c;表示目前是协议处理的中间状态&#xff0c;还需要后续的操作&#xff1b;2xx 200 204 026 成功3xx 重定向&#xff…

【激光SLAM】基于图优化的激光SLAM 方法(Grid-based)

文章目录 Graph-based SLAM数学概念 非线性最小二乘(Non-Linear Least Square)解决的问题误差函数线性化流程 非线性最小二乘在SLAM中的应用图的构建&#xff08;SLAM前端&#xff09;误差函数误差函数的线性化固定坐标系构建线性系统求解 Cartographer介绍 Graph-based SLAM …

µC/OS-II---任务就绪表

目录 任务就绪表的结构使任务进入就绪状态OS_LOWEST_PRIO <= 63(以28为例)OS_LOWEST_PRIO <= 254(以65为例)使任务脱离就绪状态获取任务就绪表中优先级最高的就绪任务优先级判定表OSUnMapTbl[ ]OS_LOWEST_PRIO <= 63OS_LOWEST_PRIO <= 254任务就绪表的结构 由两…

matlab 凸轮轮廓设计

1、内容简介 略 46-可以交流、咨询、答疑 2、内容说明 略 4 取标段的分析 取标装置是贴标机的核心部件之一&#xff0c;是影响贴标质量和贴标精度的重要因素&#xff0c;取标段是通过取标板与标签的相切运动使得涂有胶水的取标板从标签盒中粘取标签纸[4]&#xff0c;理论…

程序员的护城河是什么?最终走向……?

程序员未来会大量失业&#xff0c;就是因为社会需求少&#xff0c;导致开发者岗位减少&#xff0c;人力资源过剩所导致。Android刚开始的零几年非常火热&#xff0c;是个人都要。到如今的内卷&#xff0c;高级开发都拿着中低程序员的薪资。这是因为头部大厂形成标准化&#xff…

键盘录入 Scanner 详解

键盘录入 涉及方法 next&#xff08;&#xff09;、nextLine&#xff08;&#xff09;、nextInt&#xff08;&#xff09;、nextDouble&#xff08;&#xff09; 键盘录入得到的字符串是new出来的 1&#xff09;next&#xff08;&#xff09;、nextLine&#xff08;&#x…

【总结】Maxwell学习笔记

1.Maxwell简介 Maxwell 是一款用Java编写的MySQL变更数据抓取软件&#xff0c;它会实时监控Mysql数据库的数据变更操作&#xff08;包括insert、update、delete&#xff09;&#xff0c;并将变更数据以 JSON 格式发送给 Kafka、Kinesi等流数据处理平台 官网地址&#xff1a;M…

PTA - 求奇数分之一序列前N项和

本题要求编写程序&#xff0c;计算序列 1 1/3 1/5 ... 的前N项之和。 输入格式: 输入在一行中给出一个正整数N。 输出格式: 在一行中按照“sum S”的格式输出部分和的值S&#xff0c;精确到小数点后6位。题目保证计算结果不超过双精度范围。 输入样例: 23输出样例: …

Java 面试题基础(六)

Java 面试题基础&#xff08;六&#xff09; 前言1、深拷贝和浅拷贝&#xff1f;2、poll() 方法和 remove() 方法的区别&#xff1f;3、DelayQueue实现延时任务原理&#xff1f;4、ArrayList 与 LinkedList 的区别&#xff1f;5、用哪两种方式来实现集合的排序&#xff1f;6、L…

css控制元素像素计算方式

box-sizing: border-box; 是一个CSS属性&#xff0c;用于更改元素盒模型的计算方式。 在CSS中&#xff0c;每个元素都被视为一个盒子&#xff0c;这个盒子由内容、内边距&#xff08;padding&#xff09;、边框&#xff08;border&#xff09;和外边距&#xff08;margin&…

FFmpeg的HEVC解码器源代码学习笔记-2

摘要 这篇主要厘清FFmpeg如何调用多种视频编解码代码进行解码的主要函数调用逻辑 背景 FFmpeg作为一个视频编解码开源框架&#xff0c;被企业和个人广泛使用&#xff0c;但是一直不清楚他是怎么调用多种编解码器的&#xff0c;由于现在想做一个HEVC的码流分析器&#xff0c;…

利用HubSpot出海营销CRM扩大企业在东南亚市场的影响力

东南亚市场作为全球最具活力和潜力的市场之一&#xff0c;吸引着越来越多的企业前来拓展业务。在这个竞争激烈的市场中&#xff0c;如何高效地管理营销和客户关系成为了企业成功的关键。今天运营坛将介绍如何利用HubSpot这一出海营销CRM工具&#xff0c;实现在东南亚市场的影响…

本地部署ChatGPT

发布一下我之前做的一个本地大模型部署,不需要API key,但要有自己的账号 利用Docker 的Pandora做本地ChatGPT模型部署 先下载安装Docker,设置好运行如下 会要求升级核心,cmd运行如下命令就OK 安装Pandora 再管理员cmd中输入如下命令拉取Pandora镜像 docker pull pengzhi…

js之事件代理/事件委托

事件代理也叫事件委托&#xff0c;原理&#xff1a;利用DOM元素的事件冒泡&#xff0c;指定一个事件的处理程序就可以管理某一类型的所有事件。 事件冒泡和事件捕获 如上图所示&#xff0c;事件传播分成三个阶段&#xff1a; 捕获阶段&#xff1a;从window对象传导到目标节点&…

Nginx的重定向,nginx.conf中location的匹配,rewrite介绍,Nginx发内置变量

目录 一、Nginx的内置变量 二、Nginx中的配置选项和指令 三、Nginx常见的正则表达式 四、location匹配 4.1、location分类 4.2、location常用的匹配规则 4.3、location优先级 4.4、实际网站中使用的匹配规则 五、rewrite介绍 5.1、rewrite作用 5.2、rewrite跳转实现 5.…

【MySQL面试复习】详细说下事务的特性

系列文章目录 在MySQL中&#xff0c;如何定位慢查询&#xff1f; 发现了某个SQL语句执行很慢&#xff0c;如何进行分析&#xff1f; 了解过索引吗&#xff1f;(索引的底层原理)/B 树和B树的区别是什么&#xff1f; 什么是聚簇索引&#xff08;聚集索引&#xff09;和非聚簇索引…

猫毛过敏却想养猫时?如何缓解猫毛过敏?宠物空气净化器推荐

作为一个新养猫的主人&#xff0c;一开始并没有发现对猫咪过敏。直到养了半年才意识到这个问题&#xff0c;而此时我已经和猫咪有了深厚的感情。我不想放弃我的猫咪&#xff0c;但是留着它的话&#xff0c;我经常会因为流眼泪、打喷嚏、眼睛发红等过敏症状而影响日常生活&#…

Unity编辑器扩展之Text组件中字体替换工具

想要批量化替换项目预制体资源中Text组件引用的Font字体文件&#xff0c;可以采用以下步骤。 1、在项目的Editor文件中&#xff0c;新建一个名为FontToolEditor的C#脚本文件&#xff0c;然后把以下代码复制粘贴到新建的FontToolEditor的C#脚本文件中。 using System.Collect…

【深度学习笔记】3_14 正向传播、反向传播和计算图

3.14 正向传播、反向传播和计算图 前面几节里我们使用了小批量随机梯度下降的优化算法来训练模型。在实现中&#xff0c;我们只提供了模型的正向传播&#xff08;forward propagation&#xff09;的计算&#xff0c;即对输入计算模型输出&#xff0c;然后通过autograd模块来调…

哪只基金更值得买入?学会这套BI基金分析逻辑,稳赚不赔

投资基金是一种出色的理财方式&#xff0c;对于初次涉足基金领域的投资者而言&#xff0c;首先需要解决两个关键问题&#xff1a;一是基金是否值得投资&#xff1f;二是如何选择适合自己的基金&#xff1f; 以往盲目跟随成功的基金经理&#xff0c;或者仅仅依赖历史涨跌经验的…