Android 编译系统(Build System)剖析

news2024/11/19 5:28:39

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

不常见但是重要的命令

  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.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" "$@"

可以看出,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-mode
   if 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 = 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)
    }
 }
}

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

使用 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.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

结论

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL安装记录

背景 Windows系统重装了, 想恢复一下之前的MySQL环境, 而且本地数据库也是比较常用的, 刚好本次也在安装, 做一个简单的记录. 也算是自己的学习记录输出. 遇到的问题当然也可以同时记录在这里, 方便后 续回顾. 资料包 百度网盘 // TODO 估计放了也会被CSDN屏蔽, 这里就不放…

7 集群基本测试

1. 上传小文件到集群 在hadoop路径下执行命令创建一个文件夹用于存放即将上传的文件&#xff1a; [atguiguhadoop102 ~]$ hadoop fs -mkdir /input上传&#xff1a; [atguiguhadoop102 hadoop-3.1.3]$ hadoop fs -put wcinput/work.txt /input2.上传大文件 [atguiguhadoop1…

数学分析:场论

我们之前知道的是里斯表示定理。 这里看到&#xff0c;对于多重线性映射&#xff0c;里斯表示定理会从内积变成混合积。当然我们还是只考虑三维以内的情况。 于是我们可以把不同的1形式和2形式的下标写上&#xff0c;表示他们相当于内积或者混合积对应的那个向量。 然后还差0形…

LeetCode第1~5题解

CONTENTS LeetCode 1. 两数之和&#xff08;简单&#xff09;LeetCode 2. 两数相加&#xff08;中等&#xff09;LeetCode 3. 无重复字符的最长子串&#xff08;中等&#xff09;LeetCode 4. 寻找两个正序数组的中位数&#xff08;困难&#xff09;LeetCode 5. 最长回文子串&am…

【awd系列】Bugku S3 AWD排位赛-9 pwn类型

文章目录 二进制下载检查分析运行二进制ida分析解题思路exp 二进制下载 下载地址&#xff1a;传送门 检查分析 [rootningan 3rd]# file pwn pwn: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for …

android系统启动流程之SystemServer运行过程

SystemServer进程的启动流程&#xff1a;直接看代码&#xff1a; SystemServer是Java中的一个进程&#xff0c;执行入口是SystemServer.java.main(); SystemServer.java.main();-->new SystemServer().run();-->createSystemContext();//创建系统上下文:虽然SystemServe…

Unittest 笔记:unittest拓展生成HTM报告发送邮件

HTMLTestRunner 是一个unitest拓展可以生成HTML 报告 下载地址&#xff1a;GitHub: https://github.com/defnnig/HTMLTestRunner HTMLTestRunner是一个独立的py文件&#xff0c;可以放在Lib 作为第三方模块使用或者作为项目的一部分。 方式1&#xff1a; 验证是否安装成功&…

Flutter 状态管理引子

1、为了更好地了解状态管理&#xff0c;先看看什么是状态。 在类似Flutter这样的响应式编程框架中&#xff0c;我们可以认为U相关的开发就是对数据进行封装&#xff0c;将之转换为具体的U1布局或者组件。借用Flutter官网的一张图&#xff0c;可以把我们在第二部分做的所有开发…

AliOS-Things引入

目录 一、简介 1.1 硬件抽象层 1.2 AliOS-Things内核 rhino ​编辑 1.3 AliOS-Things组件 二、如何进行AliOS-Things开发 三、安装环境 安装python pip git 修改pip镜像源 安装aos-cube 一、简介 AliOS-Things是阿里巴巴公司推出的致力于搭建云端一体化LoT软件。AliOS-…

Linux操作系统--文件与目录结构

我们初步认识了Linux操作系统,下面我们进一步看看linux的文件与目录结构。 1.文件系统和挂载点 (1).当前的操作系统中查看文件系统 位置 > 计算机 这样你就可以看见当前操作系统中的所有目录和文件。如下所示: (2).挂载点 挂载点实际上就是linux中的磁盘文件系统的入口…

快速理解 X server, DISPLAY 与 X11 Forwarding

​ X server X server是X Window System &#xff08;简称X11或者X&#xff09;系统中的显示服务器&#xff08;display server&#xff09;&#xff0c;用于监听X client发送来的图形界面显示请求&#xff0c;并且将图形界面绘制并显示在屏幕&#xff08;screen&#xff09;…

粒子群算法的基本原理和Matlab实现

1.案例背景 1.1 PSO算法介绍 粒子群优化算法(Particle Swarm Optimization,PSO)是计算智能领域,除了蚁群算法,鱼群算法之外的一种群体智能的优化算法,该算法最早是由Kennedy和 Eberhart 在1995年提出的。PSO算法源于对鸟类捕食行为的研究,鸟类捕食时,每只鸟找到食物最简单有效…

webassembly003 ggml GGML Tensor Library part-3

关于pthread_create()和pthread_join() #include <stdio.h> #include <pthread.h>void *thread_func(void *arg) {int *num (int *)arg;printf("Hello from thread! arg%d\n", *num);pthread_exit(NULL); }int main() {pthread_t thread;int arg 10;i…

解锁开发中的创意:用户为中心的设计思维的力量

引言 设计思维&#xff0c;起源于20世纪60年代&#xff0c;是一种解决问题的方法。它不仅仅是设计师的专利&#xff0c;而是一种可以广泛应用于各种行业和领域的方法。设计思维强调了用户至中的重要性&#xff0c;认为任何问题的解决都应该从用户的需求出发。这种方法鼓励我们…

反转链表+交换两个链表的节点

目录 ​编辑 一&#xff0c;反转链表 1.题目描述 2.例子 3.题目接口 4.分析以及解题代码 1.迭代法 2.递归写法 二&#xff0c;两两交换两个链表中的节点 1.题目描述 2.例子 3.题目接口 4.题目分析以及解法 一&#xff0c;反转链表 1.题目描述 首先来看看反转链表的…

主流深度学习框架及神经网络模型汇总

目录 主流深度学习框架及神经网络模型汇总 一、人工智能的研究领域和分支 二、主流深度学习框架​编辑 1.TensorFlow 2.PyTorch 3.PaddlePaddle 4.Keras 5.Caffe/Caffe2 6.MXNet 7.Theano 8.Torch 9.CNTK 10.ONNX 三、深度学习移动端推理框架 1.TensorRT 2.TF-…

LabVIEW是如何控制硬件的?

概述 工程 师 和 科学 家 可以 使用 LabVIEW 与 数千 种 不同 的 硬件 设备 无缝 集成&#xff0c; 并 通过 方便 的 功能 和 跨 所有 硬件 的 一致 编 程 框架 帮助 节省 开发 时间。 内容 通过更简单的系统集成节省开发时间 连接到任何硬件 NI 硬件 第三方硬件 快速找到…

数据库事务四大特性

事务的4大特性&#xff08;ACID&#xff09;&#xff1a; 原子性(Atomicity)&#xff1a; 事务是数据库的逻辑工作单位&#xff0c;它对数据库的修改要么全部执行&#xff0c;要么全部不执行。 一致性(Consistemcy)&#xff1a; 事务前后&#xff0c;数据库的状态都满足所有的完…

Python之defaultdict方法详解

文章目录 字典dict介绍collections.defaultdict类 字典dict介绍 python中的dict是一个重要的数据类型,用“键”(key)来索引&#xff0c;表示为dict(key: val, …),有以下特征&#xff1a; 键可以是任何不可变(immutable)数据类型不可变数据类型有&#xff1a;数字&#xff0c…

嵌入式软件设计

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…