노트북에서 안드로이드 게임 돌리기

Shovel, Game

계기

저는 뱅드림을 픽셀3a로 플레이하고 있는데, 매번 플레이할 때마다 노트가 씹히는 문제도 있고, 새로 나온 프로젝트 세카이를 플레이 하고 싶어도 폰의 용량이 부족해 플레이하지 못하는 문제가 있어 아이패드를 살까 고민했었습니다.

하지만, 아이패드의 비싼 가격을 보고서는 터치가 되는 노트북에서 안드로이드 게임을 돌릴 수만 있다면 괜찮지 않을까? 생각을 하게 되었습니다.

결론부터 말씀드리자면 성공하였고, 굉장히 빠릿빠릿하게 돌아갑니다. 하지만 프로젝트 세카이를 돌리는 것에는 실패하였고, 그 이유와 해결방법에 대해서는 후술하겠습니다.

시행착오

주의: 다음 내용들은 제가 하다가 이것으로는 도저히 불가능하다고 생각했던 것들입니다.

빠르게 결론을 보시고 싶으신 분들은 다음 단락으로 넘어가주시기 바랍니다.

Anbox 사용

불가능하다고 생각했던 이유: 너무 불안정해 앱이 제대로 동작하지 않았습니다.

먼저 가장 처음 생각한 방법은 Anbox를 사용하는 것이었습니다. snap을 이용해서 설치하는 걸 권장하던데, 어차피 snap으로 설치하더라도 커널 리빌드는 해줘야하고 저는 개인적으로 snap을 좋아하지 않기 때문에 AUR을 통해 설치했습니다.

커널 리빌드

우선 저는 Arch Build System 에 따라 커널을 재빌드해야만 했습니다.

먼저, 다음 명령어를 통해 패키지를 가져왔고

$ cd ~
$ mkdir build && cd build
$ asp update linux
$ asp export linux

PKGBUILD 파일을 열어서 pkgbase=linux-anbox 라 수정한 후에 docs 생성하는 부분을 다 빼줬습니다.

그리고 나서, config 파일을 열어서 다음과 같이 써줬습니다.

#
# Android
# 
CONFIG_ASHMEM=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ANDROID_BINDERFS=y
CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder"
# end of Android

그 후에 $ updpkgsums를 실행하시고, gpg key를 가져오셔야 합니다. 저는 다음과 같이 가져왔습니다.

$ gpg --keyserver hkp://keys.gnupg.net --recv ABAF11C65A2970B130ABE3C479BE3E430041188
$ gpg --keyserver hkp://keys.gnupg.net --recv 647F28654894E3BD457199BE38DBBDC86092693E
$ gpg --keyserver hkp://keys.openpgp.org --recv A2FF3A36AAA56654109064AB19802F8B0D70FC30

끝으로, 다음 명령으로 커널을 빌드, 설치 후에 Grub까지 업데이트하고 리부팅 했습니다.

$ MAKEFLAGS="-j$(nproc)" makepkg -s
$ sudo pacman -U linux-anbox-5.8.6.arch1-1-x86_64.pkg.tar.zst linux-anbox-headers-5.8.6.arch1-1-x86_64.pkg.tar.zst
$ sudo grub-mkconfig -o /boot/grub/grub.cfg

리부팅 후에 다음 명령어들이 제대로 성공하면 됩니다.

$ ls -1 /dev/ashmem
$ sudo mkdir /dev/binderfs
$ sudo mount -t binder binder /dev/binderfs

아치위키 Anbox 항목Kernel/Arch Build System 항목을 따라하시면 간단히 될 것이라 생각됩니다.

anbox 실행

저는 yay를 사용하기 때문에, $ yay -S anbox-git anbox-image-gapps 명령어로 anbox를 설치했습니다.

이대로 켜면 네트워크가 안되기 때문에 따로 브릿지를 생성해줘야 하는데, 저와 같은 경우는 NetworkManager를 사용하기 때문에 다음 명령어로 브릿지를 생성했습니다.

$ nmcli con add type bridge ifname anbox0 -- connection.id anbox-net ipv4.method shared ipv4.addresses 192.168.250.1/24

이후에 $ sudo systemctl restart anbox-container-manager.service 명령어로 서비스를 다시 켜고 anbox를 실행시키시면 됩니다.

하지만 슬프게도 설정앱부터 튕기는 등 불안한 증세를 많이 보였습니다. 따라서 저는 이 방법을 포기했습니다.

Android-x86 Live 사용

불가능하다고 생각했던 이유: 불가능까지는 아니었던 것 같지만  다른 디바이스에 데이터를 저장할 바에는 OS까지 같이 거기에 저장하는게 나을 것 같아서였습니다.

그 다음으로 생각해낸 방법은 Android-x86이었습니다. 하지만, 설치하기에는 많은 부담이 있었던지라 같은 파티션을 사용해서 해보려고 했습니다. 이를 위해 저는 공식 Android-x86 사이트로부터 android-x86-9.0-r2.x86_64.rpm 을 받았습니다.

이후에, $ rpm2cpio android-x86-9.0-r2.x86_64.rpm > android-x86-9.0-r2.x86_64.cpio명령을 실행해서 cpio 파일로 변환한 후에 내용물을 까보았습니다. 이거면 직접 해볼만하겠다 싶어서 해당 파일들을 전부 /Android-x86로 옮겼습니다.

다음과 같은 폴더구조가 되었습니다.

/Android-x86/
└ android-9.0-r2/
 ├ initrd.img
 ├ kernel
 ├ system.sfs
 └ ...

그리고 /etc/grub.d/40_custom 에 다음과 같은 엔트리를 추가해주었습니다.

menuentry "Android" {
	insmod part_gpt
	search --file --no-floppy --set=root /android-x86/android-9.0-r2/system.sfs
	linux /android-x86/android-9.0-r2/kernel quiet root=/dev/ram0 androidboot.hardware=remix_x86_64 androidboot.selinux=permissive SRC=/android-x86/android-9.0-r2
	initrd /android-x86/android-9.0-r2/initrd.img
}

하지만 grub-mkconfig -o /boot/grub/grub.cfg를 실행시키고 재부팅해보니 슬프게도 부팅애니메이션에서 넘어가지 않았습니다. 원인은 여러가지 있을 것 같은데, Grub 설정이 잘못됐을 수도 있었던 거 같습니다.

하지만 결정적으로 저렇게 설치하게 되면 메모리에 저장하도록 마운트가 되고, 저걸 다른 디바이스로 바꿀 바에는 차라리 그 디바이스에 직접 설치하자는 생각을 해서 다른 방법을 선택하게 되었습니다.

사실 다 끝내고나서 생각한 거긴 한데 어떻게 img파일로 마운트를 잘 하면 가능할 법도 했던 것 같긴 하네요.

방법

그래서 다음과 같은 시행착오를 거친 후에 마지막으로 택한 방식이 직접 Android-x86을 설치하는 것이었습니다.

우선 가장 처음으로 파티션 확보를 먼저 했습니다. 마침 집에 미리 구워둔 우분투 부팅 USB가 있었던지라 GParted로 제 루트 파티션을 32기가 정도 축소시켜서 안드로이드 용으로 ext4 파티션을 하나 만들었습니다.

그 후에 $ sudo dd if=./android-x86_64-9.0-r2.iso of=/dev/(YOUR-DEVICE-HERE) 명령어를 통해 다운받은 android-x86 이미지를 USB에 구웠습니다.

그리고 Android-x86 Installation 과 같이 생긴 항목으로 들어가서 아까 전에 만든 파티션을 눌러 설치했습니다.

Grub을 설치하겠냐는 다이얼로그도 나왔던 거 같은데, 이미 제 컴퓨터에 Grub이 설치돼있어서 설치하지 않았고, 대신에 다시 아치리눅스로 부팅해서 엔트리를 하나 추가시켜줬습니다.

menuentry "Android" {
	insmod part_gpt
	search --file --no-floppy --set=root /android-9.0-r2/kernel
	linux /android-9.0-r2/kernel quiet SRC=/android-9.0-r2
	initrd /android-9.0-r2/initrd.img
}

다시 grub-mkconfig를 돌리고 부팅했더니 성공하였습니다. 하지만, 그럼에도 여러가지 문제가 남아있었고 해당 문제를 해결한 방법들을 서술하도록 하겠습니다.

문제해결

네이티브 앱에서 "앱이 중단되었습니다."

우선, 뱅드림을 다운받고 켜보니 "앱이 중단되었습니다." 만 표시되었습니다. 로그캣을 열어보니 유니티에서 x86의 지원을 중단한 것이 문제였습니다. 당연히도 제 컴퓨터는 x86_64이기 때문에 ARM 타겟으로만 컴파일된 앱을 실행할 수 없었습니다.

다행히도, 이를 해결하기 위해 libhoudini라는 번역 라이브러리가 있었고 android-x86도 이를 열심히 지원하고 있었습니다. 설정에서 "Enable Nativebridge" 를 체크하면 되는데, 열심히에 취소선을 친 이유는 이를 지원하는 스크립트와 미러에 문제가 있어 제대로 작동하지 않았기 때문입니다.

실제로 저 옵션을 체크하면 /storage/emulated/0/arm에 제대로된 파일이 아닌 이상한 중국어가 적힌 html만 받아집니다. 그 html에 적힌 링크에서 받을 수도 있었지만, 너무 느려서 저는 이 곳에서 받았습니다. houdini9_y.sfs

저 파일이 마운트되어 작동을 하는 방식인데, 해당 파일을 받고 이를 /system/etc/houdini9_y.sfs에 위치시키시고 root:root로 chown 돌리신 후에 /system/bin/enable_nativebridge를 실행시키시고 재부팅하시면 됩니다.

그러나, 이렇게 할 경우에는 프로젝트 세카이는 돌아가지 않습니다. 그 이유는 y로 끝나는 후디니 버전에서는 arm64-v8a가 지원되지 않기 때문인데, 이를 위해서는 z로 끝나는 버전이 필요합니다. 그러나 어디에서도 이 파일을 구할 수 없었습니다. 검색을 해본 결과 크롬OS에서 추출한 파일인 듯 합니다. 참조 링크 1 참조 링크 2

+ 12/20: 안드로이드 9 버전에서도 이제 x86_64가 지원되게 되었습니다.
후속 글

android-x86 구글 그룹을 뒤져본 결과 해당 파일을 가지고 있는 크롬OS가 아직 배포된 게 없어서 못 구하고 있는 듯 합니다. 따라서, 안드로이드 7.0을 다시 설치하고 이 곳에서 houdini7_z.sfs를 구하고 build.prop을 수정해서 ro.product.cpu.abilistro.product.cpu.abilist64arm64-v8a를 추가하시면 됩니다.

하지만 저는 일단 뱅드림이 돌아가는 것만으로 감사하기 때문에 하지 않았습니다.

타 OS 루트 디렉토리 소유자가 1023:1023

주의

이 내용은 저와 같이 리눅스를 USB와 같은 "제거 가능한 미디어"에 설치하신 분만 해당됩니다.
이 방법을 사용하시면 문제는 해결되는 대신 USB와 같은 미디어 자동 마운트가 작동하지 않게 됩니다.

제가 안드로이드로 부팅후에 아치리눅스로 부팅했더니 X11이 동작하지 않았습니다. 일단 놀라서 부팅 옵션에 nomodeset을 주고 부팅 후에 tty에 접근해서 뭐가 문제인지 journalctl을 분석해본 결과 조금 충격적인 일이 벌어졌습니다.

문제는 제 아치리눅스가 메인OS임에도 외장 SSD에 깔려있었고, 안드로이드가 이를 제거 가능한 미디어로 인식해서 마운트 후에 루트 디렉토리의 소유자를 1023:1023 으로 바꾼 것이었습니다. 루트 디렉터리에서 $ chown root:root . 를 입력한 후에 다시 부팅했더니 정상적으로 부팅되었습니다.

하지만 이와 같은 일이 벌어지지 않게 하기 위해서는 vold의 설정을 조금 조정해서 장치가 연결돼도 자동으로 마운트하지 않게 만들어줘야 합니다. 다음 글을 참고해서 하였습니다.

우선 ramdisk.img를 수정해야 합니다. 첫번째로 android-x86을 설치한 드라이브를 마운트 한 후에 android-9.0-r2/ramdisk.img를 복사해옵니다. 그 후에 다음과 같은 명령어로 cpio + gz를 분해하면 됩니다.

$ mkdir ramdisk
$ cd ramdisk
$ zcat ../ramdisk.img | cpio -idmv

그리고 fstab.android_x86_64파일을 수정해서 다음과 같이 3번째 줄부터 모두 주석처리해주시면 됩니다.

none			/cache		tmpfs	nosuid,nodev,noatime	defaults

# /devices/*/block/sr*		auto	auto	defaults		voldmanaged=cdrom:auto
# /devices/*/usb*/*		auto	auto	defaults		voldmanaged=usb:auto,encryptable=userdata
# /devices/*/mmc0:a*/*		auto	auto	defaults		voldmanaged=sdcard1:auto,encryptable=userdata
# /devices/*/*sdmmc*/*		auto	auto	defaults		voldmanaged=sdcard1:auto,encryptable=userdata
#
# ...

그 후에 다음 명령어로 다시 ramdisk.img를 만들어주시면 됩니다.

$ find . ! -name . | LC_ALL=C sort | cpio -o -H newc -R root:root | gzip > ../ramdisk-modified.img

새로 생성된 ramdisk-modified.img 를 android-x86이 설치된 드라이브의 android-9.0-r2/ramdisk.img로 복사하시면 됩니다. 이 전에 있던 파일을 백업해두시는 것을 권장드립니다.

결론

  1. 뱅드림은 정말 잘 됩니다.
  2. 64비트 ARM만 지원하는 게임을 하실 예정이시라면 후속 글을 참고해주세요.

여담

확실히 화면이 크니까 슬라이드 뭉게기도 힘들고, 대륙횡단 슬라이드도 틀리네요. 그래도 일단 터치 씹힘은 확실히 줄어들어서 너무 기분이 좋습니다.

두번째 여담으로, 일도리는 아쉽게도 조금의 문제가 있었습니다. 앱을 닫고 열 때마다 사용자 정보가 계속 날라가는 문제인데, 저도 어떻게 해결하지 못해서 구글 플레이랑 연동 후 시작할 때마다 데이터 불러오기를 통해 플레이하고 있습니다.