I’ve been building IONA OS — a sovereign operating system written entirely in Rust — for the past 13 years.
This month, I decided to run Android on it.
Not as a virtual machine, not as an emulator, but as a real guest running on my own hypervisor, written from scratch, in Rust, in Ring -1 (EL2).
Here’s how I did it.
Why run Android on a custom hypervisor?
IONA OS is a sovereign operating system. It has its own kernel, its own GUI, its own blockchain protocol, its own programming language (Flux), and its own AI running in Ring 0.
But a phone needs apps. And the biggest app ecosystem is Android.
Instead of building a compatibility layer from scratch, I built a hypervisor that can run a real Android system (AOSP) as a guest, completely isolated from IONA OS.
The goal:
- IONA OS runs in EL1/EL0 (native, unchanged)
- Android runs in a separate EL1/EL0 guest
- EL2 (the hypervisor) manages the isolation
- The user sees a unified UI, but the two systems are completely separate
This gives me:
- Suveranitate totală — IONA OS remains untouched
- Compatibilitate completă — all Android apps work
- Securitate maximă — a compromised Android guest cannot affect IONA
Week 1: The real AOSP diagnostic
Most people would search Stack Overflow. I downloaded the actual AOSP source code from android.googlesource.com and read it.
The error message wasn’t about a missing file. It was about a parsing failure.
Problem 1: androidboot.slot_suffix missing
The kernel command line was missing androidboot.slot_suffix. The fstab entries had slotselect, which requires this property.
Fix: Add androidboot.slot_suffix=_a to the kernel command line.
Problem 2: GPT composite disk
super.img was attached as a raw disk without a partition table. Android expects named partitions: boot_a, metadata, super, vbmeta_a, etc.
Fix: Built a real GPT disk with sgdisk:
sgdisk -o /dev/sdb
sgdisk -n 1:2048:+64M -t 1:EF00 /dev/sdb # boot_a
sgdisk -n 2:… -t 2:8300 /dev/sdb # metadata
Then wrote each image with dd at the correct sector offset.
Problem 3: /dev/block/by-name/* symlinks missing
realpath /dev/block/by-name/super failed.
Fix: Read devices.cpp in AOSP. The symlink is only created if androidboot.boot_devices is set correctly. For ARM64 under QEMU, the correct value is 4010000000.pcie, not the PCI address.
Problem 4: Sparse images
super.img and userdata.img were in Android sparse format (magic: 3aff26ed). liblp reported “invalid geometry magic signature”.
Fix: Converted with simg2img:
simg2img super.img super.raw
simg2img userdata.img userdata.raw
1.7GB sparse → 8GiB raw each.
Problem 5: AVB (Android Verified Boot)
libfs_avb: vbmeta digest error isn't allowed — AVB was blocking boot.
Fix: Read fs_mgr/libfs_avb/fs_avb.cpp and util.cpp. The standard development property is:
androidboot.verifiedbootstate=orange
This is used by every -userdebug build, not a hack.
Problem 6: APEX module ambiguities
apexd-bootstrap aborted repeatedly, once for each module with two variants installed (gatekeeper, graphics.composer, keymint, camera.provider.hal).
Fix: Read apexd error messages. Each pointed to the exact property:
ro.boot.vendor.apex.gatekeeper
ro.boot.vendor.apex.graphics.composer
Set them correctly.
Problem 7: /data mounted read-only
The fstab required ext4 for /data, but userdata.img was actually formatted as F2FS (verified with file).
Fix: Changed androidboot.hardware=cf.f2fs.hctr2 — the correct fstab variant for F2FS.
Result: __mount(..., type=f2fs)=0: Success.
Week 2: The vsock investigation
SurfaceFlinger and several vendor HALs (light, uwb, ril-daemon, bt_hci) were stuck in a restart loop.
The real cause: reading the Rust source of the lights HAL (lights.rs).
An .unwrap() on creating an AF_VSOCK socket was failing. Without virtio-vsock transport, it fails guaranteed. Real Cuttlefish runs companion processes on the host (casimir, netsimd, wmediumd) for these HALs.
We don’t have that. The fix would have been:
We skipped it. The HALs are not critical for a booting Android system.
Week 3: The real gap in the hypervisor
You asked: “repară breșa din kernel”.
The dispatch loop in hypervisor_launch_linux_image() didn’t know what to do with a real hvc from a guest. Any trap other than a stage-2 fault would “stop and report”.
The fix: A new psci module in hypervisor.rs.
Real PSCI emulation:
-
PSCI_VERSION— returns0x10000(version 1.0) -
SYSTEM_OFF— powers off the guest -
SYSTEM_RESET/RESET2— resets the guest - Everything else — honest
NOT_SUPPORTED
All constants verified from real Linux kernel headers (include/uapi/linux/psci.h), not from memory.
Verified organically: The real Android kernel queried PSCI_VERSION through IONA’s own EL2 (not QEMU firmware) and received the correct response.
Verified synthetically: New dedicated test: guest_psci_reset_test.
Regression caught before it happened: Our own test hvc calls (hvc #22, #98, etc.) used imm≠0, but real PSCI uses imm=0. Without this distinction, the synthetic boot test would have silently broken.
Verified on both paths (normal EL1 + virtualized EL2): ECDSA/ECDSA-KAT all PASS, no regression.
The final test
I deliberately provoked a known error (removed slot_suffix again) to trigger a real, controlled reboot:
- Android crashes:
InitFatalReboot: signal 6→reboot: Restarting system with command 'bootloader'. - IONA genuinely intercepts that
SYSTEM_RESETthrough its own EL2:PSCI call fid=0x84000009 -> guest power request. -
hypervisor_launch_linux_image()returns (for the first time ever with a real guest attached) — the loop no longer blocks indefinitely. -
Guest #1 (IONA itself) boots — for the first time in any test run with a real external guest attached:
launching real guest: IONA kernel boot continuation at el1_native.
What this means
- IONA OS can run Android as a guest, isolated in its own EL1/EL0 space.
- The hypervisor can intercept, emulate, and handle real requests from a real Linux kernel (PSCI, stage-2 faults, etc.).
- When Android crashes and reboots, IONA survives — it intercepts the reboot, tears down the guest, and resumes its own boot.
- The isolation works. Android cannot affect IONA OS. The kernel is completely unchanged.
What’s next
This is not a finished product yet. But the foundation is solid:
- IONA OS runs the hypervisor (EL2) — unchanged
- IONA OS runs the native kernel (EL1) — unchanged
- Android runs as a guest (EL1) — isolated
- The hypervisor manages the transition
Next steps:
- GPU acceleration for the Android guest
- Audio and input routing
- Integration into the IONA OS UI (Android apps appearing in the launcher)
The code
You can find the full source code (including the hypervisor, the PSCI emulation, and the AOSP integration) in the IONA OS repository:
github.com/Ionablokchain/Iona-OS
The project is not yet production‑ready — but the foundation is solid.
Final thoughts
Running Android on my own hypervisor was one of the hardest things I’ve done.
But it’s also proof that one person can build sovereign infrastructure — a hypervisor, a kernel, a blockchain, a language, an AI — all from scratch, all working together.
13 years of research. Every line written from scratch. And it works.
답글 남기기