With the introduction of the ART runtime came ahead-of-time (AOT) compilation to replace the Dalvik just-in-time (JIT) compilation. This is achieved on app installation when a one time process is executed to convert the APKs DEX files into a compiled app optimized for the device it is running on. Devices running the old Dalvik VM use JIT compilation that is performed at run time and only on frequently executed parts of apps. This change is designed to increase execution performance of apps on the new ART runtime.
For developers AOT compilation can cause frustration as every time an app is changed it has to be reinstalled on the target device. The AOT compilation process can take anything from a second to well over 10 seconds, the more code in an app the longer the device compilation process takes.
The good news is that it is possible to disable this AOT compilation for your debug builds, although this will cause your app to revert to being interpreted as it is executed. Disabling AOT compilation reduces the total time taken to deploy the app to the device and as a developer if you are modifying code and executing the app time after time, any increase in deployment speed is a welcome improvement. The tradeoff is a reduction in performance, although you are not likely to notice this performance hit for most types of applications. You should also consider that if you are writing an app that performs intensive computations then you may find saving a couple of seconds on installation for a compromised runtime performance is a counter-productive optimization.
Disabling ART ahead-of-time compilation
Disabling the AOT compilation is as simple as adding the application attribute android:vmSafeMode in your AndroidManifest.xml. Here is an example:
<manifest package="com.testing.sample.myapp" xmlns:android="http://schemas.android.com/apk/res/android"> <application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:vmSafeMode="true"> ...
It is important to understand that this is not an attribute that we want to override on our release builds. It is possible to apply the attribute to debug builds only by creating a new …/app/src/debug/AndroidManifest.xml file. In this new manifest file you don’t need to replicate your existing manifest and can simply include the attribute you wish to add:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application android:vmSafeMode="true" /> </manifest>
Note: It is only possible to disable AOT compilation if you have a targetSdkVersion of 22+ and you’re running a device using the ART runtime.
Execution timing of ART ahead-of-time compilation
Before you make this change you should first identify that AOT is causing a significant delay to your deployment times. For small apps it is likely that you will save less than a second of installation time and this optimization is probably not required.
The device process that performs the ahead-of-time compilation is called dex2oat and outputs logging information that allows us to see the execution time elapsed. Filter your logcat for items containing dex2oat and you will see the execution time for the process.
Here is example output with AOT compilation enabled:
07-03 10:19:02.650 21326-21326/? I/dex2oat﹕ /system/bin/dex2oat --zip-fd=6 --zip-location=/data/app/com.testing.sample.myapp/base.apk --oat-fd=7 --oat-location=/data/dalvik-cache/arm/data@firstname.lastname@example.org@email@example.com --instruction-set=arm --instruction-set-features=div --runtime-arg -Xms64m --runtime-arg -Xmx512m --swap-fd=8 07-03 10:19:03.989 21326-21326/? I/dex2oat﹕ dex2oat took 3.338s (threads: 4) arena alloc=107KB java alloc=2MB native alloc=4MB free=3MB
Output with AOT compilation disabled:
07-03 10:17:33.934 19031-19031/? I/dex2oat﹕ /system/bin/dex2oat --zip-fd=6 --zip-location=/data/app/com.testing.sample.myapp-1/base.apk --oat-fd=7 --oat-location=/data/dalvik-cache/arm/data@firstname.lastname@example.org@email@example.com --instruction-set=arm --instruction-set-features=div --runtime-arg -Xms64m --runtime-arg -Xmx512m --compiler-filter=interpret-only --swap-fd=8 07-03 10:17:34.693 19031-19031/? I/dex2oat﹕ dex2oat took 1.258ms (threads: 4) arena alloc=0B java alloc=2MB native alloc=502KB free=7MB
Checking if manifest includes vmSafeMode
The logcat output of the dex2oat process also lets you check that the vmSafeMode attribute has been correctly applied. When vmSafeMode is set to true this process will be executed with the following argument:
/system/bin/dex2oat ... --compiler-filter=interpret-only
If you are seeing this option when installing your release APK then it is likely you have included vmSafeMode in your apps main AndroidManifest.apk rather than the debug only manifest.
Another method I found for determining if vmSafeMode is set for a given APK is to use the aapt.exe tool. You will find the aapt tool in the build-tools folder of the Android SDK, which differs in location based on your chosen OS. You will probably have several different versions installed and will find it in a location such as:
Execute the list command:
aapt list -a myapkfile.apk
This should produce output including:
Android manifest: N: android=http://schemas.android.com/apk/res/android E: manifest (line=17) A: android:versionCode(0x0101021b)=(type 0x10)0x1 A: android:versionName(0x0101021c)="1.0" (Raw: "1.0") A: package="com.testing.sample.myapp" (Raw: "com.testing.sample.myapp") A: platformBuildVersionCode=(type 0x10)0x16 (Raw: "22") A: platformBuildVersionName="5.1.1-1819727" (Raw: "5.1.1-1819727") E: uses-sdk (line=22) A: android:minSdkVersion(0x0101020c)=(type 0x10)0x15 A: android:targetSdkVersion(0x01010270)=(type 0x10)0x16 E: application (line=26) A: android:label(0x01010001)=@0x7f0b0001 A: android:icon(0x01010002)=@0x7f030000 A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff A: android:vmSafeMode(0x010102b8)=(type 0x12)0xffffffff
Side effects of disabling AOT compilation
Without ahead-of-time compilation your app is going to run slower, it probably won’t be noticeable, but the runtime will have more work to do during execution. I have heard some developers have had major performance problems, such as execution of intensive processing experiencing a 10x increase in execution time. So keep an eye out for any performance problems.
So far I am happy to report that I have not run into any execution issues or unexpected behavior while testing this optimization.
Android Manifest vmSafeMode attribute: