Bypassing Android dex2oat Restrictions for targetSdkVersion ≥ 29: Analysis and Implementation
This article investigates the Android dex2oat compilation restrictions introduced for targetSdkVersion ≥ 29, analyzes their impact on app performance, explores SELinux enforcement, and presents a practical solution using system commands and binder calls to trigger dex2oat compilation for both primary and secondary APKs, improving load and runtime speed.
Dex2oat is a key component of the Android runtime (ART) that compiles DEX bytecode into optimized OAT files, improving installation, startup, and overall execution speed. It can be applied to both primary APKs (base.apk) and secondary/plugin APKs, covering a wide range of deployment scenarios.
Starting with Android 10 and enforced for apps targeting SDK 29 or higher, the system removed the ability for the application process to invoke dex2oat directly. ART now only accepts system‑generated OAT files, and SELinux policies block execution of dex2oat from untrusted_app contexts, as shown by the audit log:
type=1400 audit(0.0:569): avc: denied { execute } for name="dex2oat" dev="dm-2" ino=222 scontext=u:r:untrusted_app:s0:c12,c257,c512,c768 tcontext=u:object_r:dex2oat_exec:s0 tclass=file permissive=0The denial indicates that the untrusted_app domain lacks execute permission on the dex2oat binary, preventing the app from triggering compilation.
To work around this limitation, the article proposes using official ADB shell commands that request the PackageManager to compile an app on the system side. The commands support both primary and secondary APKs:
adb shell cmd package compile -m speed-profile -f my-package # primary APK
adb shell cmd package compile -m speed -f --secondary-dex my-package # secondary APKThese commands invoke the PackageManager’s runCompile method via a binder transaction. The implementation registers the APK’s dex path with the PackageManager, triggers compilation, and then unregisters the module. Key Java snippets include the compilation flow and binder execution:
// Execute quick compilation
@Override
public void dexOptQuicken(String pluginPackageName, int version) {
maybeInit();
registerDexModule(pluginPackageName, version);
dexOpt(COMPILE_FILTER_QUICKEN, pluginPackageName, version);
unregisterDexModule(pluginPackageName, version);
}
private void execCmd(String[] args, Callback callback) {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeFileDescriptor(FileDescriptor.in);
data.writeFileDescriptor(FileDescriptor.out);
data.writeFileDescriptor(FileDescriptor.err);
data.writeStringArray(args);
data.writeStrongBinder(null);
ResultReceiver resultReceiver = new ResultReceiverCallbackWrapper(callback);
resultReceiver.writeToParcel(data, 0);
try {
mPmBinder.transact(SHELL_COMMAND_TRANSACTION, data, reply, 0);
reply.readException();
} catch (Throwable e) {
// handle error
} finally {
data.recycle();
reply.recycle();
}
}
private String[] buildDexOptArgs(String compileFilter) {
return buildArgs("compile", "-m", compileFilter, "-f", "--secondary-dex",
mContext == null ? "" : mContext.getPackageName());
}Verification on a variety of Android 10‑12 devices (Vivo, Oppo, Xiaomi, Huawei, Pixel) shows that the registration, compilation, and unregistration steps succeed for both primary and secondary APKs. Performance measurements demonstrate substantial reductions in dex load time (up to 95 % on low‑end devices) and scenario execution time (10‑20 % improvement), confirming the effectiveness of the approach.
In conclusion, by leveraging system‑level compilation commands and binder interactions, the dex2oat restriction for targetSdkVersion ≥ 29 on Android 10+ can be bypassed, yielding significant gains in dex loading speed (≈80 % faster) and overall app runtime performance (≈11 % faster).
ByteDance Dali Intelligent Technology Team
Technical practice sharing from the ByteDance Dali Intelligent Technology Team
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.