Skip to content
Draft
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
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ RUN apt-get update && \
qemu-kvm \
iproute2 \
socat \
tzdata && \
tzdata \
squashfs-tools && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

Expand Down
181 changes: 181 additions & 0 deletions IMPLEMENTATION_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# ARM64 App Support Implementation Summary

## Overview

This implementation adds ARM translation support to dockerify-android, enabling users to run ARM/ARM64 native applications on the x86_64 Android emulator. This resolves the issue where modern Android apps that ship only with ARM native libraries (arm64-v8a) would fail to install with `INSTALL_FAILED_NO_MATCHING_ABIS`.

## Problem Statement

The original issue reported:
- The emulator only advertised `ro.product.cpu.abilist = x86_64,x86`
- Many modern Play Store apps no longer provide x86/x86_64 builds
- ARM64-only apps would fail to install with `INSTALL_FAILED_NO_MATCHING_ABIS`

## Solution

Implemented ARM translation using Intel's libhoudini library, which provides transparent ARM-to-x86 binary translation at runtime through Android's Native Bridge interface.

## Technical Implementation

### 1. Core Changes

#### Dockerfile
- Added `squashfs-tools` package for extracting .sfs archives
- Required for unpacking libhoudini distribution files

#### first-boot.sh
- **New function: `install_arm_translation()`**
- Downloads libhoudini 9_y (ARM32) and 9_z (ARM64) from official sources
- Includes fallback to GitHub mirror if primary source fails
- Extracts .sfs archives using unsquashfs
- Pushes translation libraries to appropriate system directories
- Updates build.prop with ARM ABI properties
- Creates binfmt_misc entries for ARM binary format recognition
- Implements proper error handling and cleanup

- **New function: `needs_reboot()`**
- Determines when system reboot is needed after GAPPS installation
- Simplifies complex conditional logic

- **Updated: `copy_extras()`**
- Fixed to properly handle empty directories
- Uses shell globbing instead of `ls` to avoid issues with spaces in filenames

- **Updated initialization logic**
- Added `arm_translation_needed` flag
- Restructured conditional flow for better readability
- Maintains backward compatibility with existing setups

#### docker-compose.yml
- Added `ARM_TRANSLATION` environment variable
- Set to `1` by default to enable ARM translation
- Can be configured per deployment

#### README.md
- Added ARM Translation as a key feature (2nd in the list)
- Documented `ARM_TRANSLATION` environment variable
- Updated First Boot Process section with ARM translation details
- Added troubleshooting section for ARM-related issues
- Updated roadmap to mark ARM translation as complete
- Added reference to testing documentation

#### TESTING_ARM_TRANSLATION.md (New)
- Comprehensive testing guide for ARM translation feature
- Verification steps for proper installation
- Test scenarios for different use cases
- Troubleshooting guide
- Performance notes

### 2. How It Works

1. **Installation Process:**
- System is prepared (AVB disabled, verity disabled, system remounted)
- libhoudini binaries downloaded (~10-15MB each)
- Files extracted and pushed to:
- `/system/lib/libhoudini.so` and `/system/lib/arm/*`
- `/system/lib64/libhoudini.so` and `/system/lib64/arm64/*`
- `/system/bin/houdini` and `/system/bin/houdini64`
- Build.prop updated to advertise ARM ABIs
- binfmt_misc configured for ARM binary recognition

2. **Runtime Translation:**
- Android's PackageManager sees ARM ABIs in abilist
- ARM apps can be installed
- When ARM code executes, Native Bridge intercepts it
- libhoudini translates ARM instructions to x86 in real-time
- Translation is transparent to the application

3. **Result:**
- `ro.product.cpu.abilist = x86_64,x86,arm64-v8a,armeabi-v7a,armeabi`
- Both x86 and ARM apps can run on the same system
- x86 apps run natively (no translation overhead)
- ARM apps run with translation (some performance impact)

## Key Features

### Robust Error Handling
- Fallback download sources (primary + GitHub mirror)
- Graceful handling of missing files
- Proper cleanup on failure
- Error messages for debugging

### Idempotency
- Uses marker file (`/data/.arm-translation-done`)
- Removes existing build.prop entries before adding new ones
- Can be safely run multiple times
- Safe to enable after initial setup

### Backward Compatibility
- Defaults to `ARM_TRANSLATION=0` (disabled) in environment variables table
- Enabled by default in docker-compose.yml for new users
- Existing deployments not affected unless explicitly enabled
- No changes to core emulator behavior when disabled

### Performance Considerations
- Translation adds runtime overhead for ARM code
- Simple apps and UI work well
- CPU-intensive operations show performance impact
- x86 native code runs at full speed

## Testing

Comprehensive testing documentation provided in `TESTING_ARM_TRANSLATION.md` includes:
- Prerequisites and setup instructions
- Verification steps for proper installation
- Test scenarios (fresh install, post-install enablement, Play Store apps)
- Troubleshooting guide
- Performance notes

## Files Changed

1. **Dockerfile** - Added squashfs-tools package
2. **first-boot.sh** - Added ARM translation installation logic
3. **docker-compose.yml** - Added ARM_TRANSLATION environment variable
4. **README.md** - Updated documentation
5. **TESTING_ARM_TRANSLATION.md** - New testing guide

## Commits

1. Add ARM translation (libhoudini) support for ARM64 apps
2. Improve ARM translation script with better error handling and fallbacks
3. Address code review feedback: fix file handling and simplify conditionals
4. Add comprehensive testing documentation for ARM translation
5. Add reference to ARM translation testing guide in README

## Benefits

### For Users
- Run modern ARM-only Android apps on x86_64 emulator
- No more `INSTALL_FAILED_NO_MATCHING_ABIS` errors
- Access to full Play Store catalog
- Better compatibility for CI/CD testing

### For the Project
- Implements maintainer's short-term solution
- Clean, maintainable code
- Well-documented
- Easy to test and verify
- Addresses real user pain point

## Future Considerations

This is a short-term solution as indicated by the maintainer. Potential future enhancements:
- Native ARM64 system image support
- Performance optimizations
- Support for other Android versions
- Alternative translation layers (Google's libndk_translation)

## Security Notes

- libhoudini is Intel's official ARM translation library
- Downloaded from android-x86.org (official source)
- Fallback to GitHub mirror (Arm-NativeBridge community project)
- No modifications to core system security features
- Root access required (already part of dockerify-android setup)

## Credits

- Intel for libhoudini ARM translation layer
- Android-x86 project for hosting libhoudini distributions
- SGNight/Arm-NativeBridge for mirror and documentation
- Community guides and StackOverflow discussions for implementation details
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,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 libhoudini 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 @@ -145,6 +146,9 @@ 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 (libhoudini) 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` |

> **Note:** For detailed testing instructions for ARM translation, see [TESTING_ARM_TRANSLATION.md](TESTING_ARM_TRANSLATION.md).


## 🔄 **First Boot Process**
Expand All @@ -158,10 +162,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 libhoudini ARM translation layer to enable running ARM/ARM64 native apps on x86_64:
- Downloads and installs libhoudini 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 @@ -201,6 +210,7 @@ This includes:

- [ ] Support for additional Android versions
- [x] Integration with CI/CD pipelines
- [x] ARM Translation support (libhoudini) for running ARM64 apps on x86_64
- [ ] Support ARM64 CPU architecture
- [x] PICO GAPPS installation
- [x] Support Magisk
Expand All @@ -225,10 +235,22 @@ This includes:
- 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
- ARM Translation installation adds an additional 3-5 minutes to download and install libhoudini
- 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 "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 ARM Translation was enabled after the first boot, ensure the container was restarted after the installation completed

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

Expand Down
Loading