Build categories

Choose the category that matches the changes you intend to make and how you plan to distribute the result.

Category Permitted changes Distribution and updates
custom Product identity, features, applications, or services may be changed. Publish under a distinct name and operate independent update infrastructure.
unofficial Changes should be limited to enabling or improving support for the target device. Core features and the default application set remain unchanged. Clearly identify the build as unofficial. Nightly builds and OTA updates are not provided.
community Device support is maintained to a quality level suitable for community releases, with available security updates applied. Builds may be published through the community release channel and receive OTA updates.
official The device must meet the project’s quality requirements and have an official maintainer. Builds are published through the official release channel and receive OTA updates.
Warning: A build that changes the product identity, features, default applications, or services is a custom ROM, not an /e/OS build. Remove the /e/OS name and logo, choose a distinct ROM name, clearly state that it is a fork, and do not use the official OTA infrastructure.

Community and official build sources must be hosted on the project’s GitLab instance or another trusted public source, such as LineageOS or AOSP. See Build Status for the release channels and support levels.

How to build the ROM

Warning: The Docker builder runs on any 64-bit Linux, macOS, or Windows host supported by Docker. Android sources must nevertheless be stored on a case-sensitive filesystem. On macOS, use a case-sensitive APFS volume. On Windows, use storage backed by the WSL 2 Linux filesystem or a Docker volume instead of NTFS.
Tip: Your computer must have a 64-bit processor and operating system, at least 400 GB of free storage, and 16 GB of RAM.

Install Docker

If you have not already done so, install Docker.

Get the Docker image

Tip: Please run this step before each build, to be sure to get the last docker image.
docker pull registry.gitlab.e.foundation:5000/e/os/docker-lineage-cicd:community

Find your device code

The device code can be found on /e/OS devices list or by running the following command from ADB:

adb shell getprop ro.product.device

Choose a working directory

Choose a case-sensitive filesystem with at least 400 GB of free space. Set WORK_DIR to a location on that filesystem; all source files, build artifacts, logs, and compiler cache data will be stored below it.

export WORK_DIR=/path/to/eos-build
mkdir -p \
"${WORK_DIR}/src" \
"${WORK_DIR}/zips" \
"${WORK_DIR}/logs" \
"${WORK_DIR}/ccache"

Optional: extract proprietary blobs

Skip this section for the usual Docker community build. The builder uses the public manifests and, by default, includes supported proprietary vendor files from public TheMuppets manifests.

Use this optional step only when the public manifests do not provide the vendor files required by your target device, or when the device tree you are building expects locally extracted blobs.

Tip: This step requires a device already running a build based on the same Android branch you want to compile. If you do not have access to such a device, refer to Extracting proprietary blobs from an installable zip.

To extract blobs from a connected device:

  • Connect the device to your computer with USB.
  • Enable ADB and root.
  • Go to ${WORK_DIR}/src/<branch>/device/<vendorname>/<my-device>.
  • Run the device tree extraction script:
./extract-files.sh

The blobs are usually copied to ${WORK_DIR}/src/<branch>/vendor/<vendorname>/<my-device>. Once they are in place, run the Docker build.

Start the build

Run the following command. Don’t forget to replace <my-device> with your device code and <branch> with an existing public development branch.

docker run --rm \
-v "${WORK_DIR}/src:/srv/src" \
-v "${WORK_DIR}/zips:/srv/zips" \
-v "${WORK_DIR}/logs:/srv/logs" \
-v "${WORK_DIR}/ccache:/srv/ccache" \
-e "BRANCH_NAME=<branch>" \
-e "DEVICE_LIST=<my-device>" \
-e "REPO=https://gitlab.e.foundation/e/os/android.git" \
registry.gitlab.e.foundation:5000/e/os/docker-lineage-cicd:community

Select a branch from the public e/os/android repository.

Environment variables

Pass build settings to docker run with -e "NAME=value". Only BRANCH_NAME and DEVICE_LIST must be set for a standard device build.

Variable Default Purpose
BRANCH_NAME a16 Public development branch to build. Use a versioned branch such as v4.2-a16 for a reproducible build.
DEVICE_LIST empty Device codename or comma-separated codenames.
REPO https://gitlab.e.foundation/e/os/android.git Manifest repository used to check out the sources.
CCACHE_SIZE 100G Maximum compiler-cache size.
REPO_JOBS 10 Parallel source-sync jobs; reduce this value on slow storage.
BUILD_JOBS logical CPUs + 2 Parallel Android build jobs; set a lower value to limit CPU or memory usage.
INCLUDE_PROPRIETARY true Include supported proprietary vendor files from public TheMuppets manifests.
LFS_STRICT false Fail when any Git LFS object cannot be downloaded instead of recording a warning.
IS_EMULATOR false Build an emulator system image instead of a device OTA package.
BACKUP_IMG false Generate a factory fastboot package when the device provides a factory-flash configuration.
MINIMAL_APPS false Exclude selected optional applications from the build.
ENG_BUILD false Produce an engineering build with development-oriented defaults.
OTA_URL empty Set the update-server URL embedded in the build.

The complete set of options and their current defaults is defined in Dockerfile.community.

Example for Fairphone 3/3+ using the public /e/OS v4.2 Android 15 branch:

docker run --rm \
-v "${WORK_DIR}/src:/srv/src" \
-v "${WORK_DIR}/zips:/srv/zips" \
-v "${WORK_DIR}/logs:/srv/logs" \
-v "${WORK_DIR}/ccache:/srv/ccache" \
-e "BRANCH_NAME=v4.2-a15" \
-e "DEVICE_LIST=FP3" \
-e "REPO=https://gitlab.e.foundation/e/os/android.git" \
-e "INCLUDE_PROPRIETARY=false" \
-e "BACKUP_IMG=true" \
-e "REPO_JOBS=2" \
registry.gitlab.e.foundation:5000/e/os/docker-lineage-cicd:community

REPO_JOBS=2 is suitable for a hard-disk array. The default is 10; use the default or a higher value on fast SSD storage if the network connection can keep up.

For an Android 16 x86_64 emulator image, use the emulator product and enable emulator packaging:

docker run --rm \
-v "${WORK_DIR}/src:/srv/src" \
-v "${WORK_DIR}/zips:/srv/zips" \
-v "${WORK_DIR}/logs:/srv/logs" \
-v "${WORK_DIR}/ccache:/srv/ccache" \
-e "BRANCH_NAME=v4.2-a16" \
-e "DEVICE_LIST=sdk_phone_x86_64" \
-e "REPO=https://gitlab.e.foundation/e/os/android.git" \
-e "INCLUDE_PROPRIETARY=false" \
-e "IS_EMULATOR=true" \
registry.gitlab.e.foundation:5000/e/os/docker-lineage-cicd:community

The resulting IMG-e-…-sdk_phone_x86_64.zip is an Android SDK system-image archive, not a factory-flash package for a physical device.

Android 16 currently contains a broken public AOSP Git LFS pointer in a Rust test-data archive. The community builder records this as a warning and continues because the file is not required for the system image. Set LFS_STRICT=true if every LFS object must be available in your environment.

Reference FP3 build measurements

These measurements are an example, not a minimum or a performance guarantee. They were recorded for an Android 15 FP3 build on an Intel Core i9-9900K (8 cores, 16 threads), 62.7 GiB of RAM, and a RAID 1 array made of two SATA hard disks:

Operation Measured time
Initial source checkout with Git LFS About 3 h 7 min (about 2 h 32 min for repo sync, then 35 min for Git LFS)
Resumed repo sync with REPO_JOBS=2 25 min 59 s
Android build (target-files-package and otatools) 6 h 19 min 38 s
Complete container run, including packaging 6 h 35 min 54 s
Incremental rebuild and corrected packaging 37 min 21 s

The build used up to approximately 15 logical CPU cores and 29.4 GiB of RAM. The initial checkout transferred approximately 43.9 GB and wrote about 336 GB to storage. The checkout measurements include retries and therefore are not a controlled cold-cache benchmark.

Reference Android 16 emulator build measurements

The same HDD-based host produced an Android 16 sdk_phone_x86_64 image with BUILD_JOBS=18, no compiler cache, and the following timings:

Operation Measured time
Initial checkout through the Git LFS check 4 h 3 min 25 s
Manual recovery of one broken, non-build-critical public LFS object About 22 min
Android build 6 h 15 min 34 s
emu_img_zip packaging 9 min 56 s
Complete build container run 7 h 10 min 23 s

The resulting archive was 1.60 GB. Its checksum and ZIP integrity were verified, and it contained the API 36 x86_64 SDK metadata, kernel-ranchu, ramdisk.img, system.img, and vendor.img. These measurements include an uncached build on slow storage and are not performance guarantees.

Build options

You can now customize applications installed by default in /e/OS.

  • if you want to add extra applications to the default applications: add your APK to the android_prebuilts_prebuiltapks/ directory, and set the CUSTOM_APPS environment variable accordingly in the Docker image, before building.
  • if you want to keep a minimal /e/OS build, set the MINIMAL_APPS environment variable to true (default is false). For now it’s removing LibreOffice viewer, PDFViewer, Maps and Weather.

Get your image

When your build is finished, find the packages and their .sha256sum files in ${WORK_DIR}/zips/<my-device>:

  • With BACKUP_IMG=true, IMG-e-…-<my-device>.zip is the factory fastboot package for installing on a device from scratch. It includes the partition images, flashing script, and fastboot binaries when the device provides a factory-flash configuration.
  • e-…-<my-device>.zip is the OTA package for an update or recovery-based installation.
  • With IS_EMULATOR=true, IMG-e-…-sdk_phone_x86_64.zip is an Android SDK system-image archive for creating an emulator virtual device.

Verify the checksum before flashing a device package or installing an emulator system image. For device-specific installation steps, refer to the /e/OS devices list.

Need more help

If you need help, please check with other ROM builders who are active on our forum and build /e/OS unofficial ROM’s. Internet search for guides on android ROM building would also turn up sites which should be helpful.

To find more information about our docker image and its environment variables click here.

To report an issue about a build, please refer to this guide