verify-16k-page-align 0.0.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +7 -0
- package/README.md +187 -0
- package/package.json +54 -0
- package/src/verify-16k-page-align.sh +121 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright (c) since 2021 @hebertcisco
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# verify-16k-page-align
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/verify-16k-page-align)
|
|
4
|
+
[](LICENSE.md)
|
|
5
|
+
[](#platform-support)
|
|
6
|
+
|
|
7
|
+
A shell script and npm package to verify if your Android APK/AAB native libraries are aligned to 16KB (0x4000) memory pages. This is required for compatibility with Android 15+ devices and Google Play submissions after **November 1, 2025** ([see official docs](https://developer.android.com/guide/practices/page-sizes?hl=pt-br)).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Checks all native `.so` libraries in APK/AAB for 16KB page alignment
|
|
14
|
+
- Works with both APK and AAB files
|
|
15
|
+
- Uses `readelf` or `llvm-readelf` (auto-detects)
|
|
16
|
+
- Fast, zero dependencies (besides unzip/readelf)
|
|
17
|
+
- CLI and npm global install
|
|
18
|
+
- Clear pass/fail output for CI/CD
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Why 16KB Page Alignment?
|
|
23
|
+
|
|
24
|
+
Starting with Android 15, many devices will use 16KB memory pages for improved performance and reliability. All apps targeting Android 15+ and distributed via Google Play **must** ensure their native libraries (`.so` files) are 16KB aligned. See:
|
|
25
|
+
- [Android Developers: 16 KB Page Size](https://developer.android.com/guide/practices/page-sizes?hl=pt-br)
|
|
26
|
+
- [Google Play Blog: Prepare for 16 KB page size](https://android-developers.googleblog.com/2025/05/prepare-play-apps-for-devices-with-16kb-page-size.html)
|
|
27
|
+
- [Medium: Android 15 Mandatory 16KB Memory Page Size](https://devharshmittal.medium.com/android-15-is-raising-the-bar-mandatory-16kb-memory-page-size-what-developers-need-to-know-4dd81ec58f67)
|
|
28
|
+
- [Reddit discussion](https://www.reddit.com/r/brdev/comments/1nl3fx4/android_15_seus_apps_j%C3%A1_est%C3%A3o_prontos_para_16kb/)
|
|
29
|
+
|
|
30
|
+
**Benefits:**
|
|
31
|
+
- Faster app launches (3–30% improvement)
|
|
32
|
+
- Lower battery usage
|
|
33
|
+
- Reduced memory fragmentation
|
|
34
|
+
- Required for Play Store submission (from Nov 2025)
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
### Shell script (one-liner)
|
|
41
|
+
```sh
|
|
42
|
+
sh -c "$(curl -fsSL https://raw.githubusercontent.com/hotbrainstech/verify-16k-page-align/main/src/verify-16k-page-align.sh)"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### NPM global install
|
|
46
|
+
```sh
|
|
47
|
+
sudo npm i -g verify-16k-page-align
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
### Check an APK or AAB file
|
|
56
|
+
By default, only `arm64-v8a` libraries are checked. To also check `x86_64` libraries, add `x86` as a second argument.
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
# Default: check arm64-v8a only
|
|
60
|
+
verify-16k-page-align <path-to-apk-or-aab>
|
|
61
|
+
|
|
62
|
+
# Check arm64-v8a and x86_64
|
|
63
|
+
verify-16k-page-align <path-to-apk-or-aab> x86
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or, if using the raw script:
|
|
67
|
+
```sh
|
|
68
|
+
# Default: check arm64-v8a only
|
|
69
|
+
sh ./src/verify-16k-page-align.sh <path-to-apk-or-aab>
|
|
70
|
+
|
|
71
|
+
# Check arm64-v8a and x86_64
|
|
72
|
+
sh ./src/verify-16k-page-align.sh <path-to-apk-or-aab> x86
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Or, make the script executable and run directly:
|
|
76
|
+
```sh
|
|
77
|
+
chmod +x ./src/verify-16k-page-align.sh
|
|
78
|
+
# Default: check arm64-v8a only
|
|
79
|
+
./src/verify-16k-page-align.sh <path-to-apk-or-aab>
|
|
80
|
+
# Check arm64-v8a and x86_64
|
|
81
|
+
./src/verify-16k-page-align.sh <path-to-apk-or-aab> x86
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### Example output
|
|
85
|
+
```
|
|
86
|
+
Using readelf: /usr/bin/readelf
|
|
87
|
+
Inspecting: app-release.apk
|
|
88
|
+
Found 3 native libraries
|
|
89
|
+
[OK] lib/arm64-v8a/libfoo.so aligned to 16KB (no 0x1000 LOAD segments detected).
|
|
90
|
+
[FAIL] lib/arm64-v8a/libbar.so has LOAD segment aligned to 0x1000 (4KB).
|
|
91
|
+
|
|
92
|
+
One or more native libraries are not 16KB aligned.
|
|
93
|
+
Ensure AGP >= 8.5.1, NDK r27+, and rebuild any third-party .so with 16KB page alignment.
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### CI/CD Example
|
|
97
|
+
Add to your pipeline to fail builds if any library is not 16KB aligned.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## How It Works
|
|
102
|
+
|
|
103
|
+
1. Extracts all `.so` files from your APK/AAB
|
|
104
|
+
2. Uses `readelf` or `llvm-readelf` to inspect ELF program headers
|
|
105
|
+
3. Flags any library with a LOAD segment aligned to 4KB (0x1000)
|
|
106
|
+
4. Passes if all LOAD segments are aligned to 16KB (0x4000)
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Platform Support
|
|
111
|
+
|
|
112
|
+
- Linux only (uses bash, unzip, readelf)
|
|
113
|
+
- Not supported on Windows or macOS
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Requirements
|
|
118
|
+
|
|
119
|
+
- unzip
|
|
120
|
+
- readelf or llvm-readelf (from binutils or Android NDK)
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Migration Guide
|
|
125
|
+
|
|
126
|
+
If your app or any dependency uses native code:
|
|
127
|
+
- **Update your build tools:** Use Android Gradle Plugin (AGP) >= 8.5.1 and NDK r27+ (prefer r28+)
|
|
128
|
+
- **Recompile all native libraries** with 16KB alignment
|
|
129
|
+
- **Remove hardcoded page size assumptions** (replace `4096`/`0x1000`/`PAGE_SIZE` with `sysconf(_SC_PAGESIZE)`)
|
|
130
|
+
- **Check all third-party .so files** for compliance
|
|
131
|
+
- **Test on Android 15+ emulators or real devices**
|
|
132
|
+
|
|
133
|
+
See [official migration steps](https://developer.android.com/guide/practices/page-sizes?hl=pt-br#compile-16-kb-alignment) and [Medium migration guide](https://devharshmittal.medium.com/android-15-is-raising-the-bar-mandatory-16kb-memory-page-size-what-developers-need-to-know-4dd81ec58f67).
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Troubleshooting
|
|
138
|
+
|
|
139
|
+
- If you see `[FAIL] ... has LOAD segment aligned to 0x1000 (4KB)`, update and rebuild the affected library.
|
|
140
|
+
- For AGP < 8.5.1, use `packagingOptions.jniLibs.useLegacyPackaging true` in `build.gradle` (not recommended).
|
|
141
|
+
- For NDK < r27, set linker flags: `-Wl,-z,max-page-size=16384` and `-Wl,-z,common-page-size=16384`.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## FAQ
|
|
146
|
+
|
|
147
|
+
**Q: Does this work for Java/Kotlin-only apps?**
|
|
148
|
+
A: No need—Java/Kotlin-only apps do not use native libraries and are already compatible.
|
|
149
|
+
|
|
150
|
+
**Q: What if my library is not 16KB aligned?**
|
|
151
|
+
A: Update your build tools and recompile. Contact third-party vendors for updated .so files.
|
|
152
|
+
|
|
153
|
+
**Q: Can I use this on macOS or Windows?**
|
|
154
|
+
A: No, Linux only. Use a Linux VM or Docker if needed.
|
|
155
|
+
|
|
156
|
+
**Q: Is this required for Play Store submission?**
|
|
157
|
+
A: Yes, for Android 15+ apps after Nov 1, 2025.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 🤝 Contributing
|
|
162
|
+
|
|
163
|
+
Pull requests and issues are welcome! See [GitHub Issues](https://github.com/hotbrainstech/verify-16k-page-align/issues).
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## References & Further Reading
|
|
168
|
+
- [Android 16KB Page Size Docs](https://developer.android.com/guide/practices/page-sizes?hl=pt-br)
|
|
169
|
+
- [Google Play Blog](https://android-developers.googleblog.com/2025/05/prepare-play-apps-for-devices-with-16kb-page-size.html)
|
|
170
|
+
- [Medium: Migration Guide](https://devharshmittal.medium.com/android-15-is-raising-the-bar-mandatory-16kb-memory-page-size-what-developers-need-to-know-4dd81ec58f67)
|
|
171
|
+
- [Reddit: brdev discussion](https://www.reddit.com/r/brdev/comments/1nl3fx4/android_15_seus_apps_j%C3%A1_est%C3%A3o_prontos_para_16kb/)
|
|
172
|
+
|
|
173
|
+
## Show your support
|
|
174
|
+
|
|
175
|
+
Give a ⭐️ if this project helps you!
|
|
176
|
+
|
|
177
|
+
Or buy me a coffee 🙌🏾
|
|
178
|
+
|
|
179
|
+
<a href="https://www.buymeacoffee.com/hebertcisco">
|
|
180
|
+
<img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=hebertcisco&button_colour=FFDD00&font_colour=000000&font_family=Inter&outline_colour=000000&coffee_colour=ffffff" />
|
|
181
|
+
</a>
|
|
182
|
+
|
|
183
|
+
## 📝 License
|
|
184
|
+
|
|
185
|
+
Copyright © 2025 [@hotbrainstech](https://github.com/hotbrainstech).
|
|
186
|
+
|
|
187
|
+
This project is [MIT](LICENSE) licensed.
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "verify-16k-page-align",
|
|
3
|
+
"version": "0.0.1-alpha.1",
|
|
4
|
+
"description": "A simple shell script to verify if a android app is 16k page aligned",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"private": false,
|
|
8
|
+
"author": "hotbrainstech",
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public"
|
|
11
|
+
},
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"lint": "shellcheck src/verify-16k-page-align.sh",
|
|
15
|
+
"lint:fix": "shellcheck -f gcc -o ./lib/verify-16k-page-align.sh",
|
|
16
|
+
"version": "git add -A src",
|
|
17
|
+
"postversion": "git push && git push --tags"
|
|
18
|
+
},
|
|
19
|
+
"bin": {
|
|
20
|
+
"verify-16k-page-align": "./src/verify-16k-page-align.sh"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20.0.0"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"bin/**/*"
|
|
27
|
+
],
|
|
28
|
+
"os": [
|
|
29
|
+
"linux",
|
|
30
|
+
"!darwin",
|
|
31
|
+
"!win32"
|
|
32
|
+
],
|
|
33
|
+
"bundleDependencies": [
|
|
34
|
+
"@types/node"
|
|
35
|
+
],
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/hotbrainstech/verify-16k-page-align.git"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"android",
|
|
42
|
+
"react-native",
|
|
43
|
+
"npm",
|
|
44
|
+
"module"
|
|
45
|
+
],
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/hotbrainstech/verify-16k-page-align/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/hotbrainstech/verify-16k-page-align#readme",
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^24.5.2",
|
|
52
|
+
"concurrently": "^9.2.1"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
progname="${0##*/}"
|
|
3
|
+
progname="${progname%.sh}"
|
|
4
|
+
|
|
5
|
+
# usage: check_elf_alignment.sh [path to *.so files|path to *.apk]
|
|
6
|
+
|
|
7
|
+
cleanup_trap() {
|
|
8
|
+
if [ -n "${tmp}" -a -d "${tmp}" ]; then
|
|
9
|
+
rm -rf ${tmp}
|
|
10
|
+
fi
|
|
11
|
+
exit $1
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
usage() {
|
|
15
|
+
echo "Host side script to check the ELF alignment of shared libraries."
|
|
16
|
+
echo "Shared libraries are reported ALIGNED when their ELF regions are"
|
|
17
|
+
echo "16 KB or 64 KB aligned. Otherwise they are reported as UNALIGNED."
|
|
18
|
+
echo
|
|
19
|
+
echo "Usage: ${progname} [input-path|input-APK|input-APEX]"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Parse arguments
|
|
24
|
+
if [ ${#} -lt 1 ] || [ ${#} -gt 2 ]; then
|
|
25
|
+
usage
|
|
26
|
+
exit
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
case "${1}" in
|
|
30
|
+
--help|-h|'-?')
|
|
31
|
+
usage
|
|
32
|
+
exit
|
|
33
|
+
;;
|
|
34
|
+
*)
|
|
35
|
+
dir="${1}"
|
|
36
|
+
;;
|
|
37
|
+
esac
|
|
38
|
+
|
|
39
|
+
if ! [ -f "${dir}" -o -d "${dir}" ]; then
|
|
40
|
+
echo "Invalid file: ${dir}" >&2
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Set architecture filter
|
|
45
|
+
arch_filter="arm64-v8a"
|
|
46
|
+
if [ ${#} -eq 2 ] && [ "${2}" = "x86" ]; then
|
|
47
|
+
arch_filter="arm64-v8a|x86_64"
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
if [[ "${dir}" == *.apk ]]; then
|
|
51
|
+
trap 'cleanup_trap' EXIT
|
|
52
|
+
|
|
53
|
+
echo
|
|
54
|
+
echo "Recursively analyzing $dir"
|
|
55
|
+
echo
|
|
56
|
+
|
|
57
|
+
if { zipalign --help 2>&1 | grep -q "\-P <pagesize_kb>"; }; then
|
|
58
|
+
echo "=== APK zip-alignment ==="
|
|
59
|
+
zipalign -v -c -P 16 4 "${dir}" | egrep "lib/(${arch_filter})|Verification"
|
|
60
|
+
echo "========================="
|
|
61
|
+
else
|
|
62
|
+
echo "NOTICE: Zip alignment check requires build-tools version 35.0.0-rc3 or higher."
|
|
63
|
+
echo " You can install the latest build-tools by running the below command"
|
|
64
|
+
echo " and updating your \$PATH:"
|
|
65
|
+
echo
|
|
66
|
+
echo " sdkmanager \"build-tools;35.0.0-rc3\""
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
dir_filename=$(basename "${dir}")
|
|
70
|
+
tmp=$(mktemp -d -t "${dir_filename%.apk}_out_XXXXX")
|
|
71
|
+
unzip "${dir}" lib/* -d "${tmp}" >/dev/null 2>&1
|
|
72
|
+
dir="${tmp}"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if [[ "${dir}" == *.apex ]]; then
|
|
76
|
+
trap 'cleanup_trap' EXIT
|
|
77
|
+
|
|
78
|
+
echo
|
|
79
|
+
echo "Recursively analyzing $dir"
|
|
80
|
+
echo
|
|
81
|
+
|
|
82
|
+
dir_filename=$(basename "${dir}")
|
|
83
|
+
tmp=$(mktemp -d -t "${dir_filename%.apex}_out_XXXXX")
|
|
84
|
+
deapexer extract "${dir}" "${tmp}" || { echo "Failed to deapex." && exit 1; }
|
|
85
|
+
dir="${tmp}"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
RED="\e[31m"
|
|
89
|
+
GREEN="\e[32m"
|
|
90
|
+
ENDCOLOR="\e[0m"
|
|
91
|
+
|
|
92
|
+
unaligned_libs=()
|
|
93
|
+
|
|
94
|
+
echo
|
|
95
|
+
echo "=== ELF alignment ==="
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
matches="$(find "${dir}" -type f | egrep "lib/(${arch_filter})/.*\.so$")"
|
|
99
|
+
IFS=$'\n'
|
|
100
|
+
for match in $matches; do
|
|
101
|
+
# We could recursively call this script or rewrite it to though.
|
|
102
|
+
[[ "${match}" == *".apk" ]] && echo "WARNING: doesn't recursively inspect .apk file: ${match}"
|
|
103
|
+
[[ "${match}" == *".apex" ]] && echo "WARNING: doesn't recursively inspect .apex file: ${match}"
|
|
104
|
+
|
|
105
|
+
[[ $(file "${match}") == *"ELF"* ]] || continue
|
|
106
|
+
|
|
107
|
+
res="$(objdump -p "${match}" | grep LOAD | awk '{ print $NF }' | head -1)"
|
|
108
|
+
if [[ $res =~ 2\*\*(1[4-9]|[2-9][0-9]|[1-9][0-9]{2,}) ]]; then
|
|
109
|
+
echo -e "${match}: ${GREEN}ALIGNED${ENDCOLOR} ($res)"
|
|
110
|
+
else
|
|
111
|
+
echo -e "${match}: ${RED}UNALIGNED${ENDCOLOR} ($res)"
|
|
112
|
+
unaligned_libs+=("${match}")
|
|
113
|
+
fi
|
|
114
|
+
done
|
|
115
|
+
|
|
116
|
+
if [ ${#unaligned_libs[@]} -gt 0 ]; then
|
|
117
|
+
echo -e "${RED}Found ${#unaligned_libs[@]} unaligned libs (only arm64-v8a/x86_64 libs need to be aligned).${ENDCOLOR}"
|
|
118
|
+
elif [ -n "${dir_filename}" ]; then
|
|
119
|
+
echo -e "ELF Verification Successful"
|
|
120
|
+
fi
|
|
121
|
+
echo "====================="
|