1# Ueventd
2-------
3Ueventd manages `/dev`, sets permissions for `/sys`, and handles firmware uevents. It has default
4behavior described below, along with a scripting language that allows customizing this behavior,
5built on the same parser as init.
6
7Ueventd has one generic customization parameter, the size of rcvbuf_size for the ueventd socket. It
8is customized by the `uevent_socket_rcvbuf_size` parameter, which takes the format of
9
10    uevent_socket_rcvbuf_size <size>
11For example
12
13    uevent_socket_rcvbuf_size 16M
14Sets the uevent socket rcvbuf_size to 16 megabytes.
15
16## Importing configuration files
17--------------------------------
18Ueventd reads /system/etc/ueventd.rc, all other files are imported via the `import` command, which
19takes the format of
20
21    import <path>
22This command parses an ueventd config file, extending the current configuration.  If _path_ is a
23directory, each file in the directory is parsed as a config file. It is not recursive, nested
24directories will not be parsed.  Imported files are parsed after the current file has been parsed.
25
26## /dev
27----
28Ueventd listens to the kernel uevent sockets and creates/deletes nodes in `/dev` based on the
29incoming add/remove uevents. It defaults to using `0600` mode and `root` user/group. It always
30creates the nodes with the SELabel from the current loaded SEPolicy. It has three default behaviors
31for the node path:
32
33  1. Block devices are created as `/dev/block/<basename uevent DEVPATH>`. There are symlinks created
34     to this node at `/dev/block/<type>/<parent device>/<basename uevent DEVPATH>`,
35     `/dev/block/<type>/<parent device>/by-name/<uevent PARTNAME>`, and `/dev/block/by-name/<uevent
36     PARTNAME>` if the device is a boot device.
37  2. USB devices are created as `/dev/<uevent DEVNAME>` if `DEVNAME` was specified for the uevent,
38     otherwise as `/dev/bus/usb/<bus_id>/<device_id>` where `bus_id` is `uevent MINOR / 128 + 1` and
39     `device_id` is `uevent MINOR % 128 + 1`.
40  3. All other devices are created as `/dev/<basename uevent DEVPATH>`
41
42The permissions can be modified using a ueventd.rc script and a line that beings with `/dev`. These
43lines take the format of
44
45    devname mode uid gid [options]
46For example
47
48    /dev/null 0666 root root
49When `/dev/null` is created, its mode will be set to `0666`, its user to `root` and its group to
50`root`.
51
52The path can be modified using a ueventd.rc script and a `subsystem` section. There are three to set
53for a subsystem: the subsystem name, which device name to use, and which directory to place the
54device in. The section takes the below format of
55
56    subsystem <subsystem_name>
57      devname uevent_devname|uevent_devpath
58      [dirname <directory>]
59
60`subsystem_name` is used to match uevent `SUBSYSTEM` value
61
62`devname` takes one of two options
63  1. `uevent_devname` specifies that the name of the node will be the uevent `DEVNAME`
64  2. `uevent_devpath` specified that the name of the node will be basename uevent `DEVPATH`
65
66`dirname` is an optional parameter that specifies a directory within `/dev` where the node will be
67created.
68
69For example
70
71    subsystem sound
72      devname uevent_devpath
73      dirname /dev/snd
74Indicates that all uevents with `SUBSYSTEM=sound` will create nodes as `/dev/snd/<basename uevent
75DEVPATH>`.
76
77## /sys
78----
79Ueventd by default takes no action for `/sys`, however it can be instructed to set permissions for
80certain files in `/sys` when matching uevents are generated. This is done using a ueventd.rc script
81and a line that begins with `/sys`. These lines take the format of
82
83    nodename attr mode uid gid [options]
84For example
85
86    /sys/devices/system/cpu/cpu* cpufreq/scaling_max_freq 0664 system system
87When a uevent that matches the pattern `/sys/devices/system/cpu/cpu*` is sent, the matching sysfs
88attribute, `cpufreq/scaling_max_freq`, will have its mode set to `0664`, its user to to `system` and
89its group set to `system`.
90
91## Path matching
92----------------
93The path for a `/dev` or `/sys` entry can contain a `*` anywhere in the path.
941. If the only `*` appears at the end of the string or if the _options_ parameter is set to
95`no_fnm_pathname`, ueventd matches the entry by `fnmatch(entry_path, incoming_path, 0)`
962. Otherwise, ueventd matches the entry by `fnmatch(entry_path, incoming_path, FNM_PATHNAME)`
97
98See the [man page for fnmatch](https://www.man7.org/linux/man-pages/man3/fnmatch.3.html) for more
99details.
100
101## Firmware loading
102----------------
103Ueventd by default serves firmware requests by searching through a list of firmware directories
104for a file matching the uevent `FIRMWARE`. It then forks a process to serve this firmware to the
105kernel.
106
107`/apex/*/etc/firmware` is also searched after a list of firmware directories.
108
109The list of firmware directories is customized by a `firmware_directories` line in a ueventd.rc
110file. This line takes the format of
111
112    firmware_directories <firmware_directory> [ <firmware_directory> ]*
113For example
114
115    firmware_directories /etc/firmware/ /odm/firmware/ /vendor/firmware/ /firmware/image/
116Adds those 4 directories, in that order to the list of firmware directories that will be tried by
117ueventd. Note that this option always accumulates to the list; it is not possible to remove previous
118entries.
119
120Ueventd will wait until after `post-fs` in init, to keep retrying before believing the firmwares are
121not present.
122
123The exact firmware file to be served can be customized by running an external program by a
124`external_firmware_handler` line in a ueventd.rc file. This line takes the format of
125
126    external_firmware_handler <devpath> <user [group]> <path to external program>
127
128The handler will be run as the given user, or if a group is provided, as the given user and group.
129
130For example
131
132    external_firmware_handler /devices/leds/red/firmware/coeffs.bin system /vendor/bin/led_coeffs.bin
133Will launch `/vendor/bin/led_coeffs.bin` as the system user instead of serving the default firmware
134for `/devices/leds/red/firmware/coeffs.bin`.
135
136The `devpath` argument may include asterisks (`*`) to match multiple paths. For example, the string
137`/dev/*/red` will match `/dev/leds/red` as well as `/dev/lights/red`. The pattern matching follows
138the rules of the fnmatch() function.
139
140Ueventd will provide the uevent `DEVPATH` and `FIRMWARE` to this external program on the environment
141via environment variables with the same names. Ueventd will use the string written to stdout as the
142new name of the firmware to load. It will still look for the new firmware in the list of firmware
143directories stated above. It will also reject file names with `..` in them, to prevent leaving these
144directories. If stdout cannot be read, or the program returns with any exit code other than
145`EXIT_SUCCESS`, or the program crashes, the default firmware from the uevent will be loaded.
146
147Ueventd will additionally log all messages sent to stderr from the external program to the serial
148console after the external program has exited.
149
150If the kernel command-line argument `firmware_class.path` is set, this path
151will be used first by the kernel to search for the firmware files. If found,
152ueventd will not be called at all. See the
153[kernel documentation](https://www.kernel.org/doc/html/v5.10/driver-api/firmware/fw_search_path.html)
154for more details on this feature.
155
156## Coldboot
157--------
158Ueventd must create devices in `/dev` for all devices that have already sent their uevents before
159ueventd has started. To do so, when ueventd is started it does what it calls a 'coldboot' on `/sys`,
160in which it writes 'add' to every 'uevent' file that it finds in `/sys/class`, `/sys/block`, and
161`/sys/devices`. This causes the kernel to regenerate the uevents for these paths, and thus for
162ueventd to create the nodes.
163
164For boot time purposes, this is done in parallel across a set of child processes. `ueventd.cpp` in
165this directory contains documentation on how the parallelization is done.
166
167There is an option to parallelize the restorecon function during cold boot as well. It is
168recommended that devices use genfscon for labeling sysfs nodes. However, some devices may benefit
169from enabling the parallelization option:
170
171    parallel_restorecon enabled
172
173Do parallel restorecon to speed up boot process, subdirectories under `/sys`
174can be sliced by ueventd.rc, and run on multiple process.
175    parallel_restorecon_dir <directory>
176
177For example
178    parallel_restorecon_dir /sys
179    parallel_restorecon_dir /sys/devices
180    parallel_restorecon_dir /sys/devices/platform
181    parallel_restorecon_dir /sys/devices/platform/soc
182