Anatomy of Android Build System
How are Android prebuilt apps made, and what is the build system behind them?
This article aims to share knowledge about the Android build system and integration with original equipment manufacturers (OEMs), and simplify the process of understanding the complex mechanisms of AOSP. This article serves as a quick guide into the world of the AOSP build system, rather than manually consulting the various files and their internal workflow. The Gradle build system is not involved. The Android platform build system is completely different from the Gradle-based Android application build system. It is worth mentioning that, have you ever thought about how Android pre-built applications are made and what is the build system behind them? Finding high-quality resources about the core and inner workings of the Android operating system is a common pain point for most Android developers. Framework development is not easy, and besides, building a Framework application with its complexities can be confusing.
Main points of this article
By the end of this article, you will understand and understand all the intricacies, functions, definitions and associations about the build system of the Android platform. The following are four points discussed in detail:
- environment settings
- run
source build/envsetup.sh
- run
- Select the target product to build
- run
lunch <option>
- run
- build code
- run
make <module-name>
orm <module-name>
- run
- run/flash/install on device
adb push
Push apk via- By
fastboot
flashing the mirror
But before diving into the above 4 steps, there are some prerequisites:
A. Evolution of the Android build system
B. Android.bp
andblueprint
C. Download AOSP source code
A. Evolution of the Android build system
- Before Android N version (v7.0),
Compilation is done by the GNU make tool. All rules are written in a configuration file named 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 that automatically compiles source code into executable programs and library files by reading Makefile.
What is a Makefile or .mk file? 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 version (v7.0),
At the Android level, GNU Make compilation became slow, error-prone, non-scalable, and difficult to test, so Google introduced the Ninja build system, which enables the flexibility of the Android build system through .ninja files, because the files are human- .ninja
readable .
What are ninjas? It is a compiled framework that will be compiled into files based on the corresponding .bp (blueprint) files .ninja
. Typically, .ninja
the files are not modified manually, but rather compiled by .bp(blueprint)
converting to a file ..ninja
.ninja
What are soong and .bp files? To generate .ninja
files, Google introduced the soong build system, which includes a blueprinting
tool called soong for Android.bp
parsing files into .ninja
files, and the kati tool for Android.mk
converting files into .ninja
files.
What is kati? This is a Golang and C++ based tool whose main function is to convert complex Android.mk files to ninja files.
P.S. Soong also compiled and generated a androidmk
command to convert Android.mk file to Android.bp file.
Just like Gradle has it build.gradle
, ninja has it build.ninja
.
- In the 2020 Android release notes, Google stated that they will start migrating the build system to Bazel.
B. Learn more about Android.bp and blueprinting
In Android.bp we build what we need depending on the module type.
The commonly used types and methods are as follows:
android_app
: Used to build apk, its function is the same as BUILD_PACKAGE of Android.mk.
java_library
: Generate a .jar package from a .class file. The generated jar package is not suitable for direct installation on the device, but it is used as a static_libs dependency.
static_libs
: A library that is resolved by the caller at compile time and copied into the target application by the compiler.
android_library
: Link the source code together with the Android resource files into the device's .jar file.
android_library
There are different variants of .class
generating .jar
a package from a file, and from a aapt2
generated package-res.apk
file named . The generated apk file cannot be installed directly on the device, but can be used as a dependency android_app
of a module . : Compile using the SDK's hidden API : Specifies the signature to use, as above, using the platform signature. : imports the Android archive (aar) into , which must be used as a dependency of the module .static_libs
platform_apis
certificate
android_library_import
android_app
android_app
static_libs
Let's try to create a random sample application called GlanceApp, the following is the sample Android.bp file, in the GlanceApp module, import glance_android_library
as a static dependency, and as glance_android_library
dependencies , to build .glance_java_library
content_aar_plugin
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",]
}
So, will be content_aar_plugin
added to your application, also adding glide (3rd party library) as a dependency.
Since we have privileged
set this to true, and set the certificate to platform, GlanceApp will act as a system privileged application.
C. Download AOSP source code
If you have not downloaded the AOSP source code, please use the following command to download the source code:
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)
The flowchart illustrates the following:
- Generate files from
Android.mk
and other Makefilesout/build-aosp_bluejay.ninja
. - Generate files from Android.bp
out/soong/build.ninja
. In addition, a smallerout/combined-aosp_bluejay.ninja
file is generated that is responsible for connecting the two as the entry point for execution. - Ultimately, Ninja files are the tools that really directly control source code compilation, responsible for generating apk, aar, and dex files. The signing of the APK is also done using ninja rules, and then after all this is done,
*.imgs
the file is created.
Finally, let's discuss these 3 steps in detail.
- run
source build/envsetup.sh
- select
lunch
option - run
make <module-name>
orm <module-name>
The first step of Android compilation
is running source build/envsetup.sh
.
This paves the way for subsequent compilation steps. It is crucial to understand envsetup.sh
how this corresponds to our analysis.
envsetup.sh
Script defines many functions. After executing this script, you can use Linux commands to directly execute these functions in the current console, such as lunch、mm、mmm
etc. (use hmm to view all available commands). Therefore, lunch
and mmm
are actually shell functions, equivalent to shell scripts. Let's discuss build/envsetup.sh
the rationale for implementing these commands in .
The second step of Android compilation
is to run lunch
the command. envsetup.sh
Functions in the script lunch()
set the environment for building images (*.imgs) and other artifacts (like apk, jar, .so, etc.). It AndroidProducts.mk.list
reads a list of target devices from a file named list. When the function is called print_lunch_menu()
, AndroidProducts.mk.list
it takes COMMON_LUNCH_CHOICES
the variable from it and displays it to the user. From that function, will call get_build_var()
and then call build/soong/soong_ui.bash --dumpvar-mode
.
soong_ui.bash
will call the function /build/soong/cmd/soong_ui/main.go
in , which will find all of them , and make a single one . Check out the code snippet below...main()
build.FindSources(buildCtx, config, f)
AndroidProducts.mk
COMMON_LUNCH_CHOICES
AndroidProducts.mk.list
# lunch.bash
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)
...
}
uncommon but important commands
-
set_stuff_for_environment
: Its function is to add some paths to the PATH environment variable so that we can use some other tools in the Android source code, such as an emulator, in the console that has executed lunch. -
tapas
: It sets up the build environment for building unbundled apps or APKs (normal Android packages). You can choose the chip architecture, the build variant, and the application required for the module build. For example:tapas SystemUI arm eng
-
banchan
: It sets up the build environment for building unbundled modules or APEX (local services, libraries, HAL, etc.). You can choose the chip architecture, the build variant, and the application required for the module build. For example:banchan com.android.boinic SystemUI arm eng
-
make command
These commands become very easy if you understand how the lunch command works.
m
: Compile from the top of the tree. For example:m
orm <module-name>
mm
: Build and install all modules and their dependencies in the current directory.mmm
: Builds and installs all modules and their dependencies in the provided directory. To limit which modules are built, the following syntax can be used:mmm dir/:target1,target2
. For example:mmm packages/apps/Launcher3
There are several other supported commands, you can use hmm
the command to see the list.
The third step of Android compilation
make
orm
Before Android N
the m or make command was equivalent make -f build/core/main.mk
(built via GNU make)
Currently
the m or make command is equivalent build/soong/soong_ui.bash -make-mode
, which is meant soong_ui.bash
to be the core of the build system for the Android platform.
# song_ui.bash
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" "$@"
It can be seen that soong_ui.bash
the main logic is divided into 4 parts:
Run microfactory
to set up the environment for building Go scripts. Help us soong_build_go
build the requested binary with .
soong_build_go soong_ui
Prepared the shell function call and executed soong's entry ie main.go
.
soong_build_go mk2rbc
and rbcrun
executed the entry of the bazel build system and converted the different Makefiles to Starlark
.
final execution soong_ui
.
Therefore, from point 2 we understand that the entrance of soong ismain.go
Please note: point 3 is beyond the 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 parameters are less used and not used in build/craft, so we'll skip those and discuss the --make-mode
sum below --build-mode
.
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 call cleanbuild.go
and help.sh
. clobber/clean
Used to delete the output folder, help
used to display the user manual for the command.
Next, let's dig into --make-mode
and --build - mode
.
Below is a high-level flow of the build process, and we'll discuss each join point one by one.
main.go
By config.go
setting the configuration, passing parameters such as skip, etc. kati.go
Then, the FindSources function finds the mk file to merge into and soong.go
the bp file to process and convert to ninja file, and the help ninja.go
. bazel
Only required if enabled bp2build.go
, then you need to convert .bp files to BAZEL files. For this article, we assume it is not enabled bazel
.
# main.go
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)
}
Config will send parameters to build.go
, to decide what to run and in what order. For example, if we run the following command:
build/soong/soong_ui.bash --make-mode --skip-ninja
Config's skipNinja will be true. Then proceed with:
//config.go
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)
}
}
}
Once the configuration is set, in the build process the variable "what" is set to by default runAll
.
//build.go
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)
}
}
Once all meta filters are done, like skip Kati, skip Ninja, etc., the Soong process will start.
Soong's pipeline
has a tool called bootstrap that reads a Blueprint file that describes itself and generates .bootstrap/build.ninja
a file that describes how to build a full version of it, and uses that to generate the final Ninja file that Soong sends out.
//song.go
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...)
...
}
If Bp2Build
true, it means that the Bazel build system needs to be used and needs to be executed bp2build.go
. It writes the equivalent of a file that can be built with Android.bp
Bazel .bzl
.
Google wants to offload all compilation-related tasks to Bazel. It's a huge project, and the Android code is huge. I don't know when this project will be completed. Generated
from . Afterwards, Kati will be executed to parse Makefiles, but this is not part of Soong's bootstrapping. Kati's flow Loading Android.mk is performed in build.go , which calls the flow in the file (core/main.mk), including Android.mk for each subdirectory in the following way.Android.bp
out/soong/build.ninja
runKati
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)))
Based on this logic, we often see [xxx/xxx] contains xxx at compile time. Search for files in the Android source code, find Android.mk, put the corresponding file path into AndroidProducts.mk.list
the file, and generate the ninja file for it. It uses ckati to achieve.
For example: 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 the generated ninja file looks like. Take SystemUI-core as an example.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 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
Use rule <rule-name>
, you can define a rule for reuse, the command format is as follows:
m.<module>-<variant>-*
: where and will be Android.bp/Android.mk
defined in and * can be treated as different flags like javacFlags
or kotlincFlags
.
build $ <function>
: which is actually the command to 1. aapt2
convert the XML file and the Java file to .class
a file using and the Java compiler, and then 2. .class
convert the file to .dex
a file to create a file..apk
It also has additional rules for copying all generated artifacts into the appropriate directories. Directories out/target/product/bluejay/<obj>
are used to stage "object" files, and these intermediate binary images are used to build the final program. What actually lands on the target file system is stored in out/target/product/bluejay
the root, system, and data directories under the directory. Usually, they are bundled into vbmeta.img、system.img、ramdisk.img 和 userdata.img
image files called .
These images are also made, packaged and compressed as part of the ninja files 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
in conclusion
Hope this article gave you a good understanding of the Android platform build system and AOSP.
As you may have noticed, I mentioned the Bazel build system several times in the article . It's starting to gain traction as a potential replacement for the current build system. I'd love to talk about the Bazel build system in more detail in a future article, as things develop.