Skip to content

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

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

alexlarsson wants to merge 15 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.

@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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I changed the code to automatically detect this, so there is no need to specify bootloader.

I'm not sure if refusing to use it if bootupd is present is necessarily very helpful though? What exactly is the point of that?

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'm not sure if refusing to use it if bootupd is present is necessarily very helpful though? What exactly is the point of that?

I think either an image should support/use bootupd or it doesn't.

There's some messy things, like we ended up with bootupd even on s390x/zipl even though it doesn't do anything there. Some discussions have tended to we should always have bootupd even if it's a no-op, which personally I find confusing.

AFAICS this use case won't gain anything from it, so we should just not have it installed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm not saying it would gain anything from it, and you shouldn't normally have bootupd installed. But, I can also see it running into issue when you're for random reasons get bootupd into an image (say inherited from some base image) and suddenly its refusing to work for a not entirely clear reason.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I rewrote the docs to be more generic. Working on install to-disk separately

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Lets take this discussion to #2491, but I'm very interested in how you think ostree got this wrong.

`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)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, probably,

Comment thread crates/lib/src/bootc_composefs/boot.rs
@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.

@alexlarsson

Copy link
Copy Markdown
Contributor Author

I moved the independent stuff to separate MRs and rebased this.

@alexlarsson

Copy link
Copy Markdown
Contributor Author

I rebased on master and fixed some CI failures. I also changed things around so now we just always auto-detect the backend, no need to hand-specify a bootloader.

alexlarsson added a commit to composefs/composefs-rs that referenced this pull request Sep 28, 2026
This changes some APIs, and we need the corresponding changes in
bootc from: bootc-dev/bootc#2490

We'll re-enable this once that is merged.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
@alexlarsson
alexlarsson marked this pull request as ready for review September 28, 2026 20:22
@bootc-bot
bootc-bot Bot requested a review from jeckersb September 28, 2026 20:23
@alexlarsson

Copy link
Copy Markdown
Contributor Author

I updated this to the composefs-rs 0.9.3 release and removed the draft marking.
I think this is good enough as an initial experimental version at least.

cgwalters-bot pushed a commit to cgwalters-forge/composefs-rs that referenced this pull request Sep 29, 2026
This changes some APIs, and we need the corresponding changes in
bootc from: bootc-dev/bootc#2490

We'll re-enable this once that is merged.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
@alexlarsson
alexlarsson force-pushed the aboot-support branch 3 times, most recently from 72e8eec to 0d03ff7 Compare September 30, 2026 10:53
@github-actions github-actions Bot added the area/ostree Issues related to ostree label Sep 30, 2026
@alexlarsson
alexlarsson force-pushed the aboot-support branch 4 times, most recently from 05705fe to f39c6af Compare September 30, 2026 11:19
@alexlarsson

Copy link
Copy Markdown
Contributor Author

Rebased on main

@alexlarsson

Copy link
Copy Markdown
Contributor Author

rebased to fix conflicts

@alexlarsson
alexlarsson force-pushed the aboot-support branch 2 times, most recently from 219af05 to 955a534 Compare October 2, 2026 14:55
@cgwalters cgwalters added this to the 1.17 milestone Oct 2, 2026
@alexlarsson

Copy link
Copy Markdown
Contributor Author

Rebased to fix docs conflicts

Comment thread systemd/bootc-aboot-reconcile.service
@alexlarsson

Copy link
Copy Markdown
Contributor Author

Rebased to fix conflict

@alexlarsson
alexlarsson marked this pull request as draft October 8, 2026 15:47
@alexlarsson

Copy link
Copy Markdown
Contributor Author

Hmm, I noticed some risk for regressions with old ostree aboot images, so lets not merge this quite yet. See composefs/composefs-rs#414. I'll update this with fixes in a bit.

This is needed for aboot support.

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>
An addon can sort before the primary UKI and supply the wrong kernel
version and command line. Ignore addon candidates when selecting the
kernel; addon installation continues to use the separate boot-entry
inventory.

Images with only addons now report no kernel; addons alongside vmlinuz
no longer force UKI backend selection.

Assisted-by: AI
Signed-off-by: Alexander Larsson <alexl@redhat.com>
This extends KernelType with a new Aboot version, and extends the
reporting of "bootc container inspect" to give aboot info as well.

Note: We're not recognizing traditional ostree aboot setups with an
aboot.img in /usr/lib/modules/$kver, because we will be treating these
differently, enforcing the composefs backend. Also, we want the
artifacts in /boot so that we can sign them without having that
affect the boot transformed digest.

Assisted-by: AI
Signed-off-by: Alexander Larsson <alexl@redhat.com>
This moves the code for kernel selection, composefs digest
calculation, and command-line assembly so aboot builders can reuse it
later.

Note: This is just a code motion and no significant beheviour is
changed (other than maybe some specific error message).

Assisted-by: AI
Signed-off-by: Alexander Larsson <alexl@redhat.com>
Kernel arguments from the image or --karg can contain stale composefs
digests. Apply the computed arguments after those inputs, replacing
existing values and removing duplicates so these are not duplicated,
which coudl cause confusion.

Assisted-by: AI
Signed-off-by: Alexander Larsson <alexl@redhat.com>
This uses aboot-update to build Android boot or ukiboot images,
similar to the "container ukify" command.

Assisted-by: AI
Signed-off-by: Alexander Larsson <alexl@redhat.com>
This just moves some code out, which will make later aboot changes
easier to do.

Assisted-by: AI
Signed-off-by: Alexander Larsson <alexl@redhat.com>
Pick (or allow selecting) the right bootloader for aboot images, and
install EFI files needed in case of ukiboot. Command lines in
immutable images are validated.

This changes how bootloader "none" is handled in the composefs
backend. Before it was not supported, but not its is used for android
boot aboot images, where the bootloader is not on disk but in the board.

We also need to be more careful when picking the primary boot entry,
becase discover enumerates Type2 entries before the aboot, but we
might have non-bootable Type2 entries (like addons), and we don't want
those to cover an aboot entry.

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 android boot slot info on the kernel
commandline 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 status from persistent aboot slot state and keep deployments
referenced by either slot during garbage collection.

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 which will write the image
to the next free boot partition.

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>
Document /boot-only discovery, immutable artifact command lines,
artifact-selected disk layouts, and persistent A/B update behavior.

Assisted-by: AI
Signed-off-by: Alexander Larsson <alexl@redhat.com>
@alexlarsson

Copy link
Copy Markdown
Contributor Author

Ok, added install to-disk support and an integration test for ukiboot. Leaving this as draft a bit more, as I need to look at it a bit more carefully, but I wanted to test the integration test run.

Derive Android or ukiboot disk layouts from the source image's boot
artifact when installing the running container image. With
--source-imgref, skip artifact-based layout selection rather than
inferring it from the installation host.

Validate repart definitions and the pulled artifact against the selected
layout, then initialize both slots. Keep the legacy OSTree installation
path unchanged.

Assisted-by: AI
Signed-off-by: Alexander Larsson <alexl@redhat.com>
Exercise the native aboot installer through the existing bcvk and TMT
runner on x86_64. Derive the image from the OSTree test rootfs so
backend selection must follow the boot artifact, and verify the
default disk layout, both payload slots, and boot completion. After
that we try an update and rollback.

Note: This manually installs bcvk 0.21.0, this can be dropped once
bootc-dev/actions has been updated.

Generated-by: AI
Signed-off-by: Alexander Larsson <alexl@redhat.com>

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` area/ostree Issues related to ostree

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants