Sunday, July 20, 2014

Release build optimization - Part 1

The goal of this article is to remove calls to debug log for release builds. Debug logs, which is done using Log.d(tag, msg) often contains more information that you want exposed to the public. It also takes up valuable CPU cycles.

Remove Log.d calls via Proguard

Proguard is a tool on Android that shrinks, optimize, and obfuscate your code. We want to use this on our release builds. In Gradle, we enable this either in the buildType or product flavor closure. The details can be found in the Android Tools User Guide

Example build.gradle:
Note that there are two default rules files. When you first create a project in Android Studio, you usually get a proguard-android.txt file. In order for us to tell Proguard to remove the debug log, we need it to run the optimization phase, so we need to tell it to use the proguard-android-optimization.txt file instead.

The second thing to notice here is the inclusion of a second txt file, the proguard-rules.txt. This text file is how we tell Proguard to remove calls to Log.d, Log.v, Log.i, and whatever else you think is safe to remove.

Example proguard-rules.txt
The assumenosideaffects flag is an optimization option that tells Proguard to treat the declared method as an empty method and thus is safe to remove. Details can be found in the Proguard Usage Manual.

Please note that if for whatever reason you decide to use the returned integer from Log.d and assign it to a variable, Proguard will think that it maybe a useful method and won't remove it. So make sure that whatever method you decided to use this option with does not return a value that's being used, if your intention is to remove the call.

So now if we compile the release build, we would effectively remove the Log.d. So lets take the following example set of calls

Before Proguard:
After Proguard:
As we can see, it did a decent job of removing the debug logs. But it also left something behind. It created a new class and called some function. This is the obfuscated version of the code. So what we are seeing here is that the UserInfo class is still being created. So while we no longer take up I/O cycles by logging, we are still taking up CPU and memory by creating a class that we otherwise didn't need to create. So how can we change the code such that Proguard can safely remove the creation of the UserInfo class? It turns out that if we wrap it around a final boolean of FALSE, then Proguard will remove the code since there's no way the code can be executed. So we might consider changing our code to something like this:
This is a working solution. But because it requires that you add these "if (BuildConfig.DEBUG)" statements everywhere, it may not be acceptable, depending on the size of your project.

to be continued...

No comments:

Post a Comment