Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to prevent Android app code shrinker R8 from changing line numbers?

Android Studio started to use R8 instead of ProGuard by default recently.

The stack traces from ProGuard are fairly easy to understand without using any tools despite code is obfuscated. Let's use the following example:

 java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Boolean.booleanValue()' on a null object reference
    at net.foo.anroid.Foo.wb.d(SourceFile:453)
    at net.foo.anroid.Foo.wb.a(SourceFile:213)
    at net.foo.anroid.Foo.wb.n(SourceFile:103)
    at net.foo.anroid.Foo.qa.run(Unknown Source:2)
    at java.lang.Thread.run(Thread.java:764)

Usually I know exactly to which file net.foo.anroid.Foo.wb corresponds, and the line numbers (e.g. 453, 213...) are the actual lines numbers in the source file for ProGuard.

However, for R8, the only way to figure out which line is which is looking them up in mapping.txt.

This is really a significant nuisance. If there is no good way to locate the source code quickly from a stack trace, I will go back to ProGuard for this reason alone.

Is there a way to prevent R8 from changing line numbers?

like image 298
Hong Avatar asked May 07 '19 21:05

Hong


People also ask

How do you obfuscate codes on Android?

You can use the Android ProGuard tool to obfuscate, shrink, and optimize your code. Obfuscated code can be more difficult for other people to reverse engineer. ProGuard renames classes, fields, and methods with semantically obscure names and removes unused code.

Should I use R8 or ProGuard?

R8 gives better output results than Proguard. R8 reduces the app size by 10 % whereas Proguard reduces app size by 8.5 %. The android app having a Gradle plugin above 3.4. 0 or above then the project uses R8 by default with Proguard rules only.


2 Answers

This has been discussed from time to time on the R8 team, and we went with always optimizing line numbers for a number of reasons:

  • It saved in the area of 5% on the dex size
  • For release builds where optimizations like inlining are turned on retracing is needed anyway to expand the inlined frames
  • It is one less option in the testing matrix

Right now it is always turned off for debug builds, and for release builds when both -dontoptimize (implies no inlining) and -dontobfuscate are set in the configuration.

When you use retrace (remember to use the one from Proguard version 6 or later) you don't need to cut out the stacktrace, as retrace will pass non stack trace lines through unmodified.

There is currently no library to do this in the app, and as that requires the mapping file to be included in the app that defeats the purpose of making apks small.

like image 127
sgjesse Avatar answered Oct 08 '22 13:10

sgjesse


Set these in the ProGuard configuration:

-keepattributes SourceFile,LineNumberTable

then use ReTrace jar:

ReTrace can read an obfuscated stack trace and restore it to what it would look like without obfuscation. The restoration is based on the mapping file that ProGuard can write out during obfuscation. The mapping file links the original class names and class member names to their obfuscated names.

java -jar retrace.jar [options...] mapping_file [stacktrace_file]

for example:

java -jar retrace.jar mapping.txt stacktrace.log
like image 37
Martin Zeitler Avatar answered Oct 08 '22 14:10

Martin Zeitler