This page discusses how to configure Android runtime (ART) and its compilation options. Topics
addressed here include configuration of precompilation of the system image, dex2oat
compilation options, and how to trade off system partition space, data partition space, and
performance.
See ART and Dalvik and the Dalvik executable format to work with ART. See Verifying App Behavior on the Android Runtime (ART) to ensure your apps work properly.
How ART works
ART uses ahead-of-time (AOT) compilation, and starting in Android 7, it uses a hybrid combination of AOT compilation, just-in-time (JIT) compilation, and interpretation, and the AOT compilation can be profile-guided. The combination of all these execution modes is configurable and will be discussed in this section. As an example, Pixel devices are configured to work in the following flow:
- An application is initially installed with a dex metadata (
.dm
) file distributed by Play Store, which contains a cloud profile. ART AOT-compiles the methods listed in the cloud profile. Or, if the application is installed without a dex metadata file, no AOT compilation is performed. - The first few times the application runs, methods that are not AOT-compiled are interpreted. Among the interpreted methods, those that are frequently executed are then JIT-compiled. ART generates a local profile based on the execution and combines it with the cloud profile (if one exists).
- When the device is idle and charging, a compilation daemon runs to re-compile the application based on the combined profile generated during the first few runs.
- On the subsequent runs of the application, ART uses the artifacts generated by the compilation daemon, which contain more AOT-compiled code, compared to the ones that were generated during Methods that are not AOT-compiled are still interpreted or JIT-compiled. ART updates the profile installation, based on the execution, and the profile will then be picked up by subsequent runs of the compilation daemon.
ART comprises a compiler (the dex2oat
tool) and a runtime
(libart.so
) that is loaded during boot. 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 8 release, these files are generated:
.vdex
: contains some additional metadata to speed up verification, sometimes along with the uncompressed DEX code of the APK..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 up app startup.
Compilation options
There are two categories of compilation options for ART:
- System ROM configuration: What code is AOT compiled when building a system image.
- Runtime configuration: how ART compiles and runs apps on a device.
Compiler filters
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 8,
there are four officially supported filters:
verify
: Runs only DEX code verification (no AOT compilation).quicken
: (Android 11 or lower) Runs DEX code verification and optimizes some DEX instructions to get better interpreter performance.speed
: Runs DEX code verification and AOT-compiles all methods. Doesn't preinitialize classes.speed-profile
: Runs DEX code verification, AOT-compiles methods listed in the profile, and preinitializes classes listed in the profile which lack static initialization.
System ROM configuration
Pre-installed libraries and apps are AOT-compiled when a system image is being built. This process is called dexpreopt. Such compiled files are usable as long as all dependencies remain unchanged, in particular the boot classpath.
Note: If the device takes system module updates then the boot classpath is very likely to change in the next update, which renders all dexpreopt files stale and unusable.
There are a number of ART build options available for configuring dexpreopt. How you configure these options depends on the available storage space for the system image and the number of pre-installed applications. The JARs/APKs that are compiled into a system ROM can be divided in four categories:
- Boot classpath code: compiled with the
speed-profile
compiler filter by default. - System server code (see
PRODUCT_SYSTEM_SERVER_JARS
,PRODUCT_APEX_SYSTEM_SERVER_JARS
,PRODUCT_STANDALONE_SYSTEM_SERVER_JARS
,PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS
later in this document):- (Android 14 and higher) Compiled with the
speed-profile
compiler filter by default, or compiled with thespeed
compiler filter if a profile isn't provided. - (Android 13 and lower) Compiled with the
speed
compiler filter by default.
PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
(see later in this document). - (Android 14 and higher) Compiled with the
- Product-specific core apps (see
PRODUCT_DEXPREOPT_SPEED_APPS
later in this document): compiled with thespeed
compiler filter by default. - All other apps: compiled with the
speed-profile
compiler filter by default, or compiled with theverify
compiler filter if a profile isn't provided.Configurable through
PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER
(see later in this document).
Makefile options
WITH_DEXPREOPT
DONT_DEXPREOPT_PREBUILTS
(Android 5 and higher)PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER
(Android 9 and higher)WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY
(since Android 8 MR1)LOCAL_DEX_PREOPT
PRODUCT_DEX_PREOPT_BOOT_FLAGS
PRODUCT_DEX_PREOPT_DEFAULT_FLAGS
PRODUCT_DEX_PREOPT_MODULE_CONFIGS
PRODUCT_DEXPREOPT_SPEED_APPS
(since Android 8)PRODUCT_SYSTEM_SERVER_APPS
(since Android 8)PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD
(since Android 8)WITH_DEXPREOPT_PIC
(until Android 7)WITH_DEXPREOPT_BOOT_IMG_ONLY
(until Android 7 MR1)PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
- (Android 14 and higher) If unspecified, the
speed-profile
compiler filter is used, or thespeed
compiler filter is used if a profile isn't provided. - (Android 13 and lower) If unspecified, the
speed
compiler filter is used. - If set to
speed
, thespeed
compiler filter is used. - If set to
speed-profile
, thespeed-profile
compiler filter is used, or theverify
compiler filter is used if a profile isn't provided. - If set to
verify
, theverify
compiler filter is used. PRODUCT_SYSTEM_SERVER_JARS
,PRODUCT_APEX_SYSTEM_SERVER_JARS
,PRODUCT_STANDALONE_SYSTEM_SERVER_JARS
,PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS
- (Required)
PRODUCT_SYSTEM_SERVER_JARS
: List of system server classpath JARs on the platform (that is, as part ofSYSTEMSERVERCLASSPATH
). Adding system server classpath JARs to this list is required. Failing to add system server classpath JARs to the list results in those JARs not being loaded. - (Required)
PRODUCT_APEX_SYSTEM_SERVER_JARS
: List of system server classpath JARs delivered with APEX (that is, as part ofSYSTEMSERVERCLASSPATH
). The format is<apex name>:<jar name>
. Adding APEX system server classpath JARs to this list is required. Failing to add APEX system server classpath JARs to this list results in those JARs not being loaded. - (Optional, Android 13 and lower)
PRODUCT_STANDALONE_SYSTEM_SERVER_JARS
: List of JARs that system server loads dynamically using separate classloaders (throughSystemServiceManager.startServiceFromJar
). Adding standalone system server JARs to this list isn't required but strongly recommended because it makes the JARs compiled and therefore have a good runtime performance. - (required, since Android 13)
PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS
: List of JARs delivered with APEX that system server loads dynamically using separate classloaders (that is, throughSystemServiceManager.startServiceFromJar
or declared as<apex-system-service>
). The format is<apex name>:<jar name>
. Adding standalone APEX system server JARs to this list is required. Failing to add standalone APEX system server JARs to this list results in boot failure.
Whether dex2oat
is invoked on DEX code installed on the system image. Enabled by default.
Enabling DONT_DEXPREOPT_PREBUILTS
prevents the prebuilts from being
dexpreopted. These are apps that have include $(BUILD_PREBUILT)
specified in their Android.mk
. Skipping
dexpreopt of prebuilt apps that are likely to be updated via Google Play
saves space in the system image but does add to first boot time. Note that this option has no effect
on prebuilt apps defined in Android.bp
.
PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER
specifies the default compiler filter
for dexpreopted applications. These apps are defined in Android.bp
or have
include $(BUILD_PREBUILT)
specified in their Android.mk
. If unspecified,
the default value is speed-profile
, or verify
if the value is unspecified
and a profile isn't provided.
Enabling WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY
dexpreopts only the
boot classpath and system server jars.
Dexpreopt 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 dexpreopt of apps that may immediately
receive Google Play updates since the updates would render the dexpreopted
code in the system image obsolete. This is also useful to save space on major
version upgrade OTAs because users might already have newer versions of apps in the
data partition.
LOCAL_DEX_PREOPT
supports the values true
or false
to
enable or disable dexpreopt, respectively. In addition, nostripping
can
be specified if dexpreopt 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 dexpreopt, but this last option is necessary to
allow third-party APK signatures to remain valid.
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.
Passes options to dex2oat
to control how everything besides the
boot image is compiled.
Provides the ability to pass dex2oat
options for a particular
module and product configuration. It's 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.
List of apps that have been identified as core to the products and
that 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 might be better for the
product to have these apps always AOT-compiled.
List of apps that are loaded by the system server. These apps
are compiled by default with the speed
compiler filter.
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 uses the nondebug version (libart.so
).
To switch, set the system property persist.sys.dalvik.vm.lib.2
to
libartd.so
.
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.
This option was replaced with WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY
that also preopts the system server JARs.
This option specifies the compiler filter for system server.
The following are lists of JARs that are loaded by system server. The JARs are compiled with the
compiler filter specified by PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
Boot classpath configuration
The preloaded classes list is a list of classes that Zygote initializes 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/config/preloaded-classes
by default, and it contains a list that's tuned for typical phone use. This might
be different for other devices such as wearables, and must be tuned
accordingly. Be careful when tuning this; adding too many classes wastes
memory when unused classes get loaded. Adding too few classes forces each app to
have to have its own copy, which again, wastes memory.
Example usage (in product’s device.mk
):
PRODUCT_COPY_FILES += <filename>:system/etc/preloaded-classes
Note: You must place this line before
inheriting any product configuration makefiles that get the default one from
build/target/product/base.mk
.
Runtime configuration
JIT options
The following options affect Android releases only where the ART JIT compiler is available.
dalvik.vm.usejit
: Whether or not the JIT is enabled.dalvik.vm.jitinitialsize
(default 64K): The initial capacity of the code cache. The code cache will regularly GC and increase if needed.dalvik.vm.jitmaxsize
(default 64M): The maximum capacity of the code cache.dalvik.vm.jitthreshold
(default 10000): The threshold that the "hotness" counter of a method needs to pass in order for the method to be JIT-compiled. The "hotness" counter is a metric internal to the runtime. It includes the number of calls, backward branches, and other factors.dalvik.vm.usejitprofiles
(until Android 13): Whether or not JIT profiles are enabled; this may be used even ifdalvik.vm.usejit
is false. Note that if this is false, the compiler filterspeed-profile
does not AOT-compile any method and is equivalent toverify
. Since Android 14, JIT profiles are always enabled and cannot be turned off.dalvik.vm.jitprithreadweight
(default todalvik.vm.jitthreshold
/ 20): The weight of the JIT "samples" (see jitthreshold) for the application UI thread. Use to speed up compilation of methods that directly affect users experience when interacting with the app.dalvik.vm.jittransitionweight
(default todalvik.vm.jitthreshold
/ 10): The weight of the method invocation that transitions between compile code and interpreter. This helps make sure the methods involved are compiled to minimize transitions (which are expensive).
Dex2oat options
These options affect on-device compilation (a.k.a., dexopt), and a few of them also affect dexpreopt, whereas the options discussed in the System ROM configuration section above only affect dexpreopt.
Options to control resource usage:
dalvik.vm.image-dex2oat-threads
/dalvik.vm.image-dex2oat-cpu-set
(until Android 11): The number of threads and the set of CPU cores (see below) to use for boot images.dalvik.vm.boot-dex2oat-threads
/dalvik.vm.boot-dex2oat-cpu-set
:- (until Android 11) The number of threads and the set of CPU cores (see below) to use during boot time for everything other than boot images.
- (since Android 12) The number of threads and the set of CPU cores
(see below) to use during boot time for everything, including boot images.
- Specifically, since Android 14, this corresponds to the
priority class
PRIORITY_BOOT
in ART Service.
- Specifically, since Android 14, this corresponds to the
priority class
dalvik.vm.restore-dex2oat-threads
/dalvik.vm.restore-dex2oat-cpu-set
:- (since Android 11, until Android 13) The number of threads and the set of CPU cores (see below) to use for restoring from cloud backup.
- (since Android 14) The number of threads and the set of CPU cores
(see below) to use for everything that is more latency-sensitive than normal, including
restoring from cloud backup.
- Specifically, this corresponds to the priority class
PRIORITY_INTERACTIVE_FAST
in ART Service.
- Specifically, this corresponds to the priority class
dalvik.vm.background-dex2oat-threads
/dalvik.vm.background-dex2oat-cpu-set
(since Android 14): The number of threads and the set of CPU cores (see below) to use in the background.- Specifically, this corresponds to the priority class
PRIORITY_BACKGROUND
in ART Service.
- Specifically, this corresponds to the priority class
dalvik.vm.dex2oat-threads
/dalvik.vm.dex2oat-cpu-set
: The number of threads and the set of CPU cores to use for everything else.
A set of CPU cores should be specified as a comma-separated list of CPU ids. For example to run on dex2oat on CPU cores 0-3, set:
dalvik.vm.dex2oat-cpu-set=0,1,2,3
When setting the CPU affinity properties, we recommend matching the corresponding property for the number of dex2oat threads to match the number CPUs selected to avoid unnecessary memory and I/O contention:
dalvik.vm.dex2oat-cpu-set=0,1,2,3 dalvik.vm.dex2oat-threads=4
In addition to the system properties above, you can also use task profiles to control the resource usage of dex2oat (see Cgroup Abstraction Layer).
Supported task profiles are:
Dex2OatBackground
(since Android 14) (by default inheritsDex2OatBootComplete
): Controls the resources to use in the background.- Specifically, this corresponds to the priority class
PRIORITY_BACKGROUND
in ART Service.
- Specifically, this corresponds to the priority class
Dex2OatBootComplete
:- (until Android 13) Controls the resource to use for everything after boot.
- (since Android 14) Controls the resource to use for everything
after boot and not in the background.
- Specifically, this corresponds to the priority class
PRIORITY_INTERACTIVE_FAST
andPRIORITY_INTERACTIVE
in ART Service.
- Specifically, this corresponds to the priority class
When both system properties and task profiles are specified, both take effect.
Options to control the heap size:
dalvik.vm.image-dex2oat-Xms
: Initial heap size for boot images.dalvik.vm.image-dex2oat-Xmx
: Maximum heap size for boot images.dalvik.vm.dex2oat-Xms
: Initial heap size for everything else.dalvik.vm.dex2oat-Xmx
: Maximum heap size for everything else.
The options that control initial and maximum heap size for
dex2oat
should not be reduced since they could limit what
applications can be compiled.
Options to control the compiler filter:
dalvik.vm.image-dex2oat-filter
(until Android 11): The compiler filter for boot images. Since Android 12, the compiler filter for boot images is alwaysspeed-profile
and cannot be changed.dalvik.vm.systemservercompilerfilter
(since Android 13): The compiler filter for system server. SeePRODUCT_SYSTEM_SERVER_COMPILER_FILTER
.dalvik.vm.systemuicompilerfilter
(since Android 13): The compiler filter for the System UI package.dalvik.vm.dex2oat-filter
(until Android 6): The compiler filter for everything else.pm.dexopt.<reason>
(since Android 7): The compiler filter for everything else. See ART Service Configuration for Android 14 and above, or Package Manager Configuration for Android 13 and below.
Other options to control the compilation of everything other than boot images:
dalvik.vm.dex2oat-very-large
(since Android 7.1): Minimum total dex file size in bytes to disable AOT compilation.dalvik.vm.dex2oat-swap
(since Android 7.1) (default: true): Allows using a swap file for dex2oat. This can help avoid out-of-memory crashes. Note that even if this option is turned on, dex2oat will only use a swap file under certain conditions, such as when the number of dex files is large, and the conditions are subject to change.dalvik.vm.ps-min-first-save-ms
(since Android 12): The minimum time to wait before the runtime generates a profile of the application, the first time the application is launched.dalvik.vm.ps-min-save-period-ms
(since Android 12): The minimum time to wait before updating the profile of the application.dalvik.vm.dex2oat64.enabled
(since Android 11) (default: false): Whether to use the 64-bit version of dex2oat.dalvik.vm.bgdexopt.new-classes-percent
(since Android 12) (default: 20): The min percentage, between 0 and 100, of new classes in a profile to trigger a re-compilation. Only applicable to profile-guided compilation (speed-profile
), typically during background dexopt. Note that there is also a threshold of at least 50 new classes in addition to the percentage threshold, and it's not configurable.dalvik.vm.bgdexopt.new-methods-percent
(since Android 12) (default: 20): The min percentage, between 0 and 100, of new methods in a profile to trigger a re-compilation. Only applicable to profile-guided compilation (speed-profile
), typically during background dexopt. Note that there is also a threshold of at least 100 new methods in addition to the percentage threshold, and it's not configurable.dalvik.vm.dex2oat-max-image-block-size
(since Android 10) (default: 524288) Maximum solid block size for compressed images. A large image is split into a set of solid blocks such that no block is larger than the maximum size.dalvik.vm.dex2oat-resolve-startup-strings
(since Android 10) (default: true) If true, causes dex2oat to resolve all const-strings that are referenced from methods marked as "startup" in the profile.debug.generate-debug-info
(default: false) Whether or not to generate debug information for native debugging, such as stack unwinding information, ELF symbols and dwarf sections.dalvik.vm.dex2oat-minidebuginfo
(since Android 9) (default: true) Whether or not to generate minimal amount of LZMA-compressed debug information necessary to print backtraces.
ART Service options
Since Android 14, on-device AOT compilation for apps (a.k.a. dexopt) is handled by ART Service. For information about configuring ART Service, see ART Service configuration.Package manager options
Prior to Android 14, on-device AOT compilation for apps (a.k.a. dexopt) is handled by the package manager. For information about configuring the package manager for dexopt, see Package Manager Configuration.A/B specific configuration
ROM configuration
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
apps always compile to the system partition. By default, all other
apps 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/%
Background OTA dexopt
On A/B enabled devices, applications can be compiled in the background before the reboot with 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.
JDWP options
Java Debug Wire Protocol (JDWP) thread creation in userdebug builds are controlled through the
persist.debug.dalvik.vm.jdwp.enabled
system property. By default, this property
isn't set and JDWP threads are created only for debuggable apps. To enable JDWP threads for both
debuggable and nondebuggable apps, set persist.debug.dalvik.vm.jdwp.enabled
to 1
. The device must be rebooted for changes to the property to take effect.
To debug a nondebuggable app on a userdebug build, enable JDWP by running the following command:
For devices running Android 13 and lower, the runtime creates JDWP threads for debuggable and nondebuggable apps on userdebug builds. This means that it's possible to attach a debugger or profile any app on userdebug builds.adb shell setprop persist.debug.dalvik.vm.jdwp.enabled 1
adb reboot