Build Android 15 AOSP with Jenkins and Docker on an SSH Connected Agent

This guide walks you through setting up a Jenkins pipeline to build AOSP 15 using Docker on a remote SSH-connected agent.

It builds on the base Docker setup from:
Build Android 15 AOSP with Docker on Ubuntu 24.04


Why Jenkins + Docker for AOSP?

Using Jenkins to drive your AOSP builds in Docker gives you:

  • Fully reproducible, isolated build environments
  • Clean separation between infrastructure and build logic
  • Automation-friendly setup for CI/CD integration

However, making this work in Jenkins requires a few critical adjustments. This guide explains them step-by-step.


Problems Encountered and Fixes Applied

When using the same Docker image inside Jenkins, we hit several common issues:

ProblemFix
ssh-keyscan not foundInstall openssh-client in the Dockerfile
Missing repo toolDownload in the Dockerfile
curl SSL error when downloading repoInstall ca-certificates first
repo requires python3Install python3 in Dockerfile
source fails in shRun sh with #!/bin/bash in the first line

  1. Prepare the Docker Image

Create Dockerfile, save this as aosp-builder/Dockerfile:

FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive
ENV LANG=C.UTF-8
ENV USE_CCACHE=1
ENV CCACHE_DIR=/ccache
ENV CCACHE_EXEC=/usr/local/bin/ccache

RUN apt-get update && apt-get install -y --no-install-recommends \
    git-core \
    gnupg \
    flex \
    bison \
    build-essential \
    zip \
    curl \
    zlib1g-dev \
    libc6-dev-i386 \
    x11proto-core-dev \
    libx11-dev \
    lib32z1-dev \
    libgl1-mesa-dev \
    libxml2-utils \
    xsltproc \
    unzip \
    fontconfig \
    rsync \
    openssl \
    openssh-client \
    python3 \
    ca-certificates \
    && apt-get clean

RUN curl -Lo /usr/local/bin/repo https://storage.googleapis.com/git-repo-downloads/repo && chmod +x /usr/local/bin/repo

COPY ccache /usr/local/bin/ccache

WORKDIR /workspace

Build the Image

docker build -t aosp-builder ./aosp-builder

  1. Set Up Jenkins Environment

Connect a Remote Agent

  • A Linux host with Docker installed
  • Add the user to the docker group
  • Connect it as a Jenkins SSH agent
  • Label it as: ssh-agent-with-docker

Add Gerrit Credentials, In Manage Jenkins → Credentials:

  • Kind: SSH Username with private key
  • ID: gerrit-ssh-maksonlee
  • Username: maksonlee
  • Private key: Gerrit access key

  1. Write the Jenkinsfile

Save this as Jenkinsfile in your repo:

pipeline {
  agent { label 'ssh-agent-with-docker' }

  environment {
    CCACHE_PATH = "/home/administrator/.cache/ccache"
  }

  stages {
    stage('Build AOSP') {
      steps {
        script {
          docker.image('aosp-builder').inside("-v ${CCACHE_PATH}:/ccache ") {
            sshagent(['gerrit-ssh-maksonlee']) {
              sh '''#!/bin/bash
                mkdir -p ~/.ssh
                chmod 700 ~/.ssh
                ssh-keyscan -p 29418 -H gerrit.maksonlee.com >> ~/.ssh/known_hosts

                repo init -u ssh://maksonlee@gerrit.maksonlee.com:29418/platform/manifest -b android-15.0.0_r30
                repo sync -c
                
                source build/envsetup.sh
                lunch aosp_arm64-trunk_staging-userdebug
                m
              '''
            }
          }
        }
      }
    }
  }
}

How Jenkins Uses -u When Running Docker in Pipelines

When you run code inside a Docker container in Jenkins with:

docker.image('aosp-builder').inside {
    sh 'id'
}

Jenkins executes the container using:

docker run -u $(id -u):$(id -g) ...

This ensures that files created inside the container are owned by the Jenkins agent user, not by root. This behavior prevents common permission issues when Jenkins accesses workspace files after the container step.


Behavior When UID:GID Doesn’t Exist in the Container

When Jenkins executes:

docker run -u 1001:1001 ...

but the container image (e.g. aosp-builder) doesn’t define user ID 1001 or group ID 1001 in /etc/passwd or /etc/group, Docker still runs the process, but:

Inside the Container:

  • No username is shown because there’s no entry for UID 1001.
  • The process runs with raw numeric UID:GID, which may lack:
    • A valid $HOME directory
    • Shell configuration (like .bashrc)
    • Access to files owned by standard users inside the container

Consequences:

  • Any shell prompt or utilities that rely on a username may fail or behave oddly.
  • Your build tools (like AOSP makefiles) may fail if they assume a real user exists.
  • If a tool looks for $HOME or tries to write to ~/.cache, it may fail if $HOME is unset or points to a non-existent directory.

Did this guide save you time?

Support this site

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top