diff --git a/Dockerfile b/Dockerfile index 16f43b7..75f8989 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,13 @@ RUN echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" \ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EEA14886 && \ echo oracle-java6-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections +# http://www.webupd8.org/2012/11/oracle-sun-java-6-installer-available.html +# Java 6 is no longer supported by Oracle. The binaries are no longer available for download, but if you have an Oracle account, you can still download it after logging in. +# The Oracle Java 6 installer in this article will continue to work only if you manually download Oracle JDK 6 (version 6u45), place it in the /var/cache/oracle-jdk6-installer/ folder on your computer, then install "oracle-java6-installer" as explained below in this article. +# http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase6-419409.html +# http://download.oracle.com/otn/java/jdk/6u45-b06/jdk-6u45-linux-x64.bin +COPY utils/jdk-6u45-linux-x64.bin /var/cache/oracle-jdk6-installer/ + # /bin/sh points to Dash by default, reconfigure to use bash until Android # build becomes POSIX compliant RUN echo "dash dash/sh boolean false" | debconf-set-selections && \ @@ -23,26 +30,22 @@ RUN apt-get update && \ lib32readline-gplv2-dev lib32z1-dev libesd0-dev libncurses5-dev \ libsdl1.2-dev libwxgtk2.8-dev libxml2-utils lzop \ oracle-java6-installer oracle-java6-set-default \ - pngcrush schedtool xsltproc zip zlib1g-dev && \ + pngcrush schedtool xsltproc zip zlib1g-dev graphviz && \ apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ADD https://commondatastorage.googleapis.com/git-repo-downloads/repo /usr/local/bin/ RUN chmod 755 /usr/local/bin/* # All builds will be done by user aosp -RUN useradd --create-home aosp -ADD gitconfig /home/aosp/.gitconfig -ADD ssh_config /home/aosp/.ssh/config -RUN chown aosp:aosp /home/aosp/.gitconfig +COPY gitconfig /root/.gitconfig +COPY ssh_config /root/.ssh/config # The persistent data will be in these two directories, everything else is # considered to be ephemeral VOLUME ["/tmp/ccache", "/aosp"] -# Improve rebuild performance by enabling compiler cache -ENV USE_CCACHE 1 -ENV CCACHE_DIR /tmp/ccache - # Work in the build directory, repo is expected to be init'd here -USER aosp WORKDIR /aosp + +COPY utils/docker_entrypoint.sh /root/docker_entrypoint.sh +ENTRYPOINT ["/root/docker_entrypoint.sh"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b0a4565 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +DOCKER = docker +IMAGE = kylemanna/aosp:4.4-kitkat + +aosp: Dockerfile + $(DOCKER) build -t $(IMAGE) . + +all: aosp + +.PHONY: all diff --git a/README.md b/README.md index a3492fb..2f3a9bf 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,27 @@ Android Open Source Project Docker Build Environment ==================================================== +[![Docker Stars](https://img.shields.io/docker/stars/kylemanna/aosp.svg)](https://hub.docker.com/r/kylemanna/aosp/) +[![Docker Pulls](https://img.shields.io/docker/pulls/kylemanna/aosp.svg)](https://hub.docker.com/r/kylemanna/aosp/) +[![ImageLayers](https://images.microbadger.com/badges/image/kylemanna/aosp.svg)](https://microbadger.com/#/images/kylemanna/aosp) + Minimal build environment for AOSP with handy automation wrapper scripts. Developers can use the Docker image to build directly while running the -distribution of choice, without having to worry about breaking the AOSP build -due to package updates as is sometimes common on rolling distributions like -Arch Linux. +distribution of choice, without having to worry about breaking the delicate +AOSP build due to package updates as is sometimes common on bleeding edge +rolling distributions like Arch Linux. Production build servers and integration test servers should also use the same -Docker image and environment. This eliminate most surprises in breakages by +Docker image and environment. This eliminates most surprise breakages by by empowering developers and production builds to use the exact same -environment. The hope is that breakages will be caught earlier by the devs. - -This only works (well) on Linux. Running this via `boot2docker` will result in -a very painful performacne hit due to VirtualBox's `vboxsf` shared folder -service which works terrible for **very** large builds like AOSP. It might -work, but consider youself warned. If you're aware of another way to get -around this, send a pull request! +environment. The devs will catch the issues with build environment first. -For *Mac OS X* and *Windows* users, consider -[kylemanna/vagrant-aosp](https://github.com/kylemanna/vagrant-aosp) as a good -virtual machine to enable development. +This works well on Linux. Running this via `boot2docker` (and friends) will +result in a very painful performacne hit due to VirtualBox's `vboxsf` shared +folder service which works terrible for **very** large file shares like AOSP. +It might work, but consider yourself warned. If you're aware of another way to +get around this, send a pull request! Quickstart @@ -44,11 +44,12 @@ For the terribly impatient. initializes the repo, fetches all source code, and builds. 5. In parallel you are expected to be drinking because I save you some time. + mkdir nougat ; cd nougat + export AOSP_VOL=$PWD + curl -O https://raw.githubusercontent.com/kylemanna/docker-aosp/master/tests/build-nougat.sh + bash ./build-nougat.sh - mkdir kitkat ; cd kitkat - export AOSP_VOL=$PWD - curl -O https://raw.githubusercontent.com/kylemanna/docker-aosp/master/tests/build-kitkat.sh - bash ./build-kitkat.sh + This takes about 2 hours to download and build on i5-2500k with 100Mb/s network connection. How it Works ------------ @@ -69,10 +70,41 @@ Docker container. For example to run `repo sync` in the Docker container: The `aosp` wrapper doesn't work well with setting up environments, but with some bash magic, this can be side stepped with short little scripts. See -`tests/build-kitkat.sh` for an example of a complete fetch and build of AOSP. +`tests/build-nougat.sh` for an example of a complete fetch and build of AOSP. + +[Docker Compose][] +------ + +A [Docker Compose][] file is provided in the root of this repository, you can tweak it as need be: +```yaml +version: "2" + +services: + aosp: + image: kylemanna/aosp:latest + volumes: + - /tmp/ccache:/ccache + - ~/aosp:/aosp +``` +Example run: `docker-compose run --rm aosp repo sync -j4` -- your android build directory will be in `~/aosp`. + +Issues +------ + +There are some known issues with using Docker Toolbox on macOS and current +virtualization technologies resulting in unusual user ID assignments and very +poor performing virtualization file sharing implementations with things like +VirtualBox. It's recommended to run this image completely in a virtual machine +with enough space to fit the entire build (80GB+) as opposed to mapping the +build to the local macOS file system via VirtualBox or similar. Tested ------ * Android Kitkat `android-4.4.4_r2.0.1` +* Android Lollipop `android-5.0.2_r1` +* Android Marshmallow `android-6.0.1_r80` +* Android Nougat `android-7.0.0_r14` + +[Docker Compose]: https://docs.docker.com/compose diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b21eb16 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +version: "2" + +services: + aosp: + image: kylemanna/aosp:latest + volumes: + - ~/aosp/ccache:/tmp/ccache + - ~/aosp:/aosp + - ~/.gitconfig:/root/.gitconfig diff --git a/tests/build-lollipop.sh b/tests/build-lollipop.sh new file mode 100755 index 0000000..aba9335 --- /dev/null +++ b/tests/build-lollipop.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# +# Test script file that maps itself into a docker container and runs +# +# Example invocation: +# +# $ AOSP_VOL=$PWD/build ./build-lollipop.sh +# +set -ex + +if [ "$1" = "docker" ]; then + TEST_BRANCH=${TEST_BRANCH:-android-5.0.2_r1} + TEST_URL=${TEST_URL:-https://android.googlesource.com/platform/manifest} + + cpus=$(grep ^processor /proc/cpuinfo | wc -l) + + repo init --depth 1 -u "$TEST_URL" -b "$TEST_BRANCH" + + # Use default sync '-j' value embedded in manifest file to be polite + repo sync + + prebuilts/misc/linux-x86/ccache/ccache -M 10G + + source build/envsetup.sh + lunch aosp_arm-eng + make -j $cpus +else + aosp_url="https://raw.githubusercontent.com/kylemanna/docker-aosp/master/utils/aosp" + args="bash run.sh docker" + export AOSP_EXTRA_ARGS="-v $(cd $(dirname $0) && pwd -P)/$(basename $0):/usr/local/bin/run.sh:ro" + export AOSP_IMAGE="kylemanna/aosp:5.0-lollipop" + + # + # Try to invoke the aosp wrapper with the following priority: + # + # 1. If AOSP_BIN is set, use that + # 2. If aosp is found in the shell $PATH + # 3. Grab it from the web + # + if [ -n "$AOSP_BIN" ]; then + $AOSP_BIN $args + elif [ -x "../utils/aosp" ]; then + ../utils/aosp $args + elif [ -n "$(type -P aosp)" ]; then + aosp $args + else + if [ -n "$(type -P curl)" ]; then + bash <(curl -s $aosp_url) $args + elif [ -n "$(type -P wget)" ]; then + bash <(wget -q $aosp_url -O -) $args + else + echo "Unable to run the aosp binary" + fi + fi +fi diff --git a/tests/build-marshmallow.sh b/tests/build-marshmallow.sh new file mode 100755 index 0000000..38c1cc3 --- /dev/null +++ b/tests/build-marshmallow.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# +# Test script file that maps itself into a docker container and runs +# +# Example invocation: +# +# $ AOSP_VOL=$PWD/build ./build-marshmallow.sh +# +set -ex + +if [ "$1" = "docker" ]; then + TEST_BRANCH=${TEST_BRANCH:-android-6.0.1_r80} + TEST_URL=${TEST_URL:-https://android.googlesource.com/platform/manifest} + + cpus=$(grep ^processor /proc/cpuinfo | wc -l) + + repo init --depth 1 -u "$TEST_URL" -b "$TEST_BRANCH" + + # Use default sync '-j' value embedded in manifest file to be polite + repo sync + + prebuilts/misc/linux-x86/ccache/ccache -M 10G + + source build/envsetup.sh + lunch aosp_arm-eng + make -j $cpus +else + aosp_url="https://raw.githubusercontent.com/kylemanna/docker-aosp/master/utils/aosp" + args="bash run.sh docker" + export AOSP_EXTRA_ARGS="-v $(cd $(dirname $0) && pwd -P)/$(basename $0):/usr/local/bin/run.sh:ro" + export AOSP_IMAGE="kylemanna/aosp:6.0-marshmallow" + + # + # Try to invoke the aosp wrapper with the following priority: + # + # 1. If AOSP_BIN is set, use that + # 2. If aosp is found in the shell $PATH + # 3. Grab it from the web + # + if [ -n "$AOSP_BIN" ]; then + $AOSP_BIN $args + elif [ -x "../utils/aosp" ]; then + ../utils/aosp $args + elif [ -n "$(type -P aosp)" ]; then + aosp $args + else + if [ -n "$(type -P curl)" ]; then + bash <(curl -s $aosp_url) $args + elif [ -n "$(type -P wget)" ]; then + bash <(wget -q $aosp_url -O -) $args + else + echo "Unable to run the aosp binary" + fi + fi +fi diff --git a/utils/aosp b/utils/aosp index eefa446..9579498 100755 --- a/utils/aosp +++ b/utils/aosp @@ -8,21 +8,48 @@ set -e # Override from environment -AOSP_IMAGE=${AOSP_IMAGE:-kylemanna/aosp} -AOSP_VOL=${AOSP_VOL:-/vol0} + +AOSP_IMAGE=${AOSP_IMAGE:-kylemanna/aosp:4.4-kitkat} AOSP_ARGS=${AOSP_ARGS:---rm -it} + +AOSP_VOL=${AOSP_VOL:-~/aosp-root} +AOSP_VOL=${AOSP_VOL%/} # Trim trailing slash if needed AOSP_VOL_AOSP=${AOSP_VOL_AOSP:-$AOSP_VOL/aosp} +AOSP_VOL_AOSP=${AOSP_VOL_AOSP%/} # Trim trailing slash if needed AOSP_VOL_CCACHE=${AOSP_VOL_CCACHE:-$AOSP_VOL/ccache} +AOSP_VOL_CCACHE=${AOSP_VOL_CCACHE%/} # Trim trailing slash if needed + +# Convenience function +function aosp_create_dir_if_needed { + directory=$1 + msg="aosp: Checking if $directory exists" + echo "$msg" + if [ ! -d "$directory" ]; then + echo "$msg - unexistent" + msg="Creating $directory" + echo "$msg" + mkdir -p $directory + fi + echo "$msg - ok" +} -if [ ! -d "$AOSP_VOL_AOSP" -o ! -d "$AOSP_VOL_CCACHE" ]; then - sudo mkdir -p $AOSP_VOL_AOSP $AOSP_VOL_CCACHE - sudo chmod 777 $AOSP_VOL_AOSP $AOSP_VOL_CCACHE +# Create AOSP_VOL_AOSP +aosp_create_dir_if_needed $AOSP_VOL_AOSP +aosp_create_dir_if_needed $AOSP_VOL_CCACHE + +uid=$(id -u) + +# Set uid and gid to match host current user as long as NOT root +if [ $uid -ne "0" ]; then + AOSP_HOST_ID_ARGS="-e USER_ID=$uid -e GROUP_ID=$(id -g)" fi -if [ -n "$SSH_AUTH_SOCK" ]; then +if [ -S "$SSH_AUTH_SOCK" ]; then SSH_AUTH_ARGS="-v $SSH_AUTH_SOCK:/tmp/ssh_auth -e SSH_AUTH_SOCK=/tmp/ssh_auth" fi -docker run $AOSP_ARGS $SSH_AUTH_ARGS $AOSP_EXTRA_ARGS \ +echo "" + +docker run $AOSP_ARGS $AOSP_HOST_ID_ARGS $SSH_AUTH_ARGS $AOSP_EXTRA_ARGS \ -v "$AOSP_VOL_AOSP:/aosp" -v "$AOSP_VOL_CCACHE:/tmp/ccache" \ $AOSP_IMAGE $@ diff --git a/utils/docker_entrypoint.sh b/utils/docker_entrypoint.sh new file mode 100755 index 0000000..1e0b014 --- /dev/null +++ b/utils/docker_entrypoint.sh @@ -0,0 +1,52 @@ +#!/bin/bash +set -e + +# This script designed to be used a docker ENTRYPOINT "workaround" missing docker +# feature discussed in docker/docker#7198, allow to have executable in the docker +# container manipulating files in the shared volume owned by the USER_ID:GROUP_ID. +# +# It creates a user named `aosp` with selected USER_ID and GROUP_ID (or +# 1000 if not specified). + +# Example: +# +# docker run -ti -e USER_ID=$(id -u) -e GROUP_ID=$(id -g) imagename bash +# + +# Reasonable defaults if no USER_ID/GROUP_ID environment variables are set. +if [ -z ${USER_ID+x} ]; then USER_ID=1000; fi +if [ -z ${GROUP_ID+x} ]; then GROUP_ID=1000; fi + +# ccache +export CCACHE_DIR=/tmp/ccache +export USE_CCACHE=1 + +msg="docker_entrypoint: Creating user UID/GID [$USER_ID/$GROUP_ID]" && echo $msg +groupadd -g $GROUP_ID -r aosp && \ +useradd -u $USER_ID --create-home -r -g aosp aosp +echo "$msg - done" + +msg="docker_entrypoint: Copying .gitconfig and .ssh/config to new user home" && echo $msg +cp /root/.gitconfig /home/aosp/.gitconfig && \ +chown aosp:aosp /home/aosp/.gitconfig && \ +mkdir -p /home/aosp/.ssh && \ +cp /root/.ssh/config /home/aosp/.ssh/config && \ +chown aosp:aosp -R /home/aosp/.ssh && +echo "$msg - done" + +msg="docker_entrypoint: Creating /tmp/ccache and /aosp directory" && echo $msg +mkdir -p /tmp/ccache /aosp +chown aosp:aosp /tmp/ccache /aosp +echo "$msg - done" + +echo "" + +# Default to 'bash' if no arguments are provided +args="$@" +if [ -z "$args" ]; then + args="bash" +fi + +# Execute command as `aosp` user +export HOME=/home/aosp +exec sudo -E -u aosp $args diff --git a/utils/jdk-6u45-linux-x64.bin b/utils/jdk-6u45-linux-x64.bin new file mode 100644 index 0000000..89a6f84 Binary files /dev/null and b/utils/jdk-6u45-linux-x64.bin differ