网站被恶意刷流量,大型网站建设的难点是什么,不同程序建的网站风格,visual studio在linux2.6之后#xff0c;udev取代了devfs#xff0c;但是在android中却没有udev或者mdev[1]#xff0c;而是由ueventd进程实现了类似功能#xff08;管理设备节点权限、创建设备节点#xff09;。 一#xff0c;ueventd启动过程
system/core/rootdir/init.rc
on earl…在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()函数。
二组成和功能
1ueventd 的主要组成部分 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_uniqueDeviceHandler(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_uniqueFirmwareHandler(std::move(ueventd_configuration.firmware_directories),std::move(ueventd_configuration.external_firmware_handlers)));if (ueventd_configuration.enable_modalias_handling) {std::vectorstd::string base_paths {/odm/lib/modules, /vendor/lib/modules};uevent_handlers.emplace_back(std::make_uniqueModaliasHandler(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 cant 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_uniqueImportParser(parser));------------parser.AddSingleLineParser(uevent_socket_rcvbuf_size, std::bind(ParseUeventSocketRcvbufSizeLine, _1, ueventd_configuration.uevent_socket_rcvbuf_size)); 这里请注意GetConfiguration并不创建设备节点它的作用是提供数据库当有设备节点生成的时候eventd会参考这个数据库设置设备节点的权限。
2Cold boot递归扫描/sys目录根据uevent文件静态创建设备节点
当ueventd启动时它会遍历所有在/sys注册的设备并将add写入它找到的每个uevent文件这会导致内核生成并重新发送所有当前注册设备的uevent消息。这样做是因为当这些设备注册到sysfs时ueventd根本还没有开始运行没能接收他们的uevent消息并妥善处理这样Android系统也是无法正常运行的所以需要重新生成其uevent以便ueventd对其做处理。这个过程被称为
冷启动即cold_bootcold_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);
3Hot 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文件的规则。
1ueventd 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 - 简书