mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-06 11:48:24 +00:00
refactor: drop the redundant WorkManager keep, record which reflection is removable
Reviewed every entry in the reflection contract for whether the reflection
itself could go away rather than be kept and verified. Verdicts are now in the
contract header, next to the entries they judge. One was actionable now.
**Deleted: our WorkManager rule.** androidx.work already ships
`-keepnames class * extends androidx.work.ListenableWorker` plus a
keepclassmembers for the public constructors, so
`-keep class * extends androidx.work.ListenableWorker { <init>(...); }` was pure
duplication. Removed and rebuilt: 31/31 contract checks still pass, because the
library's rule keeps the three workers. The entries stay listed so that if
androidx ever drops those rules the release fails here rather than on a phone —
which is the contract earning its keep in the other direction: it is what made
deleting a rule safe instead of a guess.
The rest, for the record:
- JNI class/method names are irreducible (`Java_<class>_<method>` is compiled
into libarti_android.so) and cost nothing anyway — AGP's default
`native <methods>` rule covers them.
- The Cast OptionsProvider is irreducible; Play Services reads the class name
from a manifest <meta-data> value.
- The Rust -> Kotlin log callback could go by inverting the flow (Kotlin polls a
native queue instead of Rust pushing via GetMethodID), which is a threading
change for one interface with one method.
- The two Jackson package keeps (~1,600 seeded members) are removable *and the
replacement already exists*: hand-written KSerializers in commonMain cover
exactly the NWC and CLINK types, are the production path on iOS, and are
cross-checked against Jackson by ClinkKotlinSerializationTest and
KotlinSerializationMapperTest. Only jvmAndroid routes these through Jackson's
reflective binding.
- The on-disk store DTOs are plain data classes; @Serializable would give them
compile-time literal names, and the files are app-private so nothing interops.
- The enum rule can go with no migration at all: give each persisted enum an
explicit `val code: String`, set the codes equal to today's constant names,
and every stored DataStore value keeps working while the literal becomes
untouchable by R8. That removes the last blanket rule, which today blocks
enum unboxing across all 707 enums in the app.
Those four are wire-format and persistence changes, so they are written down
rather than made here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEoxktEZyTrAS33vVZBiwm
This commit is contained in:
Vendored
+8
-4
@@ -187,10 +187,14 @@
|
||||
# this one out of the manifest and Class.forName()s it.
|
||||
-keep class com.vitorpamplona.amethyst.service.cast.chromecast.AmethystCastOptionsProvider { *; }
|
||||
|
||||
# WorkManager stores the worker's class name in its own database at enqueue
|
||||
# time and instantiates it by name on a later process start — including after
|
||||
# an app update, when R8 has produced a different mapping.
|
||||
-keep class * extends androidx.work.ListenableWorker { <init>(...); }
|
||||
# NOT a rule for WorkManager. It stores the worker's class name in its own
|
||||
# database at enqueue time and instantiates it by name on a later process start
|
||||
# — including after an app update that reshuffled the mapping — so the name does
|
||||
# have to survive. But androidx.work already ships exactly that in its own
|
||||
# consumer rules (`-keepnames class * extends androidx.work.ListenableWorker`
|
||||
# plus a keepclassmembers for the public constructors), so a rule here was pure
|
||||
# duplication. The three workers stay listed in the reflection contract, which
|
||||
# now verifies the LIBRARY's rule keeps doing the job.
|
||||
|
||||
# androidx.appfunctions: the KSP-generated invokers and the app_functions.xml
|
||||
# the system reads are keyed off these declarations. One class plus its
|
||||
|
||||
@@ -13,6 +13,46 @@
|
||||
# Adding reflection? Add the keep rule in amethyst/proguard-rules.pro AND a line
|
||||
# here. A rule with no line here is unverified; a line here with no rule fails.
|
||||
#
|
||||
# CAN THE REFLECTION ITSELF BE REMOVED?
|
||||
# Reviewed entry by entry. A keep rule you do not need is better than one you
|
||||
# verify, so the standing answer per mechanism:
|
||||
#
|
||||
# JNI class+method names IRREDUCIBLE. `Java_<class>_<method>` is
|
||||
# compiled into libarti_android.so. Costs us
|
||||
# nothing anyway — AGP's default
|
||||
# `native <methods>` rule covers it.
|
||||
# Rust -> Kotlin callback Removable only by inverting the flow (Kotlin
|
||||
# polls a native queue instead of Rust pushing
|
||||
# by GetMethodID). One interface, one method —
|
||||
# not obviously worth the threading change.
|
||||
# Cast OptionsProvider IRREDUCIBLE. Play Services reads the class
|
||||
# name out of a manifest <meta-data> value and
|
||||
# Class.forName()s it. Google's API, not ours.
|
||||
# WorkManager workers ALREADY GONE. androidx.work ships the keep
|
||||
# itself; our duplicate rule was deleted and
|
||||
# these entries now verify the library's.
|
||||
# Jackson NWC + CLINK REMOVABLE, and the replacement already
|
||||
# exists: hand-written KSerializers in
|
||||
# commonMain cover exactly these types, are the
|
||||
# production path on iOS, and are cross-checked
|
||||
# against Jackson by ClinkKotlinSerializationTest
|
||||
# and KotlinSerializationMapperTest. Routing
|
||||
# jvmAndroid's fromJsonTo at
|
||||
# KotlinSerializationMapper would delete both
|
||||
# package keeps (~1,600 seeded members).
|
||||
# Jackson on-disk stores REMOVABLE. Plain data classes; @Serializable
|
||||
# + kotlinx gives compile-time literal names.
|
||||
# App-private files, so no interop risk.
|
||||
# Enum constants REMOVABLE WITH NO MIGRATION. Give each
|
||||
# persisted enum an explicit `val code: String`
|
||||
# and store that instead of `.name`. Set the
|
||||
# codes equal to today's constant names and
|
||||
# every existing DataStore value keeps working,
|
||||
# while the literal is untouchable by R8. That
|
||||
# deletes the one blanket rule left
|
||||
# (`-keepclassmembers enum *`), which today
|
||||
# blocks enum unboxing across all 707 enums.
|
||||
#
|
||||
# Format — one per line, `#` comments to end of line:
|
||||
# class <fqn> class must keep its exact name
|
||||
# method <fqn> <name>... those methods must keep their names
|
||||
@@ -25,6 +65,9 @@ class com.vitorpamplona.amethyst.ui.tor.ArtiNative
|
||||
method com.vitorpamplona.amethyst.ui.tor.ArtiLogCallback onLogLine
|
||||
|
||||
# --- Named from outside the DEX ----------------------------------------------
|
||||
# No keep rule of ours backs the three workers below: androidx.work's own
|
||||
# consumer rules do. They stay listed so that if the library ever drops them,
|
||||
# the release fails here instead of on a user's phone.
|
||||
# <meta-data android:value> in the play manifest; the Cast framework
|
||||
# Class.forName()s it. AGP generates keeps for component android:name, not for
|
||||
# meta-data values, so nothing but an explicit rule protects this one.
|
||||
|
||||
Reference in New Issue
Block a user