Building LineageOS for my Mate 8

written the 17th Aug 2017

Android, being open-source, means people can take the code, make their modifications and publish it. CyanogenMod was one such project, bringing many features on top of AOSP (standard) Android we now take for granted. After some trouble with commercialisation, the project rebranded as LineageOS in December 2016. At the time of writing, the project is basically just the code from cm-14.1. Bigger changes will come when a new Android version is released to the Android Open Source Project.

Requirements

You're going to need:

  • a recent *Nix system
  • a reasonable knowledge of the command line
  • 8GB+ RAM
  • Dual-core+ CPU
  • Lots of disk space (~50GB for the actual source code, ~30GB per device and however much you want for cache)
  • 10mbps+ internet (if you want to get anything done)
  • sudo privileges
  • a Huawei Mate 8 (of course :))

a so easy to open Huawei Mate 8

You don't need to have it wide open like above, just a cable to connect it via USB.

Dependancies

bc bison build-essential curl flex git gnupg gperf libesd0-dev liblz4-tool libncurses5-dev libsdl1.2-dev libwxgtk3.0-dev libxml2 libxml2-utils lzop maven openjdk-8-jdk pngcrush schedtool squashfs-tools xsltproc zip zlib1g-dev android-tools-adb android-tools-fastboot

Additionally for 64bit systems, g++-multilib gcc-multilib lib32ncurses5-dev lib32readline6-dev lib32z1-dev.

Now we also need repo, a tool written by Google to manage git repositories. It's not the best (tsrc could be better), but it's the one chosen by the project to download all its parts easily and you should stick to it.

Ensure you have openjdk 8 and the Android SDK in your path (installed).

Prebuild parameters

  • RAM: an important consideration, as you need a decent amount. You need at least 4GB really, but I made mine 6G, so I wouldn't run into problems: export ANDROID_JACK_VM_ARGS="-Xmx6g -Dfile.encoding=UTF-8 -XX:+TieredCompilation"
  • CCACHE: CCACHE is amazing. When you get round to building, it checks to see what has changed and only builds files that are different from the build. This saves unbelievable amounts of time, as some files, hardly ever touched, only need to be built once! Activate it with export USE_CCACHE=1 and prebuilts/misc/linux-x86/ccache/ccache -M 50G where 50 is the disk space you wish to allocate to it.

Getting the code

# make the folder to store all the Android code
# This is where you can choose to store all this somewhere else
mkdir -p ~/android/system

# Move into the directory, ready to start downloading
cd ~/android/system/

# Tell repo what we want to download
# init = initialise the repositories
# https://github.com/LineageOS/android.git = the list of repositories to download
# -b cm-14.1 =  the branch or version of code we are downloading
#               this will change depending on the version *you* want. This is for cm-14.1 (CyanogenMod 14.1 based on Android 7.1.1)
repo init -u https://github.com/LineageOS/android.git -b cm-14.1

# Start the download
repo sync

At this point, (unless you have gigabit internet), go get a coffee day off. This is gonna take a HUGE while.

Device-specific code

The code we just downloaded is the general or common code for Android. Put simply, it's the stuff that's the same on all the devices.

To get specific files for a device (such as angler), we need to tell repo which device you want. As well as the open-source device specifics, you need some proprietary files (things like camera libraries or sound FX libraries). These can be either extracted from a device already running stock android: (with Developer Settings enabled - tap on Build number in Settings > About seven times), but are best downloaded online.

Just replace yourdevicecodenamehere with your device's codename. For instance, the Nexus 6P's is angler, the Nexus 9's is flounder and Motorola Moto G (2013)'s is falcon.

source build/envsetup.sh
breakfast yourdevicecodenamehere

You should see some errors, at which point you want to download the proprietary code for your manufacturer. All this can be done in the next section, once we go through some terms.

Proprietary files

Repo decides what repositories to download by looking through manifests. The main manifest (downloaded when we initialised repo) is present in ~/home/yourusername/android/system/.repo/manifest.xml and contains loads of repos needed for building common Android files.

You could edit this file, but since this is updated when new things are added to Android, your changes would always be being overwritten. So the better option is to use local manifests. If you edit ~/home/yourusername/android/system/.repo/local_manifests/roomservice.xml, where you can add and remove your own repos to the main list, without editing the main manifest.

Why on earth might you do this?

If you want to make changes to device specific files, or even common Android things, you can fork the repository you'd like to change. You can make your changes in this repo (which you own) and then incorporate those changes into your builds.

How do I make a manifest then?

Edit roomservice: nano ~/android/system/.repo/local_manifests/roomservice.xml You should see some content already here, based loosely on this:

<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote name="github" fetch=".." review="review.lineageos.org" />
<project path="where/the/files/need/to/go" name="LineageOS/name_of_repo" remote="github"/>
</manifest>

This contains all the device-specific code (excluding the proprietary stuff). To download the proprietary stuff, wander over to TheMuppets GitHub and search for your manufacturer. Take note of the name of the repository. Then add this before </manifest> at the bottom of the file:

<project path="vendor/MANUFACTURER" name="TheMuppets/NAME_OF_REPO" remote="github"/>

For instance, as I want to work on Paul Fasola's WIP for the Huawei Mate 8, I find its local manifest in local_manifests/roomservice.xml and copy/append it to .repo/local_manifests/roomservice.xml. Putting the code you will further develop in a repository dedicated to the device is a nice way to share your code, and ideally should integrate with repo (see the dedicated section).

After you've made any changes to your manifest or want to update the code from LineageOS, run:

# From your ~/android/system directory
repo sync

First build

Before you do anything, make sure your codebase is up-to-date:

# From your ~/android/system directory
repo sync

Then simply:

# Replace DEVICECODENAME with the device's codename in lowercase
brunch DEVICECODENAME

Now it's time for another coffee :-)

When it's done (returned you back to the shell prompt), you should find the build under ~/android/system/out/target/product/DEVICECODENAME/ called something like cm-14.1-20161231-UNOFFICIAL-DEVICECODENAME.zip.

Warning: You can install this image as any other official image, with again, results that will eat your cat.

Remember, you assume all risk of trying this, but you will reap the rewards! It’s pretty satisfying to boot into a fresh operating system you baked at home, and it gives you knowledge of what's inside.

Going further

Sharing your code

Sharing is caring, but it's also an important feature of LineageOS since it's built in a very composable way. Understanding how it is shared will help you get all the parts you need to build your custom/WIP ROM.

Once you've started your device folder, create your own GitHub account and set up your folder as a public GitHub repository. This is a great opportunity to learn about git, and also your source can be accessible to others who can collaborate with you.

When naming your repository, use the format android_device_VENDOR_CODENAME, where VENDOR and CODENAME use the new device's values. So, let's say your GitHub account name is "fat-tire" and your device codename is "encore", manufactured by Barnes and Noble. You should call your repository android_device_bn_encore. It would be accessible at https://github.com/fat-tire/android_device_bn_encore. Similarly, the kernel repository would be called android_kernel_bn_encore. It would be accessible at https://github.com/fat-tire/android_kernel_bn_encore.

The last thing to do is create a local manifest for other people to use to automatically download and their keep up-to-date with your changes. Here's an example, using the above scenario:

<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <project name="fat-tire/android_device_bn_encore" path="device/bn/encore" remote="github" revision="cm-10.1" />
  <project name="fat-tire/android_kernel_bn_encore" path="kernel/bn/encore" remote="github" revision="cm-10.1" />
</manifest>

note: the revision attribute is optional. If it is omitted, repo sync will use the revision specified by the <default ... /> tag in the default manifest.

Once you've tested that the local manifest file works, you can pass it on to others, who can then try out your work.

note: if you find that for some reason you need to replace or supplement other repositories provided by LineageOS, you can add additional repositories using the local manifest. Once you've got everything working, you can use Gerrit to submit stuff found in those repositories back upstream to CyanogenMod.

Adding XML overlays

It's very likely in your device_[codename].mk file, there's a line that looks like this:

DEVICE_PACKAGE_OVERLAYS := \
    device/[vendor]/[codename]/overlay

What this does is set the overlay/ folder to allow you to override any XML file used by Android frameworks or apps, just for this device. To do so, create a directory structure which mirrors the path leading to an XML file, starting from the root of your source. Then replace the file you want to overlay.

Example: Let's say you want to override some standard Android settings. Look at the file in frameworks/base/core/res/res/values/config.xml. Then copy it to device/[vendor]/[codename]/overlay/frameworks/base/core/res/res/values/config.xml. Now YOUR version will be used instead of the other one. You only need to include the settings you wish to override - not all of them, so you can pare down the file to those few that change from the default.

You can overlay any XML file, affecting layouts, settings, preferences, translations, and more.