🐕

Flutterアプリを Android15 / 16kb page size 環境で動かしたらどうなるのか

2024/09/25に公開

Android15端末から、16kb page size環境といわれる、OSが管理するメモリの単位サイズが従来の4kbより大きくなる端末が出ます。

Flutterアプリの場合、どのような影響があるのでしょうか。

16kb page sizeの概要

Android15から、OSのメモリ管理の単位(ページサイズ)が4kbだったのが、16kbに切り替えられる。
それによりアプリの起動時間などのシステムパフォーマンスが向上する(らしい)。
https://developer.android.com/guide/practices/page-sizes

アプリが影響を受けるのは、ネイティブコード(C/C++)を使用しているときです。apkを解凍したときに、共有ライブラリ(.so)として出力されているものが影響を受けます。

Flutterの場合

Flutterはネイティブコードを使用しているので影響を受けそうですが、以下issueでは、次の理由により問題ないそうです。

  • libflutter.so は16kb対応されてた
  • 16kb環境のエミュレータ (Google APIs Experimental 16k Page Size ARM 64 v8a System Image) で動かしても問題なかった

https://github.com/flutter/flutter/issues/150168

具体的に16kb対応しない場合にどのような影響があるのかというと、 試したところインストールすらできなくなりました。

実際に確かめてみましょう。

共有ライブラリ(.so)が16kb対応されているか確認

まずは、共有ライブラリ(.so)が16kb対応されてるか見ます。apkファイルを解凍すると、libフォルダがあるので、そちらに以下のスクリプト(上記リファレンスをご参考)を実行します。

alignment.sh

macで実行するので文字色を変更するコードを少し変更しています。

#!/bin/bash

# usage: alignment.sh path to search for *.so files

dir="$1"

RED="\033[0;31m"
GREEN="\033[0;32m"
ENDCOLOR="\033[0m"

matches="$(find $dir -name "*.so" -type f)"
IFS=$'\n'
for match in $matches; do
    res="$(objdump -p ${match} | grep LOAD | awk '{ print $NF }' | head -1)"
    if [[ $res =~ "2**14" ]] || [[ $res =~ "2**16" ]]; then
        echo -e "${match}: ${GREEN}ALIGNED${ENDCOLOR} ($res)"
    else
        echo -e "${match}: ${RED}UNALIGNED${ENDCOLOR} ($res)"
    fi
done
実行結果
lib/arm64-v8a/libflutter.so: ALIGNED (2**16)
lib/arm64-v8a/libnative-jpeg.so: UNALIGNED (2**12)
lib/arm64-v8a/libVkLayer_khronos_validation.so: ALIGNED (2**16)
lib/arm64-v8a/libpl_droidsonroids_gif.so: UNALIGNED (2**12)
lib/arm64-v8a/libimage_processing_util_jni.so: UNALIGNED (2**12)

たしかに libflutter.so は大丈夫そうだけど、UNALIGNEDとなっていて16kb未対応のものもありそうです...。と、とにかく、動かして見ましょう。

16kb環境で動くか

起動すらしない。
試した環境は以下

エラーログは以下。

Launching lib/main.dart on sdk gphone16k arm64 in debug mode...
✓ Built build/app/outputs/flutter-apk/app-debug.apk
Error: ADB exited with exit code 1
Performing Streamed Install

adb: failed to install path/to/build/app/outputs/flutter-apk/app-debug.apk: Failure [INSTALL_FAILED_INVALID_APK: INSTALL_FAILED_INVALID_APK: Failed to extract native libraries, res=-2]
Error launching application on sdk gphone16k arm64.

環境はAGP(Androidアプリをビルドするためのプラグイン)のバージョンが 7.3.0 ですが、
リファレンスによると 8.5.1 以上で何も変更なしでビルドOKとのことなので、当たり前の結果かと思いました...

念の為 zipalign でapkファイルを確認。

zipalign
~/Library/Android/sdk/build-tools/35.0.0/zipalign -c -P 16 -v 4 build/app/outputs/flutter-apk/app-debug.apk
...
24760320 lib/arm64-v8a/libVkLayer_khronos_validation.so (BAD - 4096)
37965824 lib/arm64-v8a/libflutter.so (BAD - 4096)
77721600 lib/arm64-v8a/libimage_processing_util_jni.so (BAD - 12288)
77754368 lib/arm64-v8a/libnative-jpeg.so (BAD - 12288)
77987840 lib/arm64-v8a/libpl_droidsonroids_gif.so (OK)
...
Verification FAILED

しっかり FAILED とでてます。

そこで、リファレンスに記載の以下の対応を入れてリトライ。

build.gradle(app)
android {
    // ...
    packagingOptions {
        jniLibs {
            useLegacyPackaging true
        }
    }

...起動した!

zipalign
~/Library/Android/sdk/build-tools/35.0.0/zipalign -c -P 16 -v 4 build/app/outputs/flutter-apk/app-debug.apk
...
43482514 lib/x86_64/libflutter.so (OK - compressed)
59375423 lib/x86_64/libimage_processing_util_jni.so (OK - compressed)
59397614 lib/x86_64/libnative-jpeg.so (OK - compressed)
59486515 lib/x86_64/libpl_droidsonroids_gif.so (OK - compressed)
Verification succesful

succesful とあり、大丈夫そうです。

疑問

起動したapkに含まれる共有ライブラリ(.so)に対して、もう一度 alignment.sh を実行してしてみたところ、結果は変わらず UNALIGNED が含まれている理由がわかりませんでした... 🤔

lib/arm64-v8a/libflutter.so: ALIGNED (2**16)
lib/arm64-v8a/libnative-jpeg.so: UNALIGNED (2**12)
lib/arm64-v8a/libVkLayer_khronos_validation.so: ALIGNED (2**16)
lib/arm64-v8a/libpl_droidsonroids_gif.so: UNALIGNED (2**12)
lib/arm64-v8a/libimage_processing_util_jni.so: UNALIGNED (2**12)

Discussion