Building Android O with a Mac

After spending several hours to analyse dozens of posts and articles to compile Android O MR1 AOSP, I decided to write a short manual to help you to build your AOSP effortlessly ;-)

This article is based on Official Android documentation: https://source.android.com/setup/requirements

My Environment

  • OS: macOS Sierra 10.12.5
  • CPU: 2,9 GHz Intel Core i5 (influence the speed compilation)
  • RAM: 8 GB 1867 MHz DDR3 (8GB minimum, recommended 16GB)
  • Disk: 200GB free space (after AOSP sources downloaded — minimum 200GB)
  • Device: Nexus 5X (bullhead)

Setup your Build Environment

xcode-select --install
  • Install Homebrew with:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
$ java -version
> java version "1.8.0_144"
  • Install GIT with:
brew install git
  • Install Python with:
brew install python
  • Install Make with:
brew install make

Creating a case-sensitive disk image

Case sensitive volume of 200GB with the following command line:

hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 200g ~/android.dmg

Install tools and libraries via MacPort

Install MacPorts: https://www.macports.org/install.php then type the following command line:

POSIXLY_CORRECT=1 sudo port install gmake libsdl git gnupg

Then create and edit the .bash_profile file with the following code:

cd ~
nano .bash_profile
# set the number of open files to be 1024
ulimit -S -n 1024
# Compiler cache
export USE_CCACHE=1
# mount the android file image
function mountAndroid { hdiutil attach ~/android.dmg.sparseimage -mountpoint /Volumes/android; }
# unmount the android file image
function umountAndroid() { hdiutil detach /Volumes/android; }
export PATH="/opt/local/bin:/opt/local/sbin:$PATH"
export PATH=~/bin:$PATH
export ANDROID_JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
export PATH=$ANDROID_JAVA_HOME/bin:$PATH

Download AOSP source code

To identify the right branch to download, check the Build number of the target device. In our case OPM5.171019.017 which isncorresponding to the branch android-8.1.0_r18.

Branches and Builds codename: https://source.android.com/source/build-numbers#source-code-tags-and-builds

Warning: when you choose a branch be sure that the branch support the targeted device!

Select the targeted AOSP version with the branch with -b parameter: android-8.1.0_r18

source ~/.bash_profile
mkdir ~/bin
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo

mountAndroid
cd /Volumes/android
mkdir WORKING_DIRECTORY
cd WORKING_DIRECTORY

git config --global user.name "Your Name"
git config --global user.email "you@example.com"

repo init -u https://android.googlesource.com/platform/manifest
repo init -u https://android.googlesource.com/platform/manifest -b android-7.1.1_r1
repo sync

Building ASOP source code

Open terminal:

cd /Volumes/android/WORKING_DIRECTORY/ 
# Set ccache
prebuilts/misc/darwin-x86/ccache/ccache -M 50G
# Clean out directory
make clobber
# Jack server configuration
export JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx6g"
./prebuilts/sdk/tools/jack-admin kill-server
./prebuilts/sdk/tools/jack-admin start-server
# Setup environment 
source build/envsetup.sh

Select the device target with lunch command, then build the sources with make command:

# Select device target
lunch
# Build sources (cofee time)
make -j4

When the build process if finished you get the following message:

[100% 7091/7091] Install system fs image: out/target/product/generic/system.img
out/target/product/generic/system.img+ maxsize=1918388736 blocksize=2112 total=1879048192 reserve=19379712
#### make completed successfully (02:52:17 (hh:mm:ss)) ####

Install new Android Build on Device

Connect the Device in USB, enable the Developer Mode, then input the following command lines in you Terminal:

cd out/target/product/<product_name> 
adb reboot bootloader
fastboot oem unlock 
fastboot flashall -w

Restore Android Image

To restore an official Android Image please download the target Image and follow the instructions:

cd ~/Downloads/bullhead-opm5.171019.017/
adb reboot bootloader
fastboot oem unlock
./flash-all.sh

Rebuild a single package

To rebuild a single package (example: Dialer App) instead of rebuild the entire baseline, use the following command lines:

cd WORKING_DIRECTORY
source build/envsetup.sh
# Select device target
lunch
# Rebuil single pacage (exemple Dialer)
mmm packages/apps/dialer/

The output APK path will be prompt by the console, or located at the following path:

# Recompiled package output
cd /out/target/product/<device_targeted>/obj/APPS/<app_name>_intermediates

How to install it

adb install -r out/target/product/<device_targeted>/system/priv-app/<app_name>/<app_name>.apk
adb reboot

System UI

Build System UI only:

cd WORKING_DIRECTORY
source build/envsetup.sh
# Select device target
lunch
# Rebuil single pacage (exemple Dialer)
mmm frameworks/base/packages/SystemUI/

How to install it

adb install -r out/target/product/<device_targeted>/system/priv-app/SystemUI/SystemUI.apk
adb reboot

Android Framework

  • Build Framework JAR only: mmm framework/base/
  • Build Framework Resources only: mmm framework/base/core/res/

How to install it

# Root the device
adb root
adb disable-verity
adb reboot
adb remount
# Remove older framework
adb shell
cd /system/framework/
rm framework-res.apk
exit
# Push the new Framework
adb push out/target/product/<device_targeted>/system/framework/framework-res.apk /system/framework/
# Reboot the device
adb reboot

Signing Build

The standard Android build uses four keys, all of which reside in build/target/product/security:

  • testkey: Generic default key for packages that do not otherwise specify a key.
  • platform: Test key for packages that are part of the core platform.
  • shared: Test key for things that are shared in the home/contacts process.
  • media: Test key for packages that are part of the media/download system.
cd /build/target/product/security/

Source: https://source.android.com/devices/tech/ota/sign_builds#certificates-keys

To sign an app with one of the existing key, use the following instruction (LOCAL_CERTIFICATE) into the associated makefile Android.mk:

Android.mk

LOCAL_CERTIFICATE := platform

Troubleshooting

Can not find Mac SDK or Required minimum for the macosx platform

Download and uncompress the exact missing Mac SDK version into the following directory:

  • /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/

Download Mac SDKs: https://github.com/phracker/MacOSX-SDKs/releases

Error: could not find jdk tools.jar

Need to defined $ANDROID_JAVA_HOME used in ~/build/core/find-jdk-tools-jar.sh

export ANDROID_JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
echo $ANDROID_JAVA_HOME
/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home

Download and install JDK before : http://www.oracle.com/technetwork/java/javase/downloads/java-archive-javase8-2177648.html#jdk-8u45-oth-JPR

Make error — already defined

If you got the following error during the AOSP compilation:

including ./go/src/github.com/google/gapid/third_party/khronos/SPIRV-Cross/jni/Android.mk ...
build/core/base_rules.mk:183: *** go/src/github.com/google/gapid/third_party/khronos/SPIRV-Cross/jni: MODULE.TARGET.STATIC_LIBRARIES.spirv-cross already defined by go/src/github.com/google/gapid/third_party/SPIRV-Cross/jni.
make: *** [out/build-aosp_arm.ninja] Error 1

Go to the already defined directory and rename simply the Android.mk file to Android_old.mk

GC overhead limit exceeded

GC overhead limit exceeded. Try increasing heap size with java option '-Xmx<size>'.
FAILED: /bin/bash out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/with-local/classes.dex.rsp
Out of memory error (version 1.2-rc4 'Carnac' (298900 f95d7bdecfceb327f9d201a1348397ed8a843843 by android-jack-team@google.com)).
GC overhead limit exceeded.
Try increasing heap size with java option '-Xmx<size>'.
Warning: This may have produced partial or corrupted output.

To increase the the heap size use the following command lines:

export JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx6g"
./prebuilts/sdk/tools/jack-admin kill-server
./prebuilts/sdk/tools/jack-admin start-server

Case-insensitive filesystem

You are building on a case-insensitive filesystem.

************************************************************
You are building on a case-insensitive filesystem.
Please move your source tree to a case-sensitive filesystem.
************************************************************
Case-insensitive filesystems not supported.

Creating a case-sensitive disk image: https://source.android.com/source/initializing#setting-up-a-mac-os-x-build-environment

Fatal error file not found

If the following error is raised during the Android building process:

external/iptables/extensions/../include/linux/netfilter_ipv4/ipt_ECN.h:13:10: fatal error: 'linux/netfilter/xt_DSCP.h' file not found
#include <linux/netfilter/xt_DSCP.h>

Please check the filename user or lower case. Remember that the Android building process is case-sensitive.

In this case create a symbolic name xt_dscp.h for the original file xt_DSCP.h with the following command lines:

cd external/iptables/extensions/../include/linux/netfilter
ln -s xt_dscp.h xt_DSCP.h

Result:

No space left on device

If the case-sensitive partition become full (no free space available):

[ 25% 2/8] build out/target/product/generic/obj/JAVA_...RARIES/SystemUI-proto-tags_intermediates/classes.jackninja: error: mkdir(out/target/product/generic/obj/JAVA_LIBRARIES/SystemUI-proto-tags_intermediates): No space left on device

Open Terminal and increase the partition size:

umountAndroid
hdiutil resize -size <new-size-you-want>g ~/android.dmg.sparseimage
mountAndroid

Missing and no known rule to make it

If the flowing error is raised during a single package compilation thought mm or mmm command:

ninja: error: 'out/target/common/obj/JAVA_LIBRARIES/metrics-helper-lib_intermediates/link_type', needed by 'out/target/common/obj/APPS/SystemUITests_intermediates/link_type', missing and no known rule to make it
12:39:35 ninja failed with: exit status 1
make: *** [run_soong_ui] Error 1

Compile the bidding library metrics-helper:

mma platform_testing/libraries/metrics-helper/

OR, go to the main makefile Android.mk and disable the Unit tests project compilation by commenting the include line:

Android.mk

include $(BUILD_PACKAGE)
# disable the sub-project makefile: ./tests/Android.mk
# include $(call all-makefiles-under,$(LOCAL_PATH))