This page discusses how to configure ART and its compilation options. Topics addressed here include configuration of pre-compilation of the system image, dex2oat compilation options, and how to trade off system partition space, data partition space, and performance.
See ART and Dalvik, the Dalvik Executable format, and the remaining pages on source.android.com to work with ART. See Verifying App Behavior on the Android Runtime (ART) to ensure your apps work properly.
ART uses ahead-of-time (AOT) compilation, and starting in Android 7.0 (Nougat or N), it uses a hybrid combination of AOT, just-in-time (JIT) compilation, and profile-guided compilation. The combination of all these compilation modes is configurable and will be discussed in this section. As an example, Pixel devices are configured with the following compilation flow:
ART comprises a compiler (the dex2oat
tool) and a runtime
(libart.so
) that is loaded for starting the Zygote. The
dex2oat
tool takes an APK file and generates one or more
compilation artifact files that the runtime loads. The number of files, their
extensions, and names are subject to change across releases, but as of the
Android O release, the files being generated are:
.vdex
: contains the uncompressed DEX code of the
APK, with some additional metadata to speed up verification..odex
: contains AOT compiled code for methods in the
APK..art (optional)
: contains ART internal
representations of some strings and classes listed in the APK, used to speed
application startup. Compilation options for ART are of two categories:
One core ART option to configure these two categories is compiler
filters. Compiler filters drive how ART compiles DEX code and is an
option passed to the dex2oat
tool. Starting in Android O, there
are four officially supported filters:
There are a number of ART build options available for configuring a system
ROM. How to configure these options depends on the available storage space for
/system
and the number of pre-installed applications. The
JARs/APKs that are compiled into a system ROM can be divided in four
categories:
WITH_DEXPREOPT
Whether dex2oat
is invoked on DEX code installed on the system image. Enabled by default.
DONT_DEXPREOPT_PREBUILTS
(since Android 5.0)
Enabling DONT_DEXPREOPT_PREBUILTS
prevents the prebuilts from being
pre-optimized. These are apps that have include $(BUILD_PREBUILT)
specified in their Android.mk
, such as Gmail. Skipping
pre-optimization of prebuilt apps that are likely to be updated via Google Play
saves /system
space but does add to first boot time.
WITH_DEXPREOPT_BOOT_IMG_ONLY
Enabling WITH_DEXPREOPT_BOOT_IMG_ONLY
pre-optimizes only the
boot classpath.
LOCAL_DEX_PREOPT
Pre-optimization can also be enabled or disabled on an individual app basis by
specifying the LOCAL_DEX_PREOPT
option in the module definition.
This can be useful for disabling pre-optimization of apps that may immediately
receive Google Play updates since the updates would render the pre-optimized
code in the system image obsolete. This is also useful to save space on major
version upgrade OTAs since users may already have newer versions of apps in the
data partition.
LOCAL_DEX_PREOPT
supports the values ‘true’ or ‘false’ to
enable or disable pre-optimization, respectively. In addition, ‘nostripping’ can
be specified if pre-optimization should not strip the classes.dex
file from the APK or JAR file. Normally this file is stripped since it’s no
longer needed after pre-optimization, but this last option is necessary to
allow third-party APK signatures to remain valid.
PRODUCT_DEX_PREOPT_BOOT_FLAGS
Passes options to dex2oat
to control how the boot image is
compiled. It can be used to specify customized image classes lists, compiled
classes lists, and compiler filters.
PRODUCT_DEX_PREOPT_DEFAULT_FLAGS
Passes options to dex2oat
to control how everything besides the
boot image is compiled.
PRODUCT_DEX_PREOPT_MODULE_CONFIGS
Provides the ability to pass dex2oat
options for a particular
module and product configuration. It is set in a product’s
device.mk
file by $(call add-product-dex-preopt-module-config,<modules>,<option>)
where <modules>
is a list of LOCAL_MODULE and LOCAL_PACKAGE names
for JAR and APK files, respectively.
PRODUCT_DEXPREOPT_SPEED_APPS (New in Android O)
List of applications that have been identified as core to the products and which are desirable to compile with the speed compiler filter. For example, persistent apps such as SystemUI get a chance to use profile-guided compilation only at the next reboot, so it may be better for the product to have these apps always AOT-compiled.
PRODUCT_SYSTEM_SERVER_APPS (New in Android O)
List of applications that are loaded by the system server. These applications will be compiled by default with the speed compiler filter.
PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD(Post Android O)
Whether to include a debug version of ART on the device. By default, this is enabled for userdebug and eng builds. The behavior can be overridden by explicitly setting the option to true or false.
By default, the device will use the non-debug version (libart.so).
To switch, set the system property persist.sys.dalvik.vm.lib.2
to
libartd.so.
WITH_DEXPREOPT_PIC (Removed in Android O)
In Android 5.1.0 through Android 6.0.1, WITH_DEXPREOPT_PIC
can
be specified to enable position-independent code (PIC). With this, compiled
code from the image doesn’t have to be relocated from /system into
/data/dalvik-cache, saving space in the data partition. However, there is a
slight runtime impact because it disables an optimization that takes advantage
of position-dependent code. Typically, devices wanting to save space in /data
should enable PIC compilation.
In Android 7.0, PIC compilation was enabled by default.
The preloaded classes list is a list of classes the zygote will initialize on startup. This saves each app from having to run these class initializers separately, allowing them to start up faster and share pages in memory. The preloaded classes list file is located at frameworks/base/preloaded-classes by default, and it contains a list that is tuned for typical phone use. This may be different for other devices, such as wearables, and should be tuned accordingly. Be careful when tuning this since adding too many classes wastes memory loading unused classes; meanwhile, adding too few forces each app to have to have its own copy, again wasting memory.
Example usage (in product’s device.mk):
PRODUCT_COPY_FILES += <filename>:system/etc/preloaded-classes
Note: This line must be placed before
inheriting any product configuration makefiles that get the default one from:
build/target/product/base.mk
The image classes list is a list of classes that dex2oat initializes ahead of time and stores in the boot.art file. This allows the zygote to load these results out of the boot.art file on startup instead of running the initializers for these classes itself during preloading. A key feature of this is that the pages loaded from the image and shared between processes can be clean, allowing them to be swapped out easily in low-memory situations. In L, by default the image classes list uses the same list as the preloaded classes list. Beginning post-L in AOSP, a custom image classes list can be specified using:
PRODUCT_DEX_PREOPT_BOOT_FLAGS
Example use (in product’s device.mk
):
PRODUCT_DEX_PREOPT_BOOT_FLAGS += --image-classes=<filename>
In post-L AOSP, a subset of classes from the boot classpath can be specified to be compiled during pre-optimization using the compiled classes list. This can be a useful option for devices that are very tight on space and can’t fit the entire pre-optimized boot image. However, note classes not specified by this list will not be compiled - not even on the device - and must be interpreted, potentially affecting runtime performance. By default, dex2oat will look for a compiled classes list in $OUT/system/etc/compiled-classes, so a custom one can be copied to that location by the device.mk. A particular file location can also be specified using:
PRODUCT_DEX_PREOPT_BOOT_FLAGS
Example usage (in product’s device.mk
):
PRODUCT_COPY_FILES += <filename>:system/etc/compiled-classes
Note: This line must be placed before
inheriting any product configuration makefiles that get the default one from:
build/target/product/base.mk
The following options affect Android releases only where the ART JIT compiler is available.
Since Android 7.0, there's a generic way to specify the level of compilation/verification that happened at various stages. The compilation levels can be configured via system properties with the defaults being:
This is the compilation filter used when installing applications through Google Play. For faster installs, try the quicken compiler filter.
This is the compilation filter used when the device is idle, charging and fully charged. Try the speed-profile compiler filter to take advantage of profile-guided compilation and save on storage.
The compilation filter used after an over-the-air update. We strongly recommend the verify compiler filter for this option to avoid very long boot times.
The compilation filter for the first time the device ever boots. The filter
used here will only affect the boot time after factory. We recommend the filter
quicken for it to avoid long times before a user gets to
use the phone for the very first time. Note that if all applications in
/system
are already compiled with the quicken compiler
filter or are compiled with the speed or speed-profile
compiler filter, the pm.dexopt.first-boot
has no effect.
Note that these options affect dex2oat
during on-device compilation as well as during pre-optimization, whereas most
of the options discussed above affect only pre-optimization.
To control dex2oat
while it’s compiling the boot image:
To control dex2oat
while it’s compiling everything besides the boot image:
On releases through Android 6.0, one additional option is provided for compiling everything besides the boot image:
Starting with Android 6.1, this becomes two additional options for compiling everything besides the boot image:
Starting with Android 7.1, two options are provided for controlling how memory is used when compiling everything besides the boot image:
The options that control initial and maximum heap size for
dex2oat
should not be reduced since they could limit what
applications can be compiled.
Starting in Android 7.0, devices may use two system partitions to enable A/B system updates. To save on the system partition size, the preopted files can be installed in the unused second system partition. They are then copied to the data partition on first boot.
Example usage (in device-common.mk
):
PRODUCT_PACKAGES += \ cppreopts.sh PRODUCT_PROPERTY_OVERRIDES += \ ro.cp_system_other_odex=1
And in device's BoardConfig.mk
:
BOARD_USES_SYSTEM_OTHER_ODEX := true
Note that boot classpath code, system server code, and product-specific core
applications always compile to the system partition. By default, all other
applications get compiled to the unused second system partition. This can be
controlled with the SYSTEM_OTHER_ODEX_FILTER
, which has a value by
default of:
SYSTEM_OTHER_ODEX_FILTER ?= app/% priv-app/%
With A/B enabled devices, applications can be compiled in the background for updating to the new system image. See App compilation in background to optionally include the compilation script and binaries in the system image. The compilation filter used for this compilation is controlled with:
pm.dexopt.ab-ota=speed-profile
We recommend using speed-profile to take advantage of profile guided compilation and save on storage.