The AOSP build system is a build system like Buildroot and OpenEmbedded. It has a number of tools: soong, kati, ninja and in Android 14 bazel.

sched – no slides 🙁

AOSP only builds the root filesystem, not kernel and bootloader. The latter are provided by the SoC vendor and built separately. There’s also the Android Common Kernel, but it’s separate.

AOSP is a collection of 1100 git repositories, managed with a repo manifest. 150GB of source, 50M SLOC. You download everything, even stuff that is never even built – and full repositories as well, not tarballs.

Once you have the source, you source build/envsetup.sh. This gives a couple of new commands, one is lunch where you specify the target. The targets are defined in AndroidProduct.mk files in the device directory. The target defines packages in PRODUCT_PACKAGES. You can dump these with get_build_var.

Building is donw with the command m. Simple command, but it takes a long time before it finishes. It iterates through all of the packages and does a build on each. The final result are image files in out/target/product/[device].

Android modules (packages) are defined in Android.bp files. There are also legacy Android.mk files, still about 1000 exist.

kati and soong create the build.ninja for ninja.

In 2008, the AOSP build system consisted of Makefiles. This doesn’t scale well, so they switched to other tooling in 2016: kati and ninja. kati parses the .mk files and outputs the build.ninja with the dependencies. In 2017, soong was added for the Blueprint (Android.bp) files. It produces the .mk files that are processed by kati. Probably the initial intention was to eventually let soong create the ninja.build itself, but we never got there. In Android 14 (later in 2023), Bazel is probably going to be introduced to replace all the rest.

Android.bp files is a JSON-like language that is quite similar to Bazel BUILD files. They are declarative, they don’t contain any logic. The logic is implemented in soong modules written in Go.

m builds the entire target, called droid. mm builds the module in the current directory. mmm takes the modules to build as arguments. All of these just call soong_ui. It builds, and prints variables (get_build_var actually just calls into soong_ui).

Android.bp files normally specify the usual build things, i.e. the source files, which libraries to link with. It installs the results in default locations. THere are different module types, like cc_binary for a C++ program. There are about 300 module types.

The build.ninja file that comes out is 6 to 10 GB. It contains the rules for each module, because at this point the build system doesn’t know yet what the target of the build is (i.e. droid).

Android.mk files look a lot like Buildroot makefiles. They specify dependencies, but it’s not possible to depend on a .bp module from a .mk file. kati parses the Android.mk files and generates a build.ninja of 600-900MB.

ninja is started from soong_ui. It calls into a subninja to the build.ninja files generated by soong and kati. You can run ninja directly, e.g. ninja -t query to see dependencies., or ninja -t graph to graph the dependencies.

Bazel should eventually replace kati, soong and ninja. In Android 13, only the kernel build uses Bazel. There’s a blog post about the plans. Bazel defines a WORKSPACE with the global configuration, and BUILD files for each module. In Android 14, Bazel should replace ninja entirely, but its input is still generated by kati and soong.