fix(android): Force 16 KB ELF alignment for libsentry-tm-perf-logger.so#6396
Merged
Conversation
The native library added in 8.17.0 (#6307) for Turbo Module performance tracking is compiled from source with the app's NDK. On NDK r27 and earlier the linker defaults to 4 KB segment alignment, so this library was the lone misaligned `.so` in the APK (all prebuilt libs are already 16 KB aligned). This tripped Android 15+'s 16 KB page size compatibility check and Google Play's 16 KB requirement for New Architecture apps — even when `enableTurboModuleTracking` was left disabled, since the library is packaged whenever the New Architecture is enabled. Pass `-Wl,-z,max-page-size=16384` to the CMake target. Verified with NDK 27 against the RN 0.86 source tree: LOAD segment alignment goes from 0x1000 (4 KB) to 0x4000 (16 KB), with no file-size change. Backward compatible with 4 KB-page devices (16 KB is a multiple of 4 KB) and a no-op on NDK r28+ where 16 KB is already the default. Fixes #6394 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
Semver Impact of This PR⚪ None (no version bump detected) 📋 Changelog PreviewThis is how your changes will appear in the changelog.
🤖 This preview updates automatically when you update the PR. |
antonis
commented
Jul 3, 2026
Guards against regressing #6394. Adds scripts/check-android-16kb-alignment.sh which unzips a built APK/AAB and asserts every bundled .so has ELF LOAD segments aligned to at least 16 KB (p_align >= 0x4000), failing otherwise. Wired into the sample-application workflow right after the New Architecture Android app build, where a real APK is produced. The script is portable across the macOS (bash 3.2) and Ubuntu CI (mawk) shells and resolves readelf from $READELF, then llvm-readelf, then readelf. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
11 tasks
📲 Install BuildsAndroid
|
alwx
approved these changes
Jul 3, 2026
Contributor
Author
|
Converting to draft to check the CI check failures |
Contributor
iOS (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| eb93136+dirty | 3843.09 ms | 1220.11 ms | -2622.98 ms |
| ad66da3+dirty | 3820.96 ms | 1214.43 ms | -2606.52 ms |
| b04af96+dirty | 3818.92 ms | 1219.76 ms | -2599.16 ms |
| 9210ae6+dirty | 3815.93 ms | 1214.14 ms | -2601.79 ms |
| ca9d079+dirty | 3835.63 ms | 1218.68 ms | -2616.95 ms |
| 09a902f+dirty | 3835.67 ms | 1217.11 ms | -2618.57 ms |
| 5a21b51+dirty | 3823.11 ms | 1214.46 ms | -2608.65 ms |
| d038a14+dirty | 3845.71 ms | 1228.11 ms | -2617.59 ms |
| 64630e5+dirty | 3842.70 ms | 1218.11 ms | -2624.60 ms |
| 0a147b2+dirty | 3838.15 ms | 1221.94 ms | -2616.21 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| eb93136+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| ad66da3+dirty | 5.15 MiB | 6.67 MiB | 1.51 MiB |
| b04af96+dirty | 4.98 MiB | 6.54 MiB | 1.56 MiB |
| 9210ae6+dirty | 5.15 MiB | 6.68 MiB | 1.53 MiB |
| ca9d079+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| 09a902f+dirty | 4.98 MiB | 6.46 MiB | 1.49 MiB |
| 5a21b51+dirty | 5.15 MiB | 6.67 MiB | 1.51 MiB |
| d038a14+dirty | 5.15 MiB | 6.67 MiB | 1.51 MiB |
| 64630e5+dirty | 4.98 MiB | 6.46 MiB | 1.49 MiB |
| 0a147b2+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
Contributor
Android (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 8929511+dirty | 405.33 ms | 452.16 ms | 46.83 ms |
| 4b87b12+dirty | 421.82 ms | 413.60 ms | -8.22 ms |
| 822d35b+dirty | 429.31 ms | 498.04 ms | 68.73 ms |
| 44c8b3f+dirty | 414.20 ms | 457.28 ms | 43.08 ms |
| 5569641+dirty | 406.43 ms | 428.51 ms | 22.08 ms |
| 580fb5c+dirty | 436.34 ms | 471.63 ms | 35.28 ms |
| 7ff4d0f+dirty | 413.81 ms | 450.64 ms | 36.83 ms |
| 6177334+dirty | 408.16 ms | 441.14 ms | 32.98 ms |
| 1e5d96d+dirty | 519.43 ms | 543.62 ms | 24.19 ms |
| f9c1ed4+dirty | 431.00 ms | 466.22 ms | 35.22 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 8929511+dirty | 43.75 MiB | 48.16 MiB | 4.41 MiB |
| 4b87b12+dirty | 43.75 MiB | 48.14 MiB | 4.39 MiB |
| 822d35b+dirty | 49.74 MiB | 54.84 MiB | 5.10 MiB |
| 44c8b3f+dirty | 48.30 MiB | 53.46 MiB | 5.15 MiB |
| 5569641+dirty | 48.30 MiB | 53.48 MiB | 5.18 MiB |
| 580fb5c+dirty | 49.74 MiB | 54.79 MiB | 5.05 MiB |
| 7ff4d0f+dirty | 48.30 MiB | 53.60 MiB | 5.30 MiB |
| 6177334+dirty | 48.30 MiB | 53.54 MiB | 5.23 MiB |
| 1e5d96d+dirty | 49.74 MiB | 54.81 MiB | 5.07 MiB |
| f9c1ed4+dirty | 49.74 MiB | 54.86 MiB | 5.12 MiB |
The initial CI run failed because the check scanned every .so in the APK, including React Native and third-party libraries (libreactnative, libhermesvm, libreanimated, librnscreens, ...) which are 4 KB aligned in the x86 build CI produces. RN aligns arm64 to 16 KB but not x86, and those libraries are outside this repo's control. Add an optional name-filter argument to the check script and pass 'libsentry' in CI so the guard verifies only the libraries this repo ships (libsentry-tm-perf-logger.so et al.). A regression that drops the max-page-size flag from our CMake target is still caught — verified locally: with the filter, our lib at 4 KB still fails the check. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
iOS (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 0bd8916+dirty | 3816.17 ms | 1215.05 ms | -2601.12 ms |
| 0a147b2+dirty | 3845.11 ms | 1230.81 ms | -2614.30 ms |
| 774257e+dirty | 3821.35 ms | 1211.96 ms | -2609.39 ms |
| acd838e+dirty | 3835.94 ms | 1215.87 ms | -2620.07 ms |
| 038a6d7+dirty | 3838.96 ms | 1218.86 ms | -2620.10 ms |
| a216cb9+dirty | 3853.25 ms | 1224.77 ms | -2628.48 ms |
| df5d108+dirty | 1207.34 ms | 1210.50 ms | 3.16 ms |
| 2c735cc+dirty | 1223.33 ms | 1224.38 ms | 1.04 ms |
| 5a010b7+dirty | 3856.76 ms | 1232.65 ms | -2624.11 ms |
| f170ec3+dirty | 3844.74 ms | 1222.67 ms | -2622.07 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 0bd8916+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| 0a147b2+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| 774257e+dirty | 5.15 MiB | 6.70 MiB | 1.54 MiB |
| acd838e+dirty | 5.15 MiB | 6.70 MiB | 1.55 MiB |
| 038a6d7+dirty | 5.15 MiB | 6.70 MiB | 1.55 MiB |
| a216cb9+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| df5d108+dirty | 3.38 MiB | 4.73 MiB | 1.35 MiB |
| 2c735cc+dirty | 3.38 MiB | 4.74 MiB | 1.35 MiB |
| 5a010b7+dirty | 5.15 MiB | 6.69 MiB | 1.54 MiB |
| f170ec3+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📢 Type of change
📜 Description
libsentry-tm-perf-logger.so— the native library introduced in 8.17.0 (#6307) for Turbo Module performance tracking — is compiled from source in the consuming app viapackages/core/android/src/main/jni/CMakeLists.txt. That CMake target did not pass amax-page-sizelink option, so on NDK r27 and earlier (RN 0.86 / Expo SDK 57 ship with NDK 27) the linker defaulted to 4 KB ELF segment alignment. Every other.sobundled by RN/AGP is already 16 KB aligned, so this was the lone misaligned library in the APK.This PR:
Adds
-Wl,-z,max-page-size=16384to the CMake target (a no-op on NDK r28+, where 16 KB is already the default):Adds a regression guard —
scripts/check-android-16kb-alignment.shunzips a built APK/AAB and asserts every bundled.sohas ELF LOAD segments aligned to at least 16 KB, failing otherwise. It is wired into thesample-applicationworkflow right after the New Architecture Android build (the only place a real APK is produced in CI).💡 Motivation and Context
Fixes #6394.
On Android 15+ with a 16 KB page size image, affected apps showed the "Android App Compatibility" dialog on every launch and ran in page-size-compat mode. This also fails Google Play's 16 KB requirement. It affected all New Architecture apps on RN ≥ 0.75, regardless of whether
enableTurboModuleTrackingwas enabled — the library is packaged whenever the New Architecture is on, and Android's installer scans every bundled.sofor alignment.💚 How did you test it?
Compiled the actual library sources (
SentryTurboModulePerfLogger.cpp+OnLoad.cpp) against the RN 0.86 source tree with NDK 27 (the toolchain RN 0.86 / Expo SDK 57 use), both with and without the flag, and inspected the ELF program headers withllvm-readelf -l:p_alignmain)0x1000(4 KB)-Wl,-z,max-page-size=163840x4000(16 KB)Backward compatibility confirmed from the fixed binary's headers: every LOAD segment satisfies
Offset ≡ VirtAddr (mod 0x4000), which impliesmod 0x1000— so it still loads correctly on 4 KB-page devices (16 KB is a multiple of 4 KB). No file-size change was observed for this library.The new
check-android-16kb-alignment.shguard was also verified locally against two synthetic APKs — one containing the fixed lib (exit 0, pass) and one containing the pre-fix 4 KB lib (exit 1, fail, offending library reported), reproducing #6394 and confirming the check would catch a future regression.📝 Checklist
sendDefaultPIIis enabled.🔮 Next steps
🤖 Generated with Claude Code