Android platform engineering
Notes on AOSP internals, the Android build system, and platform debugging. Mostly the parts that are hard to search for.
I'm Mykhailo Kryshtop, a Senior Android Platform Engineer based in Karlsruhe, Germany. More about me →
Writing
- Hundreds of commands and none of them is rg: adding your own tool to an AOSP image
Android ships one multi-call binary with 209 commands in it, for licensing reasons, and no package manager to extend it. Putting ripgrep into my Cuttlefish image took twenty minutes of actual work and one refused build — which turned out to be the interesting part, because a prebuilt binary silently opts out of every global flag Soong would have passed on your behalf.
- It is not 25 °C outside: giving the emulated car a real thermometer
Every Cuttlefish car reports a serene 25.0 °C outside, forever, because a JSON file says so. After a summer of heat waves that number started to feel like a lie, so I replaced the vehicle HAL's fake weather with the one thermometer I actually own — the CPU under the emulator — and learned where the fake car really lives and which port not to borrow from the modem.
- The trace is a database: anatomy of a 14 ms lock wait
Two lines of Trace.traceBegin around a lock told me how long one activity launch waited for it. The same probe in C++, planted in InputDispatcher, produced a thousand slices — and clicking through slices is not an analysis method. So I fed the trace to Perfetto's trace_processor and cross-examined it in SQL: the obvious suspect was acquitted, an unfair mutex barged twice, and nearly half of the headline wait turned out to be the scheduler.
- Frozen: when an AIDL interface earns a version number
Deleting one line from an Android.bp looks like paperwork. It is a one-way door with a precise entry condition — and the condition is not that the API is ready.
- Who is pid 1? Android's boot sequence, measured
Every Android boot diagram shows the same four boxes: bootloader, kernel, init, zygote. None of them mention that init execs itself three times, that the whole ordering lives in one 30-line block of init.rc, or where the seconds actually go. So I read the source and timed my own device.
- Treble, enforced: what happens when you put one binary in /system
I added a single native daemon to PRODUCT_PACKAGES and the build refused, citing a makefile I'd never opened. That error turned out to be one tripwire in a whole family of them — the machinery that keeps the system image generic enough to swap. A tour of where Treble stops being a design document and starts being a build failure.
- adb remount: the illusion of a writable /system
Coming from app development, I assumed adb remount just flips a mount flag. On a modern device that's impossible three different ways — dm-verity, EROFS, right-sized logical partitions — and the command is actually a small orchestrator that defeats each one. A tour of what it really does, straight from the android-15.0.0_r36 sources.
- I was wrong about the sandbox: strace vs. my favorite theory
Yesterday I blamed crosvm's frozen seccomp allowlist and published the diagnosis. Then I containerized my way around it, the crash followed me in, and strace pointed somewhere else entirely: Ubuntu's user-namespace hardening. A postmortem of a wrong root cause.
- The sandbox that killed my emulator: why I run Cuttlefish with --enable_sandbox=false
launch_cvd said nothing was wrong, adb saw nothing at all. The culprit: crosvm's seccomp sandbox, whose syscall allowlist is older than the kernel it runs on. On a bleeding-edge dev box, that sandbox is a liability.
- Building android-cuttlefish on Ubuntu 26.04: four layers of "too new"
Getting the Cuttlefish host packages to build on a distro newer than anything the toolchain expects: a package rename, a prebuilt linker with old sonames, and two glibc 2.42 collisions.






