古いバージョンである Android 5.1(API レベル 22 / armeabi-v7a)を、Ubuntu 上のエミュレータで実行する手順をまとめました。
経緯
検証の都合で、古い Android アプリを動かす必要が生じることがあります。しかも、そのアプリのライブラリのフォルダには 32 ビットの ARM バイナリのみが入っているような状況の場合、手軽に動作させる環境として Android のエミュレータが候補に挙がります。
そういったアプリを動かす Android エミュレータの環境として、本記事では system-images;android-22;default;armeabi-v7a のシステムイメージを動かすことにします。android-22 は API レベル 22 を意味しているので、Android 5.1 ということになります。
これを現時点で最新の Android エミュレータ(36.x 系)で動作させようとすると以下のエラーが発生して動きません。
FATAL | CPU Architecture 'arm' is not supported by the QEMU2 emulator, (the classic engine is deprecated!)
したがって動作させるにはある程度古い Android エミュレータが必要になります。試したところ Ubuntu の apt コマンドでインストールされる Android エミュレータでは動作することが確認できたため、本記事ではその手順をまとめます。
使用した環境
Ubuntu 24.04.3 LTS (CPU は x86_64)
手順
apt によるパッケージのインストール
sudo apt install google-android-cmdline-tools-13.0-installer google-android-emulator-installer android-sdk-platform-23 android-sdk-platform-tools-common adb
これを実行することで、後続の手順で使用するコマンドがインストールされます。インストールされた emulator コマンドのバージョンを確認したところ、34.1.19.0 でした。
sdkmanager コマンドによる Android SDK のパッケージのインストール
sudo sdkmanager "system-images;android-22;default;armeabi-v7a" "system-images;android-22;google_apis;armeabi-v7a"
後述しますが、本記事で動かす対象とした system-images;android-22;default;armeabi-v7a はそのまま動かそうとするとエラーが発生します。そのエラーを回避するために必要な system-images;android-22;google_apis;armeabi-v7a もインストールしています。(文字がだいぶ似ていますが、default と google_apis の部分が違います。google_apis の方には Google Play サービスなどの Google 独自コンポーネントが含まれています。)
また、今回の手順では sdkmanager コマンドによるファイルの展開先が /usr/lib/android-sdk/ 以下であるようなので sudo をつけて実行しています。
avdmanager コマンドによる Android Virtual Device(AVD)の作成
avdmanager create avd -n test -k "system-images;android-22;default;armeabi-v7a" -d "Nexus 7 2013"
この例では test という名前で AVD を作成しています。
emulator コマンドによるエミュレータの起動
emulator @test -selinux disabled
発生するエラーと解消方法
上記のコマンドを実行すると、以下のようなエラーが発生します。
ERROR | This AVD's configuration is missing a kernel file! Please ensure the file "kernel-ranchu" is in the same location as your system image.
kernel-ranchu というファイルが足りないエラーが発生しています。kernel-ranchu は Android エミュレータ用の Linux カーネルイメージです。対処として、該当ファイルを system-images;android-22;google_apis;armeabi-v7a の方からコピーしてくるとこのエラーが回避できます。
sudo cp /usr/lib/android-sdk/system-images/android-22/google_apis/armeabi-v7a/kernel-ranchu /usr/lib/android-sdk/system-images/android-22/default/armeabi-v7a/
(コピーする代わりに、emulator コマンドの -kernel オプションで指定することも可能です。)
その後 emulator コマンドを再度実行することで、エミュレータの起動に成功しました。あとは apk ファイルをインストールして起動すれば目的が達成できます。
おまけ
動かしたい Android アプリがシステムユーザー権限を要求している場合、つまり AndroidManifest.xml ファイルに以下の記述がある場合はインストールするためにもう少し作業が必要です。
android:sharedUserId="android.uid.system"
このユーザーは特別な権限を持つため、apk が Android のプラットフォーム署名鍵で署名されている必要があります。今回エミュレータで動作させた system-images;android-22;default;armeabi-v7a については、プラットフォーム署名鍵が公開されており、以下の URL から入手できます。
https://android.googlesource.com/platform/build/+/master/target/product/security/
platform.pk8 と platform.x509.pem が該当ファイルです。署名は apksigner コマンドで行えます。
apksigner sign --key platform.pk8 --cert platform.x509.pem target.apk
動かしたい apk ファイルの署名がもともとの署名から変わってしまうことを許容できるのであれば、この方法によって署名した apk ファイルをインストールすることができます。
おまけ2
本記事の手順では SELinux を無効にする指定(-selinux disabled)をしています。この指定を外してエミュレータを起動すると、エラーが発生して期待動作をしません。logcat を確認すると以下のエラーが繰り返し出力されており、処理が先に進まない状態になっているようです。
E/SurfaceFlinger( 896): hwcomposer module not found
E/SurfaceFlinger( 896): ERROR: failed to open framebuffer (I/O error), aborting
F/libc ( 896): Fatal signal 6 (SIGABRT), code -6 in tid 896 (surfaceflinger)
I/DEBUG ( 644): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( 644): Build fingerprint: 'Android/sdk_phone_armv7/generic:5.1.1/LMY48X/3079158:userdebug/test-keys'
I/DEBUG ( 644): Revision: '0'
I/DEBUG ( 644): ABI: 'arm'
I/DEBUG ( 644): pid: 896, tid: 896, name: surfaceflinger >>> /system/bin/surfaceflinger <<<
I/DEBUG ( 644): signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
I/DEBUG ( 644): r0 00000000 r1 00000380 r2 00000006 r3 00000000
I/DEBUG ( 644): r4 b6f95e38 r5 00000006 r6 00000002 r7 0000010c
I/DEBUG ( 644): r8 ffffffc4 r9 b648b158 sl 00000000 fp bef2fb7c
I/DEBUG ( 644): ip 00000380 sp bef2f998 lr b6ef2745 pc b6f15710 cpsr 60000010
I/DEBUG ( 644):
I/DEBUG ( 644): backtrace:
I/DEBUG ( 644): #00 pc 00039710 /system/lib/libc.so (tgkill+12)
I/DEBUG ( 644): #01 pc 00016741 /system/lib/libc.so (pthread_kill+52)
I/DEBUG ( 644): #02 pc 0001735f /system/lib/libc.so (raise+10)
I/DEBUG ( 644): #03 pc 00013b39 /system/lib/libc.so (__libc_android_abort+36)
I/DEBUG ( 644): #04 pc 00012f18 /system/lib/libc.so (abort+4)
I/DEBUG ( 644): #05 pc 000214ff /system/lib/libsurfaceflinger.so
I/DEBUG ( 644): #06 pc 00017841 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::init()+104)
I/DEBUG ( 644): #07 pc 00000af1 /system/bin/surfaceflinger
I/DEBUG ( 644): #08 pc 00012dc9 /system/lib/libc.so (__libc_init+44)
I/DEBUG ( 644): #09 pc 00000c08 /system/bin/surfaceflinger
試行錯誤したところ、-ramdisk オプション で system-images;android-22;google_apis;armeabi-v7a 側のramdisk.img を参照させることでこの問題を回避して動作させることができました。
emulator @test -ramdisk /usr/lib/android-sdk/system-images/android-22/google_apis/armeabi-v7a/ramdisk.img
おわりに
古いバージョンの Android を動かしたい状況はあまり起きないことだとは思いますが、同様の環境を構築する際の参考になれば幸いです。