Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recover Jetpack Compose stacktraces #2070

Closed
romtsn opened this issue May 30, 2022 · 4 comments
Closed

Recover Jetpack Compose stacktraces #2070

romtsn opened this issue May 30, 2022 · 4 comments

Comments

@romtsn
Copy link
Member

romtsn commented May 30, 2022

Problem Statement

Since compose is a declarative UI framework, there's a big usage of lambdas, which get transformed into anonymous classes, therefore stackframes that contain compose code do not really look helpful (besides the file name and line numbers, it's hard to figure out what's going on). For example:

FATAL EXCEPTION: main
                 Process: com.google.samples.apps.nowinandroid.debug, PID: 2799
                 java.lang.RuntimeException: TEST
                 	at com.google.samples.apps.nowinandroid.feature.topic.TopicScreenKt$TopicRoute$1.invoke(TopicScreen.kt:71)
                 	at com.google.samples.apps.nowinandroid.feature.topic.TopicScreenKt$TopicRoute$1.invoke(TopicScreen.kt:66)
                 	at com.google.samples.apps.nowinandroid.core.ui.component.ChipKt$NiaFilterChip$1$1.invoke(Chip.kt:48)
                 	at com.google.samples.apps.nowinandroid.core.ui.component.ChipKt$NiaFilterChip$1$1.invoke(Chip.kt:48)
                 	at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$2.invoke-k-4lQ0M(Clickable.kt:153)
                 	at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$2.invoke(Clickable.kt:142)
                 	at androidx.compose.foundation.gestures.TapGestureDetectorKt$detectTapAndPress$2$1$1.invokeSuspend(TapGestureDetector.kt:220)
                 	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                 	at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:178)
                 	at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
                 	at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
                 	at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
                 	at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
                 	at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:328)
                 	at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter$PointerEventHandlerCoroutine.offerPointerEvent(SuspendingPointerInputFilter.kt:560)
                 	at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.dispatchPointerEvent(SuspendingPointerInputFilter.kt:452)
                 	at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.onPointerEvent-H0pRuoY(SuspendingPointerInputFilter.kt:465)
                 	at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:310)
                 	at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
                 	at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
                 	at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
                 	at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
                 	at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
                 	at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
                 	at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
                 	at androidx.compose.ui.input.pointer.NodeParent.dispatchMainEventPass(HitPathTracker.kt:179)
                 	at androidx.compose.ui.input.pointer.HitPathTracker.dispatchChanges(HitPathTracker.kt:98)
                 	at androidx.compose.ui.input.pointer.PointerInputEventProcessor.process-BIzXfog(PointerInputEventProcessor.kt:80)
                 	at androidx.compose.ui.platform.AndroidComposeView.sendMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1261)
                 	at androidx.compose.ui.platform.AndroidComposeView.handleMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1211)
                 	at androidx.compose.ui.platform.AndroidComposeView.dispatchTouchEvent(AndroidComposeView.android.kt:1150)
                 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3118)
                 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2799)
                 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3118)
                 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2799)
                 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3118)
                 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2799)
                 	at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3118)
                 	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2799)
                 	at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:488)
                 	at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1871)

It'd be nice if we can recover the stackframes and make them pretty by including the actual lambda argument names (in this example it'd be NiaFilterChip$onClick and TopicRoute$onFollowClick instead of NiaFilterChip$1$1 and TopicRoute$1 respectively).

Solution Brainstorm

Probably would require some logic on the bytecode level (either through SAGP or a jvm-agent) to collect the information about lambdas and add them to the proguard-mapping file so they get correctly interpreted on the product side (or maybe we'd require some new logic on the product side as well).

https://github.com/Guardsquare/kotlin-metadata-printer might be useful to read kotlin's metadata.

@marandaneto
Copy link
Contributor

@romtsn do you know if there's a way to trace back to the original stack trace frames? e.g. #1524 (comment)
I often see libs doing this (rewriting the frames), e.g. for coroutines and rxjava, the problem is kinda the same, I guess.

@romtsn
Copy link
Member Author

romtsn commented May 31, 2022

Yeah the problem is the usage of lambdas/anonymous classes for all of them I guess. I feel like this can be done through bytecode manipulation (e.g. getting the argument name for lambda), but not sure if there's a silver bullet for all.

@adinauer
Copy link
Member

We should check if there's a library for doing this. If we can find a workaround for the meantime we should add it to the troubleshooting page.

There's a flag in the coroutines library that makes it print more verbose stack traces. This could help.

@romtsn
Copy link
Member Author

romtsn commented Apr 7, 2023

We've decided it's not worth the effort, and it's not clear what should be the outcome. At the moment, linenos are still correct and show you exactly where the error has happened. When #633 is in place, this should help even more and show surrounding code.

@romtsn romtsn closed this as not planned Won't fix, can't repro, duplicate, stale Apr 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

No branches or pull requests

3 participants