AOSP-Android.bp

在 Android 7.0 发布之前,Android 仅使用 GNU Make 描述和执行其构建规则。Make 构建系统得到了广泛的支持和使用,但在 Android 层面变得缓慢、容易出错、无法扩展且难以测试。Soong 构建系统正好提供了 Android build 所需的灵活性。

Soong 构建系统是在 Android 7.0 (Nougat) 中引入的,旨在取代 Make。它利用 Kati GNU Make 克隆工具和 Ninja 构建系统组件来加速 Android 的构建。

了解ninjia

Ninja 的配置文件就是Android.bp,Android 系统使用 Soong 工具来解析 Android.bp 转换生成 ninja文件。
为了兼容老的 mk 配置文件,Android 当初也开发了 Kati 工具来转换 mk 文件生成ninja,目前 Android Q 里边,还是支持 Android.mk 方式的。

kati是Android开发的一个基于Golang和C++的工具,主要功能是把Android中的Android.mk文件转换成Ninja文件。

相信在将来的版本中,会彻底让 mk 文件废弃,同时 Kati 也就淘汰了,只保留 bp 配置方式。

其实ninja是一个编译框架,会根据相应的ninja格式的配置文件进行编译,ninja文件一般不会手动修改,而是通过将Android.bp文件转换成ninja格文件来编译。

了解Soong

Soong类似于之前的Makefile编译系统的核心,负责提供Android.bp语义解析,并将之转换成Ninja文件。

Soong还会编译生成一个androidmk命令,用于将Android.mk文件转换为Android.bp文件,不过这个转换功能仅限于没有分支、循环等流程控制的Android.mk才有效。

Make和Soong比较

以下是 Make 配置与 Soong 在 Soong 配置(Blueprint 或 .bp)文件中完成相同操作的比较。

Make示例

1
2
3
4
5
6
7
8
9
10
11
12
13
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := libxmlrpc++
LOCAL_MODULE_HOST_OS := linux

LOCAL_RTTI_FLAG := -frtti
LOCAL_CPPFLAGS := -Wall -Werror -fexceptions
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/src

LOCAL_SRC_FILES := $(call \
all-cpp-files-under,src)
include $(BUILD_SHARED_LIBRARY)

Soong示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cc_library_shared {
name: “libxmlrpc++”,

rtti: true,
cppflags: [
“-Wall”,
“-Werror”,
“-fexceptions”,
],
export_include_dirs: [“src”],
srcs: [“src/**/*.cpp”],

target: {
darwin: {
enabled: false,
},
},
}

Android.bp文件格式

根据设计,Android.bp 文件很简单。它们不包含任何条件语句,也不包含控制流语句;所有复杂问题都由用 Go 编写的构建逻辑处理。

模块

Android.bp 文件中的模块以模块类型开头,后跟一组 name: "value", 格式的属性:

1
2
3
4
5
6
cc_binary {
name: "gzip",
srcs: ["src/test/minigzip.c"],
shared_libs: ["libz"],
stl: "none",
}

每个模块都必须具有 name 属性,并且相应值在所有 name 文件中必须是唯一的,仅有两个例外情况是命名空间和预构建模块中的 Android.bp 属性值,这两个值可能会重复。

srcs 属性以字符串列表的形式指定用于构建模块的源文件。您可以使用模块引用语法 ":<module-name>" 来引用生成源文件的其他模块的输出,如 genrulefilegroup

类型

变量和属性是强类型,变量根据第一项赋值动态变化,属性由模块类型静态设置。支持的类型为:

  • 布尔值(truefalse
  • 整数 (int)
  • 字符串 ("string")
  • 字符串列表 (["string1", "string2"])
  • 映射 ({key1: "value1", key2: ["value2"]})

映射可以包含任何类型的值,包括嵌套映射。列表和映射可能在最后一个值后面有终止逗号。

Glob

接受文件列表的属性(例如 srcs)也可以采用 glob 模式。glob 模式可以包含普通的 UNIX 通配符 *,例如 *.java。glob 模式还可以包含单个 ** 通配符作为路径元素,与零个或多个路径元素匹配。例如,java/**/*.java 同时匹配 java/Main.javajava/com/android/Main.java 模式。

变量

Android.bp 文件可能包含顶级变量赋值:

1
2
3
4
5
6
7
gzip_srcs = ["src/test/minigzip.c"],
cc_binary {
name: "gzip",
srcs: gzip_srcs,
shared_libs: ["libz"],
stl: "none",
}

变量的作用域限定在声明它们的文件的其余部分,以及所有子 Blueprint 文件。变量是不可变的,但有一个例外情况:可以使用 += 赋值将变量附加到别处,但只能在引用它们之前附加。

注释

Android.bp 文件可以包含 C 样式的多行 /* */ 注释以及 C++ 样式的单行 // 注释。

运算符

可以使用 + 运算符附加字符串、字符串列表和映射。可以使用 + 运算符对整数求和。附加映射会生成两个映射中键的并集,并附加在两个映射中都存在的所有键的值。

条件语句

Soong 不支持 Android.bp 文件中的条件语句。但是,编译规则中需要条件语句的复杂问题将在 Go(在这种语言中,您可以使用高级语言功能,并且可以跟踪条件语句引入的隐式依赖项)中处理。大多数条件语句都会转换为映射属性,其中选择了映射中的某个值并将其附加到顶级属性。

例如,要支持特定于架构的文件,请使用以下命令:

1
2
3
4
5
6
7
8
9
10
11
12
cc_library {
...
srcs: ["generic.cpp"],
arch: {
arm: {
srcs: ["arm.cpp"],
},
x86: {
srcs: ["x86.cpp"],
},
},
}

格式设置工具

Soong 包含一个针对 Blueprint 文件的规范格式设置工具,类似于 gofmt。如需以递归方式重新设置当前目录中所有 Android.bp 文件的格式,请运行以下命令:

1
bpfmt -w .

规范格式包括缩进四个空格、多元素列表的每个元素后面有换行符,以及列表和映射末尾有英文逗号。

Android.bp常用模块类型

在Android.bp中我们会基于模块类型来构建我们所需要的东西,常用的有以下几种类型

android_app

用于构建Android 应用程序安装包,是Android系统应用开发中常用的模块类型,与Android.mk中的BUILD_PACKAGE作用相同。

java_library

java_library用于将源代码构建并链接到设备的.jar文件中。默认情况下,java_library只有一个变量,它生成一个包含根据设备引导类路径编译的.class文件的.jar包。生成的jar不适合直接安装在设备上,通过会用作另一个模块的static_libs依赖项。

如果指定“installable:true”将生成一个包含“classes.dex”文件的“.jar”文件,适合在设备上安装。指定’host_supported:true’将产生两个变量,一个根据device的bootclasspath编译,另一个根据host的bootclasspath编译。

java_library_static

java_library_static作用等同于java_library,但是java_library_static已经过时,不推荐使用

android_library

android_library将源代码与android资源文件一起构建并链接到设备的“.jar”文件中。android_library有一个单独的变体,它生成一个包含根据device的bootclasspath编译的.class文件的.jar文件,以及一个包含使用aapt2编译的android资源的.package-res.apk文件。生成的apk文件不能直接安装在设备上,但可以用作android_app模块的static_libs依赖项。

cc_library

cc_library为device或host创建静态库或共享库。默认情况下,cc_library具有针对设备的单一变体。指定’host_supported:true’还会创建一个以主机为目标的库。与cc_library相关的模块类型还有cc_library_sharedcc_library_headerscc_library_static等。

Android.bp常见用法

.bp下的常见属性

介绍一些使用频率比较高的属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 构建可执行程序
android_app {
// 设定可执行的程序的名称,编译后会生成一个 CarNotification.apk
name: "CarNotification",
// 指定java源码的位置
srcs: ["src/**/*.java"],
// 指定资源文件的位置
resource_dirs: ["res"],
// 允许使用系统hide api
platform_apis: true,
// 设定apk签名为 platform
certificate: "platform",
// 如果集成的是apk且使用原签名,则使用该属性
presigned: true,
// 设定apk安装路径为priv-app
privileged: true,
// 是否启用代码优化,android_app中默认为true,java_library中默认为false
optimize: {
enabled: false,
},
// 是否预先生成dex文件,默认为true。该属性会影响应用的首次启动速度以及Android系统的启动速度
dex_preopt: {
enabled: false,
},
// 引入java静态库
static_libs: [
"androidx.cardview_cardview",
"androidx.recyclerview_recyclerview",
"androidx.palette_palette",
"car-assist-client-lib",
"android.car.userlib",
"androidx-constraintlayout_constraintlayout"
],
// 引入java库
libs: ["android.car"],
product_variables: {
pdk: {
enabled: false,
},
},
// 设定依赖模块。如果安装了此模块,则要还需要安装的其他模块的名称
required: ["privapp_whitelist_com.android.car.notification"]
}

引入第三方jar包

在项目的根目录新建 libs文件夹,放入要导入的jar包,比如 CarServicelib.jar,然后在Android.bp中引入该jar

1
2
3
4
5
6
7
8
9
10
11
java_import {
name: "CarServicelib.jar",
jars: ["libs/CarServicelib.jar"],
}
android_app {
// 省去其它属性
// 引入AndroidX库下的lib
static_libs: [
"CarServicelib.jar"
],
}

Android.bp与Android.mk对比

编译成Java库

1
2
Android.mk
include $(BUILD_JAVA_LIBRARY)
1
2
3
4
Android.bp
java_library {
......
}

编译成Java静态库

1
2
Android.mk
include $(BUILD_STATIC_JAVA_LIBRARY)
1
2
3
4
Android.bp
java_library_static {
......
}

编译成APP应用

1
2
Android.mk
include $(BUILD_PACKAGE)
1
2
3
4
Android.bp
android_app {
......
}

编译成Native动态库

1
2
Android.mk
include $(BUILD_SHARED_LIBRARY)
1
2
3
4
Android.bp
cc_library_shared {
......
}

编译成Native静态库

1
2
Android.mk
include $(BUILD_STATIC_LIBRARY)
1
2
3
4
Android.bp
cc_library_static {
......
}

编译成Native执行程序

1
2
Android.mk
include $(BUILD_EXECUTABLE)
1
2
3
4
Android.bp
cc_binary {
......
}

编译成头文件库

1
2
Android.mk
include $(BUILD_HEADER_LIBRARY)
1
2
3
4
Android.bp
cc_library_headers {
......
}

本地头文件路径

1
2
Android.mk
LOCAL_C_INCLUDES :=
1
2
Android.bp
local_include_dirs: ["xxx", ...]

依赖的静态库

1
2
Android.mk
LOCAL_STATIC_LIBRARIES :=
1
2
Android.bp
static_libs: ["xxx", "xxx", ...]

依赖的动态库

1
2
Android.mk
LOCAL_SHARED_LIBRARIES :=
1
2
Android.bp
shared_libs: ["xxx", "xxx", ...]

依赖的Java库

1
2
Android.mk
LOCAL_STATIC_JAVA_LIBRARIES :=
1
2
Android.bp
static_libs: ["xxx", "xxx", ...]