Status Update
Comments
jh...@gmail.com <jh...@gmail.com>
jh...@gmail.com <jh...@gmail.com> #2
Update: Actually, removing resourceConfigurations += "en"
doesn't help with our real project, so the only option we currently have is to disable resource shrinking completely.
ch...@google.com <ch...@google.com>
na...@vitruvian.me <na...@vitruvian.me> #3
I'm not the original poster but this issue started for us yesterday also (testing locally in a release build the second we added a string the resource Id's would be shifted around).
I tested this morning after re-syncing gradle (after toggling shrinking back on) just to see if anything changed and I haven't been able to reproduce it again yet. Would anything have changed in any google dependencies or am I just somehow avoiding the issue temporarily?
Happy to share any information needed to help troubleshooting.
ri...@google.com <ri...@google.com> #4
Thank you so much for sharing the reproduction project, but unfortunately I can't repro the issue.
Some clarifying questions:
Does this repro if you simply do ./gradlew assembleProfiling
or is this only happening in studio?
+gavra: with the module as described here would we ever change the package id?
ri...@google.com <ri...@google.com> #5
Also, could you zip up the whole project, including build artifacts, for a compilation where the apk is in a bad state, that way we can disassemble both the code and the resource table to see what is wrong?
jh...@gmail.com <jh...@gmail.com> #6
That's a very good question - it seems I can't reproduce the issue using ./gradlew assembleProfiling
, but I'm reliably able to reproduce it by running the app from Android Studio (I'm using the run config that AS generates by default).
jh...@gmail.com <jh...@gmail.com> #7
Sure, here's the same project with build artifacts generated by AS after running the app directly from AS (and never using the Gradle wrapper manually). 🙏
ri...@google.com <ri...@google.com> #8
There is certainly something strange here:
void com.example.MainActivity.onCreate(android.os.Bundle)
registers: 3, inputs: 2, outputs: 2
------------------------------------------------------------
inst# offset instruction arguments
------------------------------------------------------------
0: 0x00: InvokeSuper { v1 v2 } Landroidx/fragment/app/h;onCreate(Landroid/os/Bundle;)V
1: 0x03: Const v2, 0x7f0b001d (2131427357)
2: 0x06: InvokeVirtual { v1 v2 } Ld/l;setContentView(I)V
3: 0x09: InvokeVirtual { v1 } Ld/l;getResources()Landroid/content/res/Resources;
4: 0x0c: MoveResultObject v2
5: 0x0d: Const v0, 0x7f0d0028 (2131558440) <--------- The resource id
6: 0x10: InvokeVirtual { v2 v0 } Landroid/content/res/Resources;getString(I)Ljava/lang/String;
7: 0x13: MoveResultObject v2
8: 0x14: ConstString v0, "getString(...)"
And from the resource table:
$ ~/src/r8/third_party/aapt2/aapt2 dump resources ./google_report/sample/app/main/build/intermediates/apk/profiling/main-profiling.apk | grep -A 10 sample_string
resource 0x7f0d0024 string/sample_string_resource_broken
() "This string should be loaded from resources"
resource 0x7f0d0025 string/search_menu_title
() "Search"
resource 0x7f0d0026 string/status_bar_notification_info_overflow
() "999+"
type style id=0e entryCount=350
resource 0x7f0e0000 style/AlertDialog.AppCompat
() (style) size=0 parent=style/Base.AlertDialog.AppCompat (0x7f0e0005)
resource 0x7f0e0001 style/AlertDialog.AppCompat.Light
() (style) size=0 parent=style/Base.AlertDialog.AppCompat.Light (0x7f0e0006)
So the last string is 0x7f0d0026 and we are looking up 0x7f0d0028 - and what we actually should be looking up is 0x7f0d0024
ri...@google.com <ri...@google.com> #9
and in the generated resources that we use for the app (Ivan correct me if I am wrong here) I see the same:
$ ~/src/r8/third_party/aapt2/aapt2 dump resources ./sample/app/main/build/intermediates/linked_res_for_bundle/profiling/bundled-res.ap_ | grep sample
resource 0x7f0d0024 string/sample_string_resource_broken
but in the input jar that we would compile I see:
$ disasm.py --no-build --all ./sample/app/main/build/intermediates/compile_and_runtime_not_namespaced_r_class_jar/profiling/R.jar | grep -C 2 sample_string
#
public static int com.example.resshrinker.R$string.app_name = Int 2131558428
public static int com.example.resshrinker.R$string.sample_string_resource_broken = Int 2131558440
#
$ python3 -c "print(hex(2131558440))"
0x7f0d0028
ri...@google.com <ri...@google.com> #10
Over to Ivan: do you agree that this seems like a broken dependency setup somewhere? alternatively, it would be the resource shrinker in the bundle pipeline that was mangling the resources. Where do I see the originally assigned ids?
ga...@google.com <ga...@google.com>
ga...@google.com <ga...@google.com> #11
This issue is caused by usage of stable IDs (automatically injected by the IDE as -Pandroid.injected.enableStableIds=true
), but the root cause is that 2 tasks are not configured in the same way:
LinkAndroidResForBundleTask
does not take the stable ids as input - produces proto output used by the resource shrinkerLinkApplicationAndroidResourcesTask
does take the stable ids as input - produces *.ap_ and resource IDs used by R8
This results in different IDs assigned by these 2 tasks (I was flip-flopping between string names aaaa
and zzzz
):
~/Android/Sdk/build-tools/33.0.2/aapt2 dump resources ~/Downloads/google_report/sample/app/main/build/intermediates/linked_res_for_bundle/profiling/bundled-res.ap_ | grep zzzzz
resource 0x7f0d0026 string/zzzzz
~/Android/Sdk/build-tools/33.0.2/aapt2 dump resources
~/Downloads/google_report/sample/app/main/build/intermediates/processed_res/profiling/out/resources-profiling.ap_ | grep zzzzz
resource 0x7f0d0027 string/zzzzz
It also means that 0x7f0d0026
is used as input for resource shrinking, but 0x7f0d0027
is used as resource id that gets inlined by R8 (as it is never modified).
Workaround
When using resource shrinking, build from the command line and use AGP to deploy the APK. Disabling android.injected.enableStableIds
in gradle.properties
is not possible at the moment as IDE-injected property wins.
Description
When certain build features are used together, the resource shrinker mangles resource IDs. Resource ID integers in the resulting binary are wrong, which at runtime leads either to
The behavior is not totally deterministic - some builds are fine, but sometimes, renaming the XML resource is enough (!) to get the crash. Sometimes, a clean build, AS restart, or invalidate caches & restart command fixes things, but only temporarily, until the next rename.
To reproduce, please run the attached project, distilled from a real-world project:
R.string.sample_string_resource
resource to anything else, and try again.android.content.res.Resources$NotFoundException: String resource ID #0x7f0d0027
(full stack trace below).The issue can be mitigated by not using certain build features. Each one of the following fixes the problem independently:
isShrinkResources = false
.resourceConfigurations += "en"
.settings.gradle.kts
andbuild.gradle.kts
).Notes:
Thanks, and let me know if I can help further. 🙏
Full stack trace:
System info: