How Proguard Optimization Causes illegalAccesError on Dalvik

Our android app faced illegalAccessError in another internal module at run time, and it only happened on android 4.4. It’s tricky because this error should be caught during compilation and only one app had this issue.
Eventually I found the root cause is that project used “proguard-android-optimize.txt” instead of “proguard-android” for ProGuard, it will do extra optimization, e.g. inline methods, modifier the access of class and members and etc. And this make exception occur.

illegalAccessError Occurs at Run Time Because of Optimization

This exception was thrown if an application attempts to touch a field or a method that it does not have access to. When illegalAccessError occurs at run time, it means the definition of a class has incompatibly changed.

However, why Proguard optimization would change our definition of classes? This is because when using proguard-android-optimize, it will do optimization for your jars after compiling whole project (so it won’t have any build error).

ProGuard reads compiled jars and then subsequently optimizes, obfuscates. At the end, ProGuard will optionally change the package for a class, repackage class files that are renamed, inlining some methods, or change access permission of these accessed fields. ProGuard writes the processed results to one or more output jars.

Classes that look for resource files in their package directories will no longer work properly if they are moved elsewhere, some virtual machines would have problems with the processed code otherwise. And… this makes illegalAccessError occur at rum time.

Interesting, we also found when app needn’t multidex, illegalAccessError won’t occur even with Proguard optimization with same modules.

Only Android 4.4 Has This Access Error Exception !!??

This access error only happened at android 4.4. Here is assumption I guess, (if there are any mistakes, please feel free to inform me on comments.)

  1. For android 5.0+(ART): 
    as official document says, ART performs AOT compilation which compiles multi DEX files into compiled app executable at install time. android 5.0+ probably works around because ART natively supports loading multiple DEX files from APK file and compile them into a single OAT file before executing.
  2. For android 4.3 and below: 
    I didn’t know the difference or change log of Dalvik versions, however, android 4.4 has remove -allowaccessmodification from the basic Proguard flags because “it seems with that flag Proguard modifies the class files in a way that Dalvik does not like.” So I guess Android 4.4’s Dalvik cannot work well with -allowaccessmodification on Proguard’s optimization

Optimizations Introduces Certain Risks

Here is comment of proguard-android-optimize.txt:

Adding optimization introduces certain risks, since for example not all optimizations performed by ProGuard works on all versions of Dalvik.

Although ProGuard has encountered unexpected error, typically in the optimization step, you should be able to test thoroughly when turning on optimization.

To fix errors and force ProGuard to keep certain code, class or method, add a -keep line in the ProGuard configuration file. Alternatively, use the @Keep annotation to the code you want to keep because proguard-android-optimize.txt already supports@Keep in its definition after gradle 2.2+.