たくさんの自由帳
Androidのお話
たくさんの自由帳
投稿日 : | 0 日前
文字数(だいたい) : 5924
目次
本題
こうしき
対応する必要があるか確認
はじめに
AGP をバージョンアップ
対応パターン
使ってるライブラリがネイティブコードを使ってる場合
AndroidX の .so ファイルのみが表示されている場合
証拠は
俺がライブラリ作者だ / ネイティブコードをビルドしている場合
すでに 16KB ページサイズに対応しているか確認
対応方法
環境
最短ルート
Android Studio で有効にする
Android Studio を使わない他の C++ プロジェクトで CMakeLists.txt に指定する
Rust などのクロスコンパイルで Android 向けビルドを 16KB ページサイズに対応させる
16KB ページサイズの動作確認
16KB ページサイズでビルドしたら古い端末で動くの?
どうもこんばんわ。
前回貼り付け忘れた画像です。かわいい

Android と Rust - たくさんの自由帳
https://takusan.negitoro.dev/posts/android_rust/
前回NDKを使うアプリを作りました。そうです、各 CPU アーキテクチャ向けにビルドするあれです。NDKを使う(使った)アプリを開発する際、この16KB ページサイズに対応する必要があります。

Supporta dimensioni di pagina da 16 kB. | Compatibility | Android Developers
https://developer.android.com/guide/practices/page-sizes?hl=it

Get your apps ready for 16 KB page size devices
Android is adopting a 16 KB memory page size to improve performance. Use this guide to ensure your app is compatible with the new page size.
https://android-developers.googleblog.com/2024/12/get-your-apps-ready-for-16-kb-page-size-devices.html

Adding 16 KB Page Size to Android
Android 15 has been refactored to support using 16 KB page sizes, and file systems like EROFS and F2FS have been made compatible.
https://android-developers.googleblog.com/2024/08/adding-16-kb-page-size-to-android.html
リリース APKを作った後に、Analyze APK ...を押すことで、APKの中を見れます。
で、こんな感じに、libフォルダがあれば対応が必要です。
が、今のアプリ開発だとlibandroidx.graphics.path.soが入ってしまう?
この記事で言うネイティブコードは、クロスプラットフォームの人たちが言う 各プラットフォームの開発言語 (Swift / Kotlin) の事では無く、C++やRustのような Android NDK が必要なコードのことを指します。
ネイティブライブラリに関しても同じ。
AGPバージョン8.5.1以上にすると共有ライブラリのパッケージを更新するのセクションは完了しそう。
ネイティブコードを使ってる場合は、自分で対応するにしろ、対応してもらうにしろ何にしろAGPのアップデートが必要そう?(よくわからない)
私の環境のAndroid Gradle Pluginは8.8.2。Android StudioにはAGP Upgrade Assistantがついているので古い場合は上げちゃえば良さそう。
多分このよっつ?
AndroidXのlibandroidx.graphics.path.so、libdatastore_shared_counter.soだけ入ってる場合
androidx.から始まる(Android Jetpack)のライブラリが.soファイルに依存しているAndroid StudioでCMakeLists.txtとかを書いてC++をコンパイルしている場合Androidへ持ち込んでいる場合ライブラリ作者にお願いしてきてください
よろしくお願いします
libandroidx.graphics.path.soやlibdatastore_shared_counter.soとかが表示されている場合。androidx.のライブラリを入れたら付いてきた場合。
この場合は、すでに 16KB ページサイズでライブラリを配布しているので問題ない(はず)です。観測してる範囲では。
後述するのですが、C++のビルド時に参照するCMakeLists.txtを見ると、16KB ページサイズでビルドするように追記されてました
がんばろう
macOS / Linuxの場合はシェルスクリプトで確認できます。適当にテキストファイルを.shで作り、シェルスクリプトを貼り付けてください。vimだとペーストモードが便利。
Linuxしか確認できていませんが、chmodで実行権限をつけた後、./check_elf_alignment.sh {APKのパス}コマンドで動くはず。
chmod +x check_elf_alignment.sh
./check_elf_alignment.sh app-release.apkWindowsの場合はWSL2か、あとはコマンドを愚直に叩く方法もある→ 
Support 16 KB page sizes | Compatibility | Android Developers
https://developer.android.com/guide/practices/page-sizes
GitBashじゃ動かなかった、unzip dir lib/*の箇所でエラーになるのと、GitBashでもobjdumpがwindowsに無い。以下が実行結果です、UNALIGNEDが16KB ページサイズ未対応で、ALIGNEDが対応済みです。もっぱら自分が用意した.soが未対応ですね、、
/tmp/app-release_out_6q4W9/lib/arm64-v8a/libandroid_jni.so: UNALIGNED (2**12)
/tmp/app-release_out_6q4W9/lib/arm64-v8a/libandroid_jni_without_simd.so: UNALIGNED (2**12)
/tmp/app-release_out_6q4W9/lib/arm64-v8a/libandroidx.graphics.path.so: ALIGNED (2**14)
/tmp/app-release_out_6q4W9/lib/arm64-v8a/libjnidispatch.so: ALIGNED (2**16)
/tmp/app-release_out_6q4W9/lib/arm64-v8a/libandroid_rust_uniffi.so: UNALIGNED (2**12)対応する必要があるCPU アーキテクチャはARM 64 ビット(arm64-v8a)、x86_64です。32bitはいいらしい。
この3つ?
Android StudioでCMakeLists.txtを使ってC++をビルドしている場合C++プロジェクトをAndroid NDKでビルドして.soと.hをAndroid Studioへ持ち込んでいる場合Android NDKでRustとかからクロスコンパイルしている場合Android NDK r27を使います。
後述しますがr28を使えれば一番早いです。
Android NDK r28以上を使って、あとはいつも通りビルドする。
バージョンが上げられる場合は多分これが一番早い。
Android Studio以外でビルドする場合はNDKのパスをr28に置き換えれば良さそう。Android StudioでC++ビルドする場合は、app/build.gradle (.kts)でndkVersion = ""を28のものにする必要があります。以下例。
android {
// 以下省略...
defaultConfig {
// 以下省略...
ndkVersion = "28.0.13004108"
}
// 以下省略...
}一番多そう雰囲気(なぜか変換できる)。
C++コードをAndroid Studioで書いている場合。
この場合はappフォルダ内のbuild.gradle (.kts)にarguments += listOf("-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON")を書き足せばいいはず。
多分こう。
android {
namespace = "io.github.takusan23.cppnativesample"
compileSdk = 35
defaultConfig {
applicationId = "io.github.takusan23.cppnativesample"
minSdk = 21
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
// これを足す
// This block is different from the one you use to link Gradle
// to your CMake or ndk-build script.
externalNativeBuild {
// For ndk-build, instead use the ndkBuild block.
cmake {
// Passes optional arguments to CMake.
arguments += listOf("-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON")
}
}
}
// 以下省略...これでAPKを作成しもう一度チェックしてみると、ちゃんとarm64-v8a、x86_64でALIGNEDになってました。
takusan23@DESKTOP-ULEKIDB:~$ ./check_elf_alignment.sh app-release-cpp.apk
Recursively analyzing app-release-cpp.apk
NOTICE: Zip alignment check requires build-tools version 35.0.0-rc3 or higher.
You can install the latest build-tools by running the below command
and updating your $PATH:
sdkmanager "build-tools;35.0.0-rc3"
=== ELF alignment ===
/tmp/app-release-cpp_out_BGTqn/lib/x86_64/libcppnativesample.so: ALIGNED (2**14)
/tmp/app-release-cpp_out_BGTqn/lib/arm64-v8a/libcppnativesample.so: ALIGNED (2**14)
/tmp/app-release-cpp_out_BGTqn/lib/x86/libcppnativesample.so: UNALIGNED (2**12)
/tmp/app-release-cpp_out_BGTqn/lib/armeabi-v7a/libcppnativesample.so: UNALIGNED (2**12)
Found 2 unaligned libs (only arm64-v8a/x86_64 libs need to be aligned).次はこのパターンAndroid Studio以外でCMakeLists.txtを使って共有ライブラリをビルドしている場合。
CMakeLists.txtを使ってリンカーに引数をつければいいらしい。
というわけでAndroid向けにビルドできる適当なプロジェクトで試します。今回はUltraHDR画像を作るlibultrahdrをビルドしてみる。Android向けが公式にサポートされてるので。
(Androidの機能だからそれはそう)
building.mdに従えば出来るはず。cmakeとninjaをaptからinstallして、Android NDKをダウンロードして、指示通りコマンドを叩くだけ感。
しかし、これでビルドして.soをAPKに入れても16K ページサイズに対応してないのでUNALIGNEDになります。
/tmp/app-release-other-project_out_7tCyK/lib/arm64-v8a/libuhdr.so: UNALIGNED (2**12)というわけでAndroidビルドで使ってる?CMakeLists.txtを探します。libultrahdrの場合はandroid.cmakeがそれだったので、一番下にこれを書き足しました。target_link_optionsはなんかエラーになってしまった。
# Android 15 16K page-size support.
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-z,max-page-size=16384")あとはこれでビルドすればいいはず。出来た.soをmain/jniLibsのCPU アーキテクチャのところに格納して終わりのはず。
以下は面倒くさがってarm64-v8aしかビルドしてませんが、これでALIGNEDになりました。libuhdr.soです。
takusan23@DESKTOP-ULEKIDB:~$ ./check_elf_alignment.sh app-release-other-project-16k.apk
Recursively analyzing app-release-other-project-16k.apk
NOTICE: Zip alignment check requires build-tools version 35.0.0-rc3 or higher.
You can install the latest build-tools by running the below command
and updating your $PATH:
sdkmanager "build-tools;35.0.0-rc3"
=== ELF alignment ===
/tmp/app-release-other-project-16k_out_EFo2u/lib/x86_64/libcppnativesample.so: ALIGNED (2**14)
/tmp/app-release-other-project-16k_out_EFo2u/lib/arm64-v8a/libcppnativesample.so: ALIGNED (2**14)
/tmp/app-release-other-project-16k_out_EFo2u/lib/arm64-v8a/libuhdr.so: ALIGNED (2**14)
/tmp/app-release-other-project-16k_out_EFo2u/lib/x86/libcppnativesample.so: UNALIGNED (2**12)
/tmp/app-release-other-project-16k_out_EFo2u/lib/armeabi-v7a/libcppnativesample.so: UNALIGNED (2**12)
Found 2 unaligned libs (only arm64-v8a/x86_64 libs need to be aligned).
=====================Rustのcargoはその他のビルドシステムに当たるので、-Wl,-z,max-page-size=16384をどうにかして渡す必要があります。
cargo buildの際に、RUSTFLAGSで-C link-arg=に突っ込めば良さそう感。なのでこれでいいはず。
RUSTFLAGS='-C link-arg=-Wl,-z,max-page-size=16384' cargo build --release --target aarch64-linux-android
RUSTFLAGS='-C link-arg=-Wl,-z,max-page-size=16384' cargo build --release --target x86_64-linux-androidできた.soを同様にjniLibsに配置すればいいはず。APK作ってチェックしてみたけど大丈夫そう。libandroid_rust_jni.soがx86_64とarm64-v8aでALIGNEDになってます!!
takusan23@DESKTOP-ULEKIDB:~$ ./check_elf_alignment.sh app-release-rust-jni.apk
Recursively analyzing app-release-rust-jni.apk
NOTICE: Zip alignment check requires build-tools version 35.0.0-rc3 or higher.
You can install the latest build-tools by running the below command
and updating your $PATH:
sdkmanager "build-tools;35.0.0-rc3"
=== ELF alignment ===
/tmp/app-release-rust-jni_out_bm5NF/lib/x86_64/libandroid_rust_jni.so: ALIGNED (2**14)
/tmp/app-release-rust-jni_out_bm5NF/lib/x86_64/libandroidx.graphics.path.so: ALIGNED (2**14)
/tmp/app-release-rust-jni_out_bm5NF/lib/arm64-v8a/libandroid_rust_jni.so: ALIGNED (2**14)
/tmp/app-release-rust-jni_out_bm5NF/lib/arm64-v8a/libandroidx.graphics.path.so: ALIGNED (2**14)
/tmp/app-release-rust-jni_out_bm5NF/lib/x86/libandroid_rust_jni.so: UNALIGNED (2**12)
/tmp/app-release-rust-jni_out_bm5NF/lib/x86/libandroidx.graphics.path.so: ALIGNED (2**14)
/tmp/app-release-rust-jni_out_bm5NF/lib/armeabi-v7a/libandroid_rust_jni.so: UNALIGNED (2**12)
/tmp/app-release-rust-jni_out_bm5NF/lib/armeabi-v7a/libandroidx.graphics.path.so: ALIGNED (2**14)
Found 2 unaligned libs (only arm64-v8a/x86_64 libs need to be aligned).エミュレーターで試せるらしい。
起動できた。
逆に16KB ページサイズに対応してないと以下のような例外で落ちる。
FATAL EXCEPTION: main
Process: io.github.takusan23.androidrustjni, PID: 16320
java.lang.UnsatisfiedLinkError: dlopen failed: empty/missing DT_HASH/DT_GNU_HASH in "/data/app/~~S5iS_B60dhn6WlqTEzvegg==/io.github.takusan23.androidrustjni-HG0y1lLFYvVg6MvQNC3k2g==/lib/x86_64/libandroid_rust_jni.so" (new hash type from the future?)
at java.lang.Runtime.loadLibrary0(Runtime.java:1081)
at java.lang.Runtime.loadLibrary0(Runtime.java:1003)
at java.lang.System.loadLibrary(System.java:1765)
at io.github.takusan23.androidrustjni.MainActivity.<clinit>(MainActivity.kt:42)
at java.lang.Class.newInstance(Native Method)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)
at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:44)
at android.app.Instrumentation.newActivity(Instrumentation.java:1448)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3941)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4235)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:112)
at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:174)
at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:109)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:81)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2636)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loopOnce(Looper.java:232)
at android.os.Looper.loop(Looper.java:317)
at android.app.ActivityThread.main(ActivityThread.java:8705)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886)で書かれてる通り、16KB ページサイズでビルドした共有ライブラリは4KB デバイスでも動くそうな。
一応古い端末を起動して試してみたけど、Galaxy S7 Edge(Snapdragon 820 (64bit) / Android 7)で起動できた。16KB ページサイズの.soに置き換えるで問題なさそう。
おわりです。お疲れ様でした。888