如何在 R8 混淆后使用 retrace 获得正确的行号?

How can I get correct line numbers using retrace after R8 obfuscation?

我正在使用 Android Studio 4.1.3 及其各种捆绑工具(AGP 4.1.3、Gradle 6.5、Android SDK 构建工具 31-rc2、平台工具 31.0 .1,SDK 工具 26.1.1)。我正在使用默认的 R8 工具。

我正在像这样混淆发布版本:

release {
   // Enables code shrinking, obfuscation, and optimization for only
   // your project's release build type.
   minifyEnabled true

   // Enables resource shrinking, which is performed by the
   // Android Gradle plugin.
   shrinkResources false

   // Includes the default ProGuard rules files that are packaged with
   // the Android Gradle plugin. To learn more, go to the section about
   // R8 configuration files.
   proguardFiles getDefaultProguardFile(
           'proguard-android.txt'),
           'proguard-rules.pro'
}

我的 Proguard-rules.pro 文件顶部有这个:

# hide the original source file name.
-renamesourcefileattribute SourceFile

-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod

发布版本创建后,这里是一个堆栈跟踪示例 - 第一行显示它混淆了 class 名称 (SplashActivity$a),将源重命名为 'SourceFile',并且混淆了行号(2):

at com.reddragon.intouch.ui.SplashActivity$a.onStart(SourceFile:2)
at io.reactivex.rxjava3.observers.DisposableObserver.onSubscribe(SourceFile:2)
at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.onSubscribe(SourceFile:15)
at io.reactivex.rxjava3.internal.operators.observable.ObservableSubscribeOn.subscribeActual(SourceFile:2)
at io.reactivex.rxjava3.core.Observable.subscribe(SourceFile:12)
at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn.subscribeActual(SourceFile:4)
at io.reactivex.rxjava3.core.Observable.subscribe(SourceFile:12)
at io.reactivex.rxjava3.core.Observable.subscribeWith(SourceFile:1)
at com.reddragon.intouch.ui.SplashActivity.onCreate(SourceFile:16)
at android.app.Activity.performCreate(Activity.java:7183)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

将 retrace.bat 工具(位于 ~\SDK\tools\proguard\bin 中)与发布版本中的相应 mappings.txt 文件一起使用,针对该堆栈跟踪结果产生以下输出:

at com.reddragon.intouch.ui.SplashActivity.void onStart()(SourceFile:2)
at io.reactivex.rxjava3.observers.DisposableObserver.void onSubscribe(io.reactivex.rxjava3.disposables.Disposable)(SourceFile:2)
at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.void onSubscribe(io.reactivex.rxjava3.disposables.Disposable)(SourceFile:15)
at io.reactivex.rxjava3.internal.operators.observable.ObservableSubscribeOn.void subscribeActual(io.reactivex.rxjava3.core.Observer)(SourceFile:2)
at io.reactivex.rxjava3.core.Observable.void subscribe(io.reactivex.rxjava3.core.Observer)(SourceFile:12)
at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn.void subscribeActual(io.reactivex.rxjava3.core.Observer)(SourceFile:4)
at io.reactivex.rxjava3.core.Observable.void subscribe(io.reactivex.rxjava3.core.Observer)(SourceFile:12)
at io.reactivex.rxjava3.core.Observable.io.reactivex.rxjava3.core.Observer subscribeWith(io.reactivex.rxjava3.core.Observer)(SourceFile:1)
at com.reddragon.intouch.ui.SplashActivity.void onCreate(android.os.Bundle)(SourceFile:16)
at android.app.Activity.performCreate(Activity.java:7183)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

请注意,class 名称已正确去混淆(SplashActivity$a 变成了 SplashActivity$1),但行号没有去混淆(它仍然显示第 2 行是错误的)。有趣的是,如果我将此部分包含在 build.gradle:

debug {
  debuggable true
  minifyEnabled true

  // Enables resource shrinking, which is performed by the
  // Android Gradle plugin.
  shrinkResources false

  // Includes the default ProGuard rules files that are packaged with
  // the Android Gradle plugin. To learn more, go to the section about
  // R8 configuration files.
  proguardFiles getDefaultProguardFile(
          'proguard-android.txt'),
          'proguard-rules.pro'
}

对于调试版本,堆栈跟踪输出隐藏了文件名(显示为 'SourceFile'),class 名称被混淆,但行号保持不变:

at com.reddragon.intouch.ui.SplashActivity$a.onStart(SourceFile:313)
at io.reactivex.rxjava3.observers.DisposableObserver.onSubscribe(SourceFile:74)
at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.onSubscribe(SourceFile:106)
at io.reactivex.rxjava3.internal.operators.observable.ObservableSubscribeOn.subscribeActual(SourceFile:34)
at io.reactivex.rxjava3.core.Observable.subscribe(SourceFile:13095)
at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn.subscribeActual(SourceFile:45)
at io.reactivex.rxjava3.core.Observable.subscribe(SourceFile:13095)
at io.reactivex.rxjava3.core.Observable.subscribeWith(SourceFile:13148)
at com.reddragon.intouch.ui.SplashActivity.onCreate(SourceFile:309)
at android.app.Activity.performCreate(Activity.java:7183)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

为什么在 运行 从 'release' 构建的堆栈跟踪上回溯后我无法取回原始行号?为什么行号在 'debug' 构建中没有被混淆?

我也遇到过类似的问题。尽管 Google 在 https://developer.android.com/studio/build/shrink-code#decode-stack-trace

中声称,R8 似乎并不尊重 -keepattributes LineNumberTable,SourceFile

我最终通过在 gradle.properties 中设置 android.enableR8=false 而使用 ProGuard。

上述解决方案在 Gradle 5 发布后将无法使用。