Why Android N’s Hybrid Compilation Breaks Hot Patches and How to Fix It
This article analyzes why Android N’s hybrid AOT/interpret/JIT compilation prevents Tinker hot‑patches from working, explains the underlying ART mechanisms such as profile files and app images, and proposes practical strategies to restore patchability on modern Android devices.
First, Tinker’s internal open‑source release was delayed for internal review, which pushed back the public beta by about a month.
At the end of June a patch was rolled out to WeChat, but on Android N the app failed to start, throwing an IllegalAccessError linked to the patched dex file.
Android N’s Hybrid Compilation Mode
Android N introduces a mixed compilation model that combines AOT compilation, interpretation, and JIT. The model addresses four main problems:
Long installation time – full AOT on large apps can take minutes.
Excessive ROM usage – AOT binaries can be many times larger than the original dex.
Performance and power consumption – compiling only hot code reduces CPU and battery load.
Slow OTA updates – full AOT on every app during OTA is time‑consuming.
To balance these concerns, Android N manages three modes (interpret, AOT, JIT) and compiles “hot code” during idle, charging periods.
Compilation Filters in Android N
The file compiler_filter.h defines twelve filters. The most relevant defaults are:
install and first‑boot use interpret‑only (no machine‑code generation).
ab‑ota and bg‑dexopt use speed‑profile, compiling only code identified as hot.
forced‑dexopt uses speed, performing full AOT compilation.
Profile Files
During normal execution, ART’s profile_saver.cc collects resolved classes and methods and writes them to /data/misc/profiles. The data can be inspected with the profman tool:
profman --profile-file=/data/misc/profiles/cur/0/tinker.sample.android/primary.prof --dump-only
The dump shows entries such as base.apk:classes2.dex indicating which dex files and methods are hot and will be compiled in speed‑profile mode.
dex2oat Compilation
When the device is charging and idle, BackgroundDexOptService schedules a job that runs dex2oat with parameters like:
dex2oat --dex-file=./base.apk --oat-file=./base.odex --compiler-filter=speed-profile --app-image-file=./base.art --profile-file=./primary.prof ...
This generates both an .odex file and an app‑image ( base.art) that caches compiled hot code.
App Image Loading
At launch the runtime loads the oat file via OpenDexFilesFromOat. If an app image exists, OpenImageSpace loads it, and UpdateAppImageClassLoadersAndDexCaches inserts its classes into the ClassTable. Subsequent class lookups first check this table via ClassLinker::LookupClass, bypassing the original dex.
Consequences for hot patches: If a patched class already resides in the app image, the patch cannot replace it because the class is already cached in the ClassTable.
Hot‑Patch Scenarios on Android N
Patched classes are not in the app image – the patch works normally.
Only some patched classes are in the app image – partial updates may cause address mismatches and crashes.
All patched classes are in the app image – the patch is ignored but does not crash.
Possible Solutions
Instrumentation – attempting to prevent classes from being added to the app image via instrumentation does not work because the profile collector uses ClassLinker::GetResolvedClasses, which ignores instrumentation.
Mini‑loader approach – loading most code dynamically avoids the app image, but it reintroduces slow first‑launch times on pre‑N devices and forfeits the benefits of hybrid compilation on N.
Runtime replacement of PathClassLoader – create a new ClassLoader for post‑patch code while keeping the original Application class loaded by the default PathClassLoader. Two variants:
Proxy‑Application with reflection to swap the real Application (easy integration but fragile).
Full Application proxy where the original Application never runs (more robust but higher integration cost).
Both approaches avoid performance loss when no patch is applied; however, discarding the app image after a patch incurs roughly a 15% slowdown on launch due to missing cached hot code.
Tinker’s Future Plans
On Android N, Tinker’s full‑merge strategy degrades hybrid compilation because dynamically loaded code is compiled with the speed filter, consuming more ROM. The roadmap includes:
Generating a full dex for Dalvik devices.
Generating a minimal mini.dex for ART devices, containing only modified classes and any classes whose fields, methods, or interfaces changed, plus their subclasses.
This selective merging respects the complex inter‑dex references and alignment constraints of the dex format.
Conclusion
Android N’s hybrid compilation fundamentally changes how hot‑patches interact with the runtime. Understanding profile files, app images, and class loading paths is essential for designing reliable patch mechanisms. The article invites further discussion and collaboration to improve Tinker’s compatibility across both Dalvik and ART.
WeChat Client Technology Team
Official account of the WeChat mobile client development team, sharing development experience, cutting‑edge tech, and little‑known stories across Android, iOS, macOS, Windows Phone, and Windows.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
