Skip to content

Android Automotive »

Build Android system and Kernel images

AOSP, led by Google, is an open source operating system for mobile devices. Andoid now aday can run on many different devices, including Vehicle Infortainment systems. Android Automotive has the base of Android platform, with additional functions for IVI systems. It well supports apps built for Android as well as those built for Android Auto.

Last update: 2022-06-30

This guide is based on AOSP android-10.0.0_r47 and android-12.1.0_r8

Android Open Source Project#

Android is an open source software stack created for a wide array of devices with different form factors. Android’s primary purpose is to create an open software platform available for carriers, OEMs, and developers to make their innovative ideas a reality and to introduce a successful, real-world product that improves the mobile experience for users.

Android Framework Stack

Android development releases are organized into families, with alphabetical codenames. You can look up the codenames and the version numbers in Codenames, Tags, and Build Numbers.

Android Code Search allows you to search AOSP without downloading anything. You can use Code Search to view the AOSP source code, switch between open source branches, and navigate cross-references.

AOSPXRef is a web-based code browsers similar to Android Code Search.

Android Automotive#

Android Automotive is a base Android platform that runs pre-installed IVI system Android applications as well as optional second- and third-party Android Applications. Android Automotive offers openness, customization, and scale to automotive infotainment systems and head units.

These things below can be confusing:

  • Android Auto is a platform running on the user’s phone, projecting the Android Auto user experience to a compatible in-vehicle infotainment system over a USB connection. Android Auto supports apps designed for in-vehicle use.

  • Android Automotive is an operating system and platform running directly on the in-vehicle hardware. It is a full-stack, open source, highly customizable platform powering the infotainment experience. Android Automotive supports apps built for Android as well as those built for Android Auto.

Google Automotive Services (GAS) is a collection of applications and services that automotive OEMs can choose to license and integrate into their in-vehicle infotainment (IVI) systems.

Android Automotive Framework Stack

Build AOSP System Image#

The official guide at usually is updated to the latest version. Building an older version of AOSP may need some modifications.


Host machine

It is recommended to have Ubuntu 20.04 LTS, because Windows and MacOS are not supported, and Google repo is updated to Python 3.

You can optionally follow some tweaks to get better performance on your host machine such as: use noatime and remove journal feature of disk storing source code.

Host packages

sudo apt install \
    git curl \
    build-essential flex bison \
    libncurses5 libssl-dev libelf-dev

Repo and Git tool

Install repo from the package management:

sudo apt install repo

If it is not working, try to install manually:

mkdir -p ~/.bin
curl > ~/.bin/repo
chmod a+rx ~/.bin/repo
echo 'PATH="${HOME}/.bin:${PATH}"' >> ~/.bashrc
source ~/.bashrc

On Ubuntu 20.04, /usr/bin/env/python is not pointing to python3, so install below package:

sudo apt install python-is-python3

Set git user:

git config --global ""
git config --global "vuquangtrong"

Download and Build#

Git clone modes

Read details in Get up to speed with partial clone and shallow clone.

  • Full clone

    This is the default mode. All blobs and trees are downloaded.

  • Partial clone

    If using Git version 2.19 or greater, --partial-clone option is used to parialy download the needed objects.

    • Blobless: Remove all file history with the option:
      --partial-clone --clone-filter=blob:none

    • Treeless: Remove all directory history with the option:
      --partial-clone --clone-filter=tree:0

  • Shallow clone

    An older feature that does something very similar to a Treeless clone is Shallow clone with the option --depth=1. This truncates the history to only download current commit.

Android version

Version API Codename Release date Major changes
12.1 32 S Mar 2022
12 31 S Oct 2021
11 30 R Sep 2020 New Permission Controls
10 29 Q Mar 2019 HIDL is deprecated, use AIDL every where
9 28 P Aug 2018
8.1 27 O Dec 2017
8.0 26 O Aug 2017 Use HIDL instead of classical HAL
7.1 25 N Aug 2016

Initialize the repo:

Go to and select a target branch.

In this example, use shallow clone to reduce download time. If you need to read full log, or contribute back to the upstream repo, please fully clone the repo.

export AOSP_BRANCH="android-10.0.0_r47"
repo init \
    -u \
    -b $AOSP_BRANCH \
export AOSP_BRANCH="android-12.1.0_r8"
repo init \
    -u \
    -b $AOSP_BRANCH \

Download source code:

To speed up, use the -c (current branch) option.

repo sync -c -j$(nproc) && sync

The download takes few hours to complete.

Apply modifications

There is one Python 2 script in AOSP 10.0.0_r47 which needs modified:

Install Python 2:

sudo apt install python2

Then edit the she-bang of the script to use Python 2:

- #!/usr/bin/python
+ #!/usr/bin/python2

All build scripts are converted to Python 3.

Setup environment:

source build/

Run lunch with no arguments to list all targets.

You're building on Linux

Lunch menu... pick a combo:
    1. aosp_arm-eng
    2. aosp_arm64-eng
    3. aosp_blueline-userdebug
    4. aosp_bonito-userdebug
    5. aosp_car_arm-userdebug
    6. aosp_car_arm64-userdebug
    7. aosp_car_x86-userdebug
    8. aosp_car_x86_64-userdebug
    9. aosp_cf_arm64_phone-userdebug
    10. aosp_cf_x86_64_phone-userdebug
    11. aosp_cf_x86_auto-userdebug
    12. aosp_cf_x86_phone-userdebug
    13. aosp_cf_x86_tv-userdebug
    14. aosp_crosshatch-userdebug
    15. aosp_marlin-userdebug
    16. aosp_sailfish-userdebug
    17. aosp_sargo-userdebug
    18. aosp_taimen-userdebug
    19. aosp_walleye-userdebug
    20. aosp_walleye_test-userdebug
    21. aosp_x86-eng
    22. aosp_x86_64-eng
    23. beagle_x15-userdebug
    24. fuchsia_arm64-eng
    25. fuchsia_x86_64-eng
    26. hikey-userdebug
    27. hikey64_only-userdebug
    28. hikey960-userdebug
    29. hikey960_tv-userdebug
    30. hikey_tv-userdebug
    31. m_e_arm-userdebug
    32. mini_emulator_arm64-userdebug
    33. mini_emulator_x86-userdebug
    34. mini_emulator_x86_64-userdebug
    35. poplar-eng
    36. poplar-user
    37. poplar-userdebug
    38. qemu_trusty_arm64-userdebug
    39. uml-userdebug
Which would you like? [aosp_arm-eng]:

You're building on Linux

Lunch menu... pick a combo:
    1. aosp_arm-eng
    2. aosp_arm64-eng
    3. aosp_barbet-userdebug
    4. aosp_blueline-userdebug
    5. aosp_blueline_car-userdebug
    6. aosp_bonito-userdebug
    7. aosp_bonito_car-userdebug
    8. aosp_bramble-userdebug
    9. aosp_bramble_car-userdebug
    10. aosp_car_arm-userdebug
    11. aosp_car_arm64-userdebug
    12. aosp_car_x86-userdebug
    13. aosp_car_x86_64-userdebug
    14. aosp_cf_arm64_auto-userdebug
    15. aosp_cf_arm64_phone-userdebug
    16. aosp_cf_x86_64_foldable-userdebug
    17. aosp_cf_x86_64_pc-userdebug
    18. aosp_cf_x86_64_phone-userdebug
    19. aosp_cf_x86_64_tv-userdebug
    20. aosp_cf_x86_auto-userdebug
    21. aosp_cf_x86_phone-userdebug
    22. aosp_cf_x86_tv-userdebug
    23. aosp_coral-userdebug
    24. aosp_coral_car-userdebug
    25. aosp_crosshatch-userdebug
    26. aosp_crosshatch_car-userdebug
    27. aosp_crosshatch_vf-userdebug
    28. aosp_flame-userdebug
    29. aosp_flame_car-userdebug
    30. aosp_oriole-userdebug
    31. aosp_oriole_car-userdebug
    32. aosp_raven-userdebug
    33. aosp_raven_car-userdebug
    34. aosp_redfin-userdebug
    35. aosp_redfin_car-userdebug
    36. aosp_redfin_vf-userdebug
    37. aosp_sargo-userdebug
    38. aosp_sargo_car-userdebug
    39. aosp_slider-userdebug
    40. aosp_sunfish-userdebug
    41. aosp_sunfish_car-userdebug
    42. aosp_trout_arm64-userdebug
    43. aosp_trout_x86-userdebug
    44. aosp_whitefin-userdebug
    45. aosp_x86-eng
    46. aosp_x86_64-eng
    47. arm_krait-eng
    48. arm_v7_v8-eng
    49. armv8-eng
    50. armv8_cortex_a55-eng
    51. armv8_kryo385-eng
    52. beagle_x15-userdebug
    53. beagle_x15_auto-userdebug
    54. car_ui_portrait-userdebug
    55. car_x86_64-userdebug
    56. db845c-userdebug
    57. fuchsia_arm64-eng
    58. fuchsia_x86_64-eng
    59. gsi_car_arm64-userdebug
    60. gsi_car_x86_64-userdebug
    61. hikey-userdebug
    62. hikey64_only-userdebug
    63. hikey960-userdebug
    64. hikey960_tv-userdebug
    65. hikey_tv-userdebug
    66. pixel3_mainline-userdebug
    67. poplar-eng
    68. poplar-user
    69. poplar-userdebug
    70. qemu_trusty_arm64-userdebug
    71. sdk_car_arm-userdebug
    72. sdk_car_arm64-userdebug
    73. sdk_car_portrait_x86_64-userdebug
    74. sdk_car_x86-userdebug
    75. sdk_car_x86_64-userdebug
    76. silvermont-eng
    77. uml-userdebug
    78. yukawa-userdebug
    79. yukawa_sei510-userdebug

Which would you like? [aosp_arm-eng]:

Target in format <product_name>-<build_variant> where build_variant can be:

  • user: Limited access; suited for production
  • userdebug: Like user but with root access and debug capability; preferred for debugging
  • eng: Development configuration with additional debugging tools

Select target:

lunch aosp_car_x86_64-eng

lunch sdk_car_x86_64-eng
PRODUCT_SOONG_NAMESPACES=device/generic/goldfish device/generic/goldfish-opengl hardware/google/camera hardware/google/camera/devices/EmulatedCamera device/generic/goldfish device/generic/goldfish-opengl

A target can include other base targets, such as

  • inherit device/generic/car/emulator/
  • inherit $(SRC_TARGET_DIR)/product/


m all -j$(nproc)

The compilation takes hours to complete.

The minimum required amount of free memory is around 16 GB, and even with that, some configurations may not work. If you run into segfaults or other errors, try reducing your -j value.

AOSP is built successfully

AOSP SDK is built successfully

Source Code structure#

There are many folders in the root folder of AOSP, here are short descriptions of them:

art: Android Runtime
Implementation of Android Runtime layer.
bionic: C-runtime library
Android is not using glibc like most Linux distributions. Instead, the c-library is called bionic and is based mostly on BSD-derived sources.
bootable: Boot and Startup
Bootloader, and some tools for recovery, flashing such as fastboot.
build: Target and build directions
An important file here is the script that will help you a lot when working with the platform source. Running this script in a shell will enable commands to set up environment variables, build specific modules and grep in source code files.
cts: Compatibility Test
The test suite to ensure that a build complies with the Android specification.
dalvik: Dalvik Virtual Machine
This will build the virtual machine.
development: Development platform
Projects which are related to development such as the source code for the SDK and NDK tools. Normally not a folder you touch when working with the platform for a target.
device: Product
Build configuration, hardware modules and specific code for different devices.
external: External open source components
Contains source code for all external open source projects such as SQLite, FreeType and WebKit.
frameworks: Android framework
The implementation of key services such as the System Server with the Package- and Activity managers. A lot of the mapping between the java application APIs and the native libraries is also done here.
hardware: Hardware implementation
The Android Hardware Abstraction Layer specification and implementation.
Helper functions for use with JNI.
kernel: Prebuilt kernel files
Just binary files, source code does not come here.
packages: Applications
Source code of default application such as Contacts, Calendar.
prebuilt: Binary tools
Files that are distributed in binary form for convenience. Examples include the cross compilations toolchain for different development machines.
system: Android core
That is the minimal Linux system that is started before the Dalvik VM and any java based services are enabled. This includes the source code for the init process and the default init.rc script that provide the dynamic configuration of the platform.
sdk: Base additional apps
Useful apps that developers can leverage on and can be enhanced further as part of the operating system.

Build tricks#

Make targets

Here is a list of different make targets you can use to build different parts of the system:

  • make sdk - build the tools that are part of an SDK (adb, fastboot, etc.)
  • make snod - build the system image from the current software binaries
  • make services
  • make runtime
  • make droid - make droid is the normal build.
  • make all - make everything, whether it is included in the product definition or not
  • make clean - remove all built files (prepare for a new build).
    Same as rm -rf out/<configuration>/
  • make modules - shows a list of submodules that can be built.
    List of all LOCAL_MODULE definitions.
  • make <local_module> - make a specific module (note that this is not the same as directory name. It is the LOCAL_MODULE definition in the file)
  • make clean-<local_module> - clean a specific module
  • make bootimage TARGET_PREBUILT_KERNEL=/path/to/bzImage - create a new boot image with custom bzImage.

Helper macros and functions

There are some helper macros and functions that are installed when you source They are documented at the top of, but here is information about a few of them:

  • hmm - List this help text
  • lunch <product_name>-<build_variant> - Load product & build variant config (driver files, device specific configs, etc.).
  • tapas [<App1> <App2> ...] [arm|x86|mips|armv5|arm64|x86_64|mips64] [eng|userdebug|user] - command is for building unbundled apps. If you don’t supply a build variant, it defaults to eng.
  • provision - Flash device with all required partitions. Options will be passed on to fastboot.

Build Macros and functions

  • croot - change directory to the top of the tree
  • m - execute ‘make’ from the top of the tree (even if your current directory is somewhere else)
  • mm - builds all the modules in the current directory
  • mmm <dir1> ... - Builds all the modules in the supplied directories, but not their dependencies. To limit the modules being built use the syntax: mmm dir/:target1,target2.
  • mma - Builds all the modules in the current directory, and their dependencies.
  • mmma <dir1> ... - Builds all the modules in the supplied directories, and their dependencies.

Grep macros and functions

  • cgrep <PATTERN> - Greps on all local C/C++ files.
  • ggrep <PATTERN> - Greps on all local Gradle files.
  • jgrep <PATTERN> - Greps on all local Java files.
  • resgrep <PATTERN> - Greps on all local res/*.xml files.
  • mangrep <PATTERN> - Greps on all local AndroidManifest.xml files.
  • mgrep <PATTERN> - Greps on all local Makefiles files.
  • sepgrep <PATTERN> - Greps on all local sepolicy files.
  • sgrep <PATTERN> - Greps on all local source files.
  • godir <filename> - Go to the directory containing a file

Build logs#

You can find the individual commands that AOSP build system executes to compile the image in the file <aosp_root_dir>/out/verbose.log.gz. It is the compressed package that contains the verbose log of your last build. Just extract the verbose.log.gz package, and you will get verbose.log file.

Run Emulator#

The Android emulator runs a virtual CPU that Google calls Goldfish. The Emulator, in fact, is a QEMU Virtual Machine which is prebuilt for a target AOSP.

VM acceleration#

Linux-based systems support VM acceleration through the KVM software package.

Check KVM:

sudo apt install -y cpu-checker
INFO: /dev/kvm exists
KVM acceleration can be used

AOSP Emulator#

If you run emulator in the same terminal that is set up for building AOSP, system will call to the local emulator which is shipped as a prebuilt package in the AOSP source:

which emulator

With this prebuilt emulator, you may get some issue with new Kernel image, such as below error:

emulator: ERROR: Can't parse 'Linux version ' string in kernel image file: 'Linux version 4.14.282-g21e1e64073ff-dirty (build-user@

To fix this case, you need to find a suitable kernel version for your emulator. for example, kernel for latest Andoird 11 can not run on prebuilt QEMU for an old Android 11 version.

Emulator Command Line#

Emulator Command Line provides options to run an emulator. Basically, for development:

emulator -verbose -show-kernel -selinux permissive -writable-system
  • -verbose: displays which files and settings are actually selected when starting
  • -shell: open root shell
  • -show-kernel: option to show the kernel console, it’s good for debugging
  • -selinux {disabled|permissive}: SELinux not enforced
  • -writable-system: writable system image
  • -no-boot-anim: disable the boot animation
  • -no-snapshot: do not save system state
  • -wipe-data: remove all user data

KVM Permission

If you see an error with this message:

ProbeKVM: This user doesn't have permissions to use KVM (/dev/kvm).\
The KVM line in /etc/group is: [LINE_NOT_FOUND]

If we see LINE_NOT_FOUND, the kvm group may need to be created along with permissions:

sudo groupadd -r kvm

Then ensure /lib/udev/rules.d/50-udev-default.rules contains something like:

# KERNEL=="kvm", GROUP="kvm", MODE="0660"

and then run:

sudo gpasswd -a $USER kvm

If we see kvm:... but no username at the end, running the following command may allow KVM access:

sudo gpasswd -a $USER kvm

You may need to log out and back in for changes to take effect.

Run the Emulator

Run the Emulator

To check the kernel version, run uname -a in the emulator kernel console, e.g. it’s version 5.10.66 in the above picture.


If you run abd in the same terminal that is set up for building AOSP, system will call to the local adb which is shipped as a prebuilt package in the AOSP source:

which adb

You can install adb and connect to the Emulator from any terminal, but the version of adb may different to the one running on the emulator:

sudo apt install adb

Then list all devices:

adb devices
Android Debug Bridge version 1.0.39
Version 1:8.1.0+r23-5~18.04
Installed as /usr/lib/android-sdk/platform-tools/adb

And connect to the Emulator:

adb -e shell

Build Kernel#

These instructions guide you through the process of selecting the right sources, building the kernel, and embedding the results into a system image built from the Android Open Source Project (AOSP).

Find Kernel Makefile#

The Android tree contains only prebuilt kernel binaries. When AOSP system image is build, it copies the prebuilt kernel image to the output folder.

I wrote a script to list all included Makefiles in a tree view:

import sys
from os.path import exists

__FILE    = "\u001b[32mFile   : " # green
__INHERIT = "\u001b[33mInherit: " # yellow
__SEARCH  = "\u001b[31mSearch : " # read
__INCLUDE = "\u001b[36mInclude: " # cyan
__NONE    = "\u001b[0m"           # reset

def indent(level, type, line):
    print(type, end="")
    for _ in range(level):
        print("  ", end="")
    print(line, end="")

def find(file, level, type):
    if exists(file):
        indent(level, type, file)
        with open(file, "r") as f:
            for line in f.readlines():
                if line.startswith("$(call inherit-product"):
                    line = line.replace("$(SRC_TARGET_DIR)", "build/target")
                    line = line.split(",")[1]
                    line = line.strip()
                    line = line[:-1]
                    find(line, level+1, __INHERIT)
                if line.startswith("include"):
                    line = line.split(" ")[1]
                    line = line.strip()
                    find(line, level+1, __INCLUDE)
                if search in line:
                    indent(level+1, __SEARCH, line.strip())

if len(sys.argv) >= 3:
    root = sys.argv[1]
    search = sys.argv[2]

    print("Search for\n\u001b[31m" + search + "\u001b[0m\nin");
    find(root, 0, __FILE)

Our build target is aosp_car_x86_64, let find the makefile

find device -name

Run search for :kernel in the target Makefile:


python \
    "device/generic/car/" \
Search for
Found:  prebuilts/qemu-kernel/x86_64/$(PRODUCT_KERNEL_VERSION)/kernel-qemu2:kernel-ranchu
Ok, the :kernel word is in the file device/generic/goldfish/



    device/generic/goldfish/data/etc/advancedFeatures.ini:advancedFeatures.ini \
    device/generic/goldfish/data/etc/encryptionkey.img:encryptionkey.img \
    device/generic/goldfish/data/etc/advancedFeatures.ini:images/x86_64/advancedFeatures.ini \
    device/generic/goldfish/data/etc/encryptionkey.img:images/x86_64/encryptionkey.img \


So, it is clear that, the prebuilt kernel file at the version 4.14:


will be copied to:


Our build target is sdk_car_x86_64, let find the makefile

find device -name

Run search for :kernel in the target Makefile:


python \
    "device/generic/goldfish/car/" \
Search for
Found:        $(EMULATOR_KERNEL_FILE):kernel-ranchu

Ok, the :kernel word is in the file device/generic/goldfish/

include device/generic/goldfish/



which includes device/generic/goldfish/


KERNEL_MODULES_PATH := kernel/prebuilts/common-modules/virtual-device/$(TARGET_KERNEL_USE)/x86-64

    $(KERNEL_MODULES_PATH)/virt_wifi.ko \

    $(filter-out $(KERNEL_MODULES_EXCLUDE), $(wildcard $(KERNEL_MODULES_PATH)/*.ko))

EMULATOR_KERNEL_FILE := kernel/prebuilts/$(TARGET_KERNEL_USE)/x86_64/kernel-$(TARGET_KERNEL_USE)

So, it is clear that, the prebuilt kernel file at the version 5.10:


will be copied to:


Android Common Kernels#

Android Common Kernels is used to run on Emulator.

KMI kernel branch:

Android 11 introduced GKI, which separates the kernel into a Google-maintained kernel image and vendor maintained-modules, which are built separately.

Android 11:

  • android11-5.4

Android 12:

  • android12-5.4
  • android12-5.10

Legacy dessert kernel branches:

Legacy dessert kernels were created to guarantee that new feature development didn’t interfere with merging from the Android Common Kernel.

Android 10:

  • android-4.9-q
  • android-4.14-q
  • android-4.19-q

Android 11

  • android-4.14-stable
  • android-4.19-stable

Legacy release kernel branches:

Release kernels are maintained to provide backports of patches cited in the monthly Android Security Bulletin. They were created for each launch kernel when there was a new Android platform release.

Android 10:

  • android-4.9-q-release
  • android-4.14-q-release
  • android-4.19-q-release

Build custom kernel#

Download kernel and the target branch

The above example use the AOSP android-10.0.0_r47, which uses the kernel 4.14.

Checking on, there are some versions with 4.14 version:

  • common-android-4.14 = common-android-4.14-stable has kernel/common at android-4.14-stable → this is for Android 11.
  • q-common-android-4.14 has kernel/common at android-4.14-q → build config for goldfish is not completed.
  • q-goldfish-android-goldfish-4.14-dev has kernel/common at android-goldfish-4.14-dev → having goldfish in name seems good for emulator.
export KERNEL_BRANCH="q-goldfish-android-goldfish-4.14-dev"
mkdir kernel-$KERNEL_BRANCH && cd kernel-$KERNEL_BRANCH
repo init \
    -u \

The above example use the AOSP android-12.1.0_r8, which uses the kernel 5.10. So, you can select the Android Common Kernel on branch common-android12-5.10.

export KERNEL_BRANCH="common-android12-5.10"
mkdir kernel-$KERNEL_BRANCH && cd kernel-$KERNEL_BRANCH
repo init \
    -u \

Then sync the source code:

repo sync -c -j$(nproc) && sync

Build the kernel:

Install libs for building kernel:

sudo apt install libssl-dev libelf-dev

A common kernels are generic, customizable kernels and therefore don’t define a default configuration. We have to set some environment settings:

Environment variable Description Example
BUILD_CONFIG Build config file from where you initialize the build environment. The location must be defined relative to the Repo root directory. Defaults to build.config. Mandatory for common kernels. BUILD_CONFIG=common/build.config.<target>.x86_64
CC Override compiler to be used. Falls back to the default compiler defined by build.config. CC=clang
DIST_DIR Base output directory for the kernel distribution. DIST_DIR=/path/to/my/dist
OUT_DIR Base output directory for the kernel build. OUT_DIR=/path/to/my/out

bzImage vs vmlinux

  • Big Z Image bzImage is a compressed version of the vmlinux with extra headers for booting up.
  • vmlinux is a statically linked executable file that contains the Linux Kernel.

Build the kernel (without Link Time Optimization (LTO) for testing):

BUILD_CONFIG=goldfish/build.config.goldfish.x86_64 \
LTO=none \

If the build succeeds, there is a log to show the kernel image destination:

Files copied to /mnt/work/kernel-q-goldfish-android-goldfish-4.14-dev/out/x86_64/dist

Check the kernel file:

Linux kernel x86 boot executable bzImage, version 4.14.175-g1aec57a9 (build-user@build-host) #1 SMP PREEMPT Wed May 4 05:03:19 UTC 2022, RO-rootFS, swap_dev 0x7, Normal VGA

Fast re-build

Not supported!

From Android 11, Google introduced GKI, which separates the kernel into a Google-maintained kernel image and vendor maintained-modules, which are built separately.

Build the kernel (without Link Time Optimization (LTO) for testing):

BUILD_CONFIG=common/build.config.gki.x86_64 \
LTO=none \

After build complete, check the kernel file:

file out/android12-5.10/dist/bzImage 
Linux kernel x86 boot executable bzImage, version 5.10.110-android12-9-00168-g131b12d50f16 (build-user@build-host) #1 SMP PREEMPT Fri May 27 16:2, RO-rootFS, swap_dev 0x15, Normal VGA

Build vendor’s modules, Android 12 Cuttlefish and Goldfish converge, so they share the same kernel virtual_device which can be built as below:

BUILD_CONFIG=common-modules/virtual-device/build.config.virtual_device.x86_64 \
LTO=none \

Fast re-build

By default, Kernel is always built with mrproper target which removes all generated files + config + various backup files to create a clean build.

When developing on one or a few modules, we can skip the some initial steps and start re-build immediately:

BUILD_CONFIG=common-modules/virtual-device/build.config.virtual_device.x86_64 \
LTO=none \

Include custom kernel#

For making a vendor module for kernel, refer to Kernel Module guide.

Create a soft link to built custom kernel in AOSP root folder:

ln -s /mnt/work/kernel-q-goldfish-android-goldfish-4.14-dev kernel-custom
ln -s /mnt/work/kernel-common-android12-5.10 kernel-custom

Edit the kernel make file:


    device/generic/goldfish/data/etc/advancedFeatures.ini:advancedFeatures.ini \
    device/generic/goldfish/data/etc/encryptionkey.img:encryptionkey.img \

    device/generic/goldfish/data/etc/advancedFeatures.ini:images/x86_64/advancedFeatures.ini \
    device/generic/goldfish/data/etc/encryptionkey.img:images/x86_64/encryptionkey.img \


KERNEL_MODULES_PATH := kernel-custom/out/android12-$(TARGET_KERNEL_USE)/dist

    $(KERNEL_MODULES_PATH)/virt_wifi.ko \

    $(filter-out $(KERNEL_MODULES_EXCLUDE), $(wildcard $(KERNEL_MODULES_PATH)/*.ko))


Finally, make system image again:

m all -j$(nproc)

and run the emulator:

emulator -verbose -show-kernel -selinux permissive -writable-system

Use adb to access to the Emulator shell and check the Kernel version.

Soong Build System#

The Soong build system was introduced in Android 7.0 (Nougat) to replace Make. It leverages the Kati GNU Make clone tool and Ninja build system component to speed up builds of Android.

Blueprint file format

By design, Android.bp files are simple. They don’t contain conditionals or control flow statements; all complexity is handled by build logic written in Go.

A module in an Android.bp file starts with a module type followed by a set of properties in name: "value" format.

Every module must have a name property, and the value must be unique across all Android.bp files, except for the name property values in namespaces and prebuilt modules, which may repeat. The srcs property specifies the source files used to build the module, as a list of strings.

Soong can build many modules, refer to Soong Modules Reference and select a target module for more details.

Below are examples for cc_binary, and cc_library_shared with their corresponding old Makefiles:


cc_binary {
    name: "invcase",
    srcs: ["invcase.c"],
    shared_libs: ["libinvcase"],
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := invcase
LOCAL_SRC_FILES:= invcase.c

Shared Library#

cc_library_shared {
    name: "libinvcase",
    srcs: ["libinvcase.c"],
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libinvcase
LOCAL_SRC_FILES:= libinvcase.c