Skip to content

Align native .so LOAD segments to 16 KB (blocks any targetSdk 35+ upload)#9

Open
xroche wants to merge 3 commits into
masterfrom
native-16kb-alignment
Open

Align native .so LOAD segments to 16 KB (blocks any targetSdk 35+ upload)#9
xroche wants to merge 3 commits into
masterfrom
native-16kb-alignment

Conversation

@xroche

@xroche xroche commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Every .so we ship links its LOAD segments at 4 KB, which Play rejects at targetSdk 35+. Play checks ZIP-entry alignment and ELF segment alignment separately, and the first already passed, so the problem was invisible to the checks we had.

The fix is one linker flag on the current NDK r26d. The release APK comes out the same size either way, because lld shifts vaddr rather than file offsets. The .so are not byte-identical, since p_align, the RW segment p_vaddr and the relocations tracking it all move, but nothing is padded or reordered. NDK r28 only makes 16 KB the default, so that bump stays separate.

The CI guard matters as much as the flag, since alignment regresses with no build error. It fails on a 4 KB build and passes on a 16 KB one, and it compares its walk against the archive listing so a partial enumeration cannot pass on a subset.

Known gaps, deliberately out of scope: the guard asserts ELF p_align only, while Play also wants ZIP-entry alignment and RELRO. ZIP alignment currently passes on AGP 8.6 defaults rather than on anything we set, so an AGP downgrade or a hand-set packaging option would produce an APK that Play rejects and this guard passes green. Nothing builds or checks an AAB either, and that is the artifact Play actually takes. None of it bites while targetSdk is 25, but all of it wants a tracker note before we upload.

xroche and others added 3 commits July 17, 2026 10:17
Play checks two things and we only satisfied one. ZIP-entry alignment
already passed (zipalign -P 16, extractNativeLibs=false), which is what
our notes recorded. ELF LOAD alignment did not: every shipped .so linked
at 4 KB, so an upload at targetSdk 35 would be rejected.

lld shifts vaddr rather than file offsets, so the .so bytes and the
release APK size are identical either way. NDK r28 makes 16 KB the
default, but it is not needed here and can stay a separate bump.

The CI guard is there because this regresses silently: nothing in a
normal build reports segment alignment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
Review found the guard could pass on a subset. find runs inside a process
substitution, where set -e cannot see its exit status and pipefail does not
reach, so a truncated walk checked whatever it got and still printed the
success banner. The old empty-list test only ever proved that at least one
.so turned up.

Comparing the walk against the archive's own listing asserts completeness
instead, and catches unzip under-extracting for free. Confirmed against a
find stub that emits one path and exits 1: the previous guard reported
"16 KB aligned: 1 .so" and exited 0, this one exits 1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
Review follow-ups, none of them blocking. The zero-.so APK, which is the
likelier regression here, died in the extraction step with unzip's own
"filename not matched" and rc 11 before any of our checks ran; it now says
what actually happened, and a genuinely unreadable archive is reported
separately rather than sharing that message.

find grows -type f so a directory named foo.so cannot reach readelf. That
also removes one of the two ways a count could agree over different sets,
the other needing a duplicate entry name that no Android build tool emits.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant