Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android MultiDex - Questions on Inner Workings

I recently discovered the new MultiDex functionality from Android for working with apps having more than 65,000 references. See: https://developer.android.com/tools/building/multidex.html

Can someone help me understand the following questions:

1) How does the Gradle build plugin determine what to put in the primary dex file (classes.dex) vs the secondary dex files? Based on the doc there are certain things required to be in primary dex but it doesn't give any examples. Are all activities required to be in the primary dex file?

Quoted Text:

There are complex requirements regarding what classes are needed in the primary dex file when executing in the Dalvik runtime. The Android build tooling updates handle the Android requirements, but it is possible that other included libraries have additional dependency requirements including the use of introspection or invocation of Java methods from native code. Some libraries may not be able to be used until the multidex build tools are updated to allow you to specify classes that must be included in the primary dex file.

2) When building only for Android API Level 21 (Android L) and above, there is different behavior in the Gradle Build Plugin. It says it is much faster because it "Builds each module of the application (including dependencies) as separate dex files. This is commonly referred to as pre-dexing." What is the definition of a module in Android? Is this the Java Library, Android Library, and Android application modules mentioned here: http://developer.android.com/sdk/installing/studio-build.html#projectModules? Do Remote or Local Binary Dependencies (ex:Jars) count as separate modules and thus get put into a different dex file or do they get included in the module depending on them?

like image 341
AnDev123 Avatar asked Nov 25 '14 01:11

AnDev123


2 Answers

What is being placed in main-dex?

There are three sequential tasks that calculate which classes should be packaged in main dex:

collect{variant}MultiDexComponents task

This task writes the class names of all the application components (application, activities, services, receivers, providers) to a text file according to manifest. That is, if you have a component that is not registered in manifest it won't be placed in main-dex. And there're other non-manifest classes - annotations for example. To see a full list check out the CreateManifestKeepList.groovy task in plugin sources.
The output of this task is manifest_keep.txt file.

shrink{variant}MultiDexComponents task

This task invokes ProGuard to create a shrinked jar with only the classes that are mentioned in manifest_keep.txt file.
The output of this task is componentClasses.jar file.

create{variant}MainDexClassList task

This task takes the componentClasses.jar file, and for each class calculates direct references hierarchy (for more info see implementation). That is, if one of your component classes has a field of type X, then this X class will be added to main-dex list as well.
The output of this task is maindexlist.txt, which includes list of all the classes that will be packaged into a main dex.

What happens if my minSdk is 21?

None of the above tasks are run if your minSdk version is 21 - no main-dex list calculation required. This is because in ART, all the dex files converted into a single .oat file during the app installation. And therefore no runtime ClassLoader patching required.

like image 147
Alex Lipov Avatar answered Nov 15 '22 21:11

Alex Lipov


1) The gradle plugin internally uses Proguard to create two jar files in the intermediates/multi-dex build folder. One will be the primary dex, the rest will be spread out over dex 2, 3 etc.

The collect{variant}MultiDexComponents task is responsible for creating the keep file for proguard, you can see this file and other proguard parameters used in the variant specific subdirectory of the folder I mentioned above. Hopefully this will be customisable in the long run.

There is also currently a bug relating to test projects in 1.0.0-rc1 of the gradle plugin (https://code.google.com/p/android/issues/detail?id=80741). With some small changes the workaround I posted there can also be used to add your own entries to the keep list (thus ensuring your classes end up in the primary dex) right now.

2) Modules refer to modules from a Gradle perspective, but these can indeed be the different items mentioned in the list you linked to. If you do a pre-lollipop gradle build from the commandline with --info as a flag you can see all the dex files being passed to dx. (Note that this should not a multidex enabled build or one with preDexLibraries = false).

like image 35
thoutbeckers Avatar answered Nov 15 '22 21:11

thoutbeckers