replacing the ramdisk init script
2024 update
Requirements
- Continue to be as small as possible
- Optimise for speed
- Be modular, hackable, and maintainable
We likely intend to merge -extra into the ramdisk for most devices. This will help with speed, decrease the complexity, and make the initramfs generally more reliable and easier to work on.
Performance
The initramfs needs to do a bunch of loosely related tasks to get the rootfs unlocked and loaded. We want to do these as soon as possible.
The best way to do this declaratively. We have a bunch of tasks:
- launch udev
- launch bootsplash (depends on framebuffer)
- find rootfs (depends on storage devices being detected)
- prompt for FDE password (depends on input devices)
- switch root (depends on root partition being found and unlocked)
Each have dependencies, but can be run as soon as possible once those dependencies are resolved.
The init process should provide a mechanism to express these dependencies and resolve them. udev events obviously play a big part here, it takes a while for udev to process all events after starting up, we should react to these events as they happen. The current initramfs waits for everything to be handled before doing anything else, which is really slow.
Action items
-
Investigate udev and alternatives, although we somewhat need udev rules to handle libinput quirks for unl0kr. Can we avoid pulling all udev rules into the initramfs? -
Investigate how partition scanning is done with udev, it's really slow on Qualcomm devices with many partitions. Ideally we would not have to bother processing ones we don't care about. -
Investigate existing ramdisk init systems and see if any fit our needs, if not -
Explore different options for programming languages. -
Make initramfs-extra optional: postmarketos-mkinitfs!48
I have briefly looked into the idea of using Rust + Lua, having the complicated udev and system interfacing handled in Rust, with the "machinery" (describing the dependencies, binaries to run, etc) in Lua. This is basically like an embedded version of systemd, where the service files also contain the implementation code. The aim would be to avoid needing busybox in the initramfs at all.
OG 2021 issue
The current ramdisk init daemon leaves a lot to be desired, with recent work towards supporting new unlocker applications and my attempt to get the ondev installer working on android devices it's become quite clear that the current init shell script is reaching its limits.
we recently had some discussion about this in #devel, as replacing it requires answering a few important questions:
- what problems do have with the current init?
- what should the first stage init do?
- what language should it be written in?
current problems
beyond the issues mentioned above, the current init is quite hard to maintain, is not particularly consistent in behaviour, it's old and was never designed to do all the things it does now.
what should the first stage init do?
the current init daemon does a few things:
- runs arbitrary hooks
- mounts the boot and rootfs partitions as well as the on device installer.
- runs the FDE unlocker
- sets up rndis
- what else?
Should it do all these things? Maybe a second-stage ramdisk would be more suited to some of these tasks. A second stage ramdisk could also implement a recovery UI and support for emergency calling (#1337).
which language?
this is a contentious one, personally i think C++ is a good choice, it's a reliable systems language which offers good abstractions, its also used for the Android init system which has similar goals to us - although theres is far more complicated.
shell script is also an option, although i think care would have to be taken to avoid the same pitfalls as the current implementation. I think a compiled language with good *nix support offers much better integration with stuff like configuring the kernel, poking devices etc.
C is also an option, although it feels like not a great choice when compared to the alternatives with much more modern and easy to use standard libraries.
Other options exist like Rust and Go. Go is already used for mkinitfs and seems to be a good fit there, it's a garbage collected language and one I'm not super familiar with either. Rust seems like not an idea choice as it doesn't seem to play well with BPO and pmbootstrap (See HKDM in 21.12), it also doesn't lend itself to newbies very well.
let me know what you all think! I'm creating this issue just to write down current thoughts.