From 2f4c67a5c8172c6c02de6ab6f62d10aecf62ad81 Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Wed, 5 Aug 2026 21:11:38 +0200 Subject: [PATCH] Keep what saved instance state is restored through Restoring the manager after its process had been reaped crashed, which is #871 -- and #834 before it, on Android 13. Two rules are missing, and the second one only became visible once the first was in place. R8 shrank values() out of 105 of the 106 enums in the released manager, because nothing calls it any more: Kotlin compiles `entries` to a separate synthetic field, so the generated method is left without a call site. Enum.valueOf looks that method up by name, so an enum written into a Bundle -- Parcel has no enum case and java.lang.Enum is Serializable, so it goes out as VAL_SERIALIZABLE -- cannot be read back. The navigation suite scaffold state is one such enum, and it sits at the root of every screen. CREATOR is found the same way, by a reflective field lookup R8 cannot see, and it was gone from every Parcelable the manager did not already keep by name. A `mutableStateOf` that survives process death is a ParcelableSnapshotMutableState, so with the enums fixed the same restore threw BadParcelableException instead. Both stanzas are AGP's, from proguard-android-optimize.txt. That file stopped being passed to proguardFiles in #263, five years ago; the legacy manager had copied CREATOR back by hand, the rewrite in #796 did not, and it declared no enums at all, so neither rule was missed until the Compose manager needed them. Verified on a Pixel 6 (Android 17) and a Galaxy A52s (Android 14): open the manager, background it, kill the host process so the icicle comes back through a Parcel, reopen. Before, that crashed every time; after, state restores across repeated cycles, including the Logs tab and an open bottom sheet. --- manager/proguard-rules.pro | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/manager/proguard-rules.pro b/manager/proguard-rules.pro index 469d8bc2c..d56c113ca 100644 --- a/manager/proguard-rules.pro +++ b/manager/proguard-rules.pro @@ -23,6 +23,29 @@ # Gson models are constructed reflectively from field names. -keepclassmembers class org.matrix.vector.manager.data.model.** { ; } +# An enum's constants are reached reflectively: Enum.valueOf asks the class for its values() +# method by name. Kotlin no longer calls that method itself — `entries` compiles to its own +# synthetic field — so the last call site is usually gone and R8 shrinks values() away, which +# leaves every enum in the APK undeserializable. Compose saved instance state is what reaches it +# here: Parcel has no enum case and java.lang.Enum is Serializable, so a saved enum is written +# as VAL_SERIALIZABLE, and restoring the activity after its process died threw +# NoSuchMethodException on the navigation suite's own state value (#871). AGP's +# proguard-android-optimize.txt carries this stanza, but that file has not been on the +# proguardFiles list since #263, so it has to be written out here. +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +# The same restore path reaches Parcelables, and finds their CREATOR by a reflective field lookup +# that R8 cannot see either, so it drops the field from every class that does not otherwise +# reference it. Compose keeps its own state in one: a `mutableStateOf` that survives process death +# is a ParcelableSnapshotMutableState, and reading it back threw BadParcelableException. The legacy +# manager carried this rule by hand; the rewrite in #796 did not bring it across. +-keepclassmembers class * implements android.os.Parcelable { + public static final ** CREATOR; +} + # OkHttp / Okio ship analysis-only references to optional platform classes. -dontwarn okhttp3.internal.** -dontwarn org.conscrypt.**