Android15で追加される16KBページサイズの対応について詳しくみていく

みなさん、こんにちは。kokadaと申します。
現在、案件ではAndroidアプリの保守に関わっており、そこで今回のタイトルにもある16KB対応についてしらべたので共有します。
おそらくですが、こちらはAndroid 15ですぐに影響が出るものではなくAndroid 16で対応必須になってくるような項目になるかなと思っています。
ただ、Android 16のリリースが早まることもあり、早めに調査しておいて良い項目だと思うのでぜひみなさん確認してみてください。
公式情報は[こちら](https://developer.android.com/about/versions/15/behavior-changes-all?_gl=1*qq85ys*_up*MQ..*_ga*MjA1OTU5ODk2Ny4xNzI0NDY1NTY1*_ga_6HH9YJMN9M*MTcyNDQ2NTU2NC4xLjAuMTcyNDQ2NTU2NC4wLjAuMA#16-kb)

# 16KBページサイズとは？

Android 15からOS側でページサイズが16KBに対応されることになりました。
では、16KBページサイズになると何が嬉しいのかというと、公式は以下のように述べています。

16KBに対応する理由は性能向上が見込めるため
- システムがメモリ不足の状況にあるときのアプリの起動時間が短縮: 平均で 3.16% 短縮され、テストした一部のアプリでは大幅な改善（最大 30%）を達成
- アプリ起動時の消費電力の削減: 平均 4.56% を削減
- カメラの起動の高速化: ホットスタートが平均 4.48% 高速化、コールド スタートが平均 6.60% 高速化
- システムの起動時間の改善: 平均 1.5%（約 0.8 秒）改善

というふうになっています。
iOSではすでに対応済みなのですが、やはり端末ごとにCPUやメモリサイズが異なることなどの要因から対応が遅くなっていましたが、ついに16KB対応に踏み切ったということになります。

では、16KB対応というのはOSベースのものになり、4KBにしか対応していないアプリを16KB環境では動作できません。
そのため、16KB対応完了版のAndroid 15がinstallされた端末では対応が完了していない4KB対応のアプリは起動時にクラッシュが発生します。

## 16KB対応が必要かどうかチェックする方法

じつは通常のAndroidアプリではあまり対応は多くありません。
すべてのライブラリや SDK を含め、Java プログラミング言語または Kotlin で記述されたコードのみを使用しているアプリの場合、すでに 16 KB のデバイスをサポートしています。
Android 15 SDKをセットアップしてAndroid Studio等でビルドすれば、それでアプリ側としては完了します。
他に対応する項目としては、利用している**ライブラリ**になります。

ライブラリ側でネイティブのコードで書かれている場合、ライブラリ側で対応が必要になります。
またndkを用いてビルドを行っていたりする場合も対応が必要になります。
ただ、利用しているライブラリ一つ一つを確認するのは手間がかかるため、公式が確認するための[スクリプト](https://developer.android.com/guide/practices/page-sizes?_gl=1*a7lgi3*_up*MQ..*_ga*MzMwMTU0MzEyLjE3MzMwMjU2MTk.*_ga_6HH9YJMN9M*MTczMzAyNTYxOS4xLjAuMTczMzAyNTYxOS4wLjAuMTM0MjU1NzIyMQ..#alignment-use-script)を用意してくれています。

こちらを利用して以下のように実行すると出力結果が得られます。

手元で実装しているMAUIを用いてビルドしたアプリで試してみました。
```
$ unzip APK_NAME.apk -d /tmp/my_apk_out
$ alignment.sh /tmp/my_apk_out | grep "arm64-v8a"
/tmp/my_apk_out/lib/arm64-v8a/libSystem.Native.so: \e[31mUNALIGNED\e[0m (2**12)
/tmp/my_apk_out/lib/arm64-v8a/librealm-wrappers.so: \e[31mUNALIGNED\e[0m (2**12)
/tmp/my_apk_out/lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so: \e[31mUNALIGNED\e[0m (2**12)
/tmp/my_apk_out/lib/arm64-v8a/libmonosgen-2.0.so: \e[31mUNALIGNED\e[0m (2**12)
/tmp/my_apk_out/lib/arm64-v8a/libSkiaSharp.so: \e[31mUNALIGNED\e[0m (2**12)
/tmp/my_apk_out/lib/arm64-v8a/libHarfBuzzSharp.so: \e[31mUNALIGNED\e[0m (2**12)
/tmp/my_apk_out/lib/arm64-v8a/libSystem.IO.Compression.Native.so: \e[31mUNALIGNED\e[0m (2**12)
```

というように出力が得られます。
ここをみてみると、UNALIGNEDという言葉が出ています。
ここが全てALIGNEDになっていれば対応として完了になります。

別の方法としては[ApkAnalyzerを利用して確認する方法](https://developer.android.com/guide/practices/page-sizes?_gl=1*1va3mue*_up*MQ..*_ga*MzMwMTU0MzEyLjE3MzMwMjU2MTk.*_ga_6HH9YJMN9M*MTczMzAyNTYxOS4xLjAuMTczMzAyNTYxOS4wLjAuMTM0MjU1NzIyMQ..#identify-native-code)がありますが、コレだと対応済みかどうかはわからないので一つずつみていく必要があります。
なので、上記の方法がおすすめです。

## 対応が必要なライブラリが見つかった場合

対応が必要なライブラリがちゃんと保守されているのであれば問題ないのですが、長くメンテナンスされていないようなライブラリ等を利用しているのであれば、こちらでFork等を行なってメンテナンスを行うか、代替ライブラリを探す必要が出てきます。
基本的な対応としては、ライブラリをアップデートしてみて対応が完了しているのか確認しましょう。
もし対応しているのであればそれで問題ありません。

もし、自分たちでネイティブを使ったライブラリを作成しているのであれば、ビルドの設定を変更することで改善できます。
ndkを利用しているものに関しては、ビルド時に設定を追加すればOKです。

ndk27以上はサポートされているので、
**APP_SUPPORT_FLEXIBLE_PAGE_SIZES**
をtrueにするだけでOK 

ndk26以下は
**max-page-size=16384**
に設定すればOK

他にチェックする項目としては以下の二つになります。
#### ページサイズをハードコーディングしている場合
過去の実装でページサイズを指定しているような場所がある場合に、4096とハードコーディングしている箇所を探し、それをPAGE_SIZEを参照するように修正しましょう。

#### mmap()関数を実行している箇所の実装を確認・見直しを行う
mmapは動作時にメモリ量を指定する箇所があるが、そこをMAP_FIXEDに指定されているかどうかを確認する。
指定せずに利用する場合がある場合は別のものへの置き換えを検討する必要があります。


## 16KB環境で動作確認する方法

現在公式が要している環境は以下の四つがメインです。

[エミュレータで16KBに対応したAndroid 15を動かす](https://developer.android.com/guide/practices/page-sizes?_gl=1*hyl61u*_up*MQ..*_ga*MzMwMTU0MzEyLjE3MzMwMjU2MTk.*_ga_6HH9YJMN9M*MTczMzAyNTYxOS4xLjAuMTczMzAyNTk5OS4wLjAuMTM0MjU1NzIyMQ..#16kb-emulator)
[16 KB ページサイズの Cuttlefish を動かす](https://source.android.com/docs/core/architecture/16kb-page-size/getting-started-cf-arm64-pgagnostic?hl=ja)
[Pixel6, pixel6 proに16KBのイメージを入れて動かす](https://source.android.com/docs/core/architecture/16kb-page-size/flash-pixel6-with-16kb-kernel?hl=ja)(おすすめしない)
[pixel 8, pixel 8 pro で最新版Android 15で動作確認](https://android-developers.googleblog.com/2024/08/adding-16-kb-page-size-to-android.html)(おすすめ)

私が手元でpixel6にフラッシュした場合は一日程度で文鎮化してしまいました...。
なので、どうしても実物の端末で動作確認したい場合はpixel 8を利用するのが良いと思います。

現在利用している端末がちゃんと16KBに対応しているか確認する場合は以下のコマンドを実行してみてください。

4KBの場合は
```
$ adb shell getconf PAGE_SIZE
4096
```

16KBの場合は
```
$ adb shell getconf PAGE_SIZE
16384
```

となります。
Pixel8等で動作確認をしていた場合にちゃんと変更したのに反映されていない場合があったので、念のためにこちらのコマンドを実行することが良いと思います。

## リリースするアプリが4KB版16KB版二つ出す必要があるのか？

ここが個人的に結構気になっていた箇所です。
16KB版が4KB端末で動作しないことは確認していましたが、16KB対応したアプリが4KBで問題なく動作するのかという点です。
私の手元で確認したところ、ここは動作していました。
そのため、16KB一つリリースすれば問題ありません。
公式にも以下の記述がありました。

>...applications and SDKs have been built with 4 KB page size in mind, they need to be re-aligned to 16 KB so the binaries are compatible with both 4 KB and ...

## まとめ

通常のAndroidアプリであればそこまで大きな変更は必要ないです。
なので、念のために今のうちにチェックをしておきましょう！
もし、クロスプラットフォーム(MAUI, Flutterなど)を利用している場合はライブラリ等の対応もあるので、アップデートやライブラリの置き換え検討など含めて早めに動いておくことをお勧めします！

## 追記

Android 16から16KBページサイズは標準搭載になるようです。
しかし、Android側で互換モードを準備しているようです。
なので、対応が遅れたといえど、すぐにユーザに影響が出ることはなさそうです。
https://developer.android.com/about/versions/16/behavior-changes-all?hl=ja#16-kb-compatibility-mode
4KBのアプリは警告が出てしまいますが、それを出ないように対応することはできるので、対応に時間がかかる場合はそちらで一時対応するのは良いと思います。

## 追記2

https://android-developers.googleblog.com/2025/05/prepare-play-apps-for-devices-with-16kb-page-size.html
こちらのブログ内で、11/1までに対応必須という風に明言されました。

> Starting November 1st, 2025, all new apps and updates to existing apps submitted to Google Play and targeting Android 15+ devices must support 16 KB page sizes.