Zorgan
Zorgan

Reputation: 9123

Log statements after Android Gradle plugin 3.4.0 (with R8 Compiler)

Android's new R8 compiler detects and safely removes unused classes, fields, methods, and attributes from your app and its library dependencies among other things.

Does it also remove Log statements? E.g. if I build my Release APK, ready for launch, am I safe to leave my Log statements in my app?

Log.d("LogStatement", variable.toString())

or do I have to remove them every time I upload/update my app to Google Play?

Upvotes: 2

Views: 1051

Answers (3)

JohPuc
JohPuc

Reputation: 21

Short answer: it depends.

As you can see at this issue for R8: https://issuetracker.google.com/issues/73708157

It depends on which logger you are using. And of course you have to define the proper ProGuard-rules.

When using the ProGuard-rules as mentioned by Younes Charfaoui, the call to the logger will be removed. This works only, when using plain Strings:

Log.d("LogTag", "My log statement");

--> will be properly removed.

But when using (automatic) StringBuilder at logging:

Log.d("LogTag", "My log statement will show some variable: " + variable);

only the call to the logger will be removed.
This means, the StringBuilder-part will remain visible in the resulting ByteCode.
You have to watch out, not to use any automatic StringBuilders.
Another example:

@Override
public void onCreate(Bundle savedInstanceState) {
  Log.d("MyFragment::onCreate", "will be removed"); // will be dropped
  Log.d("MyFragment::onCreate::", savedInstanceState.toString()); // call for toString() will remain
}

see:

invoke-virtual {p1}, Landroid/os/Bundle;->toString()Ljava/lang/String;

There are ProGuard rules which are only supported by ProGuard and not yet by R8, which would easily remove the remaining StringBuilders: assumenoexternalsideeffects, assumenoexternalreturnvalues.

When using logging with automatic StringBuilder you have:

  • bad performance as the StringBuilder performs its action and the result is unused.
  • crippled your obfuscation, because anyone who tries to disassemble your apk and reads the ByteCode might understand the obfuscated code much easier due to the remaining StringBuilder of your debug log-statements.

To really make sure, that your logging code is removed with R8 you have two options:

  • Use a logger library which supports message building (like slf4j), where you can write:
logger.debug("My log statement will show some variable: {} and maybe another one: {}", variable1, variable2);
  • Use a test around each call to logger (is really ugly to read and increases your code complexity, just if you care for static code analysis like sonarqube).
    Logger.SHOW_LOG must be a public static final boolean with the value = false, so the code optimization will detect the whole line as unused code and properly removes everything in between.
if (Logger.SHOW_LOG) {
  logger.debug("My log statement will show some variable: " + variable1 + " and maybe another one: " + variable2);
}

also see: http://www.slf4j.org/faq.html#logging_performance

If you also think, that this should be working with R8 the same as it did with ProGuard, please star one of the following issues:
Add support for Proguard 6 -assumenoexternalsideeffects optimization option
Add support for Proguard 6 -assumenoexternalreturnvalues optimization option
Improve unused StringBuilder elimination

Upvotes: 2

Mohammed Abdul Bari
Mohammed Abdul Bari

Reputation: 398

I am not sure, if you are still looking for an answer for this, but, it is not removed, if you inspect the apk using apk analyzer (use the mapping file for readability), you would see the Log class does exist. And like @Younes Charfaoui mentioned you can add those proguard rules to remove it.

Upvotes: 0

Younes Charfaoui
Younes Charfaoui

Reputation: 1161

No, at all, you can do this via Proguard Tools. In build.gradle you can enable Proguard

release {
        minifyEnabled true

        proguardFiles getDefaultProguardFile(
                'proguard-android-optimize.txt'),
                'proguard-rules.pro'
    }

Modify the proguard-rules.pro file, which should live under your standard Android app directory:

-assumenosideeffects class android.util.Log {
  public static *** v(...);
  public static *** d(...);
  public static *** i(...);
  public static *** w(...);
  public static *** e(...);
}

I hope this answer helps you.

Upvotes: 1

Related Questions