How to Build the /e/OS ROM?
Edit
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. |
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
Install Docker
If you have not already done so, install Docker.
Get the 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.
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_APPSenvironment variable accordingly in the Docker image, before building. - if you want to keep a minimal /e/OS build, set the
MINIMAL_APPSenvironment 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>.zipis 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>.zipis the OTA package for an update or recovery-based installation.- With
IS_EMULATOR=true,IMG-e-…-sdk_phone_x86_64.zipis 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