From d8b7f3f1de7094b6f38caf0e2bd4f307ea8bd86d Mon Sep 17 00:00:00 2001 From: David Schachter Date: Fri, 31 Jul 2026 17:14:08 -0700 Subject: [PATCH 1/2] ADFA-3604: Fix Gson model classes stripped by R8 (6th shrink bug) Found via a "Failed to load template archive ... Abstract classes can't be instantiated!" error on-device. Same root cause as the other shrink bugs fixed in this branch: Gson deserializes these classes only via reflection (gson.fromJson(..., X::class.java)), never a direct `new` R8 can trace, so it strips the constructor and Gson's runtime then reports the class as abstract. Fixes templates-impl's TemplatesIndex/TemplateJson/etc., and two more instances found by auditing every gson.fromJson call site in the repo: OpenedFilesCache/OpenedFile (no prior rule at all) and the breakpoint persistence models. Verified on-device: templates load cleanly, zero FATAL EXCEPTION in logcat, Kotlin project init still succeeds. Co-Authored-By: Claude Sonnet 5 --- app/proguard-rules.pro | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index e00a2a82ca..c758cfbc4d 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -112,10 +112,12 @@ } -keep class com.itsaky.androidide.utils.DialogUtils { public ; } -# APK Metadata --keep class com.itsaky.androidide.models.ApkMetadata { *; } --keep class com.itsaky.androidide.models.ArtifactType { *; } --keep class com.itsaky.androidide.models.MetadataElement { *; } +# Gson model classes deserialized only via reflection (gson.fromJson(..., +# X::class.java)), same "R8 strips the unreachable constructor" issue as +# templates.impl.zip above. Covers OpenedFilesCache/OpenedFile (no prior +# rule) as well as the APK metadata classes already listed individually. +-keep class com.itsaky.androidide.models.** { *; } +-keep class com.itsaky.androidide.lsp.debug.model.** { *; } # Parcelable -keepclassmembers class * implements android.os.Parcelable { @@ -164,6 +166,13 @@ -keep class * implements com.google.gson.JsonSerializer -keep class * implements com.google.gson.JsonDeserializer +# Gson model classes: nothing calls `new TemplatesIndex(...)` directly -- +# only gson.fromJson(..., TemplatesIndex::class.java) does, via reflection. +# With no traceable constructor call, R8 strips the constructor and Gson's +# runtime then reports the class as abstract ("Failed to load template +# archive ... Abstract classes can't be instantiated!"). +-keep class com.itsaky.androidide.templates.impl.zip.** { *; } + -keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName ; } From 74e27524a2358f5e77cc25a5c1a7d7a91a71bd2a Mon Sep 17 00:00:00 2001 From: David Schachter Date: Fri, 31 Jul 2026 17:31:13 -0700 Subject: [PATCH 2/2] ADFA-3604: Fix JDI debugger connector stripped by R8 (7th shrink bug) Found via a "Network access error" dialog on-device -- misleading, since the app's debug-connect failure handler always appends a network-access suggestion regardless of actual cause. The real error was buried in logcat: "java.lang.Error: no Connectors loaded" from com.sun.tools.jdi.VirtualMachineManagerImpl, caused by a ServiceConfigurationError failing to instantiate SocketAttachingConnector/SocketListeningConnector. Same root cause as the other shrink bugs: JDI loads these via ServiceLoader, which R8 can't trace, so it stripped their no-arg constructors. This exact fix was already anticipated and left commented out in this file ("Initial rules to enable when R8 is shrinking to address exceptions") from before shrinking was ever genuinely enabled -- just needed uncommenting now that it is. Verified on-device: JDWP listener starts successfully, no dialog, zero FATAL EXCEPTION in logcat. Co-Authored-By: Claude Sonnet 5 --- app/proguard-rules.pro | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index c758cfbc4d..ac7714569f 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -206,9 +206,18 @@ -keep class com.itsaky.androidide.plugins.** { *; } -keep interface com.itsaky.androidide.plugins.** { *; } -## Initial rules to enable when R8 is shrinking to address exceptions -#-keep class com.sun.tools.jdi.** { *; } -#-keep class com.sun.jdi.** { *; } +## ADFA-3604: JDI's SocketAttachingConnector/SocketListeningConnector are +## loaded via ServiceLoader (META-INF/services), which R8 can't trace, so it +## stripped their no-arg constructors. This surfaced as +## "ServiceConfigurationError: Provider ... could not be instantiated" -> +## "java.lang.Error: no Connectors loaded" from VirtualMachineManagerImpl, +## which the app then reports to the user as a generic "Network access +## error" (the debug-connect failure handler always appends a network +## suggestion regardless of cause) even though this has nothing to do with +## network permissions. This is exactly the exceptions these rules were +## anticipating -- enabling them now that shrinking is genuinely on. +-keep class com.sun.tools.jdi.** { *; } +-keep class com.sun.jdi.** { *; } ## R8 Kotlin metadata workaround for Kotlin 2.3.0 compatibility ## Suppresses D8 errors when parsing kotlin metadata for StopWatch inline functions