Android 编译系统(Build System)剖析

Android Build System剖析

Android预构建应用是如何制作的,背后的构建系统又是什么?

本文旨在分享关于Android构建系统以及与原始设备制造商(OEM)集成的知识,简化理解AOSP复杂机制的过程。与手动查阅各种文件及其内部工作流程相比,本文可以作为进入AOSP构建系统领域的快速指南。不涉及Gradle构建系统,Android平台构建系统与基于Gradle的Android应用构建系统截然不同,值得一提的是,大家是否曾想过Android预构建应用是如何制作的,背后的构建系统又是什么?对于大多数Android开发者来说,寻找关于Android操作系统核心和内部运行机制的优质资源是一个共同的痛点。Framework的开发并不容易,此外,构建一个带有其复杂性的Framework应用可能会令人困惑。

本文要点

在本文结尾,您将理解并了解有关Android平台构建系统的所有复杂性、功能、定义和关联。以下是四个详细讨论的要点:

  1. 环境设置
    • 运行 source build/envsetup.sh
  2. 选择要构建的目标产品
    • 运行 lunch <option>
  3. 构建代码
    • 运行 make <module-name>m <module-name>
  4. 在设备上运行/刷写/安装
    • 通过 adb push 推送apk
    • 通过 fastboot 刷写镜像

但在深入探讨以上4个步骤之前,有一些先决条件:

A. Android构建系统的演进

B. Android.bpblueprint

C. 下载AOSP源代码

A. Android构建系统的演进

  • Android N版本(v7.0)之前,

编译是由GNU make工具完成的。所有规则都写在一个名为Makefile的配置文件中,make工具会根据Makefile中的指令编译代码。

什么是make? make是一种自动化构建工具,通过读取Makefile将源代码自动编译为可执行程序和库文件。

什么是Makefile或.mk文件? Makefile定义了目标程序的依赖关系和生成目标程序的相关规则。

就像Gradle有build.gradle一样,make有Makefile(main.mk)。

  • 在Android N版本(v7.0)之后,

在Android层面,GNU Make编译变得缓慢、容易出错、不可扩展且难以测试,因此Google引入了Ninja构建系统,该系统通过.ninja文件实现了Android构建系统的灵活性,因为.ninja文件是人类可读的。

什么是ninja? 它是一个编译框架,将根据相应的.bp(blueprint)文件编译成.ninja文件。通常情况下,.ninja文件不会手动修改,而是通过将.bp(blueprint)转换为.ninja文件来编译.ninja文件。

什么是soong和.bp文件? 为了生成.ninja文件,Google引入了soong构建系统,其中包括一个名为blueprinting的工具,用于将Android.bp文件解析为.ninja文件,并引入了kati工具,用于将Android.mk文件转换为.ninja文件。

什么是kati? 这是一个基于Golang和C++的工具,其主要功能是将复杂的Android.mk文件转换为ninja文件。

附:Soong还编译并生成了一个androidmk命令,将Android.mk文件转换为Android.bp文件。

就像Gradle有build.gradle一样,ninja有build.ninja

  • 在2020年的Android发行说明中,Google表示他们将开始将构建系统迁移到Bazel。

B. 详细了解Android.bp和blueprinting

在Android.bp中,我们会根据模块类型构建所需内容。

常用的类型和方法如下:

android_app:用于构建apk,其功能与Android.mk的BUILD_PACKAGE相同。
java_library:从.class文件生成.jar包。生成的jar包不适合直接在设备上安装,而是将其用作static_libs依赖项。
static_libs:在编译时由调用者解析的库,并由编译器复制到目标应用程序中。
android_library:将源代码与Android资源文件一起链接到设备的.jar文件中。
android_library具有不同的变体,从.class文件生成.jar包,以及从aapt2生成的名为package-res.apk的文件。生成的apk文件不能直接在设备上安装,但可以用作android_app模块的static_libs依赖项。
platform_apis:使用SDK的隐藏API进行编译
certificate:指定要使用的签名,如上所述,使用平台签名。
android_library_import:将Android存档(aar)导入到android_app,必须将其用作android_app模块的static_libs依赖项。

让我们尝试创建一个名为GlanceApp的随机示例应用程序,以下是示例Android.bp文件,在GlanceApp模块中,将 glance_android_library 引入为静态依赖项, 而glance_android_library 又将glance_java_librarycontent_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",]
}

因此,将content_aar_plugin添加到您的应用程序中,同时还将glide(第三方库)作为依赖项添加。

由于我们已将privileged设置为true,并将证书设置为platform,GlanceApp将充当系统特权应用程序。

C. 下载AOSP源码

如果你还没有下载AOSP源码,请使用下面命令下载源码:

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)

Android.mk与Android.bp转成Ninja编译文件
该流程图说明了以下内容:

  1. Android.mk和其他Makefiles生成out/build-aosp_bluejay.ninja文件。
  2. 从Android.bp生成out/soong/build.ninja文件。此外,还会生成一个较小的out/combined-aosp_bluejay.ninja文件,负责将两者连接起来,作为执行入口。
  3. 最终,Ninja文件是真正直接控制源代码编译的工具,负责生成apk、aar和dex文件。APK的签名也是使用ninja规则完成的,然后完成这一切后,会创建*.imgs文件。

最后,让我们详细讨论这3个步骤。

  1. 运行source build/envsetup.sh
  2. 选择lunch选项
  3. 运行make <module-name>m <module-name>

Android编译的第一步

是运行source build/envsetup.sh

这为后续的编译步骤铺平了道路。了解envsetup.sh与我们的分析对应关系至关重要。

envsetup.sh脚本定义了许多函数。在执行此脚本后,您可以使用Linux命令在当前控制台直接执行这些函数,比如lunch、mm、mmm等(使用hmm查看所有可用命令)。因此,lunchmmm实际上是shell函数,相当于shell脚本。让我们讨论一下在build/envsetup.sh中实现这些命令的原理。

Android编译的第二步

是运行lunch命令。envsetup.sh脚本中的lunch()函数设置用于构建图像(*.imgs)和其他构件(如apk、jar、.so等)的环境。它从名为AndroidProducts.mk.list的文件列表中读取目标设备的列表。当调用print_lunch_menu()函数时,它会从AndroidProducts.mk.list中获取COMMON_LUNCH_CHOICES变量并显示给用户。从该函数中,将调用get_build_var(),然后调用build/soong/soong_ui.bash --dumpvar-mode

soong_ui.bash会调用/build/soong/cmd/soong_ui/main.go中的main()函数,该函数会调用build.FindSources(buildCtx, config, f),从而找到所有的AndroidProducts.mk,并制作一个带有单个COMMON_LUNCH_CHOICESAndroidProducts.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 dashvariant_and_version=${selection#*-} # Trim everything up to first dashif [ "$variant_and_version" != "$selection" ]; thenvariant=${variant_and_version%%-*}if [ "$variant" != "$variant_and_version" ]; thenversion=${variant_and_version#*-}fifi...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)...
}

不常见但是重要的命令

  1. set_stuff_for_environment:其功能是将一些路径添加到PATH环境变量中,以便我们可以在已执行lunch的控制台中使用Android源代码中的一些其他工具,例如模拟器。

  2. tapas:它为构建未捆绑的应用程序或APK(正常的Android包)设置构建环境。您可以选择芯片架构、构建变体以及模块构建所需的应用程序。例如:tapas SystemUI arm eng

  3. banchan:它为构建未捆绑的模块或APEX(本地服务、库、HAL等)设置构建环境。您可以选择芯片架构、构建变体以及模块构建所需的应用程序。例如:banchan com.android.boinic SystemUI arm eng

  4. make命令

如果您理解了lunch命令的原理,这些命令将变得非常容易。

  • m:从树的顶部进行编译。例如:mm <module-name>
  • mm:构建并安装当前目录中的所有模块及其依赖项。
  • mmm:构建并安装所提供目录中的所有模块及其依赖项。要限制构建的模块,可以使用以下语法:mmm dir/:target1,target2。例如:mmm packages/apps/Launcher3

还有其他几个支持的命令,可以使用hmm命令查看列表。

Android编译的第三步

makem

在Android N之前
m或make命令相当于make -f build/core/main.mk(通过GNU make构建)

目前
m或make命令相当于build/soong/soong_ui.bash -make-mode,这意味着soong_ui.bash是Android平台构建系统的核心。

# song_ui.bash
source ${TOP}/build/soong/scripts/microfactory.bashsoong_build_go soong_ui android/soong/cmd/soong_ui
soong_build_go mk2rbc android/soong/mk2rbc/cmd
soong_build_go rbcrun rbcrun/cmdcd ${TOP}
exec "$(getoutdir)/soong_ui" "$@"

可以看出,soong_ui.bash的主要逻辑分为4部分:

运行microfactory,为构建Go脚本设置环境。帮助我们使用soong_build_go构建所请求的二进制文件。
soong_build_go soong_ui准备了shell函数调用并执行了soong的入口即main.go
soong_build_go mk2rbcrbcrun执行了bazel构建系统的入口,并将不同的Makefile转换为Starlark
最终执行soong_ui
因此,从第2点我们理解了soong的入口即main.go

请注意:第3点超出了本文的范围。

main.go中,必须采用以下4个参数之一:

--dumpvar-mode
--dumpvars-mode
--make-mode
--build-mode

前两个参数使用较少且不用于构建/制作,因此我们将跳过这些,讨论下面的 --make-mode--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-modeif inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) {clean(ctx, config)return}if inList("help", config.Arguments())) {help(ctx, config)return}...}
}

还有其他几个参数,如clobber/cleanhelp,它们调用cleanbuild.gohelp.shclobber/clean用于删除输出文件夹,help用于显示命令的用户手册。

接下来,让我们深入探讨 --make-mode--build - mode

以下是构建过程的高级流程,我们将逐个讨论每个连接点。
构建过程的高级流程
main.go通过config.go设置配置,传递参数如skip等。然后,FindSources函数查找要合并到kati.go的mk文件和要处理并转换为ninja文件的soong.go的bp文件,以及借助ninja.go。只有在启用了bazel时,才需要bp2build.go,然后需要将.bp文件转换为BAZEL文件。对于本文,我们假设未启用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会将参数发送到build.go,以决定要运行什么以及以什么顺序运行。例如,如果我们运行以下命令:
build/soong/soong_ui.bash --make-mode --skip-ninja
Config的skipNinja将为true。然后继续进行:

//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 = truec.skipKati = true} else if arg == "--skip-kati" {c.skipKati = true} else if arg == "--soong-only" {c.skipKati = truec.skipKatiNinja = true...c.arguments = append(c.arguments, arg)}}
}

一旦配置设置完成,在构建流程中,默认情况下变量“what”被设置为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)}
}

一旦所有元过滤器完成,比如跳过 Kati、跳过 Ninja 等,Soong 进程就会开始。

Soong 的流程
有一个名为 bootstrap 的工具,它读取描述自身的 Blueprint 文件,并生成描述如何构建其完整版本的 .bootstrap/build.ninja 文件,并使用它来生成 Soong 发出的最终 Ninja 文件。

//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...)...
}

如果 Bp2Build 为 true,意味着需要使用 Bazel 构建系统,需要执行 bp2build.go。它会编写等效于可使用 Bazel 构建的 Android.bp 文件的 .bzl 文件。
Google 希望将所有与编译相关的任务交给 Bazel。这是一个庞大的项目,而 Android 代码也很庞大。我不知道这个项目何时会完成。
Android.bp 生成 out/soong/build.ninja。此后,将执行 Kati 来解析 Makefiles,但这不是 Soong 引导的一部分。
Kati 的流程
加载 Android.mk
在 build.go 中执行 runKati,它调用文件中的流程(core/main.mk),以以下方式包括每个子目录的 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)))

基于这个逻辑,在编译时我们经常会看到 [xxx/xxx] 包含 xxx。在 Android 源代码中搜索文件,找到 Android.mk,并将相应的文件路径放入 AndroidProducts.mk.list 文件,然后为其生成 ninja 文件。它使用 ckati 来实现。

例如:命令:ckati,-f build/make/core/main.mk

从 Android.mk 和其他 Makefiles 中,将生成 out/build-<product_name>.ninja 文件。

我们来讨论一下生成的 ninja 文件是什么样的。以 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:1m.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-jdkrule m.SystemUI-core_android_common.aidlcommand = 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: 9def94a8716a4acf60f436254037b1e48158f63767ed67940332f88206e735f1restat = truerule m.SystemUI-core_android_common.lintcommand = 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.textprotorspfile = out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/lint-srcs.listrspfile_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-versionbuild $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_licdescription = ${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

使用 rule <rule-name>,你可以定义一个用于重用的规则,命令格式如下:

m.<module>-<variant>-*:其中 和 将在 Android.bp/Android.mk 中定义,而 * 可以视为不同的标志,如 javacFlagskotlincFlags

build $ <function>:其中 实际上是用于 1. 使用 aapt2 和 Java 编译器将 XML 文件和 Java 文件转换为 .class 文件,然后 2. 将 .class 文件转换为 .dex 文件以创建 .apk 文件的命令。

它还有其他规则,用于将所有生成的构件复制到相应的目录中。目录 out/target/product/bluejay/<obj>用于分期“object”文件,这些中间二进制映像用于构建最终的程序。实际上落入目标文件系统的内容存储在 out/target/product/bluejay 目录下的 root、system 和 data 目录中。通常,它们被捆绑成称为 vbmeta.img、system.img、ramdisk.img 和 userdata.img 的镜像文件。

这些镜像的制作、打包和压缩也是由 Kati 生成的 ninja 文件的一部分。

rule m.microdroid_vbmeta_bootconfig_android_arm64_armv8-a.vbmetacommand = 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

结论

希望这篇文章让你对Android平台构建系统和AOSP有了较好的了解。
正如你可能注意到的,我在文章中多次提到了Bazel构建系统。它已经开始受到关注,有可能会取代当前的构建系统。我很愿意在未来的文章中更详细地谈论Bazel构建系统,随着事态的发展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/108410.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

零售再增长,直播登“C位”,美团稳稳交出成绩单

8月24日&#xff0c;美团发布2023年中期业绩和二季报&#xff0c;财报显示其二季度实现营收680亿元&#xff0c;同比增长33.4%&#xff1b;实现净利润47.13亿元&#xff0c;同比扭亏为盈&#xff0c;调整后净利润达历史最高水平。其中&#xff0c;与消费市场走势息息相关的美团…

攻防演练期间一次对某企业的渗透测试

免责声明 由于传播、利用本文章说黑客所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者说黑客不为此承担任何责任&#xff0c;一旦造成后果请自行承担&#xff01; 前言 某次攻防演练中&#xff0c;主办方只提供了目标…

大数据精准营销获客能为企业带来哪些东西?

广告圈里一句名言:我知道我的广告浪费了一半&#xff0c;但我不知道浪费了哪一半。当前&#xff0c;越来越多的企业在大数据思维指导下进行广告投放&#xff0c;广告能通过对人群的定向&#xff0c;投放给准确的目标顾客&#xff0c;特别是互联网广告现在能够做到根据不同的人向…

YOLO目标检测——脑肿瘤检测数据集下载分享

脑肿瘤检测数据集是用于训练和评估脑肿瘤检测算法和模型的数据集&#xff0c;共同500张高清图像。 数据集点击下载&#xff1a;YOLO脑肿瘤检测数据集500图像.rar

HRS--人力资源系统(Springboot+vue)--打基础升级--(六)分页查询 + 重置按钮

一&#xff1a;先弄个简单的重置按钮 1.界面设计就放在搜索框同一列的位置 2. 在点击重置按钮时&#xff0c;清空搜索框内的内容&#xff0c;同时触发一次无条件查询(这个写法有bug&#xff0c;下面会有说明) 二&#xff1a;做分页 在MyBatis中&#xff0c;有多种方法可以实现分…

Lingo软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 Lingo是一款专门为解决线性和非线性优化问题而设计的专业软件&#xff0c;广泛应用于运筹学、工程管理、交通管理、生产调度、物流管理等领域。它提供了一个易于使用的界面和灵活的求解器&#xff0c;能够高效地求解大规模的线性…

Android 面试之Glide做了哪些优化?

前言 Glide可以说是最常用的图片加载框架了&#xff0c;Glide链式调用使用方便&#xff0c;性能上也可以满足大多数场景的使用&#xff0c;Glide源码与原理也是面试中的常客。 但是Glide的源码内容比较多&#xff0c;想要学习它的源码往往千头万绪&#xff0c;一时抓不住重点.…

快速排序笔记

一、quick_sort方法中如果 il,jr 会死循环的分析 1、示例代码 void quick_sort(int a[],int l,int r){if(l>r) return;int il,jr; //此处设置会导致死循环int x num[(lr)>>1];while(i<j){while(a[i] <x); //死循环的地方while(a[--j] >x);if(i<j) swap(a…

使用Nacos与Spring Boot实现配置管理

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Unittest自动化测试框架vs Pytest自动化测试框架

引言 前面一篇文章Python单元测试框架介绍已经介绍了python单元测试框架&#xff0c;大家平时经常使用的是unittest&#xff0c;因为它比较基础&#xff0c;并且可以进行二次开发&#xff0c;如果你的开发水平很高&#xff0c;集成开发自动化测试平台也是可以的。而这篇文章主要…

关于UG/NX二次开发的历史和发展前景

UG/NX是一款广泛应用于计算机辅助设计与制造领域的软件&#xff0c;具有强大的二次开发能力。本文将介绍UG/NX二次开发的历史和发展前景。 一、UG/NX二次开发的历史 UG/NX最初由美国UGS公司&#xff08;后被西门子收购&#xff09;开发&#xff0c;是一款集成了CAD、CAM和CAE…

【C++】5、构建:CMake

文章目录 一、概述二、实战2.1 内部构建、外部构建2.2 CLion Cmake 一、概述 CMake 是跨平台构建工具&#xff0c;其通过 CMakeLists.txt 描述&#xff0c;并生成 native 编译配置文件&#xff1a; 在 Linux/Unix 平台&#xff0c;生成 makefile在苹果平台&#xff0c;可以生…

点云平面拟合和球面拟合

一、介绍 In this tutorial we learn how to use a RandomSampleConsensus with a plane model to obtain the cloud fitting to this model. 二、代码 #include <iostream> #include <thread> #include <pcl/point_types.h> #include <pcl/common/io.…

带你启用window10专业版系统自带的远程桌面

启用window10专业版系统自带的远程桌面 文章目录 启用window10专业版系统自带的远程桌面前言1.找到远程桌面的开关2. 找到“应用”项目3. 打开需要远程操作的电脑远程桌面功能 总结 前言 Windows操作系统作为应用最广泛的个人电脑操作系统&#xff0c;在我们身边几乎随处可见。…

LeetCode-227-基本计算器Ⅱ

题目描述&#xff1a; 给你一个字符串表达式 s &#xff0c;请你实现一个基本计算器来计算并返回它的值。 整数除法仅保留整数部分。 你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。 注意&#xff1a;不允许使用任何将字符串作为数学表达式计…

Android初学之android studio运行java/kotlin程序

第一步骤&#xff1a;File—>New—>New Module&#xff0c;然后弹出一个框&#xff0c;&#xff08;左边&#xff09;选择Java or Kotlin Library&#xff0c;&#xff08;右边&#xff09;编辑自己的图书馆名、包名、类名&#xff0c;选择Java一个语言&#xff0c;然后F…

c++ 判断基类指针指向的真实对象类型

在 c 面向对象使用中&#xff0c;我们常常会定义一个基类类型的指针&#xff0c;在运行过程中&#xff0c;这个指针可能指向一个基类类型的对象&#xff0c;也可能指向的是其子类类型的对象&#xff0c;那现在问题来了&#xff0c;我们如何去判断这个指针到底执行了一个什么类型…

超声波创始人杨子超:AI Agents崛起

2023年7月23日&#xff0c;超声波俱乐部AI Open Day在北京举办&#xff0c;百位AI领域顶级创业者、知名投资人汇聚一堂。超声波创始人杨子超进行了一场精彩的分享&#xff0c;以下为杨子超的分享整理&#xff1a; 分享嘉宾&#xff1a;杨子超 超声波创始人分享主题&#xff1a;…

Nginx详解 一:编译安装Nginx和Nginx模块

文章目录 1.HTTP 和 Nginx1.1 Socket套接字1.2 HTTP工作机制1.2.1一次http事务1.2.2 资源类型1.2.3提高HTTP连接性能 2. I/O模型2.1 I/O模型相关概念2.2 网络I/O模型2.2.1 **阻塞型** **I/O** 模型&#xff08;blocking IO&#xff09;2.2.2 **非阻塞型** **I/O** **模型** **(…

【JAVA】String 类

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈Java &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; String 1. 字符串构造2. String对象的比…