Skip to content

composefs: Add support for android boot (both regular and ukiboot) - #2490

Draft
alexlarsson wants to merge 13 commits into
bootc-dev:mainfrom
alexlarsson:aboot-support
Draft

alexlarsson wants to merge 13 commits into
bootc-dev:mainfrom
alexlarsson:aboot-support

Conversation

@alexlarsson

Copy link
Copy Markdown
Contributor

Add experimental aboot support to the composefs backend. This supports both
Android boot v2 images on systems with boot_a/boot_b partitions and no ESP,
and ukiboot images on systems with an ESP.

The series adds bootc container aboot to build boot artifacts, teaches
container inspect and composefs installation to recognize them, and implements
slot-aware status, updates, rollback, reconciliation, and garbage collection.
Updates are staged without writing a boot partition; at shutdown, bootc
verifies the artifacts and uses aboot-deploy to flash the inactive slot.

There is also some generic changes:

  • Include dtb in deploy digest
  • Show queued rollbacks in bootc status.

This is marked draft atm, because it pulls in the composefs-rs branch from composefs/composefs-rs#399. Once that is landed we should do a release and update bootc to that instead.

I have follow-on work to use this to build images, which I have used to test stuff:

I was able with this to use a Dockerfile to build Fedora 44 images that boot on x86_64/aarch64 with ukiboot, and aarch64 with u-boot with android boot support. I think we can later add some integration test for this, but atm its a bit painful until all the other dependency changes have landed.

Otherwise there is no difference in bootc status after a rollback.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
This really is part of what an individual uki "boots".

Signed-off-by: Alexander Larsson <alexl@redhat.com>
This is the branch used in the pr:
 composefs/composefs-rs#399

This change is temporary, and we should replace it with
a released version.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
Add the Aboot boot type and map composefs-boot aboot entries to it.

Reject aboot operations before modifying bootloader state until the
deployment and lifecycle paths are implemented.

Assisted-by: AI
Signed-off-by: Alexander Larsson <alexl@redhat.com>
Move kernel selection, composefs digest calculation, and kernel command-line
assembly out of the ukify implementation. This prepares the same inputs for
reuse by the aboot image builder.

Assisted-by: AI

Signed-off-by: Alexander Larsson <alexl@redhat.com>
This is similar to `bootc container ukify`, but builds aboot images
using aboot-update.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
…boot()

This is just some code motion that will make later changes easier to
do.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
If the container has an aboot-*.img file, then its type is
aboot. Also update the json. This will be read by e.g. image-builder.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
Allow composefs installation with Android boot v2 and ukiboot
payloads. Validate the embedded composefs command line and record
a boot digest covering the kernel, initrd, and optional DTB.

Use bootloader=none for Android boot without requiring an ESP.
Add bootloader=ukiboot to provision the EFI loader and slot addons.
Prefer files from /boot in the untransformed source image, allowing
signed binaries to override the packaged copies under /usr.

Partition payloads remain the responsibility of the image builder.
Updates, slot tracking, and post-boot management are left for later.

Assisted-by: AI

Signed-off-by: Alexander Larsson <alexl@redhat.com>
Aboot systems do not use BLS entries or necessarily have an ESP, so identify
them from the booted deployment origin before initializing boot storage.

Record the deployment observed in the active A/B slot using a generated
reconciliation service. Add a mutation lock for future update operations and
helpers to atomically record or invalidate slot mappings. An absent mapping
represents an invalid slot and does not retain a deployment.

Skip ESP discovery and legacy boot-entry migration for aboot systems.

Assisted-by: AI

Signed-off-by: Alexander Larsson <alexl@redhat.com>
Build aboot status from the running deployment, transient staged state,
and valid observed slot mappings without inspecting BLS or ESP files.

Use the resulting deployment list as the GC roots for aboot. Treat
missing or malformed slot mappings as invalid, skip bootloader artifact
cleanup, and leave shared objects to repository reachability GC.

Keep soft reboot disabled and explicitly reject rollback and deployment
deletion until controller-aware implementations are available.

Assisted-by: AI

Signed-off-by: Alexander Larsson <alexl@redhat.com>
Implement staging, finalization, and boot-time reconciliation for aboot
deployments.

Stage the boot image and optional vbmeta alongside the deployment and
record their hashes in persistent pending state. At shutdown, verify the
payloads, record the attempt, invalidate the non-booted slot mapping when
known, and invoke aboot-deploy.

On the following boot, use the active deployment to determine whether the
attempt succeeded. Clean up successful attempts while retaining failed
candidates without automatically retrying them.

Persist download-only state, support applying previously downloaded
updates, and reconstruct the transient staged state during reconciliation.

Assisted-by: AI
Signed-off-by: Alexander Larsson <alexl@redhat.com>
Signed-off-by: Alexander Larsson <alexl@redhat.com>
@github-actions github-actions Bot added area/install Issues related to `bootc install` area/documentation Updates to the documentation labels Sep 23, 2026
@bootc-bot
bootc-bot Bot requested a review from cgwalters September 23, 2026 17:38

```toml
[install]
bootloader = "none"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Echoing a comment from before, can't we just detect aboot.img (and aboot-update and do this by default)?

Should we also require bootupd to not be present? I think we should - that's how the current systemd-boot flow is supported.

bootloader = "none"
```

The disk layout must (in `disk.yaml`) provide the platform's `boot_a` and `boot_b`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disk.yaml is an image builder concept, let's describe it slightly more generically (for example it might be good to have an example specification of these in systemd-repart format?)

That said...one thing we could do is change to-disk (our default partitioner) to include repart definitions (after #2314 ) lands and automatically use them if aboot.img is detected.

Comment on lines +63 to +68
An update stores the new boot image (and optional vbmeta image) under
`/state/deploy/<deployment-id>/aboot/`. A persistent pending record under
`/state/boot/aboot/` tracks those artifacts and their hashes. Staging does not write
either boot partition. At shutdown, bootc verifies the artifacts, records the attempt, and
calls `aboot-deploy` to flash the inactive slot.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to study/understand this more, it's part of the core control loop and I don't think we got it quite right with ostree, would be good not to repeat that.

I want to be crystal clear about what is source of truth vs not, what needs to be persistent etc.

`bootc container aboot` computes the V1 and V2 composefs digests of the rootfs,
adds both to the kernel command line, and invokes `aboot-update` to create the
artifact. See [EROFS formats](experimental-composefs.md#erofs-formats) for why
both digests are included. `/etc/aboot.cfg` controls whether `aboot-update`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(We should evnetually support a /usr/lib variant too I think)

hasher.update(&vmlinuz).context("hashing vmlinuz")?;
hasher.update(&initramfs).context("hashing initrd")?;

uki_reader.seek(SeekFrom::Start(0))?;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one can be split out as a prep PR

@cgwalters

Copy link
Copy Markdown
Collaborator

Copying over composefs/composefs-rs#399 (comment) - would have been nice to have a rough sketch of a design draft for this linked and gather a bit of consensus on it.

Could have basically just been fe1ea1a#diff-8df22b9d26bdc5a49b7c7557b59e35583771fb6bd56bb735479048f176cec622 filed as an issue?

It may still be worth filing one as the right place to discuss high level things as opposed to implementation code concerns.

@alexlarsson

Copy link
Copy Markdown
Contributor Author

@cgwalters I've done this work as much to learn about the composefs bootc backend as to do the work, because I had not looked at it before. So, it would have been hard for me to come up with the design up front. However, I agree that we need a highlevel discussion, and that will fit better in an issue, then we can do the code nitpicking here later. I'll type one up to get us started.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/documentation Updates to the documentation area/install Issues related to `bootc install`

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants