R8 retrace というツールを使うことで難読化されたスタックトレースを戻すことができる:
入手
command-line tools として SDK に含まれているのでそれが使えると便利。僕の環境だとここにあります:
~/Library/Android/sdk/cmdline-tools/latest/bin/retrace
or スタンドアローンで適当なバージョンのものを DL して使うことができるという具合です:
wget https://storage.googleapis.com/r8-releases/raw/8.1.50/r8retrace.jar
使い方
実行するコマンドはこういう具合です:
retrace mapping.txt <stacktrace-file>
or DL した jar を使う場合はこういうかんじ:
java -cp r8retrace.jar com.android.tools.r8.retrace.Retrace mapping.txt <stacktrace-file>
<stacktrace-file>
はスタックトレースをコピーするなりして適当なファイルにまとめておきます。指定しない場合は標準入力でスタックトレースを入力することもできます。
mapping.txt
は対象の build variant のビルドで出力されたものを指定する必要があります:
app/build/outputs/mapping/<yourapp>/mapping.txt
たとえばこういうスタックトレースがあるとしたら:
FATAL EXCEPTION: main
Process: io.github.manganoito.myapp20250203, PID: 10207
java.lang.IllegalStateException: test error
at a.a.b(SourceFile:81)
at G0.a.c(SourceFile:53)
at z.a.a(SourceFile:44)
at z.a.c(SourceFile:9)
at q.l.g(SourceFile:220)
at z.a.g(SourceFile:52)
at U.i1.g(SourceFile:125)
at z.a.g(SourceFile:52)
at s.d.w(SourceFile:15)
at s.o.k(SourceFile:197)
at s.s.i(SourceFile:33)
at s.n0.a(SourceFile:45)
at s.n.a(SourceFile:5)
at s.s.j(SourceFile:7)
at R.p.h(SourceFile:22)
at R.p.g(SourceFile:120)
at R.k.d(SourceFile:184)
at q.o.g(SourceFile:881)
at R.m.a(SourceFile:72)
at T.q.e(SourceFile:42)
at B.t.f(SourceFile:277)
at a.a.H(SourceFile:60)
at B.r.a(SourceFile:48)
at T.b0.a(SourceFile:145)
at T.G.N(SourceFile:126)
at T.G.e(SourceFile:92)
at m.e.a(SourceFile:56)
at T.q.e(SourceFile:42)
at I.u.v(SourceFile:1)
at T.v.e(SourceFile:11)
at I.u.v(SourceFile:1)
at T.v.e(SourceFile:11)
at m.i.v(SourceFile:117)
at T.v.e(SourceFile:11)
at B.t.f(SourceFile:277)
at a.a.H(SourceFile:60)
at B.r.a(SourceFile:48)
at T.b0.a(SourceFile:145)
at T.G.N(SourceFile:126)
at T.G.e(SourceFile:92)
at R.B.a(SourceFile:39)
at T.q.e(SourceFile:42)
at B.t.f(SourceFile:277)
at a.a.H(SourceFile:118)
at B.r.a(SourceFile:48)
at T.b0.a(SourceFile:145)
at T.G.N(SourceFile:126)
at T.N.c(SourceFile:17)
at T.N.l(SourceFile:18)
at T.N.i(SourceFile:62)
at U.u.onMeasure(SourceFile:84)
at android.view.View.measure(View.java:26496)
at U.a.onMeasure(SourceFile:67)
at android.view.View.measure(View.java:26496)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:26496)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1608)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:878)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:26496)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:760)
at android.view.View.measure(View.java:26496)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:4042)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:2658)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2964)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2371)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9297)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1231)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
at android.view.Choreographer.doCallbacks(Choreographer.java:899)
at android.view.Choreographer.doFrame(Choreographer.java:832)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7924)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
出力はこうなります:
~/Library/Android/sdk/cmdline-tools/latest/bin/retrace app/build/outputs/mapping/release/mapping.txt trace.log
FATAL EXCEPTION: main
Process: io.github.manganoito.myapp20250203, PID: 10207
java.lang.IllegalStateException: test error
at io.github.manganoito.myapp20250203.MainActivityKt.Greeting(MainActivity.kt:35)
at io.github.manganoito.myapp20250203.ComposableSingletons$MainActivityKt$lambda-1$1.invoke(MainActivity.kt:23)
at io.github.manganoito.myapp20250203.ComposableSingletons$MainActivityKt$lambda-1$1.invoke(MainActivity.kt:22)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:118)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayoutWithMeasureFix$1$1$bodyContentPlaceables$1.invoke(Scaffold.kt:303)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayoutWithMeasureFix$1$1$bodyContentPlaceables$1.invoke(Scaffold.kt:285)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$3$1$1.invoke(LayoutNodeSubcompositionsState.java:991)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$3$1$1.invoke(LayoutNodeSubcompositionsState.java:477)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm_jvm.kt:97)
at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3593)
at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3520)
at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:743)
at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:1122)
at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:3874)
at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:649)
at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:635)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcomposeInto(SubcomposeLayout.kt:500)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:472)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:463)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:447)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$Scope.subcompose(SubcomposeLayout.kt:872)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayoutWithMeasureFix$1$1.invoke-0kLqBqw(Scaffold.kt:285)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayoutWithMeasureFix$1$1.invoke(Scaffold.kt:179)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:709)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.java:252)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.java:251)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.java:503)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:502)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:258)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
at androidx.compose.foundation.layout.BoxMeasurePolicy.measure-3p2s80s(Box.kt:122)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:646)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:646)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
at androidx.compose.foundation.layout.FillNode.measure-3p2s80s(Size.kt:699)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.java:252)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.java:251)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.java:503)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:502)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:258)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
at androidx.compose.ui.layout.RootMeasurePolicy.measure-3p2s80s(RootMeasurePolicy.kt:38)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.java:252)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.java:251)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.java:2441)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:502)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:258)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.kt:1145)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:354)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureOnly(MeasureAndLayoutDelegate.kt:562)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureOnly(MeasureAndLayoutDelegate.kt:407)
at androidx.compose.ui.platform.AndroidComposeView.onMeasure(AndroidComposeView.android.kt:1058)
at android.view.View.measure(View.java:26496)
at androidx.compose.ui.platform.AbstractComposeView.internalOnMeasure$ui_release(ComposeView.android.kt:302)
at androidx.compose.ui.platform.AbstractComposeView.onMeasure(ComposeView.android.kt:289)
at android.view.View.measure(View.java:26496)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:26496)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1608)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:878)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:26496)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:760)
at android.view.View.measure(View.java:26496)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:4042)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:2658)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2964)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2371)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9297)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1231)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
at android.view.Choreographer.doCallbacks(Choreographer.java:899)
at android.view.Choreographer.doFrame(Choreographer.java:832)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7924)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
期待通りというかんじで以上です。ちなみに標準入力経由の場合は入力後 (Mac) Control + D / (Win/Linux) Control + Z + Enter で出力できます。
経緯
https://issuetracker.google.com/issues/284177365#comment19 をみていて、恥ずかしながらこれで初めて知った次第です。