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

问题描述

我使用的是 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

发布版本创建后,这里是一个示例堆栈跟踪 - 第一行显示它混淆了类名(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$1.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)

请注意,类名正确地被去混淆了(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”),类名被混淆,但行号保持不变:

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)

在“发布”版本的堆栈跟踪上运行回溯后,为什么我无法取回原始行号?为什么在“调试”版本中没有混淆行号?

解决方法

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

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

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

一旦 Gradle 5 发布,上述解决方案将不再适用。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...