Mobile Development 20 min read

Bypassing Android 10+ dex2oat Restrictions for Performance Optimization

This technical article investigates the Android 10+ dex2oat limitation that blocks app‑initiated compilation, analyzes its SELinux enforcement, and presents a practical solution using system commands and binder calls to trigger dex2oat for both primary and secondary APKs, achieving significant load‑time and runtime improvements.

ByteDance Terminal Technology
ByteDance Terminal Technology
ByteDance Terminal Technology
Bypassing Android 10+ dex2oat Restrictions for Performance Optimization

In Android, the dex2oat tool compiles DEX bytecode into optimized OAT files, improving dex load speed, code execution speed, installation time and overall user experience. Starting with Android 10 and targetSdkVersion>=29 , the runtime no longer allows the application process to invoke dex2oat , which leads to slower loading and higher ANR rates.

The restriction is enforced by SELinux policies; log entries such as type=1400 audit(...): avc: denied { execute } for name="dex2oat" ... show that the untrusted app context is blocked from executing the compiler. Comparing Android 9 and Android 10 source reveals that the code path that triggers dex2oat from the ClassLoader was removed, confirming the official explanation.

Several bypass ideas were examined—lowering targetSdkVersion , masquerading the app as a system process, disabling SELinux, or modifying SELinux rules—but all proved impractical due to required system privileges or permanent ROM changes.

The viable solution leverages the system’s own compilation APIs. Using adb shell cmd package compile with options like -m speed-profile -f my-package or -m speed -f my-package , the system can be instructed to compile both primary and secondary APKs. The article also shows how to invoke the same functionality directly via the PackageManager binder interface, constructing command arguments and sending them with a SHELL_COMMAND_TRANSACTION transaction.

Implementation details include methods to initialize the PackageManager binder, register a temporary dex module with notifyDexLoad , build command arguments, execute them via execCmd , and clean up with reconcile-secondary-dex-files . The code adapts to Android R+ and earlier versions, handling instruction‑set detection and different notifyDexLoad signatures.

Verification on a variety of devices (Vivo, Oppo, Xiaomi, Huawei, Pixel) shows that the approach works across Android 10, 11 and 12, with the only incompatibility on modified Oppo ROMs. Performance tests demonstrate up to 95% reduction in dex load time on low‑end devices and 80% faster dex loading overall, while scenario runtime improves by around 11% on high‑end phones.

In conclusion, by delegating dex compilation to the system through official commands or binder calls, developers can effectively bypass the targetSdkVersion>=29 restriction on Android 10+, achieving substantial improvements in dex load speed and application responsiveness.

MobilePerformanceOptimizationAndroidADBSELinuxDex2oat
ByteDance Terminal Technology
Written by

ByteDance Terminal Technology

Official account of ByteDance Terminal Technology, sharing technical insights and team updates.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.