谷歌商店已经在2025年11月1号开始限制所有上传的app必须适配16KB对齐,否则将无法发布。
因此需要排查app中引入的so文件是否适配了16KB对齐。
如果已经有so文件,想快速排查是否已经适配16KB对齐,可以尝试如下方法:
- Android ndk中已经包含检测so文件的工具:aarch64-linux-android-readelf,该文件在ndk的很多目录中都有,我们可以选择任意路径下的文件,以macOS系统为例:
/Users/[username]/Library/Android/sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/
其中的[username]替换为用户名,21.4.7075529替换为本机安装的ndk版本。
- 打开命令行工具,cd到上述目录,然后执行命令:
./aarch64-linux-android-readelf -l /Users/[username]/sw/libtest.so
-l后面的参数表示so文件的路径,替换为实际路径。
已经适配16KB对齐的结果示例:
Elf file type is DYN (Shared object file)
Entry point 0x2726c0
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000001f8 0x00000000000001f8 R 8
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000813040 0x0000000000813040 R E 4000
LOAD 0x0000000000813040 0x0000000000817040 0x0000000000817040
0x000000000004bba8 0x000000000004bba8 RW 4000
LOAD 0x000000000085ec00 0x0000000000866c00 0x0000000000866c00
0x0000000000002ed8 0x000000000011e990 RW 4000
DYNAMIC 0x000000000085ad80 0x000000000085ed80 0x000000000085ed80
0x00000000000001e0 0x00000000000001e0 RW 8
GNU_RELRO 0x0000000000813040 0x0000000000817040 0x0000000000817040
0x000000000004bba8 0x000000000004bfc0 R 1
GNU_EH_FRAME 0x0000000000155584 0x0000000000155584 0x0000000000155584
0x0000000000038eac 0x0000000000038eac R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0
NOTE 0x0000000000000238 0x0000000000000238 0x0000000000000238
0x00000000000000b0 0x00000000000000b0 R 4
Section to Segment mapping:
Segment Sections...
00
01 .note.android.ident .note.gnu.build-id .dynsym .gnu.version .gnu.version_r .gnu.hash .hash .dynstr .rela.dyn .rela.plt .rodata .gcc_except_table .eh_frame_hdr .eh_frame .text .plt
02 .fini_array .data.rel.ro .init_array .dynamic .got .got.plt
03 .data .bss
04 .dynamic
05 .fini_array .data.rel.ro .init_array .dynamic .got .got.plt
06 .eh_frame_hdr
07
08 .note.android.ident .note.gnu.build-id
上述结果3个LOAD段的Align参数都是4000,这是16进制形式,转为10进制就是16384,即16KB对齐。
未适配16KB对齐的结果示例:
Elf file type is DYN (Shared object file)
Entry point 0x259540
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000001f8 0x00000000000001f8 R 8
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000751e40 0x0000000000751e40 R E 1000
LOAD 0x0000000000751e40 0x0000000000752e40 0x0000000000752e40
0x0000000000049890 0x0000000000049890 RW 1000
LOAD 0x000000000079b6e0 0x000000000079d6e0 0x000000000079d6e0
0x0000000000002de8 0x000000000010bed0 RW 1000
DYNAMIC 0x0000000000797ec0 0x0000000000798ec0 0x0000000000798ec0
0x00000000000001e0 0x00000000000001e0 RW 8
GNU_RELRO 0x0000000000751e40 0x0000000000752e40 0x0000000000752e40
0x0000000000049890 0x000000000004a1c0 R 1
GNU_EH_FRAME 0x0000000000147bf4 0x0000000000147bf4 0x0000000000147bf4
0x0000000000036b14 0x0000000000036b14 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0
NOTE 0x0000000000000238 0x0000000000000238 0x0000000000000238
0x00000000000000b0 0x00000000000000b0 R 4
Section to Segment mapping:
Segment Sections...
00
01 .note.android.ident .note.gnu.build-id .dynsym .gnu.version .gnu.version_r .gnu.hash .hash .dynstr .rela.dyn .rela.plt .rodata .gcc_except_table .eh_frame_hdr .eh_frame .text .plt
02 .fini_array .data.rel.ro .init_array .dynamic .got .got.plt
03 .data .bss
04 .dynamic
05 .fini_array .data.rel.ro .init_array .dynamic .got .got.plt
06 .eh_frame_hdr
07
08 .note.android.ident .note.gnu.build-id
上述结果3个LOAD段的Align参数都是1000,这是16进制形式,转为10进制就是4096,即4KB对齐。说明此so不支持16KB对齐,需要重编。
可能需要适配16KB对齐的结果示例:
Elf file type is DYN (Shared object file)
Entry point 0x19e60
There are 7 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x000000000043d970 0x000000000043d970 R E 10000
LOAD 0x0000000000446310 0x0000000000446310 0x0000000000446310
0x000000000000cce8 0x0000000000038ad0 RW 10000
DYNAMIC 0x000000000044e7b8 0x000000000044e7b8 0x000000000044e7b8
0x0000000000000210 0x0000000000000210 RW 8
NOTE 0x00000000000001c8 0x00000000000001c8 0x00000000000001c8
0x0000000000000024 0x0000000000000024 R 4
GNU_EH_FRAME 0x00000000003e91c0 0x00000000003e91c0 0x00000000003e91c0
0x000000000000f644 0x000000000000f644 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x0000000000446310 0x0000000000446310 0x0000000000446310
0x0000000000009cf0 0x0000000000009cf0 R 1
Section to Segment mapping:
Segment Sections...
00 .note.gnu.build-id .hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .plt .text .rodata .eh_frame_hdr .eh_frame
01 .init_array .fini_array .data.rel.ro .dynamic .got .data .bss
02 .dynamic
03 .note.gnu.build-id
04 .eh_frame_hdr
05
06 .init_array .fini_array .data.rel.ro .dynamic .got
上述结果3个LOAD段的Align参数都是10000,这是16进制形式,转为10进制就是65536,即64KB对齐。理论上来说,64KB对齐的so是支持16KB对齐的,但是有可能早期的ndk编译出来的so在16KB对齐的设备上会崩溃,因此此种情况需要测试一下,看看结果。如果功能正常不崩溃,则不需要适配。否则需要基于较新的ndk重新编译或改为16KB对齐。
说明:
上述方式只是可以初步排查出没有适配的so,没有适配的so一定需要重编。对于其他情况,就需要实际验证再确定是否需要重编了。