A Samsung OneUI Bug Leaked `top` Processes for Years, Crashing Banking and Government Apps Across China
The bug had been silently crashing Chinese banking, tax, railway, and carrier apps on Samsung devices for years without generating crash reports, because the kill came from AMS rather than an app-level exception. It demonstrates how a single unclosed subprocess in a vendor-customized APEX module can degrade an entire device, and why shelling out to command-line tools from a system service is a pattern worth auditing in any Android skin.
Samsung's Chinese OneUI builds contain a CPU-monitoring routine in `service-samsung-shell.jar` that calls `top -b -n 1` via `Runtime.exec`. The reader loop exits after 8 lines without ever calling `destroy()` or `close()`, leaving the `top` process orphaned as a phantom process owned by `system_server`. Each cold start or app install triggers the call when free storage drops below 3 GB, with a minimum 5-minute cooldown between invocations.
Once 32 phantom processes accumulate, Android's `trimPhantomProcessesIfNecessary` begins killing them in order of parent oom_adj. Because `system_server` runs at oom_adj -900, the cleanup logic preferentially terminates phantom processes belonging to ordinary apps. Apps protected by the enterprise version of the Bangcle packer fork a detection child process; when that child is killed, the parent app exits immediately, producing a crash that APM platforms never see because it is not a native crash.
The bug only affects mainland China firmware, where a region-gated `mIpmAntiAgingController` enables the code path. OneUI 8.5 replaces the `top` call with a proc-filesystem read, closing the leak. Users who enabled "Disable child process restrictions" merely masked the symptom while `system_server` accumulated hundreds of leaked processes and file descriptors, sometimes causing spontaneous reboots.
A single unclosed subprocess in a vendor APEX module evaded detection for years because the resulting app exits were not crashes — AMS killed the process, so APM tools never collected a stack trace.
Parsing `top` output by hardcoded column index is fragile across Android versions; the code also reads column 10 (MEM) instead of column 9 (CPU), making the CPU measurement useless even when it runs.
The phantom-process trimmer sorts by parent oom_adj, which means a leak in a high-priority system process punishes ordinary apps rather than the leaker — a design that turns a resource leak into a user-visible denial of service.
Region-gating the bug behind a China-only code path, combined with Samsung's low Chinese market share, meant the issue received almost no engineering attention despite affecting essential government and financial apps.
The discussion is thin — one joke and one note of personal vindication. No substantive debate or competing technical views surface.
See top comments, translated →