page.title=Configuring ART @jd:body

In this document

Introduction

This document is intended to discuss how to configure ART and its compilation options. Topics addressed here include configuration of pre-compilation of the system image, dex2oat compilation options at first boot (and post-OTA), 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.

How ART works

ART is the new Android runtime for the Android 5.0 (Lollipop or L) release and beyond. Dalvik is no longer available.

Please note, this section merely summarizes ART’s configuration. For an in-depth description, see the Android runtime presentation conducted at Google I/O 2014.

ART uses ahead-of-time (AOT) compilation. This means that, at installation, dex code is compiled to native code in OAT files, which replace Dalvik’s odex files. This has several implications:

Compilation options

Dex file compilation takes more time than dexopt, which can be noticeable when all of a user’s apps must be compiled during first boot (after factory reset or after receiving an OTA). To reduce the amount of compilation needed, ART supports the option of pre-optimizing libraries and applications in the system partition. Including the pre-optimized dex files takes space in the system image, so these options trade first boot time for system image size. Note that OTAs are relatively infrequent and subsequent boot times should be the same with or without pre-optimization.

WITH_DEXPREOPT

Pre-optimization is controlled by the build option WITH_DEXPREOPT. Before the L release, this was enabled by default in “user” builds. Starting in L, this option is opt-in and needs to be enabled in the product configuration such as a device’s BoardConfig.mk file.

Enabling WITH_DEXPREOPT causes everything in the system image to be pre-optimized. If this makes the system image too large, additional options can be specified to reduce the amount of pre-optimization. Note that all the following build options with “PREOPT” in the name must have WITH_DEXPREOPT enabled to work.

Example usage (in product’s BoardConfig.mk):

WITH_DEXPREOPT := true

DONT_DEXPREOPT_PREBUILTS

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.

Example usage (in product’s BoardConfig.mk):

WITH_DEXPREOPT := true
DONT_DEXPREOPT_PREBUILTS := true

WITH_DEXPREOPT_BOOT_IMG_ONLY

Enabling WITH_DEXPREOPT_BOOT_IMG_ONLY only pre-optimizes the boot image, which consists of boot.art with the image classes and boot.oat with code for the boot classpath. Enabling this saves significant /system space but means all apps will be optimized at first boot. Typically it is better to selectively disable app pre-optimization via DONT_DEXPREOPT_PREBUILTS or add-product-dex-preopt-module-config.

Example usage (in product’s BoardConfig.mk):

WITH_DEXPREOPT := true
WITH_DEXPREOPT_BOOT_IMG_ONLY := true

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.

Example usage (in app’s Android.mk):

LOCAL_DEX_PREOPT := false

PRODUCT_DEX_PREOPT_*

Beginning post-L release in the Android Open Source Project (AOSP), a number of flags have been added that give further control to how pre-optimization is done. 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, all of which are described in later sections. Similarly, PRODUCT_DEX_PREOPT_DEFAULT_FLAGS controls default flags to pass to dex2oat for compilation of everything besides the boot image, namely jar and apk files.

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. Through this flag, it is possible to have fine-grained control of pre-optimization for each dex file and a specific device. Such tuning allows /system space to be maximally used to improve first boot time.

Example usage (in product’s device.mk):

PRODUCT_DEX_PREOPT_DEFAULT_FLAGS := --compiler-filter=interpret-only
$(call add-product-dex-preopt-module-config,services,--compiler-filter=space)

Preloaded Classes List

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.

Image Classes List

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 usage (in product’s device.mk):

PRODUCT_DEX_PREOPT_BOOT_FLAGS += --image-classes=<filename>

Compiled Classes List

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.

Compiler Filters

In L, dex2oat takes a variety of --compiler-filter options to control how it compiles. Passing in a compiler filter flag for a particular app specifies how it’s pre-optimized. Here’s a description of each available option:

WITH_DEXPREOPT_PIC

In post-L AOSP, 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.

Example usage (in product’s device.mk):

WITH_DEXPREOPT := true
WITH_DEXPREOPT_PIC := true

WITH_ART_SMALL_MODE

For devices with very limited space, WITH_ART_SMALL_MODE can be enabled. This option compiles the boot classpath and nothing else, greatly reducing first boot time since most compilation is skipped. It also saves on storage because there is no compiled code for apps. However, this impacts runtime performance since app code has to be interpreted. The impact is limited since most performance sensitive code in the framework is still compiled, but regressions may appear in benchmarking.

Example usage (in product’s device.mk):

WITH_ART_SMALL_MODE := true

In future releases, this build option will be removed since it can be done with this (in product’s device.mk):

PRODUCT_PROPERTY_OVERRIDES += \
     dalvik.vm.dex2oat-filter=interpret-only \
     dalvik.vm.image-dex2oat-filter=speed

dalvik.vm Properties

Most dalvik.vm properties in ART are similar to Dalvik, but there are a few additional ones as described below. 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:

The options that control initial and maximum heap size for dex2oat should not be reduced since they could limit what applications can be compiled.

Sample Usage

The goal of these compiler options is to utilize available space in the system and data partition to reduce the amount of dex2oat that must be performed by the device.

For devices with ample system and data space, enabling dex pre-optimization is all that is necessary.

BoardConfig.mk:

WITH_DEXPREOPT := true

If this causes the system image to become too large, the next thing to try is disabling pre-optimization of the prebuilts.

BoardConfig.mk:

WITH_DEXPREOPT := true
DONT_DEXPREOPT_PREBUILTS := true

Again, if the system image is still too large, try pre-optimizing only the boot image.

BoardConfig.mk:

WITH_DEXPREOPT := true
WITH_DEXPREOPT_BOOT_IMG_ONLY := true

However, limiting to pre-optimizing only the boot-image means all apps will have to be optimized on first boot. In order to avoid this, it is possible to combine these high level flags with more fine-grained controls to maximize the amount of pre-optimized apps.

For instance, if disabling the pre-optimization of the prebuilts almost fits into the system partition, compiling the boot classpath with the ‘space’ option may make it fit. Note this compiles fewer methods in the boot classpath, potentially interpreting more code and impacting runtime performance.

BoardConfig.mk:

WITH_DEXPREOPT := true
DONT_DEXPREOPT_PREBUILTS := true

device.mk:

PRODUCT_DEX_PREOPT_BOOT_FLAGS := --compiler-filter=space

If a device has very limited system partition space, it’s possible to compile a subset of classes in the boot classpath using the compiled classes list. Boot classpath methods that aren’t in this list will have to be interpreted, which could affect runtime performance.

BoardConfig.mk:

WITH_DEXPREOPT := true
WITH_DEXPREOPT_BOOT_IMG_ONLY := true

device.mk:

PRODUCT_COPY_FILES += <filename>:system/etc/compiled-classes

If a device has both limited space in the system and data partitions, compiler filter flags can be used to disable compilation of certain apps. This will save space in both system and data, as there won’t be any compiled code, but these apps will have to be interpreted. This example configuration would pre-optimize the boot classpath but prevent compilation of other apps that are not prebuilts. However, to prevent noticeable performance degradation of system_server, the services.jar is still compiled but optimized for space. Note that user-installed applications will still use the default compiler filter of speed.

BoardConfig.mk:

WITH_DEXPREOPT := true
DONT_DEXPREOPT_PREBUILTS := true

device.mk:

PRODUCT_DEX_PREOPT_DEFAULT_FLAGS := --compiler-filter=interpret-only
$(call add-product-dex-preopt-module-config,services,--compiler-filter=space)

For a major version upgrade OTA, it can be useful to blacklist certain apps from being pre-optimized since they will likely be out of date. This can be done by specifying LOCAL_DEX_PREOPT (for all products) or with PRODUCT_DEX_PREOPT_MODULE_CONFIGS (for a particular product).

BoardConfig.mk:

WITH_DEXPREOPT := true

Android.mk (of blacklisted apps):

LOCAL_DEX_PREOPT := false