Skip to main content

ReDroid Tutorial: Running Android in Docker to Play ARM Mobile Games on an x86 PC

·
Categories Linux Self-Hosting
Tags ReDroid Android Docker Linux Scrcpy
Table of Contents

ReDroid (Remote anDroid) is a solution for self-hosting a “cloud phone”. It runs an Android system container through Docker, then uses Scrcpy’s screen mirroring feature to connect to the Android desktop.

Playing FGO with ReDroid on Linux

ReDroid is also a solution for running Android apps on a computer with open source software. Because never mind cloud phones, many Android mobile gaming emulators are closed source software. By comparison, ReDroid is open source except for the ARM translator. Even better, ReDroid supports GPU acceleration plus an ARM-to-x86 translator, so it can play most 3D mobile games.

For Linux users, this is also an efficient way to run Android apps on a Linux computer besides Waydroid and Android-x86 virtual machines. And it is more suitable than Waydroid as a cloud phone. See Self-hosting a cloud phone

This article discusses how to use ReDroid on an x86 Linux computer to play ARM mobile games. We will add an ARM translator plus the Google services framework to the ReDroid image for the best user experience.

1. ReDroid System Requirements
#

Any Linux distribution should work.

This article demonstrates running ReDroid on an x86 computer. As for ARM computers, some netizens have reported successful deployment on Oracle ARM servers, and I have also tested that ReDroid can run on Raspberry Pi 5.

If the computer is x86, it can only run Android apps with x86 architecture. However, many mobile games only have ARM versions, so ReDroid needs to install an ARM translator such as libndk or libhoudini.

For playing mobile games, I recommend at least 8GB RAM, because ARM-to-x86 instruction translation can sometimes consume a large amount of RAM.

For GPU acceleration, I recommend using drivers supported by Linux Mesa, such as Intel and AMD GPUs, where 3D acceleration works out of the box. Nvidia is not recommended.


Regarding Android versions, the redroid:11.0.0-latest and redroid:12.0.0-latest images published by the Redroid author already have Google’s ARM translator libndk built in. I tried them and found that only Android 11 is relatively stable, and GApps also works, so this article uses the Android 11 image.

2. Install ReDroid Prerequisites
#

ReDroid’s Github has installation instructions for major Linux distributions. I use Ubuntu as the demonstration system.

  1. First prepare the binder kernel module. On Ubuntu 24.04, run the following commands to install the necessary binder kernel module:
sudo apt install linux-modules-extra-`uname -r`

sudo modprobe binder_linux devices="binder,hwbinder,vndbinder"
  1. Add the above kernel module to automatic loading on boot
echo 'binder_linux options binder_linux devices="binder,hwbinder,vndbinder"' | sudo tee -a /etc/modules-load.d/redroid.conf
  1. Install Docker for running containers

  2. Install the ADB tool

  3. Finally install Scrcpy.

If you want a graphical Scrcpy interface integrated with key mapping, you can install QtScrcpy instead. You can also try the web version ws-scrcpy.

3. Install GApps into the ReDroid Image in Advance
#

The image published by the ReDroid author is vanilla Android and does not come preinstalled with GApps. You can go to Docker Hub to find ReDroid images prebuilt by others. Some include GApps, so you would not need to build it yourself. Of course, use them at your own risk.

Here we use ayasa520’s Remote-Android Script to automatically pull the ReDroid image and install GApps onto it. It only supports Android 11 images.

This script can also be used to install components such as libndk, libhoudini, Magisk, and Widevine DRM.

  1. Clone the Remote-Android Script repository and create a Python virtual environment
sudo apt install lzip python3 python3-venv python3-pip

git clone https://github.com/ayasa520/redroid-script.git

cd redroid-script

python3 -m venv venv

venv/bin/pip install -r requirements.txt
  1. Pull the Android 11 image and install GApps
venv/bin/python3 redroid.py -a 11.0.0 -g
  1. This gives you an image with GApps included: redroid/redroid:11.0.0_gapps.

4. Start the ReDroid Container with docker-compose
#

  1. This step is only needed for Nvidia graphics cards. Intel and AMD graphics card users can skip directly to the next step. ReDroid’s support for Nvidia graphics cards is poor. If possible, I recommend using integrated graphics instead. If you insist on using Nvidia, create a virtual machine to run ReDroid. Because Nvidia’s closed source driver cannot let ReDroid use GPU acceleration, you need to run a QEMU virtual machine and install ReDroid inside it to achieve hardware acceleration through virtio-gpu. But since this is paravirtualization, performance loss will be significant. If you do not create a virtual machine and your computer has no integrated graphics, ReDroid will use software rendering. If you can accept software rendering performance, then you do not need to install a virtual machine.
Create a virtual machine for running ReDroid

Install QEMU + Virt Manager, download Ubuntu 24.04, and create a 64GB Ubuntu virtual machine

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

Boot into the virtual machine, then install Docker.

qemu-system-x86_64 -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. Create a directory for storing Android data, and add docker-compose
mkdir ~/redroid

cd redroid

vim docker-compose.yml
  1. Fill in the following contents:
services:
  redroid:
    image: redroid/redroid:11.0.0_gapps # Use the ReDroid image with GApps created earlier
    stdin_open: true
    tty: true
    privileged: true
    ports:
      - 127.0.0.1:5555:5555 # ADB port. For stronger security, set it to listen only on the local localhost port
    volumes:
      - ./redroid-11-data:/data # Store data in the current directory
    command:
      - androidboot.redroid_width=720 # Phone resolution
      - androidboot.redroid_height=1280
      - androidboot.redroid_dpi=320
      - androidboot.redroid_fps=60
      - androidboot.redroid_gpu_mode=host # Enable host GPU hardware acceleration. host means GPU acceleration; guest means software rendering
      - ro.product.cpu.abilist0=x86_64,arm64-v8a,x86,armeabi-v7a,armeabi # Settings related to libndk
      - 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. Start the service
sudo docker compose up -d
  1. Use ADB to connect to the local ReDroid. Since it is local, fill in localhost for the IP. If ReDroid is deployed remotely, change it to the remote host’s IP.
adb connect localhost:5555

# If it cannot connect, use the following commands to see what happened inside the container
sudo docker ps
sudo docker exec <容器ID> logcat
sudo docker logs <容器ID>
  1. Run Scrcpy and connect to Android:
scrcpy -s localhost:5555 --audio-codec=aac
  1. Then you will see the Android desktop.

  2. Google Play services may pop up a “device is not certified” error message.

  3. Run the following commands to obtain the Android device ID, register the device on the Google website, wait about 30 minutes, then restart the Redroid container before logging into 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\";"'
  1. To confirm whether ReDroid’s 3D acceleration works properly, install AIDA64 and see whether it can recognize your computer’s GPU model.

  2. If you want to strengthen security, I recommend setting ReDroid’s docker-compose network to listen only on the local localhost port (ports: 127.0.0.1:5000:5000). If you want to expose ReDroid to the external network, be careful with firewall settings. Do not expose ADB’s port 5000 directly to the public internet, or there will be serious security concerns.

5. How to Install APKs on ReDroid
#

At present, even with libndk installed, the Android 11 Play Store still refuses to download ARM apps. Please use app stores such as APKPure to install apps.

Besides downloading APKs with the browser inside the container, you can also use ADB to install APKs into the ReDroid container. For example, download Line’s APK from ApkMirror, then install it with ADB:

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

Scrcpy supports dragging APKs into the window to install them.

You can also transfer files with ADB’s pull and push commands.

6. How to “Power On and Off” ReDroid
#

If you want to power off ReDroid, close the Scrcpy window and then stop the container:

cd ~/redroid

sudo docker compose down

Afterward, you can start ReDroid again with this command. The /data data of the ReDroid container is located in ~/redroid/redroid-11-data, and can be used to back up files from multiple systems.

cd ~/redroid

sudo docker compose up -d

adb connect localhost:5555

scrcpy -s localhost:5555 --audio-codec=aac

7. ReDroid Multi-Instance Example
#

See ReDroid muliple instances

Appendix
#

Manually install GApps into the ReDroid image

The ReDroid author says Google services framework is proprietary software and cannot be built in, so you have to install it yourself. The first method is recompiling the ReDroid image, and the second is manually installing OpenGApps.

I do not recommend the first method. It is time-consuming, and the GApps compilation tutorial provided by the author also has the problem of other apps being unable to detect it.

Here we use the second method: manual installation.

  1. Go to OpenGapps and download Android 11 GApps for x86_64 architecture. Choose the minimal pico version.

  2. Extract it, and you will see the following directories

open_gapps-x86_64-11.0-pico-20220503
├── Core
├── GApps
├── META-INF
├── Optional
  1. Under the extracted directory open_gapps-x86_64-11.0-pico-20220503, create a system directory.

  2. Next, extract all .lz files inside the Core and GApps directories, and place the APK directories inside them into the corresponding installation directories under the system directory. For example, the GoogleTTS directory under GApps/googletts-x86_64/nodpi/app/ should be placed under /system/app.

  3. After placing them, the directory structure under system should look like this:

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. Run the following commands to obtain root permission:
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. Next, push the system directory to the ReDroid system and grant permissions:
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. Restart the ReDroid container:
cd ~/redroid
sudo docker compose down
sudo docker compose up -d
  1. Start Scrcpy
scrcpy -s localhost:5555 --audio-codec=raw
  1. Open system settings → Apps, tap the upper-right corner to show system apps, and enable permissions for Google Play services and Play Store.
Manually extract libndk to build an Android image

libndk is proprietary software developed by Google and included in Android Studio’s emulator. According to the ReDroid author’s instructions, we can manually extract libndk from a newer Android emulator and stuff it into the vanilla ReDroid system.

Here I use Android 13 as an example. Note that the author does not guarantee it will definitely work.

  1. Install Android Studio and add an Android 13 virtual machine

  2. Connect through ADB

adb devices
adb shell
su
  1. Package libndk
{ find /system -name arm* -type d; find /system -name *ndk_translation*; find /system/etc -name *arm*; } | tar -cf /sdcard/nb.tar -T -
  1. Package libndk.so
find system -type l | tar -cf /sdcard/so.tar -T -
  1. Exit ADB and transfer the above files back to the local machine
exit
exit
adb pull /sdcard/nb.tar .
adb pull /sdcard/so.tar .
  1. Add libndk.so to the libndk archive
tar -xvf so.tar
find system -type l | tar -rf libndk_translation.tar -T -
  1. Add DOCKERFILE and fill in the following contents:
FROM redroid/redroid:13.0.0-latest

ADD libndk_translation.tar /
  1. Start building the Android 13 image containing libndk. Afterward, this image redroid:13.0.0-libndk can be used to run the container.
docker build . -t redroid:13.0.0-libndk

References
#

Related


Thank you for reading. Public comments are not available on this website. I write to explore ideas honestly, not to chase social engagement or traffic. I would be glad to hear your thoughts after reading the article with care. If you found any errors, technical issues, or would like to share feedback, feel free to contact me via the email listed on the About page.