Skip to content

ci: Run x86_64-linux-android tests on Cuttlefish virtual devices#5269

Open
10ne1 wants to merge 1 commit into
rust-lang:mainfrom
10ne1:android-cuttlefish-x86_64
Open

ci: Run x86_64-linux-android tests on Cuttlefish virtual devices#5269
10ne1 wants to merge 1 commit into
rust-lang:mainfrom
10ne1:android-cuttlefish-x86_64

Conversation

@10ne1

@10ne1 10ne1 commented Jul 9, 2026

Copy link
Copy Markdown

Description

Part of #5262 (please see it for background and discussion).

This migrates x86_64-linux-android testing off the deprecated 2016-era infrastructure and onto the modern Cuttlefish-based images and contains just one commit for the migration itself.

Further PRs will be posted for the Android toolchain version ask by Trevor as well as to migrate the aarch64 CI.

Some observations from my testing and validation:

  • I pinned the jobs to the released Android 17 official image so new releases don't break CI. It's getting tested with the existing API 28 NDK.
  • Whole job takes ~7.5 minutes (the guest boots in ~1 minute under KVM).
  • The full tier2 matrix still passes (the remaining Android targets stay on the legacy SDK emulator for now).
  • I also validated that Add mallopt and related constants for Android #4459, which crashes the old emulator, passes. We will also need the aarch64 migration to fully unblock it (I'm working on it).
  • SELinux is left enforcing in the guest, unlike Mesa CI, which needs to swap GPU drivers inside the guest, so we don't need -guest_enforce_security=false. This means we keep the env as close to real devices as possible.

One implementation decision is worth highlighting (or changing):

I had to pass -enable_sandbox=false, which disables crosvm's minijail device sandbox, because Ubuntu >= 24.04 uses AppArmor to block the unprivileged user namespaces minijail requires. I opted to disable it because the sandbox value in this environment is basically null, it's a defense-in-depth against a hostile guest, but CI runners are ephemeral, there are no untrusted Android apps and the test code already runs unsandboxed on the host in every other non-Cuttlefish/crosvm job.

MesaCI doesn't have this problem because it's running Debian images which are not as restrictive. AFAIK only Ubuntu is available on the GitHub runners, not Debian. In effect, I mirrored the Debian runtime behavior.

If reviewers/maintainers wish, I can try two alternatives (feel free to suggest others):

  1. Set kernel.apparmor_restrict_unprivileged_userns=0. This allows unprivileged userns host-wide so minijail works, however it weakens the whole host runner for a single process.
  2. Grant crosvm a userns exception via an AppArmor profile. I haven't actually tried this yet, but it should be the proper Ubuntu way to fix it, though it adds another moving part and an additional maintenance burden to keep the profile working on newer Ubuntus.

A libc-0.2 backport might be desired to get the new Android CI infra there as well, but I'll leave it up to the maintainers / reviewers to decide.

Sources

No library/API changes; CI-only. Infrastructure references:

Checklist

CI-only change: no src/ or libc-test/semver modifications.

  • Relevant tests in libc-test/semver have been updated (N/A)
  • No placeholder or unstable values (N/A)
  • Tested: validated in my fork on GitHub-hosted runners. This PR's own CI run exercises it directly.

AI disclosure

This PR was written with the help of Claude Code, but was not vibe-coded. I'm not a fan of vibe-coding.

I used AI to better understand the codebase myself (asked it a lot of questions), review both my code and any code generated by AI, used it especially to detect bugs and corner-cases and suggest fixes, however I very carefully reviewed & edited each code/comment lines, the commit messages and so on, until I was satisfied with the result.

Even this PR description was written entirely by myself and only reviewed by AI for errors.

@rustbot

rustbot commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in an Android module

cc @maurer

@rustbot rustbot added A-CI Area: CI-related items S-waiting-on-review labels Jul 9, 2026
@tgross35

Copy link
Copy Markdown
Contributor

Thank you for getting this going! I know extremely little about android CI so pinging the maintainers for help: @chriswailes @jfgoog @maurer @pirama-arumuga-nainar

Comment thread .github/workflows/ci.yaml Outdated
Comment thread .github/workflows/ci.yaml Outdated
Comment thread ci/cuttlefish-setup.sh Outdated
Comment thread .github/workflows/ci.yaml Outdated
Comment thread .github/workflows/ci.yaml Outdated
@tgross35 tgross35 added the stable-nominated This PR should be considered for cherry-pick to libc's stable release branch label Jul 10, 2026
10ne1 added a commit to 10ne1/libc that referenced this pull request Jul 10, 2026
Instead of the script escalating privileges itself with internal sudo
calls, make the CI job invoke it with sudo and fail fast when run as a
plain user, so nobody accidentally reconfigures their machine by
running it locally with passwordless sudo.

The fetch/launch phase still has to run unprivileged because cvd
refuses to run as root, so re-exec it as the sudo-invoking user via
runuser, which also picks up the freshly added kvm/cvdnetwork/render
group memberships without a relogin (runuser does initgroups and
resets HOME to that user's home, which is where the device directory
lives).

Requested-by: Trevor Gross <tmgross@umich.edu>
Link: rust-lang#5269 (comment)

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
10ne1 added a commit to 10ne1/libc that referenced this pull request Jul 10, 2026
Instead of a dedicated collection script and upload-artifact step,
stop the device with an inline CI step (so its logs are flushed) and
let create-artifacts.py bundle whatever logs the boot produced into
the existing inspection archive, using a second positional tar -C
pointing at the device's runtime directory.

Requested-by: Trevor Gross <tmgross@umich.edu>
Link: rust-lang#5269 (comment)

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
10ne1 added a commit to 10ne1/libc that referenced this pull request Jul 10, 2026
Instead of a dedicated collection script and upload-artifact step,
stop the device with an inline CI step (so its logs are flushed) and
let create-artifacts.py bundle whatever logs the boot produced into
the existing inspection archive, using a second positional tar -C
pointing at the device's runtime directory.

Requested-by: Trevor Gross <tmgross@umich.edu>
Link: rust-lang#5269 (comment)

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
@10ne1 10ne1 force-pushed the android-cuttlefish-x86_64 branch from 9c7959c to 9056199 Compare July 10, 2026 19:33
@rustbot

rustbot commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@10ne1

10ne1 commented Jul 10, 2026

Copy link
Copy Markdown
Author

@tgross35 I addressed all your requests, so I kindly ask for a re-review (it's only 1 commit now).

I'll address the detecting targeted Android version from headers in a separate PR, since by doing that I uncovered another, pre-existing, bug.

@10ne1 10ne1 requested a review from tgross35 July 10, 2026 19:38
The new ci/cuttlefish-setup.sh is heavily inspired by Mesa CI's
cuttlefish-runner.sh, credited in the script.

For more details, see the following issue, of which this is part of:
rust-lang#5262

In a nutshell, the libc x86_64 job never booted Android: it extracted
bionic from a 2016-era (API 24) image and ran the test binaries directly
on the Ubuntu host kernel. This makes the CI test boot the official
stock Android 17 image via Cuttlefish.

The virtual device boots inside the test container, self-contained:
Cuttlefish host packages are installed in the x86_64-linux-android
image and the container entrypoint creates the tap networking via
the deb's sysv script as root, then drops to an unprivileged user.

The container needs only the virtualization device nodes plus
CAP_NET_ADMIN, the same flags upstream uses for its own containerized
Cuttlefish CI, so nothing on the CI host is mutated and a local run
reduces to the usual ./ci/run-docker.sh with no host setup beyond KVM.

The container still cross-compiles with the NDK and drives the device
over adb, reusing the runtest-android.rs wrapper unchanged.

Device logs are uploaded as CI artifacts (again similar to Mesa).

The other Android targets stay on the legacy SDK emulator for now.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CI Area: CI-related items O-android O-linux S-waiting-on-review stable-nominated This PR should be considered for cherry-pick to libc's stable release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants