page.title=Configuring ART @jd:body
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.
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:
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.
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
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
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
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
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)
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 usage (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.
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:
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
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
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.
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