Blog Infos
Author
Published
Topics
,
Author
Published

 

Ever wondered how the Android Pre-built Apps were made, and what was the build system behind it?

One common pain point that most Android developers face is finding quality resources on the core and internal functioning of the Android Operating System.

Framework development is not easy and on top of it, building a framework app along with its intricacies can be confusing.

Over the last two years, I have accumulated a wealth of knowledge about the Android Build System and its integration with original equipment manufacturers (OEMs).

This article aims to share these learnings and simplify the process of understanding AOSP’s complex mechanisms. Instead of manually going through various files and their internal workflows, this can act as a quick guide to entering the realm of the AOSP build system.

We are not discussing gradle build system here, Android Platform build system is very different from the Android Application build system which is based on gradle.

What will you learn here?

By the end of this article, you’ll understand and be aware of all the intricacies, functionalities, definitions, and linkages around Android’s Platform Build System. In the following four points, we would be discussing in deep detail one by one.

  1. Setting up the environment
    – source build/envsetup.sh
  2. Choose a target product to build with
    – lunch <option>
  3. Building the code
    – make <module-name> or m <module-name>
  4. Run/flash/install on the device
    – Push the apk via adb push
    – Flash the image via fastboot

But before we deep dive into above mentioned 4 steps, there are some pre-requisites :

A. Evolution of the Android build System

B.Android.bp and blueprinting

C.Download AOSP Source

A. Evolution of the Android build System
– Before Android N(v7.0),

The compilation was done by a tool GNU make. All rules were written in a configuration file called Makefile and the make tool will compile the code according to the instructions in the Makefile.

What is make? make is an automated build tool, make automatically builds the source code into executable programs and library files by reading Makefile.

What is Makefile or .mk File? The Makefile defines the dependencies of the target program and the relevant rules for generating the target program.

Just like Gradle has build.gradle, make has Makefile (main.mk).

– After Android N(v7.0)

at the Android level, GNU Make compilation was becoming slow, error-prone, non-scalable, and difficult to test, soGoogle introduced the Ninja build system which provided flexibility to the Android build system, as the .ninja files were humanly readable.

What is ninja? It is a compilation framework, which will be compiled according to the .bp(blueprint) file in the corresponding .ninja file. Generally, .ninja file will not be modified manually rather .ninja is compiled by converting the .bp(blueprint) into a .ninja file.

What is soong and .bp File? To generate .ninja files, Google introduced soong build system with a tool called blueprint that parses Android.bp files to .ninja files, and also introduced kati tool to convert Android.mk files to .ninja files.

What is katiA tool based on Golang and C++, the main function is to convert complex Android.mk files into ninja files

P.S.: Soong also compiles and generates an androidmk command that converts Android.mk file to an Android.bp file

Just like Gradle has build.gradle, ninja has build.ninja.

– During the Release notes of Android in 2020, Google said that they will start migrating the build system to Bazel.
B. We have to know about Android.bp and blueprinting in detail

In Android.bp, we will build what we need based on the module type.

The commonly used types and methods are as follows:

  • android_app: It is used to build apk, which has the same function as Android.mk BUILD_PACKAGE.
  • java_library: It produces a .jar bundle from .class files. The resulting jar is not suitable for direct installation on the device, rather it will be used as a static_libs dependency.
  • static_libs: libraries resolved in a caller at compile-time and copied into a target application by the compiler
  • android_library: Build and link the source code with the Android resource files into the device’s .jar file.
    android_library has a different variant that produces a .jar bundle from .class files. and a file named package-res.apk generated from aapt2. The generated apk file cannot be installed directly on the device but can be used as android_app module‘s static_libs dependency.
  • platform_apis: Compile with SDK’s hide api
  • certificate: Specifies what signature is used, as above, the platform signature is used.
  • android_library_import : Imports a android archive (aar) to android_app which must be used as a android_app module ‘s static_libs dependency.

Let’s try to create a random sample App called GlanceApp, Below is the Sample Android.bp file where in the GlanceApp module, glance_android_library is introduced as a static dependency, which in turn has glance_java_library and content_aar_plugin as the dependency to make GlanceApp.apk

java_library {
name: "glance_java_library",
srcs: [
"src/com/android/glance/file/**.java",
],
jarjar_rules: ":jarjar-rules-shared",
}
android_library {
name: "glance_android_library",
manifest: "tests/AndroidManifest-base.xml",
additional_manifests: ["tests/AndroidManifest.xml"],
resource_dirs: [
"res",
],
srcs: [
"src/**/*.kt",
"src/**/*.java",
],
static_libs: [
"glance_java_library",
"content_aar_plugin",
"glide-annotation-and-compiler-prebuilt",
],
libs: [
"android.test.base",
],
kotlincflags: ["-Xjvm-default=enable"],
aaptflags: [
"--extra-packages",
],
plugins: ["dagger2-compiler","glide-annotation-processor"],
}
android_app {
name: "GlanceApp",
static_libs: [
"glance_android_library",
],
resource_dirs: [],
platform_apis: true,
system_ext_specific: true,
certificate: "platform",
privileged: true,
kotlincflags: ["-Xjvm-default=enable"],
dxflags: ["--multi-dex"],
required: [ "privapp_whitelist_com.android.glance",],
aaptflags: ["--auto-add-overlay",],
platform_apis: true,
certificate: "platform",
optimize: {enabled: false,},
sdk_version: "core_platform",
}
android_library_import {
name: "content_aar_plugin",
aars: ["libs/content_aar_plugin.aar"],
static_libs: ["androidx-constraintlayout_constraintlayout",]
}
view raw Android.bp hosted with ❤ by GitHub

so content_aar_plugin is added to your app with glance_android_library. I have added glide (third party library) as a dependency too.

since we have specified privileged to true and certificate to the platform, GlanceApp will act as a system-privileged app.

C. Download AOSP Source, If you haven’t done already

We will use Pixel 6a (codenamed “bluejay”) as the device example. We will walk through it in a succinct manner without detailed explanations.

mkdir android-13.0.0_r12
cd android-13.0.0_r12
repo init --depth=1 -u https://android.googlesource.com/platform/manifest -b android-13.0.0_r12
repo sync  --force-sync --no-clone-bundle --no-tags -j$(nproc)

Read for the complete AOSP setuphttps://medium.com/@goyaljai/build-aosp-co-180bb3995dbc

Now that you have learned about almost all of the prerequisites…
Wait !! Have a look at the high level diagram first.

 

Existing Android.mk and existing Android.bp will be converted to Ninja respectively.

 

What does this flow diagram say?

From Android.mk and other Makefiles, out/build-aosp_bluejay.ninja files will be generated.

From Android.bpout/soong/build.ninja will be generated. In addition, a smaller out/combined-aosp_bluejay.ninja file will be generated, which is responsible for connecting the two as the execution entry.

In the end, Ninja files are the tools that really directly control source code compilation and are responsible for generating apk, aar, and dex files. The signing of the APK is also done using ninja rules and then once this all is done, *.imgs are created.

Finally, The time has come. Let’s State the detailed discussed on these 3 steps.

  1. source build/envsetup.sh
  2. lunch <option>
  3. make <module-name> or m <module-name>
The First Step of Android Compilation

source build/envsetup.sh.

This paves the way for subsequent compilation steps. It is essential to understand what envsetup.sh corresponds to our analysis.

so the envsetup.sh script defines many functions. After executing this script, you can directly execute these functions in the current console using Linux commands, such as lunchmmmmm, etc. (use hmm to see all available commands). So lunchmmm are essentially a shell function, which is equivalent to a shell script. Let’s discuss the implementation principles of these commands in build/envsetup.sh.

The Second Step of the Android Compilation

lunch

lunch() function in envsetup.sh script sets the environment for building the images (*.imgs) and other artifacts like apk, jar, .so, etc. It reads a list of target devices from a list of files called AndroidProducts.mk.list. It takes COMMON_LUNCH_CHOICES variables from AndroidProducts.mk.list and shows to the user when print_lunch_menu() is called, from this function, get_build_var() is called which in turn calls build/soong/soong_ui.bash — dumpvar-mode

soong_ui.bash calls /build/soong/cmd/soong_ui/main.go into the main() function which calls build.FindSources(buildCtx, config, f) which finds all the AndroidProducts.mk and makes AndroidProducts.mk.list with a single COMMON_LUNCH_CHOICES. Check the snippets below …

function print_lunch_menu()
{
...
choices=$(TARGET_BUILD_VARIANT= get_build_var COMMON_LUNCH_CHOICES 2>/dev/null)
...
}
function get_build_var()
{
...
build/soong/soong_ui.bash --dumpvar-mode $1)
}
func main() {
...
config := c.config(buildCtx, args...)
...
f := build.NewSourceFinder(buildCtx, config)
defer f.Shutdown()
build.FindSources(buildCtx, config, f)
...
}
function lunch()
{
print_lunch_menu
...
read selection
...
product=${selection%%-*} # Trim everything after first dash
variant_and_version=${selection#*-} # Trim everything up to first dash
if [ "$variant_and_version" != "$selection" ]; then
variant=${variant_and_version%%-*}
if [ "$variant" != "$variant_and_version" ]; then
version=${variant_and_version#*-}
fi
fi
...
TARGET_PRODUCT=$product \
TARGET_BUILD_VARIANT=$variant \
TARGET_PLATFORM_VERSION=$version \
export TARGET_PRODUCT=$(get_build_var TARGET_PRODUCT)
export TARGET_BUILD_VARIANT=$(get_build_var TARGET_BUILD_VARIANT)
export TARGET_PLATFORM_VERSION=$(get_build_var TARGET_PLATFORM_VERSION)
...
}
view raw lunch.bash hosted with ❤ by GitHub

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

, ,

Brick by Brick: Building Open Source libraries

So you have an idea, and you want to publish a library for it? But where do you start? Doing Open Source is a fine art which requires skill you don’t easily learn on schoolbooks.
Watch Video

Brick by Brick: Building Open Source libraries

Paolo Rotolo & Nicola Corti
Android Engineer & Kotlin GDE - Android
Nextome & React

Brick by Brick: Building Open Source libraries

Paolo Rotolo & Nic ...
Android Engineer & K ...
Nextome & React

Brick by Brick: Building Open Source libraries

Paolo Rotolo & N ...
Android Engineer & Kotlin ...
Nextome & React

Jobs

I want to discuss some less discussed yet important commands here.

1. set_stuff_for_environment: Its function is to add some paths to the PATH environment variable so that we can use some more tools in the Android source code in the console that has executed lunch. for eg. emulator

2. tapas: It sets up the build environment for building unbundled apps or rather APKs i.e. Normal Android Packages. You can choose chip architecture, and build variants and apps needed for the module to be built. eg : tapas SystemUI arm eng

3. banchan: It sets up the build environment for building unbundled modules or rather APEXs i.e. native services, libraries, HALs, etc. You can choose chip architecture, and build variants and apps needed for the module to be built. eg: banchan com.android.boinic SystemUI arm eng

4. make commands

If you understood the principle of the lunch command, these commands will be very easy.

  • m: Makes from the top of the tree. eg: m or m <module-name>
  • mm: Builds and installs all of the modules in the current directory and their dependencies.
  • mmm: Builds and installs all of the modules in the supplied directories and their dependencies. To limit the modules being built, use the syntax: mmm dir/:target1,target2. eg: mmm packages/apps/Launcher3

There are several more commands supported, use hmm command to see the list.

The Third Step of Android Compilation

make or m

Previously (before Android N)

m or make command was equivalent to make -f build/core/main.mk (built via GNU make)

Currently

m or make command is equivalent to build/soong/soong_ui.bash — make- mode which means that soong_ui.bash is the main heart of the Android Platform Build Systems.

source ${TOP}/build/soong/scripts/microfactory.bash
soong_build_go soong_ui android/soong/cmd/soong_ui
soong_build_go mk2rbc android/soong/mk2rbc/cmd
soong_build_go rbcrun rbcrun/cmd
cd ${TOP}
exec "$(getoutdir)/soong_ui" "$@"
view raw soong_ui.bash hosted with ❤ by GitHub

It can be seen that the main logic of soong_ui.bash has 4 parts

  1. run microfactory to set up the environment for building go scripts. helps us to use soong_build_go to build the requested binary.
  2. soong_build_go soong_ui prepares the shell function calls and executes the entrance of soong i.e. main.go
  3. soong_build_go mk2rbc and rbcrun execute the entrance of bazel build system and converts different makefiles to Starlark
  4. finally executes soong_ui

so from point 2, we understand that the entrance of soong i.e. main.go

please note : point 3, is out of scope of this article

in main.go, one of the following 4 parameters must be taken:

  • — dumpvar-mode
  • — dumpvars-mode
  • — make-mode
  • — build-mode

The first two are not much used and are not used for building/making so we will skip these and discuss — make-mode and — build-mode below.

func main() {
 ...
 if os.Args[1] == " --dumpvar-mode" {
 dumpVar(buildCtx, config, os.Args[2:])
 } else if os.Args[1] == " --dumpvars-mode" {
 dumpVars(buildCtx, config, os.Args[2:])
 } else {
   //build --make-mode and --build-mode
   if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) {
     clean(ctx, config)
     return
   }
   if inList("help", config.Arguments())) {
     help(ctx, config)
     return
   }
   ...
 }
}

There are several other parameters like clobber/clean and help which calls cleanbuild.go and help.shclobber/clean is to delete the output folder and help is used to display the user manual for command.

Let’s deep dive into — — make — mode and — — build — mode below.

This is the High-level flow for the build process, we will discuss every junction one by one now.

High level flow for the build process

main.go sets up the config via config.go with passed parameters like skip etc. then FindSources function finds the sources to combine the mk files for kati.go and bp files for soong.go to process and convert to ninja files with the help of ninja.gobp2build.go is only needed if bazel is enabled, then .bp files need to be converted to BAZEL files. For this article, we assume that bazel is not enabled.

function main() {
c, args, err := getCommand(os.Args)
...
buildCtx := build.Context{ContextImpl: &build.ContextImpl{
Context: ctx,
Logger: log,
Metrics: met,
Tracer: trace,
Writer: output,
Status: stat,
}}
config := c.config(buildCtx, args...)
...
build.FindSources(buildCtx, config, f)
...
c.run(buildCtx, config, args, logsDir)
}
view raw main.go hosted with ❤ by GitHub

Config will send the args to build.go’s to decide what to run and in which sequence. For example if we run the command like:

build/soong/soong_ui.bash --make-mode --skip-ninja

Config’s skipNinja will be true. And follow-on:

func config parseArgs(ctx Context, args []string) {
for i := 0; i < len(args); i++ {
arg := strings.TrimSpace(args[i])
...
if arg == "--skip-ninja" {
c.skipNinja = true
} else if arg == "--skip-make" {
c.skipConfig = true
c.skipKati = true
} else if arg == "--skip-kati" {
c.skipKati = true
} else if arg == "--soong-only" {
c.skipKati = true
c.skipKatiNinja = true
...
c.arguments = append(c.arguments, arg)
}
}
}
view raw config.go hosted with ❤ by GitHub

Once the config is set, in Build flow, the variable “what” by default is set to “runAll

func Build(ctx Context, config Config) {
...
what := RunAll
...
if config.SkipKati() {
ctx.Verboseln("Skipping Kati as requested")
what = what &^ RunKati
}
if config.SkipKatiNinja() {
ctx.Verboseln("Skipping use of Kati ninja as requested")
what = what &^ RunKatiNinja
}
if config.SkipSoong() {
ctx.Verboseln("Skipping use of Soong as requested")
what = what &^ RunSoong
}
if config.SkipNinja() {
ctx.Verboseln("Skipping Ninja as requested")
what = what &^ RunNinja
}
...
if what&RunSoong != 0 {
runSoong(ctx, config)
}
if what&RunKati != 0 {
genKatiSuffix(ctx, config)
runKatiCleanSpec(ctx, config)
runKatiBuild(ctx, config)
runKatiPackage(ctx, config)
ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0666) // a+rw
}
...
if what&RunNinja != 0 {
if what&RunKati != 0 {
installCleanIfNecessary(ctx, config)
}
runNinjaForBuild(ctx, config)
}
// Currently, using Bazel requires Kati and Soong to run first, so check whether to run Bazel last.
if what&RunBazel != 0 {
runBazel(ctx, config)
}
}
view raw build.go hosted with ❤ by GitHub

Once all the meta filters are complete, like skip Kati, skip Ninja, etc, the soong process will start.

Soong’s Flow

There is a tool called bootstrap that reads the Blueprint files that describe itself and emits .bootstrap/build.ninja that describes how to build its full version and use that to produce the final Ninja file that Soong emits.

func runSoong(ctx Context, config Config) {
...
buildMode := config.bazelBuildMode()
integratedBp2Build := buildMode == mixedBuild
...
bootstrapBlueprint(ctx, config)
...
ninja := func(name, ninjaFile string, targets ...string) {
...
ninjaArgs := []string{
"-d", "keepdepfile",
"-d", "stats",
"-o", "usesphonyoutputs=yes",
"-o", "preremoveoutputs=yes",
"-w", "dupbuild=err",
"-w", "outputdir=err",
"-w", "missingoutfile=err",
"-j", strconv.Itoa(config.Parallel()),
"--frontend_file", fifo,
"-f", filepath.Join(config.SoongOutDir(), ninjaFile),
}
...
}
...
if config.Bp2Build() {
targets = append(targets, config.Bp2BuildMarkerFile())
}
...
ninja("bootstrap", "bootstrap.ninja", targets...)
...
}
view raw soong.go hosted with ❤ by GitHub

If Bp2Build is true which means that if Bazel build system is needed, bp2build.go needs to be executed. It writes .bzl files that are equivalent to Android.bp files that are capable of being built with Bazel.

Google wants to hand over all compilation-related tasks to bazel. It’s a big project, and the Android code is too huge. I don’t know when it will be completed.

from Android.bp, out/soong/build.ninja will be generated. After this, Kati is executed to parse the Makefiles, but that’s not part of bootstrapping Soong.

Kati’s Flow

Android.mk loading
in build.go runKati is executed. which calls the flow in the file (core/main.mk), including each subdirectory in the following way for Android.mk

subdir_makefiles := $(SOONG_OUT_DIR)/installs-$(TARGET_PRODUCT).mk $(SOONG_ANDROID_MK)
# Android.mk files are only used on Linux builds, Mac only supports Android.bp
ifeq ($(HOST_OS),linux)
  subdir_makefiles += $(file <$(OUT_DIR)/.module_paths/Android.mk.list)
endif
subdir_makefiles += $(SOONG_OUT_DIR)/late-$(TARGET_PRODUCT).mk
subdir_makefiles_total := $(words int $(subdir_makefiles) post finish)
.KATI_READONLY := subdir_makefiles_total

$(foreach mk,$(subdir_makefiles),$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] including $(mk) ...)$(eval include $(mk)))

Because of this logic, we can often see [xxx/xxx] including xxx at compile time. Search for files in the Android source code, Android.mk, and put the corresponding file path into the Android.mk.list file and then generate the ninja file for it. It uses ckati to do it.

eg : command: ckati, -f build/make/core/main.mk

From Android.mk and other Makefiles, out/build-<product_name>.ninja files will be generated.

Let’s discuss what a generated ninja file looks like. Taking Example for SystemUI-core

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Module: SystemUI-core
# Variant: android_common
# Type: android_library
# Factory: android/soong/android.ModuleFactoryAdaptor.func1
# Defined: frameworks/base/packages/SystemUI/Android.bp:69:1
m.SystemUI-core_android_common.moduleDesc = //frameworks/base/packages/SystemUI:SystemUI-core
m.SystemUI-core_android_common.moduleDescSuffix = $ [common]
m.SystemUI-core_android_common.javacFlags = -Xlint:-dep-ann
m.SystemUI-core_android_common.kotlincFlags = -Xjvm-default=enable -Xsam-conversions=class -no-stdlib -no-jdk
rule m.SystemUI-core_android_common.aidl
command = rm -rf out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/gen/aidl/aidl0.tmp && mkdir -p out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/gen/aidl/aidl0.tmp && FLAGS=' -Iframeworks/base/core/java -Iframeworks/base/drm/java -Iframeworks/base/graphics/java -Iframeworks/base/identity/java -Iframeworks/base/keystore/java -Iframeworks/base/location/java -Iframeworks/base/lowpan/java -Iframeworks/base/media/java -Iframeworks/base/media/mca/effect/java -Iframeworks/base/media/mca/filterfw/java -Iframeworks/base/media/mca/filterpacks/java -Iframeworks/base/mms/java -Iframeworks/base/opengl/java -Iframeworks/base/rs/java -Iframeworks/base/sax/java -Iframeworks/base/telecomm/java -Iframeworks/base/telephony/java -Iframeworks/base/packages/SystemUI -Iframeworks/base/packages/SystemUI/src --min_sdk_version=current -Iframeworks/base/packages/SystemUI/' && out/host/linux-x86/bin/aidl -dout/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/gen/aidl/frameworks/base/packages/SystemUI/src/com/android/systemui/assist/IAssistHandleService.aidl.d $$FLAGS frameworks/base/packages/SystemUI/src/com/android/systemui/assist/IAssistHandleService.aidl out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/gen/aidl/aidl0.tmp/frameworks/base/packages/SystemUI/src/com/android/systemui/assist/IAssistHandleService.java && out/host/linux-x86/bin/soong_zip -srcjar -write_if_changed -o out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/gen/aidl/aidl0.srcjar -C out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/gen/aidl/aidl0.tmp -D out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/gen/aidl/aidl0.tmp && rm -rf out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/gen/aidl/aidl0.tmp # hash of input list: 9def94a8716a4acf60f436254037b1e48158f63767ed67940332f88206e735f1
restat = true
rule m.SystemUI-core_android_common.lint
command = out/host/linux-x86/bin/sbox --sandbox-path out/soong/.temp --output-dir out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/lint --manifest out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/lint.sbox.textproto
rspfile = out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/lint-srcs.list
rspfile_content = ${in}
build $
out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/manifest_fixer/AndroidManifest.xml: g.java.manifestFixer $
frameworks/base/packages/SystemUI/AndroidManifest.xml | ${g.android.soong.java.config.ManifestFixerCmd}
description = ${m.SystemUI-core_android_common.moduleDesc}fix manifest${m.SystemUI-core_android_common.moduleDescSuffix}
args = --library --targetSdkVersion 33 --minSdkVersion 33 --raise-min-sdk-version
build $
out/soong/.intermediates/development/samples/SystemUI/SystemUI/android_common/meta_lic: g.android.licenseMetadataRule | ${g.android.licenseMetadataCmd} || $
out/soong/.intermediates/build/soong/java/core-libraries/core-public-stubs-system-modules/android_common/meta_lic $
out/soong/.intermediates/build/soong/java/core-libraries/legacy.core.platform.api.stubs/android_common/meta_lic $
out/soong/.intermediates/external/apache-http/org.apache.http.legacy/android_common/meta_lic $
out/soong/.intermediates/frameworks/base/android_stubs_current/android_common/meta_lic $
out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/meta_lic out/soong/.intermediates/frameworks/base/ext/android_common/meta_lic $
out/soong/.intermediates/frameworks/base/framework/android_common/meta_lic $
out/soong/.intermediates/frameworks/base/test-base/android.test.base/android_common/meta_lic $
out/soong/.intermediates/frameworks/base/test-mock/android.test.mock/android_common/meta_lic $
out/soong/.intermediates/libcore/core-lambda-stubs/android_common/meta_lic $
out/soong/.intermediates/system/libhidl/transport/base/1.0/android.hidl.base-V1.0-java/android_common/meta_lic $
out/soong/.intermediates/system/libhidl/transport/manager/1.0/android.hidl.manager-V1.0-java/android_common/meta_lic
description = ${m.SystemUI_android_common.moduleDesc}license metadata${m.SystemUI_android_common.moduleDescSuffix}
args = -mt android_app -r development/samples/SystemUI -mc UNKNOWN -p "Android" -k SPDX-license-identifier-Apache-2.0 -c notice -n 'build/soong/licenses/LICENSE:Android' -d 'out/soong/.intermediates/build/soong/java/core-libraries/core-public-stubs-system-modules/android_common/meta_lic:dynamic' -d out/soong/.intermediates/build/soong/java/core-libraries/legacy.core.platform.api.stubs/android_common/meta_lic -d 'out/soong/.intermediates/external/apache-http/org.apache.http.legacy/android_common/meta_lic:dynamic' -d 'out/soong/.intermediates/frameworks/base/android_stubs_current/android_common/meta_lic:dynamic' -d 'out/soong/.intermediates/frameworks/base/android_stubs_current/android_common/meta_lic:dynamic' -d out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/meta_lic -d out/soong/.intermediates/frameworks/base/ext/android_common/meta_lic -d out/soong/.intermediates/frameworks/base/framework/android_common/meta_lic -d 'out/soong/.intermediates/frameworks/base/test-base/android.test.base/android_common/meta_lic:dynamic' -d 'out/soong/.intermediates/frameworks/base/test-mock/android.test.mock/android_common/meta_lic:dynamic' -d out/soong/.intermediates/libcore/core-lambda-stubs/android_common/meta_lic -d 'out/soong/.intermediates/libcore/core-lambda-stubs/android_common/meta_lic:dynamic' -d 'out/soong/.intermediates/system/libhidl/transport/base/1.0/android.hidl.base-V1.0-java/android_common/meta_lic:dynamic' -d 'out/soong/.intermediates/system/libhidl/transport/manager/1.0/android.hidl.manager-V1.0-java/android_common/meta_lic:dynamic' -s out/host/linux-x86/framework/android.test.base-hostdex.jar -s out/soong/.intermediates/build/soong/java/core-libraries/legacy.core.platform.api.stubs/android_common/dex/legacy.core.platform.api.stubs.jar -s out/soong/.intermediates/frameworks/base/android_stubs_current/android_common/dex/android_stubs_current.jar -s out/soong/.intermediates/frameworks/base/framework/android_common/combined/framework.jar -s out/soong/.intermediates/libcore/core-lambda-stubs/android_common/withres/core-lambda-stubs.jar -s out/target/product/barbet/system/framework/android.hidl.base-V1.0-java.jar -s out/target/product/barbet/system/framework/android.hidl.manager-V1.0-java.jar -s out/target/product/barbet/system/framework/android.test.base.jar -s out/target/product/barbet/system/framework/android.test.mock.jar -s out/target/product/barbet/system/framework/ext.jar -s out/target/product/barbet/system/framework/framework-res.apk -s out/target/product/barbet/system/framework/oat/arm/android.hidl.base-V1.0-java.odex -s out/target/product/barbet/system/framework/oat/arm/android.hidl.base-V1.0-java.vdex -s out/target/product/barbet/system/framework/oat/arm/android.hidl.manager-V1.0-java.odex -s out/target/product/barbet/system/framework/oat/arm/android.hidl.manager-V1.0-java.vdex -s out/target/product/barbet/system/framework/oat/arm/android.test.base.odex -s out/target/product/barbet/system/framework/oat/arm/android.test.base.vdex -s out/target/product/barbet/system/framework/oat/arm/android.test.mock.odex -s out/target/product/barbet/system/framework/oat/arm/android.test.mock.vdex -s out/target/product/barbet/system/framework/oat/arm/org.apache.http.legacy.odex -s out/target/product/barbet/system/framework/oat/arm/org.apache.http.legacy.vdex -s out/target/product/barbet/system/framework/oat/arm64/android.hidl.base-V1.0-java.odex -s out/target/product/barbet/system/framework/oat/arm64/android.hidl.base-V1.0-java.vdex -s out/target/product/barbet/system/framework/oat/arm64/android.hidl.manager-V1.0-java.odex -s out/target/product/barbet/system/framework/oat/arm64/android.hidl.manager-V1.0-java.vdex -s out/target/product/barbet/system/framework/oat/arm64/android.test.base.odex -s out/target/product/barbet/system/framework/oat/arm64/android.test.base.vdex -s out/target/product/barbet/system/framework/oat/arm64/android.test.mock.odex -s out/target/product/barbet/system/framework/oat/arm64/android.test.mock.vdex -s out/target/product/barbet/system/framework/oat/arm64/org.apache.http.legacy.odex -s out/target/product/barbet/system/framework/oat/arm64/org.apache.http.legacy.vdex -s out/target/product/barbet/system/framework/org.apache.http.legacy.jar -s out/target/product/barbet/system/framework/org.apache.http.legacy.jar.prof -t out/soong/.intermediates/development/samples/SystemUI/SystemUI/android_common/SystemUI.apk -i out/target/product/barbet/system/app/SystemUI/SystemUI.apk
view raw sample.ninja hosted with ❤ by GitHub

rule <rule-name>: a rule with <rule-name> can be defined for reuse with command

m.<module>-<variant>-*: <module> and <variant> will be defined in Android.bp/Android.mk and * can be thought of as the different flags like javacFlags or kotlincFlags.

build $ <function>: <function> is basically the commands for 1. conversion of XML files, Java files using aapt2 and Java Compiler to create .class files, and then 2. .class files to .dex files to create .apk finally.

It has other rules as well, to copy all the generated artifacts to the corresponding directories. The directory ‘out/target/product/bluejay/<obj>’ is used for staging “object” files, which are intermediate binary images used for building the final programs. Stuff that actually lands in the file system of the target is stored in the directories root, system, and data, under ‘out/target/product/bluejay’. Usually, these are bundled up into image files called vbmeta.img, system.img, ramdisk.img, and userdata.img.

Let me know if you want one more article, discussing the above flow of how different images get generated, apk’s gets signed and vbmeta.img is verified.

The making, packing, and zipping of these imgs is also part of ninja files that were generated by Kati.

rule m.microdroid_vbmeta_bootconfig_android_arm64_armv8-a.vbmeta
command = out/host/linux-x86/bin/avbtool make_vbmeta_image --key external/avb/test/data/testkey_rsa4096.pem --algorithm SHA256_RSA4096 --rollback_index $$(date -d 'TZ="GMT" 2022-09-05' +%s | head -1 | tr -d '$
') --rollback_index_location 0 --chain_partition bootconfig:1:out/soong/.intermediates/packages/modules/Virtualization/microdroid/microdroid_vbmeta_bootconfig/android_arm64_armv8-a/bootconfig.avbpubkey --chain_partition uboot_env:2:out/soong/.intermediates/packages/android_arm64_armv8-a/uboot_env.avbpubkey
--output out/soong/.intermediates/packages/modules/Virtualization/microdroid/microdroid_vbmeta_bootconfig/android_arm64_armv8-a/microdroid_vbmeta_bootconfig.img && truncate -s 65536 out/soong/.intermediates/packages/modules/Virtualization/microdroid/microdroid_vbmeta_bootconfig/android_arm64_armv8-a/microdroid_vbmeta_bootconfig.img # hash of input list: f8343f0c11db644e49c173205360d2628cff5f895d40de988e2f1dfac75e3524
view raw imgs.ninja hosted with ❤ by GitHub
Conclusion

This article has been kept to a level where it is not only informative and useful but also dives into finer details. Hopefully, this has given you a decent learning of the Android platform build systems and AOSP in general.

As you might have observed, I have mentioned Bazel Build System 2–3 times in this article. It has started to gain traction, and will potentially be replacing the current build system.

I would love to talk more about Bazel Build System in another article as and when things unfold.

Do drop me a follow on LinkedIn!!

Cheers !!

This article was previously published on proandroiddev.com

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog

Bazel for Android. Part 1 — Getting Started

Bazel for Android is a series of blog posts that shows the basics of…
READ MORE
blog
To build successful open-source software, you must first plan a solid strategy. In this…
READ MORE
blog
Bazel is a popular build tool that is used for developing software projects. It…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu