Since about two years I’m using a LG G6 smartphone. It shipped initially with Android 7 and later got an update to Android 8. Their Android version comes with some LG specific modifications. Nothing too far off from vanilla Android. The UI is fine, I have no trouble in using it. What bothers me are all these pre-installed apps (bloatware). Here is a complete list of all installed apps on my LG G6:
Thanks. But no thanks.
Entering the world of custom ROMs
This is way too much bloat for my taste. A lot of useless, proprietary LG apps that, maybe or maybe not, want to phone home – in addition to all the standard Google spyware. On top of that, I’m accusing LG of developing not the most secure software in the world (*wink* *wink*1). Every listed app is a potential attack surface. To be fair: Most of the apps can be uninstalled or deactivated.
Since I’m a privacy and security focused guy, I tried out an alternative Android ROM quite early after I purchased the G6. One of the most obvious choices is LineageOS. Their modifications are relative minimal. They have some unique features, but most of them are unobtrusive. The list of pre-installed apps is, compared to LG’s list, really small. Most of the apps are even open source.
As far as I remember correctly I tested the version 14.1 based on the now deprecated CyanogenMod. Unfortunately, this is the last official release for LG G6 up until now. It’s based on Android 7.1, released somewhere end of 2016. LG itself released an update to Android 8.0 later on, but no official release from Lineage was ever published.
But we’re not finished here: I wanted to get rid of Google too! Using Android without Google sounds like a contradiction, since Android is development by Google. The Android Open Source Project (AOSP) itself is open software. In fact, LineageOS is based on the AOSP project. Nonetheless, more and more essential parts of the OS are now closed source. I want an operation system with no, or at least with as little as possible closed source components. That means, I have to get rid of all Google services including Mail, Geo-Location, Push-Notifications or even the Play Store itself. Just using LineageOS with gapps does not take me closer to this goal.
To the rescue: microG
The microG project tries to re-implement all those proprietary user space apps and libraries. (Almost) all functionality can be archived with microG without using any Google service or closed source component. There’s only one catch: You can’t just use any random Android ROM, neither the original from your vendor nor LineageOS.
To use the full potential of microG, you have to modify some deep rooted system files. The microG team is aware of this problem and has a solution: They provide custom LineageOS builds available with full microG and native F-Droid support.
For most users, this is probably the best solution available. Depending on you actual device, it’s quite easy (read: there are a lot of tutorials) to install custom ROMs. However, if you have for any reason a non officially supported device, you are also out of luck here. In my case, the last LineageOS release available is 14.1 (aka Android Nougat 7.1). Version 16.0 (Android Pie 9.0) is the most recent one at the moment. I could live with an older Android release, if there weren’t all those unfixed security holes.
Building your own ROM
Even though there are no official Lineage releases, there are unofficial ones! These are created and maintained by a loosely coupled community of vastly different users. Some ports are working great, some are buggy and some are just for testing. In my case, the unofficial LineageOS 16.0 ports is quite stable without any major limitations. VoLTE and Wifi calling doesn’t work. Or 5.0 Ghz hotspot. Nothing fundamental. Nothing I really need.
Unfortunately all these ROMs are prepared to be used in combination with Google services, not with microG. But at least we have the source code and can build our own Android ROM.
Step 1: Setup a development environment
Before we can start creating our own custom ROM, we need to have all necessary tools installed. The simplest way I found was using the docker image from the microG team that they use them self to build their version of LineageOS. The source code to build the docker image is available at Github. Alternatively, a prebuilt image is ready to download at Docker Hub.
docker-compose to set up a new docker container:
version: '3' services: lineage-build: image: lineageos4microg/docker-lineage-cicd volumes: - "/srv/lineage-build/lineage:/srv/src" - "/srv/lineage-build/zips:/srv/zips" - "/srv/lineage-build/logs:/srv/logs" - "/srv/lineage-build/cache:/srv/ccache" - "/srv/lineage-build/keys:/srv/keys" - "/srv/lineage-build/manifests:/srv/local_manifests" environment: - "BRANCH_NAME=lineage-16.0" - "DEVICE_LIST=h870" - "SIGN_BUILDS=true" - "SIGNATURE_SPOOFING=restricted" - "INCLUDE_PROPRIETARY=false" - "CUSTOM_PACKAGES=GmsCore GsfProxy FakeStore MozillaNlpBackend NominatimNlpBackend com.google.android.maps.jar FDroid FDroidPrivilegedExtension" - "ALLOW_MISSING_DEPENDENCIES=true" - "WITH_SU=true"
You need to change at least the device name at line 14. You probably need to change some more variables depending on your system configuration and your own taste. More details and examples can be found in their repository.
Step 2: Configuration
The build script needs to know where the sources for your device is located.
If your device is officially supported, then you can skip this section, otherwise you need to create a configuration file – a so called
All manifest files must be saved under
/srv/lineage-build/manifests (or whatever you defined in the volume section of your docker-compose file).
The name of the manifest file is not important but should end with
The configuration for my device looks like this:
<?xml version="1.0" encoding="UTF-8"?> <manifest> <project name="LG-G6-dev/android_kernel_lge_msm8996" path="kernel/lge/msm8996" remote="github" revision="caf" /> <project name="LG-G6-dev/android_device_lge_h870" path="device/lge/h870jd" remote="github" revision="aoscp" /> <project name="LG-G6-dev/android_device_lge_msm8996-common" path="device/lge/msm8996-common" remote="github" revision="pie" /> <project name="LG-G6-dev/proprietary_vendor_lge" path="vendor/lge" remote="github" revision="caf" /> <project name="LG-G6-dev/android_device_lge_g6-common" path="device/lge/g6-common" remote="github" revision="pie" /> </manifest>
The kernel sources, device tree, vendor blobs, etc are located in different github repositories.
You will most likely find all necessary information for your device in the xda forums.
You can also try to find the right repos with the help of the Github search function.
For example, the device tree is most likely called
Some repositories contain a file called
lineage.dependencies that will help to find further source location like the common tree or vendor blob.
You will most likely also want to include prebuilt packages for microG und F-Droid. You can do this by creating another manifest XML file with the following content:
<?xml version="1.0" encoding="UTF-8"?> <manifest> <project name="lineageos4microg/android_prebuilts_prebuiltapks" path="prebuilts/prebuiltapks" remote="github" revision="master" /> </manifest>
3. Step 3: Compiling
Starting the container will fetch all necessary git repositories and start compiling your Android ROM:
This will take several hours depending on your hardware.
The installable zip file will be located at
/srv/lineage-build/zips (if everything works).
You can then install the zip file with TWRP.
Don’t forget to back up all your data!
Newest Android security patch level. Yeahh!
Errors while building the kernel
At first I had problems building the Linux kernel. Traditionally the Linux kernel must be build with gcc. For some time now the kernel developers tried to get rid of all the gcc specific code. I am not sure what the current state is for the vanilla kernel, but as far as I know gcc is in most cases your only option.
The Android Linux kernel is not vanilla.
They added a lot of custom patches.
One of the thing they changed, was that the Android kernel can be fully build with CLANG instead of gcc.
But at least in my case I had trouble with it and got some obscure error messages while building the kernel.
The simplest fix for me was to build the kernel with gcc.
To do this, you just have to set the
TARGET_KERNEL_CLANG_COMPILE to false in
Unfortunately, this file will be overwritten each time you use the
/root/init.sh script that gets called automatically when you start the container.
My solution to this problem is to use a file called
/root/userscripts/pre-build.sh to overwrite this value each time:
echo "Disable CLANG kernel build" sed -i '1s/^/TARGET_KERNEL_CLANG_COMPILE = false\n/' /srv/src/LINEAGE_16_0/vendor/lineage/build/tasks/kernel.mk
The provided build script will call this file before the actual build starts. The kernel will now be build with gcc :)
Normally you would only need to restart the container to update and rebuild everything. Normally. Sometimes, actually quite often, it fails due to problems updating all git repositories. In the end, I updated my docker-compose file to let it run in the background indefinitely:
services: lineage-build: image: lineageos4microg/docker-lineage-cicd stdin_open: true tty: true entrypoint: - /bin/bash [...]
I can then jump straight into the container with
docker exec -ti lineageos_lineage-build_1 bash and run the following command to update all repositories:
cd LINEAGE_16_0 repo sync -c --force-sync
If there is any problem, e.g. file conflicts, I can then fix them manually until the repo sync command works.
Afterwards a simple
/root/init.sh will start the normal build process.