Skip to main content

Setting up AOSP CI/CD Pipeline

Overview

Setting up an effective CI/CD pipeline for projects based on AOSP (Android Open Source Project) presents unique challenges due to the underlying AOSP build system, device customizations, and vendor adaptations. Traditional CI/CD systems often require significant customization or struggle to efficiently manage AOSP-based workflows, such as validating changes that span across multiple Git repositories simultaneously.

HexDroid offers a specialized CI/CD system designed specifically to address the intricacies of AOSP development. It streamlines the process by providing built-in support for common AOSP tasks and workflows, simplifying configuration and improving efficiency where generic solutions may fall short.

This guide will walk you through configuring a robust CI/CD pipeline for your AOSP project using HexDroid. We'll cover recommended practices and provide practical examples for creating essential pipelines:

  • Pull Request Validation: Ensuring code quality and integration integrity before merging changes.
  • Nightly Builds: Automating regular builds of the main development branch for internal testing and validation.

By following this guide, you'll learn how to leverage HexDroid to automate your AOSP build, test, and release processes, leading to faster development cycles and more reliable builds.

tip

HexDroid recommends having a separate repository where all AOSP CI/CD workflows will live.
In this article we assume the repository name is aosp-ci.

Validating merge/pull requests

Pull request validation is a critical element of any AOSP development workflow. It ensures your team catches integration issues early, before they reach the main branch.

  1. Create the Workflow File
  2. Configure the Pipeline: Use the template below as a starting point and customize it to your project's needs.
  3. Commit and Push: Commit the pipeline file to your repository and push it to the main branch.
  4. Verify Setup: Create a test pull request to verify that the validation pipeline is triggered correctly.

In your aosp-ci repository, create a new workflow file at .hexdroid/pr-build.yaml.

name: My AOSP Validation Build
version: 1.0

trigger:
- pull_request:
repo_regex: "MyOrg/aosp-manifest"
source_branch_regex: "(task|feature)/(.*)"
target_branch_regex: "aosp-15"
comment:
enabled: true

stages:
aosp_cf_x86_64_phone:
agent:
container:
image: my_aosp_builder:latest
steps:
- aosp:
manifest:
url: https://android.googlesource.com/platform/manifest
revision:
from: source_branch
name: default.xml
lunch:
product_name: aosp_cf_x86_64_phone
release_config:
- trunk_staging
- # this empty entry builds without any release config
build_variant:
- eng
- userdebug
- user
build:
commands:
- m installclean
- m dist
artifact:
paths:
- out/dist/otatools.zip
- out/dist/aosp_cf_x86_64_phone-target_files-root.zip
- out/dist/aosp_cf_x86_64_phone-ota-root.zip

Developer workflow

AOSP is a multi-repository project, which can make it challenging to validate changes that span across multiple repositories. Traditional CI systems often fall short in these scenarios. HexDroid CI is built to handle this complexity by supporting multi-repo workflows out of the box.

Imagine a developer needs to add a new HAL API. In this case:

  • The API definition lives in the vendor/my-org/hardware/ repository.
  • The device-specific implementation is in device/my-org/hardware/ repository.

Since these changes are closely related, they need to be validated together as part of the same build. HexDroid CI allows this by using a temporary manifest branch.

To group the changes, the developer can create a temporary branch in the manifest repository that pins both affected projects to the appropriate feature branch. For example:

- <project path="vendor/my-org/hadrware" name="aosp-vendor-my-org-hardware" />
- <project path="device/my-org/hadrware" name="aosp-device-my-org-hardware" />
+ <project path="vendor/my-org/hadrware" name="aosp-vendor-my-org-hardware" revision="feature/add-hal-api" />
+ <project path="device/my-org/hadrware" name="aosp-device-my-org-hardware" revision="feature/add-hal-api" />

After creating a temp PR with this manifest branch, HexDroid CI will:

  • Sync the code using the custom manifest.
  • Build the combined changes.

This approach ensures that cross-repository changes can be tested in a single environment like they would be once merged. It reduces integration risk and improves developer confidence before merging the change.

Once the build is finished, and pull request(s) are ready to merge - then the developer can merge the vendor/my-org/hardware/ and device/my-org/hardware/, and decline the manifest temp pull request.

tip

If a job needs to be re-triggered, leaving a comment [CI CHECK] on the pull request will re-trigger the job.

Pipeline Options Explained

Let's break down the key parts of the pull request validation configuration:

Manifest Configuration

manifest:
url: https://android.googlesource.com/platform/manifest
+ revision:
+ from: source_branch
name: default.xml

HexDroid automatically selects the correct manifest revision based on the pipeline trigger.

In this example, revision.from: source_branch means the manifest will be checked out using the same branch that triggered the job, for example: feature/add-hal-api.

Nightly builds

The goal of having nightly builds is to provide the latest integrated software to developers/testing teams, to achieve this the CI/CD pipeline must do the following:

  • Build&Test the software
  • Create an internal distribution build for developers/testing teams

In aosp-ci repository, create a new file at .hexdroid/nightly.yaml path, with the following starter template:

name: My AOSP Nightly Build
version: 1.0

trigger:
- cron:
ref: refs/heads/master
expression: "0 0 * * *"

stages:
aosp_cf_x86_64_phone:
agent:
container:
image: my_aosp_builder:latest
steps:
- aosp:
manifest:
url: https://android.googlesource.com/platform/manifest
revision: main
name: default.xml
lunch:
product_name: aosp_cf_x86_64_phone
release_config:
- trunk_staging
- # this empty entry builds without any release config
build_variant:
- eng
- userdebug
- user
build:
commands:
- m installclean
- m dist
artifact:
paths:
- out/dist/api/*
- out/host/linux-x86/cvd-host_package.tar.gz
- out/dist/otatools.zip
- out/dist/aosp_cf_x86_64_phone-target_files-root.zip
- out/dist/aosp_cf_x86_64_phone-ota-root.zip
release:
payloads:
- file:
path: out/dist/aosp_cf_x86_64_phone-ota-root.zip
type: ota
distributed: true
- file:
path: out/dist/aosp_cf_x86_64_phone-target_files-root.zip
type: target_files
distributed: false
- file:
path: out/dist/otatools.zip
type: otatools
distributed: false
meta:
target:
type: execs
separator: /
command:
- get_build_var PRODUCT_BRAND
- get_build_var TARGET_DEVICE
- get_build_var TARGET_PRODUCT
- get_build_var TARGET_BUILD_VARIANT
- get_build_var BUILD_VERSION_TAGS
version_code:
type: file
path: out/build_date.txt
version_name:
type: file
path: out/dist/build.prop
regex: "ro\\.system\\.build\\.id=(.+)"

Pipeline Options Explained

Let's break down the key parts of the night build pipeline configuration:

Trigger

Starter template sets up cron configuration so that your nightly AOSP pipeline will be triggered at midnight UTC every day. This can be expanded to have multiple cron triggers or even be triggered on push to the main branch of any AOSP repository. Refer to triggers documentation to find out all available triggers.

Stages

The template pipeline only defines one stage; however, in the production environment you will likely have more than one AOSP build target (e.g., multiple products, which can be based on different aosp versions).

HexDroid recommends having a stage per product, especially if these products do not share the same AOSP base, having multiple stages means stages can run in parallel so that the total time to build all products is not a sum of each product.

Example:

stages:
product_1:
# configuration for product 1
product_2:
# configuration for product 2
product_3:
# configuration for product 3

Different products can also be split into their own pipeline files so that they are concise.

Agent

This defines the environment of the stage; the most common configuration is to specify a container image, which provides a consistent and reproducible runtime for all commands in the stage.

Steps

In this example, we only have one aosp step defined. aosp step is HexDroid defined step, designed to make CI/CD for AOSP understandable, and declarative. Full documentation for the aosp step can be found here.

This step will be expanded into multiple steps, such as manifest sync and pinning, then building for each product sub-configuration, such as user, userdebug builds.

This pipeline provides some opinionated options, such as what artifacts to upload, as well as how to set up OTA releases.

CI Artifacts

At minimum HexDroid recommends uploading the following build artifacts:

  • out/dist/otatools.zip
  • out/dist/*-target_files-root.zip
  • out/dist/*-ota-root.zip

When CI uploads build artifacts, they will be nicely grouped by aosp lunch target, which makes it easier to find a relevant file, especially when file names are the same:

Artifacts list grouped by AOSP lunch target

OTA Release

aosp step comes with built-in release update(ota) management, which makes it easy to create release, distribute it for your internal users, as well as later rolling out to production.

When uploading OTA releases, at minimum it's recommended to upload the following payloads:

release:
payloads:
- file:
path: out/dist/aosp_cf_x86_64_phone-ota-root.zip
type: ota
distributed: true
- file:
path: out/dist/aosp_cf_x86_64_phone-target_files-root.zip
type: target_files
distributed: false
- file:
path: out/dist/otatools.zip
type: otatools
distributed: false

aosp_cf_x86_64_phone-ota-root.zip is set distributed: true as this file is available to end target to download and apply,

We also upload target_files and otatools as distributed: false - this means these files will be visible in HexDroid Release Management, and these files later can be used to re-sign builds with release/production keys.

note

Files that are uploaded in release step will be automatically included as CI artifact - so there is no need to duplicate paths, in artifact and release steps.