Android Emulator Development, Anbox, & Waydroid

Building a Custom Anbox Container Image: Modifying the RootFS and Kernel

Google AdSense Native Placement - Horizontal Top-Post banner

Introduction

Anbox (Android in a Box) provides a way to run Android applications on GNU/Linux distributions by putting the core Android operating system into a container. Unlike traditional emulators, Anbox uses your host system’s kernel to run Android, leveraging LXC containers for isolation and performance. While the default Anbox image is sufficient for many, advanced users often need to customize the Android RootFS or even the underlying kernel to install specific tools, integrate custom services, or support specialized hardware. This expert-level guide delves into the intricate process of modifying the Anbox container image, covering both RootFS and kernel customization.

Anbox Architecture Overview

Before diving into modifications, it’s crucial to understand Anbox’s unique architecture:

  • Host Kernel Modules: Anbox relies on two essential kernel modules: anbox-binder and anbox-ashmem. These modules bridge the Android-specific inter-process communication (Binder) and shared memory (Ashmem) mechanisms to the host Linux kernel, eliminating the need for full kernel emulation.
  • LXC Container: The Android system itself runs within an LXC (Linux Containers) container. This provides a lightweight, performant, and isolated environment for Android, utilizing many of the host kernel’s features directly.
  • RootFS (SquashFS Image): The core Android filesystem, known as the RootFS, is provided as a read-only SquashFS image. This image contains all the Android binaries, libraries, frameworks, and system applications. When Anbox starts, this SquashFS image is mounted and layered with a writable overlay filesystem.
  • Session Manager: Manages the lifecycle of Android containers.
  • Android Container: The actual Android instance, running within LXC.

Our focus will be on manipulating the SquashFS RootFS and, in more advanced scenarios, ensuring kernel module compatibility or building custom modules.

Prerequisites

To follow this guide, you’ll need a Linux environment with the following tools:

  • anbox-modules-dkms (installed and loaded)
  • lxc (LXC tools, often part of your distribution)
  • squashfs-tools (for unsquashfs and mksquashfs)
  • debootstrap or an equivalent tool (if creating a base image from scratch, though we’ll modify an existing one)
  • Basic build tools: gcc, make, flex, bison, libssl-dev, libelf-dev, etc. (for kernel compilation)
  • An existing Anbox installation with its default image.

Step 1: Obtaining and Extracting the Base Anbox RootFS

The first step is to get the base Anbox Android image and extract its contents. Anbox typically stores its image in /var/lib/anbox/android.img.

First, stop the Anbox session manager to ensure the image isn’t in use:

sudo systemctl stop anbox-container-manager.service

Copy the original image to a working directory and extract it:

mkdir -p ~/anbox_custom_imagecd ~/anbox_custom_imagecp /var/lib/anbox/android.img .unsquashfs android.img

This command will create a directory named squashfs-root containing the full Android RootFS.

Step 2: Modifying the RootFS

Now that you have an extracted RootFS, you can modify it. You’ll typically use chroot to enter the extracted filesystem and make changes as if you were inside the Android container itself. For some operations, you might need to mount virtual filesystems.

sudo mount --bind /dev squashfs-root/devsudo mount --bind /proc squashfs-root/procsudo mount --bind /sys squashfs-root/syssudo chroot squashfs-root /system/bin/sh

Once inside the chrooted environment, you can:

  • Install additional binaries: If the base Android image has a package manager (like apt if it’s Debian-based, or apk for Alpine), you can use it. However, Android’s RootFS usually doesn’t have a traditional Linux package manager. You’ll often need to cross-compile tools or copy pre-built Android binaries (e.g., from an NDK toolchain) directly into directories like /system/bin or /system/xbin.

Example: Adding a simple ‘hello’ script:

# Inside chroot:echo '#!/system/bin/sh' > /system/bin/hellosleep 1echo 'Hello from custom Anbox!'chmod +x /system/bin/helloexit

(Then exit the chroot with exit)

  • Modify system configuration files: Edit files under /system/etc or /vendor/etc.
  • Inject custom applications: Place .apk files into /data/app (though this might require more intricate setup with package manager databases). A simpler approach is to use ADB once the container is running.
  • Change permissions: Ensure correct file permissions and ownership for new files (e.g., chown root:shell /system/bin/hello, chmod 755 /system/bin/hello).

After making changes, unmount the virtual filesystems:

sudo umount squashfs-root/devsudo umount squashfs-root/procsudo umount squashfs-root/sys

Step 3: Understanding the Anbox Kernel Modules

Anbox’s core functionality relies on the anbox-binder and anbox-ashmem kernel modules. These modules provide the necessary interfaces for Android’s Binder IPC and Ashmem shared memory within the host Linux kernel. When you install anbox-modules-dkms, these modules are built against your currently running host kernel.

Kernel modifications are significantly more complex and often not necessary unless:

  • You need to support specific hardware or drivers *within* the Anbox container that require host kernel support.
  • You are running a custom, non-standard Linux kernel on your host system for which the DKMS package fails to build.
  • You wish to add new kernel features or security hardening specific to the Android container’s interaction with the host.

For most RootFS customizations, you do not need to recompile your kernel or the Anbox modules.

Step 4: Building a Custom Kernel (Advanced/Optional)

If you absolutely need a custom kernel or need to rebuild the Anbox modules against a specific kernel source, here’s a high-level overview:

  1. Obtain Kernel Source: Download the source code for your host Linux kernel (e.g., from kernel.org or your distribution’s repositories) or an AOSP common kernel if you’re trying to emulate a specific Android environment very closely.
  2. Configure Kernel: Navigate to the kernel source directory and configure it. You can often start with your current kernel’s config:
  3. cd /usr/src/linux-source-X.Y.Zcp /boot/config-$(uname -r) .configmake olddefconfigmake menuconfig

    Ensure all necessary Android-related kernel options (like ASHMEM, BINDER, ANDROID_LOGGER, etc.) are enabled. These are usually present in modern kernels but confirm. Save your configuration.

  4. Compile Kernel (Optional): If you want to replace your host kernel, compile and install it. This is a non-trivial process and beyond the scope of this article, involving commands like make -j$(nproc), make modules_install, and make install.
  5. Build Anbox Modules Against Custom Kernel: If you’re using a custom kernel source or just want to ensure compatibility, you can manually build the anbox-binder and anbox-ashmem modules against your custom kernel source tree. The anbox-modules-dkms package usually handles this, but for a custom kernel not managed by DKMS, you’d navigate to the Anbox kernel modules source (e.g., /usr/src/anbox-modules-X.Y) and run:
  6. sudo KERNELDIR=/path/to/your/custom/kernel/source make modules_install

    This will install the compiled modules into the appropriate location for your custom kernel. You’ll need to reboot with your custom kernel and ensure the modules are loaded.

This step is highly advanced and requires a deep understanding of Linux kernel compilation and module management.

Step 5: Re-packaging the Custom RootFS

Once your RootFS modifications are complete, you need to package it back into a SquashFS image:

cd ~/anbox_custom_image# Ensure previous android.img is renamed or removed to avoid conflictssudo mksquashfs squashfs-root custom_android.img -comp xz -b 256K -no-progress

The -comp xz -b 256K options provide good compression, and -no-progress suppresses verbose output. Adjust these as needed.

Step 6: Deploying the Custom Image

With your custom_android.img ready, the final step is to tell Anbox to use it. Anbox’s configuration is typically managed by a configuration file or systemd unit files.

  1. Replace the image: Move your custom image to the expected Anbox location:
  2. sudo mv custom_android.img /var/lib/anbox/android.img

    It’s highly recommended to back up the original android.img before overwriting it.

  3. Restart Anbox: Start the Anbox session manager:
  4. sudo systemctl start anbox-container-manager.service
  5. Verify: Start an Anbox session (e.g., by launching an Android app) and verify your changes. If you added a custom binary, you could try to execute it via adb shell.

If Anbox fails to start, check the system logs (journalctl -u anbox-container-manager.service) for errors. Often, permissions or an incorrectly built RootFS can cause issues.

Conclusion

Customizing the Anbox container image, particularly its RootFS, opens up a world of possibilities for developers, testers, and embedded systems engineers. From injecting debugging tools to pre-installing specific applications or even modifying system behavior, the ability to control the underlying Android environment is powerful. While kernel modifications are more involved and less frequently needed, understanding their role and the general process can be invaluable for highly specialized use cases. This guide provides a solid foundation for taking control of your Anbox environment and tailoring it to your exact needs, transforming Anbox from a generic Android runner into a highly specialized development and testing platform.

Android Mobile Specs & Compare Directory

Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!

Compare Devices Specs →
Google AdSense Inline Placement - Content Footer banner