快轉到主要內容

ReDroid教學:用Docker跑Android系統,在x86電腦玩ARM手機遊戲

分類   Linux系統 虛擬機與容器技術
標籤   ReDroid Android Docker Linux Scrcpy
🗓️ 民國112年 癸卯年
✍ 切換正體/簡體字
目錄

English version

ReDroid (Remote anDroid) 是自架「雲手機」的方案,透過docker在電腦上跑Android系統容器,再利用Scrcpy的鏡射螢幕功能連線到Android桌面。

ReDroid也是在電腦上用開源軟體跑Android APP的解決方案。因為別說雲手機了,很多Android手遊模擬器都是閉源軟體哪。相較之下,ReDroid除了ARM轉譯器以外都是開源的。更棒的是ReDroid支援GPU加速+ARM轉x86的轉譯器,這樣就可以玩大多數手機3D遊戲了。

對Linux用戶來說,這更是除了 Waydroid和Android-x86以外,在Linux電腦高效率跑Android APP的方法。並且它比Waydroid更適合當作雲手機使用

參見 自架雲手機

本文將討論如何在x86架構的Linux電腦,用ReDroid玩ARM架構的手機遊戲。我們會在ReDroid映像檔加入ARM轉譯器+Google服務框架,以達成最佳使用體驗。

P.S. Windows和MacOS也可以用Docker跑ReDroid。

1. ReDroid需要用到的軟體
#

如果要用ReDroid玩手機遊戲,建議x86架構的電腦至少要有8GB以上RAM,因為有時ARM在轉譯成x86指令時會佔用大量RAM。

ReDroid在 Github上有各大Linux發行版的安裝說明,Windows的WSL請參考我寫的 這篇

  1. 由於我是Arch Linux,要更換核心為linux-zen。在安裝linux-zen核心之後,更新GRUB選項。重開機,在GRUB選單的Advanced Options選取以linux-zen核心開機。
# 如果有Nvidia驅動,記得將其換成DKMS版本
sudo pacman -R nvidia
sudo pacman -S nvidia-dkms
# 確認沒有安裝binder_linux-dkms
yay -R binder_linux-dkms

# 安裝linux-zen核心
sudo pacman -S linux-zen linux-zen-headers
sudo mkinitcpio -p linux-zen
sudo grub-mkconfig -o /boot/grub/grub.cfg
  1. 接著安裝 Docker,用於執行容器

  2. 安裝ADB和Scrcpy。Scrcpy現已包含傳輸音效的功能。

sudo pacman -S android-tools
sudo pacman -S scrcpy

* 想要整合按鍵映射的圖形化Scrcpy界面,可以改裝 QtScrcpy

2. 建立ReDroid虛擬機
#

僅Nvidia顯示卡需要,因Nvidia閉源驅動無法讓ReDroid使用GPU加速,需要跑一個QEMU虛擬機,再在裡面裝ReDroid透過Virtio-gpu達成硬體加速。不然的話ReDroid會走軟體渲染。

參考 在使用 NVIDIA 显卡时为 redroid 开启3d加速 redroid nVidia GPU support #282

  1. 下載Ubuntu 22.04 ISO,安裝QEMU + Virt Manager,建立一個64GB的Ubuuntu虛擬機
qemu-img create -f qcow2 ubuntu.qcow2 64GB
qemu-system-x86_64 -boot d -cdrom "ubuntu-22.04.1-desktop-amd64.iso" -enable-kvm -smp 4 -device intel-hda -device hda-duplex  -device virtio-vga-gl  -net nic -net user,hostfwd=tcp::5555-:5555    -cpu host  -m 4096  -display sdl,gl=on -hda ubuntu.qcow2
  1. 開機進虛擬機,然後再 裝Docker
qemu-system-x86_64 c  -enable-kvm -smp 4 -device intel-hda -device hda-duplex  -device virtio-vga-gl  -net nic -net user,hostfwd=tcp::5555-:5555    -cpu host  -m 4096  -display sdl,gl=on -hda ubuntu.qcow2

3. 啟動ReDroid
#

大部分電腦是x86架構,只能執行x86版的Android APP,然而很多手機遊戲只有ARM版,所以ReDroid需要ARM轉譯器。

Redroid作者發布的redroid:11.0.0-latestredroid:12.0.0-latest映像檔已內建Google開發的ARM轉譯器libndk,我試過只有Android 11比較穩定,Gapps也可以用,所以下面以Android 11為例。

  1. 建立存放資料的目錄,新增docker-compose
mkdir ~/redroid
cd redroid
vim docker-compose.yml
  1. 填入以下內容
version: "3"
services:
  redroid:
    image: redroid/redroid:11.0.0-latest
    stdin_open: true
    tty: true
    privileged: true
    ports:
      - "5555:5555"
    volumes:
    # 資料存放在目前目錄下
      - ./redroid-11-data:/data
    command:
    # 啟用GPU硬體加速
      - androidboot.redroid_gpu_mode=auto
    # 設定libndk相關
      - ro.product.cpu.abilist0=x86_64,arm64-v8a,x86,armeabi-v7a,armeabi
      - ro.product.cpu.abilist64=x86_64,arm64-v8a
      - ro.product.cpu.abilist32=x86,armeabi-v7a,armeabi
      - ro.dalvik.vm.isa.arm=x86
      - ro.dalvik.vm.isa.arm64=x86_64
      - ro.enable.native.bridge.exec=1
      - ro.dalvik.vm.native.bridge=libndk_translation.so
      - ro.ndk_translation.version=0.2.2
  1. 啟動服務
sudo docker compose up -d
  1. 用ADB連線至本機的ReDroid:
adb connect localhost:5555

# 如果連不上,用以下指令看一下容器內部發生什麼問題
sudo docker exec <容器ID> logcat
sudo docker logs <容器ID>
  1. 執行Scrcpy,連線到Android桌面:
scrcpy -s localhost:5555 --audio-codec=raw
  1. 這樣就會看到Android的桌面了。

4. 安裝Google服務框架
#

接下來我們要手動安裝Google服務框架。如果你覺得很麻煩請考慮使用 Remote-Android Script自動化安裝。


作者說Google服務框架是專有軟體無法內建,那麼就得自行安裝了。第一個方法是重新編譯映像檔,第二個是手動安裝OpenGApps。

不推薦第一個方法,耗時而且作者提供的GApps編譯教學又有其他APP偵測不到的問題。

這裡採用第二個方法:手動安裝,過程參考自: Install GApps Manually - Google Groups

  1. OpenGapps下載x86_64架構的Android 11 GApps,選擇最小化的pico版。

  2. 解壓縮,會看到以下目錄

open_gapps-x86_64-11.0-pico-20220503
├── Core
├── GApps
├── META-INF
├── Optional
  1. 在解壓縮的目錄open_gapps-x86_64-11.0-pico-20220503下面新增system目錄。

  2. 接著,將CoreGApps目錄裡面的.lz檔案都解壓縮,並將裡面的APK目錄按照對應的安裝目錄放到system目錄。例如GApps/googletts-x86_64/nodpi/app/下的GoogleTTS目錄要放到/system/app

  3. 放好之後,system下的目錄結構應該會長這樣:

system
├── app
│   ├── GoogleCalendarSyncAdapter
│   │   └── GoogleCalendarSyncAdapter.apk
│   ├── GoogleContactsSyncAdapter
│   │   └── GoogleContactsSyncAdapter.apk
│   ├── GoogleExtShared
│   │   └── GoogleExtShared.apk
│   └── GoogleTTS
│       └── GoogleTTS.apk
├── etc
│   ├── default-permissions
│   │   ├── default-permissions.xml
│   │   └── opengapps-permissions-q.xml
│   ├── permissions
│   │   ├── com.google.android.dialer.support.xml
│   │   ├── com.google.android.maps.xml
│   │   ├── com.google.android.media.effects.xml
│   │   ├── privapp-permissions-google.xml
│   │   └── split-permissions-google.xml
│   ├── preferred-apps
│   │   └── google.xml
│   └── sysconfig
│       ├── dialer_experience.xml
│       ├── google_build.xml
│       ├── google_exclusives_enable.xml
│       ├── google-hiddenapi-package-whitelist.xml
│       └── google.xml
├── framework
│   ├── com.google.android.dialer.support.jar
│   ├── com.google.android.maps.jar
│   └── com.google.android.media.effects.jar
├── priv-app
│   ├── AndroidAutoPrebuiltStub
│   │   └── AndroidAutoPrebuiltStub.apk
│   ├── AndroidMigratePrebuilt
│   │   └── AndroidMigratePrebuilt.apk
│   ├── CarrierSetup
│   │   └── CarrierSetup.apk
│   ├── ConfigUpdater
│   │   └── ConfigUpdater.apk
│   ├── GoogleBackupTransport
│   │   └── GoogleBackupTransport.apk
│   ├── GoogleExtServices
│   │   └── GoogleExtServices.apk
│   ├── GoogleFeedback
│   │   └── GoogleFeedback.apk
│   ├── GoogleOneTimeInitializer
│   │   └── GoogleOneTimeInitializer.apk
│   ├── GooglePackageInstaller
│   │   └── GooglePackageInstaller.apk
│   ├── GooglePartnerSetup
│   │   └── GooglePartnerSetup.apk
│   ├── GoogleRestore
│   │   └── GoogleRestore.apk
│   ├── GoogleServicesFramework
│   │   └── GoogleServicesFramework.apk
│   ├── Phonesky
│   │   └── Phonesky.apk
│   ├── PrebuiltGmsCore
│   │   └── PrebuiltGmsCore.apk
│   └── SetupWizard
│       └── SetupWizard.apk
└── product
    └── overlay
        └── PlayStoreOverlay.apk
  1. 執行以下指令取得root權限:
adb connect localhost:5555
adb -s localhost:5555 root
adb -s localhost:5555 remount
adb -s localhost:5555 shell "rm -rf system/priv-app/PackageInstaller"
  1. 接著將system目錄推送到ReDroid系統,並賦予權限:
adb -s localhost:5555 push system /
adb -s localhost:5555 shell "pm grant com.google.android.gms android.permission.ACCESS_COARSE_LOCATION"
adb -s localhost:5555 shell "pm grant com.google.android.gms android.permission.ACCESS_FINE_LOCATION"
adb -s localhost:5555 shell "pm grant com.google.android.setupwizard android.permission.READ_PHONE_STATE"
adb -s localhost:5555 shell "pm grant com.google.android.setupwizard android.permission.READ_CONTACTS"
adb reboot
  1. 重新啟動ReDroid容器:
cd ~/redroid
sudo docker compose down
sudo docker compose up -d
  1. 啟動Scrcpy
scrcpy -s localhost:5555 --audio-codec=raw
  1. 開啟系統設定 → 應用程式,點選右上角顯示系統應用程式,將Google Play服務和Play商店的權限都開啟。

  2. 執行以下指令取得Android裝置ID,到 Google網站註冊裝置,等個30分鐘後重新啟動Redroid容器,才能登入Google Play。

adb -s localhost:5555 root
adb -s localhost:5555 shell 'sqlite3 /data/data/com.google.android.gsf/databases/gservices.db \
    "select * from main where name = \"android_id\";"'

5. ReDroid安裝APK
#

目前即使有安裝libndk,Android 11的Play商店還是不給下載ARM架構的APP,請配合APKPure之類的應用程式商店安裝APP。

除了用容器內部的瀏覽器下載APK外,你還可以用ADB安裝APK至ReDroid容器。比方說到 ApkMirror下載Line的APK,接著用ADB安裝:

adb -s localhost:5555 install "jp.naver.line.android.apk"

你也可以用ADB的pullpush指令傳輸檔案。

關於螢幕解析度的調整,請參閱 ReDroid Scrcpy的使用說明。

6. ReDroid如何「開關機」
#

如果要將ReDroid關機,將Scrcpy視窗關閉後,停止容器:

cd ~/redroid
sudo docker compose down

之後可以再用此指令啟動ReDroid。ReDroid容器的/data資料位於~/redroid/redroid-11-data目錄,可以用來備份多個系統的檔案。

cd ~/redroid
sudo docker compose up -d
adb connect localhost:5555
scrcpy -s localhost:5555

附錄:手動抽取libndk建置Android映像檔
#

libndk是Google開發的專有軟體,含在Android Studio的模擬器裡面。根據 ReDroid作者指示,我們可以手動從新版Android模擬器抽取libndk,再將其塞到ReDroid原生系統裡面。

這裡以Android 13為例,注意作者沒保證說一定能用。

  1. 安裝Android Studio,新增Android 13的虛擬機

  2. 透過ADB連線

adb devices
adb shell
su
  1. 將libndk打包
{ find /system -name arm* -type d; find /system -name *ndk_translation*; find /system/etc -name *arm*; } | tar -cf /sdcard/nb.tar -T -
  1. 將libndk.so打包
find system -type l | tar -cf /sdcard/so.tar -T -
  1. 退出ADB,將以上檔案傳回本機
exit
exit
adb pull /sdcard/nb.tar .
adb pull /sdcard/so.tar .
  1. 將libndk.so加入到libndk的壓縮檔
tar -xvf so.tar
find system -type l | tar -rf libndk_translation.tar -T -
  1. 新增DOCKERFILE,填入以下內容:
FROM redroid/redroid:13.0.0-latest

ADD libndk_translation.tar /
  1. 開始建置含有libndk的Android 13映像檔,之後這個映像檔redroid:13.0.0-libndk就能拿去執行容器了。
docker build . -t redroid:13.0.0-libndk

相關文章

ReDroid,在Windows電腦架設Android雲手機的方法
分類   Linux系統 虛擬機與容器技術
標籤   ReDroid Docker Android Windows Subsystem for Linux Scrcpy
Android-x86 QEMU虛擬機安裝教學,在Linux上執行手機APP,支援GPU加速的VM
分類   Linux系統 虛擬機與容器技術
標籤   Android-X86 Linux QEMU VirGL Scrcpy
QEMU/KVM虛擬機Nvidia雙GPU直通,Linux Host對Linux Guest
分類   Linux系統 虛擬機與容器技術
標籤   GPU Passthrough QEMU Nvidia Linux

留言板

此處提供二種留言板。點選按鈕,選擇您覺得方便的留言板。要討論程式碼請用Giscus,匿名討論請用Disqus。

這是Giscus留言板,需要Github帳號才能留言。支援markdown語法,若要上傳圖片請貼Imgur或Postimages。您的留言會在Github Discussions向所有人公開。

這是Disqus留言板,您可能會看到Disqus強制投放的廣告。有時留言可能會被系統判定需審核,導致延遲顯示,請見諒。若要上傳圖片請貼Imgur或Postimages。