Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ RUN apt-get update && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Bake in Google ndk_translation prebuilts (ARM-on-x86 native bridge).
# Source: Kaz205 fork (Chrome OS Android 11 / guybrush_cheets) — matches the emulator's API 30.
ARG NDK_TRANSLATION_REPO=Kaz205/vendor_google_proprietary_ndk_translation-prebuilt
ARG NDK_TRANSLATION_REF=chromeos_guybrush
RUN mkdir -p /opt/ndk-translation && \
wget -q -O /tmp/ndk.tar.gz \
"https://codeload.github.com/${NDK_TRANSLATION_REPO}/tar.gz/refs/heads/${NDK_TRANSLATION_REF}" && \
tar -xzf /tmp/ndk.tar.gz \
--strip-components=2 \
-C /opt/ndk-translation \
"$(basename "$NDK_TRANSLATION_REPO")-${NDK_TRANSLATION_REF}/prebuilts" && \
rm /tmp/ndk.tar.gz

# Set up Android SDK
RUN mkdir -p /opt/android-sdk/cmdline-tools && \
cd /opt/android-sdk/cmdline-tools && \
Expand Down
28 changes: 23 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![GitHub Issues](https://img.shields.io/github/issues/shmayro/dockerify-android)](https://github.com/shmayro/dockerify-android/issues)
[![GitHub Stars](https://img.shields.io/github/stars/shmayro/dockerify-android?style=social)](https://github.com/shmayro/dockerify-android/stargazers)

**Dockerify Android** is a Dockerized Android emulator supporting multiple CPU architectures (**x86** and **arm64** in the near future ...) with native performance and seamless ADB & Web access. It allows developers to run Android virtual devices (AVDs) efficiently within Docker containers, facilitating scalable testing and development environments.
**Dockerify Android** is a Dockerized Android emulator supporting multiple CPU architectures (**x86** and **ARM/ARM64 apps** via ndk_translation) with native performance and seamless ADB & Web access. It allows developers to run Android virtual devices (AVDs) efficiently within Docker containers, facilitating scalable testing and development environments.

### 🔥 **Key Feature: Web Interface Access** 🌐

Expand Down Expand Up @@ -49,6 +49,7 @@ Access and control the Android emulator directly in your web browser with the in
## 🔧 **Features**

- **🌐 Web Interface:** Access the emulator directly from your browser with the integrated [scrcpy-web](https://github.com/Shmayro/ws-scrcpy-docker) interface.
- **🔄 ARM Translation Support:** Run ARM/ARM64 native applications on x86_64 emulator using ndk_translation layer. This allows installation of modern Android apps that ship only with ARM native libraries (arm64-v8a, armeabi-v7a).
- **Root and Magisk Preinstalled:** Comes with root access and Magisk preinstalled for advanced modifications.
- **PICO GAPPS Preinstalled:** Includes PICO GAPPS for essential Google services.
- **Seamless ADB Access:** Connect to the emulator via ADB from the host and other networked devices.
Expand Down Expand Up @@ -148,6 +149,7 @@ scrcpy -s localhost:5555
| `SCREEN_DENSITY` | Screen pixel density in DPI | device default |
| `ROOT_SETUP` | Set to `1` to enable rooting and Magisk. Can be turned on after the first start but cannot be undone without recreating the data volume. | `0` |
| `GAPPS_SETUP` | Set to `1` to install PICO GAPPS. Can be turned on after the first start but cannot be undone without recreating the data volume. | `0` |
| `ARM_TRANSLATION` | Set to `1` to enable ARM translation (ndk_translation) for running ARM/ARM64 apps on x86_64. Can be turned on after the first start but cannot be undone without recreating the data volume. | `0` |


## 🔄 **First Boot Process**
Expand All @@ -161,10 +163,15 @@ The first time you start the container, it will perform a comprehensive setup pr
- Remount system as writable
- Install Magisk for root access
- Reboot to apply root
4. **Extras Copied:** Pushes everything from the `extras` directory to `/sdcard/Download` so files like APKs or Magisk modules are ready for manual installation on the device.
5. **Configuring optimal device settings**
4. **ARM Translation Installation** (when `ARM_TRANSLATION=1`): Installs ndk_translation ARM translation layer to enable running ARM/ARM64 native apps on x86_64:
- Installs ndk_translation for both ARM32 (armeabi-v7a) and ARM64 (arm64-v8a) support
- Updates system properties to advertise ARM ABI support
- Configures native bridge for transparent ARM-to-x86 translation
- After installation, the device will report `ro.product.cpu.abilist = x86_64,x86,arm64-v8a,armeabi-v7a,armeabi`
5. **Extras Copied:** Pushes everything from the `extras` directory to `/sdcard/Download` so files like APKs or Magisk modules are ready for manual installation on the device.
6. **Configuring optimal device settings**

`ROOT_SETUP` and `GAPPS_SETUP` are checked on every start. If you enable them after the first boot, the script installs the requested components once and marks them complete so they won't run again. Removing them later requires recreating the data volume.
`ROOT_SETUP`, `GAPPS_SETUP`, and `ARM_TRANSLATION` are checked on every start. If you enable them after the first boot, the script installs the requested components once and marks them complete so they won't run again. Removing them later requires recreating the data volume.

> **Important:** The first boot can take 10-15 minutes to complete. You'll know the process is finished when you see the following log output:
> ```
Expand Down Expand Up @@ -210,7 +217,7 @@ Builds from the `main` branch are published as development images using `edge` a

- [ ] Support for additional Android versions
- [x] Integration with CI/CD pipelines
- [ ] Support ARM64 CPU architecture
- [x] ARM Translation support (ndk_translation) for running ARM64 apps on x86_64
- [x] PICO GAPPS installation
- [x] Support Magisk
- [x] Adding web interface of [scrcpy](https://github.com/Shmayro/ws-scrcpy-docker)
Expand All @@ -234,10 +241,21 @@ Builds from the `main` branch are published as development images using `edge` a
- This is normal, as the first boot process needs to perform several operations including:
- Installing GAPPS (if enabled)
- Rooting the device (if enabled)
- Installing ARM Translation (if enabled)
- Configuring system settings
- The process can take 10-15 minutes depending on your system performance
- You can monitor progress with `docker logs -f dockerify-android`

- **ARM/ARM64 Apps Still Not Installing:**
- Ensure `ARM_TRANSLATION=1` is set in your docker-compose.yml or environment variables
- Check that the first boot completed successfully with `docker logs dockerify-android | grep -i "ARM translation"`
- Verify ARM ABIs are available:
```bash
adb shell getprop ro.product.cpu.abilist
```
Should show: `x86_64,x86,arm64-v8a,armeabi-v7a,armeabi`
- If you enabled `ARM_TRANSLATION` after the first boot, restart the container to run the install step

- **Emulator Not Starting:**
- **Check Container Logs:**

Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ services:
#SCREEN_DENSITY: 227
ROOT_SETUP: 0 # set to 1 to enable rooting
GAPPS_SETUP: 0 # set to 1 to install PICO GAPPS
ARM_TRANSLATION: 1 # set to 1 to enable ARM translation (allows ARM64 apps)
privileged: true
devices:
- /dev/kvm
Expand Down
61 changes: 57 additions & 4 deletions first-boot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,49 @@ install_root() {
touch /data/.root-done
}

install_arm_translation() {
prepare_system
echo "Installing ARM translation (ndk_translation) ..."

adb push /opt/ndk-translation/bin /system/
adb push /opt/ndk-translation/etc /system/
adb push /opt/ndk-translation/lib /system/
adb push /opt/ndk-translation/lib64 /system/

adb shell '
chmod 755 /system/bin/ndk_translation_program_runner_binfmt_misc /system/bin/ndk_translation_program_runner_binfmt_misc_arm64
chmod -R 755 /system/bin/arm /system/bin/arm64
for f in /system/build.prop /vendor/build.prop /product/build.prop /system_ext/build.prop /odm/build.prop; do
[ -f "$f" ] || continue
sed -i -e "/^ro\.product\.cpu\.abilist/d" \
-e "/^ro\.dalvik\.vm\.native\.bridge/d" \
-e "/^ro\.enable\.native\.bridge/d" \
-e "/^ro\.dalvik\.vm\.isa\./d" \
-e "/^ro\.ndk_translation\./d" "$f"
done
cat >> /system/build.prop <<EOF
ro.product.cpu.abilist=x86_64,x86,arm64-v8a,armeabi-v7a,armeabi
ro.product.cpu.abilist32=x86,armeabi-v7a,armeabi
ro.product.cpu.abilist64=x86_64,arm64-v8a
ro.dalvik.vm.isa.arm=x86
ro.dalvik.vm.isa.arm64=x86_64
ro.enable.native.bridge.exec=1
ro.enable.native.bridge.exec64=1
ro.dalvik.vm.native.bridge=libndk_translation.so
ro.ndk_translation.version=0.2.3
EOF
'

adb reboot
touch /data/.arm-translation-done
}

copy_extras() {
adb wait-for-device
# Push any Magisk modules for manual installation later
for f in $(ls /extras/*); do
adb push $f /sdcard/Download/
for f in /extras/*; do
[ -e "$f" ] || continue
adb push "$f" /sdcard/Download/
done
}

Expand All @@ -89,13 +127,24 @@ socat tcp-listen:"5555",bind="$LOCAL_IP",fork tcp:127.0.0.1:"5555" &

gapps_needed=false
root_needed=false
arm_translation_needed=false
if bool_true "$GAPPS_SETUP" && [ ! -f /data/.gapps-done ]; then gapps_needed=true; fi
if bool_true "$ROOT_SETUP" && [ ! -f /data/.root-done ]; then root_needed=true; fi
if bool_true "$ARM_TRANSLATION" && [ ! -f /data/.arm-translation-done ]; then arm_translation_needed=true; fi

needs_reboot() {
# Reboot needed if only GAPPS was installed (no root or ARM translation)
[ "$gapps_needed" = true ] && [ "$root_needed" = false ] && [ "$arm_translation_needed" = false ]
}

# Skip initialization if first boot already completed.
if [ -f /data/.first-boot-done ]; then
[ "$gapps_needed" = true ] && install_gapps && [ "$root_needed" = false ] && adb reboot
if [ "$gapps_needed" = true ]; then
install_gapps
needs_reboot && adb reboot
fi
[ "$root_needed" = true ] && install_root
[ "$arm_translation_needed" = true ] && install_arm_translation
apply_settings
copy_extras
exit 0
Expand All @@ -104,8 +153,12 @@ fi
echo "Init AVD ..."
echo "no" | avdmanager create avd -n android -k "system-images;android-30;default;x86_64"

[ "$gapps_needed" = true ] && install_gapps && [ "$root_needed" = false ] && adb reboot
if [ "$gapps_needed" = true ]; then
install_gapps
needs_reboot && adb reboot
fi
[ "$root_needed" = true ] && install_root
[ "$arm_translation_needed" = true ] && install_arm_translation
apply_settings
copy_extras

Expand Down
Loading