Using multiple .dex files for Android instrumentation

Overview

When using multiple .dex for Android auto-instrumentation, there is a limit on the number of referenced methods in a given .dex file. The specification limit for this number is 65,536. Android refers to that limit as the 64K reference limit.

Android introduced the ART runtime with Android 5.0, which natively supports multi-dex applications. But for platforms prior to Android 5.0, Android uses the Davlik runtime, which only supports single-dex applications. The multidex support library lets you use additional .dex files after the MultiDex.install() task completes. Therefore all classes loaded at the app start must be part of the primary .dex file (classes.dex).

Because the auto-instrumentor inserts the agent start-up routine into the application start procedure, the agent code has to be part of the primary .dex file. The auto-instrumentor moves some classes from the primary .dex file into another .dex file if there is not enough space in the primary .dex file. For most applications, the default settings should work, but for some apps you must fine-tune the settings.

Note

The auto-instrumentor analyzes class dependencies based on the byte code of for application start procedure. If you hide your dependencies, for example with reflection, the auto-instrumentor can't detect all your application start dependencies. If you use the Android Gradle multiDexKeepFile and/or multiDexKeepProguard properties, adding the specified classes also to the corresponding auto-instrumentor properties is recommended, or use the DTXMultiDexKeepFile property as descripted in the next section.

You should test the application start on a device with Android 4.4 or lower. If the application crashes with a java.lang.NoClassDefFoundError, then you have to add the missing class to the corresponding auto-instrumentation properties.

Fine-tune the multidex preparation step

Following properties fine-tune auto-instrumentation for mutlidex applications.

  • Use the DTXPrimaryDexLimit and DTXSecondaryDexLimit properties to configure the limit of referenced methods for the primary and the secondary .dex files.
  • Use the DTXMultiDexKeep and DTXMultiDexKeepFile properties to configure the auto-instrumentor internal main dex list.

The instrumentation step increases the number of referenced methods (depending on your implementation) and fails if the number of referenced methods exceeds the 64K limit. The auto-instrumentor also adds the agent code into the primary .dex file. For every .dex file, the number of referenced methods is analyzed and adapted before the instrumentation step. The auto-instrumentator adapts the number of referenced methods by moving a precalculated number of classes from the .dex file to another .dex file. Use the DTXPrimaryDexLimit and DTXSecondaryDexLimit properties to configure the final limit of referenced methods for this step. Use the DTXPrimaryDexLimit property to set the limit for the primary .dex file (classes.dex) and the DTXSecondaryDexLimit property sets the limit for the secondary .dex files, such as classes2.dex.

Currently, the auto-instrumentor can't calculate the number of added methods and therefore uses default values for the limits. The default value for DTXPrimaryDexLimit is around 62K and for DTXSecondaryDexLimit it is nearly 64K. This configuration should fit most applications and also keeps the changes to a minimum. If the auto-instrumentation fails for your application, then you have to update the two properties.

For the primary .dex file the auto-instrumentor generates an internal main dex list and does not move the classes to another .dex file. If using the Android Gradle plugin to build you APK file, set the DTXMultiDexKeepFile property. The Android Gradle plugin generates a maindexlist.txt file. This file contains a list of classes, which have to be part of the primary .dex file. You should specify this file with the DTXMultiDexKeepFile property. For example:

DTXMultiDexKeepFile=<path_to_project>/<project>/<module>/build/intermediates/multi-dex/<build_variant>/maindexlist.txt

You can also specify you own class list in a file, to be part of the primary .dex file. Only one class per line is accepted. The class name must end with the .class suffix. Separate the package parts with a slash (for example com/example/Foo.class). You can only specify one file for the DTXMultiDexKeepFile property. The auto-instrumentor does not analyze the specified classes' dependecies. You must track them manually.

Use the DTXMultiDexKeep property if you don't want to track dependencies manually. The auto-instrumentor analyzes the specified classes and keeps these classes with their dependencies in the primary .dex file. Use the DTXMultiDexKeep to create a list of packages and classes. For example:

DTXMultiDexKeep=com.example.*, com.example2.Foo

This property is very useful when for resolving a java.lang.NoClassDefFoundError message on application start-up for an Android 4.x device. Add the classes (mentioned in the error message) to the DTXMultiDexKeep property. The auto-instrumentor detects the class dependencies.

Build an ajusted APK file

To reduce auto-instrumentor execution time, you can also fine-tune the Android build process to generate an adjusted APK file. With this file, you can skip the mult-idex preparation step from the auto-instrumentor. Ensure there is enough space for the mobile agent in the primary .dex file. You can reach this goal with the --minimal-main-dex or --set-max-idx-number option from the dx command. You can set this option with using additional Parameters property from the Android Gradle plugin.

--minimal-main-dex option: Use this option to have Android store classes only needed for the application start procedure in the primary .dex file.

dexOptions {
        additionalParameters '--minimal-main-dex'
}

--set-max-idx-number option: Use this option to have Android reduce the referenced method limit to the specified value. This setting is used for all your APK .dex files.

dexOptions {
        additionalParameters '--set-max-idx-number=62000'
}
Note

Before you modify your application settings, you should aware of the main dex list and how you can add missing classes to the main dex list.