一、Soong 编译系统
在 Android 7.0 公布之前,Android 仅应用 GNU Make 形容和执行其构建规定。在Android零碎级编译中,Make 构建零碎失去了宽泛的反对和应用,但它有一些毛病:编译迟缓、容易出错、无奈扩大且难以测试,而Soong 构建零碎正好提供了 Android build 所需的灵活性。
Soong 构建零碎是在 Android 7.0 (Nougat) 中引入的,旨在取代 Make。它利用 Kati GNU Make 克隆工具和 Ninja 构建零碎组件来减速 Android 的构建,Soong的编译流程图如下。
Soong编译系统下,本来打算输出是.bp文件,输入是.ninja文件,然而因为零碎中的.mk文件还没有被齐全打消掉,因而提供kati和ckati工具将.mk/Makefile文件转换为.ninja文件。.ninja成为编译系统的汇编文件,是不须要人为去批改的,相当于配置文件来调用gcc、java、clang等编译器去编译。
Soong编译系统的设计思维是打消.mk文件中的if/else等逻辑,使.bp文件只是一个简略的编译逻辑,这些简单的抉择配置逻辑应该放在更高层,比方应用更好调试的Python来编写。
二、Android.bp
Android.bp的呈现就是为了替换Android.mk文件。bp跟mk文件不同,它是纯正的配置,没有分支、循环等流程管制,不能做算数逻辑运算。如果须要管制逻辑,那么能够应用Android.mk或者Go语言进行编写。
2.1 示例
Android.bp 文件中的模块以模块类型结尾,而后是一组格局属性:name: value,在一点上Android.bp的语法结构与JSON的语法结构类似,都是以键值对的模式编写,比方。
<a href="https://www.gaodaima.com/tag/android" title="查看更多关于android的文章" target="_blank">android</a>_app { name: "Provision", srcs: ["**/*.java"], platform_apis: true, product_specific: true, certificate: "platform", }
每个模块都必须具备 name 属性,并且相应值在所有 name 文件中必须是惟一的,仅有两个例外情况是命名空间和预构建模块中的 Android.bp 属性值,这两个值可能会反复。
srcs 属性以字符串列表的模式指定用于构建模块的源文件。能够应用模块援用语法 “:<module-name>” 来援用生成源文件的其余模块的输入,如 genrule 或 filegroup。
android_app{}
下面代码的意思是,该模块用于构建一个apk。如果要给模块指定一个名字,能够应用上面的形式。
name: "Provision",
如果指定了 android_app 模块类型(在代码块的结尾),就须要设定该模块的name 。此设置会为模块命名,生成的 APK 将与模块名称雷同,不过带有 .apk 后缀。例如,在本例中,生成的 APK 将命名为 Provision.apk
srcs: ["**/*.java"],
下面代码的srcs用于指定以后的模块编译的源码地位,*示意通配符 。
platform_apis: true,
设置该标记后会应用sdk的hide的api來编译。编译的APK中应用了零碎级API,必须设定该值。和Android.mk中的LOCAL_PRIVATE_PLATFORM_APIS的作用雷同 。
product_specific: true,
设置该标记后,生成的apk会被装置在Android零碎的product分区,和Android.mk中LOCAL_PRODUCT_MODULE作用雷同。
certificate 用于指定APK的签名形式。如果不指定,默认应用testkey签名。与LOCAL_CERTIFICATE作用雷同。 Android中共有四中签名形式:
- testkey:一般apk,默认应用该签名。
- platform:该apk实现一些零碎的外围性能。通过对系统中存在的文件夹的拜访测试,这种形式编译进去的apk所在过程的UID为system。
- shared:该apk须要和home/contacts过程共享数据。
- media:该apk是media/download零碎中的一环。
2.2 常见模块类型
在Android.bp中,咱们会基于模块类型来构建咱们所须要的货色,罕用的有以下几种类型:
- cc_library_shared:编译成动静库,相似于Android.mk中的BUILD_SHARED_LIBRARY。
- cc_binary:编译成可执行文件,相似于Android.mk中的BUILD_EXECUTABLE。
- name:编译出的模块的名称,相似于Android.mk中的LOCAL_MODULE。
- srcs:源文件,相似于Android.mk中的LOCAL_SRC_FILES。
- local_include_dirs:指定门路查找头文件,相似于Android.mk中的LOCAL_C_INCLUDES。
- shared_libs:编译所依赖的动静库,相似于Android.mk中的LOCAL_SHARED_LIBRARIES。
- static_libs:编译所依赖的动态库,相似于Android.mk中的LOCAL_STATIC_LIBRARIES。
- cflags:编译Flag,相似于Android.mk中的LOCAL_CFLAGS。
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编译。
android_library
android_library将源代码与android资源文件一起构建并链接到设施的“.jar”文件中。android_library有一个独自的变体,它生成一个蕴含依据device的bootclasspath编译的.class文件的.jar文件,以及一个蕴含应用aapt2编译的android资源的.package-res.apk文件。生成的apk文件不能间接装置在设施上,但能够用作android_app模块的static_libs依赖项。
2.3 设置变量
在bp中能够通过=号来设定一个全局变量。
src_path = ["**/*.java"] android_app { name: "Provision", srcs: src_path, platform_apis: true, product_specific: true, certificate: "platform", }
三、根底语法
3.1 数据类型
Android.bp中变量和属性是强类型,变量依据第一项赋值动态变化,属性由模块类型动态设置,反对的类型为:
- 布尔值(true或 false)
- 整数 (int)
- 字符串(”string”)
- 字符串列表 ([“string1”, “string2”])
- 映射 ({key1: “value1”, key2: [“value2”]})
3.2 条件语句
Soong 不反对 Android.bp 文件中的条件语句。编译规定中如果须要解决条件语句,那么须要在 Go中进行解决。大多数条件语句都会转换为映射属性,其中抉择了映射中的某个值并将其附加到顶级属性。
例如,要反对特定的架构文件,能够应用以下命令:
cc_library { ... srcs: ["generic.cpp"], arch: { arm: { srcs: ["arm.cpp"], }, x86: { srcs: ["x86.cpp"], }, }, }
3.3 运算符
能够应用 + 运算符附加字符串、字符串列表和映射。能够应用 + 运算符对整数求和。附加映射会生成两个映射中键的并集,并附加在两个映射中都存在的所有键的值。
3.4 示例
Android.bp位于Android 10 : packages/apps/Car/Notification 目录下,参考示例如下:
// 构建可执行程序 android_app { // 设定可执行的程序的名称,编译后会生成一个 CarNotification.apk name: "CarNotification", // 指定java源码的地位 srcs: ["src/**/*.java"], // 指定资源文件的地位 resource_dirs: ["res"], // 容许应用零碎hide api platform_apis: true, // 设定apk签名为 platform certificate: "platform", // 设定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"] } // As Lib android_library { name: "CarNotificationLib", srcs: ["src/**/*.java"], resource_dirs: ["res"], manifest: "AndroidManifest-withoutActivity.xml", platform_apis: true, optimize: { enabled: false, }, dex_preopt: { enabled: false, }, static_libs: [ "androidx.cardview_cardview", "androidx.recyclerview_recyclerview", "androidx.palette_palette", "car-assist-client-lib", "android.car.userlib", "androidx-constraintlayout_constraintlayout" ], libs: ["android.car"], product_variables: { pdk: { enabled: false, }, }, }
四、常见问题
4.1 引入第三方jar
在理论开发中,常常须要在app中引入第三方的jar。在Android.bp中,引入第三方的jar能够依照上面的形式。
首先,在我的项目的根目录新建 libs文件夹,放入要导入的jar包,比方 CarServicelib.jar,而后在Android.bp中引入该jar。
java_import { name: "CarServicelib.jar", jars: ["libs/CarServicelib.jar"], } android_app { // 省去其它属性 static_libs: [ "CarServicelib.jar" ], }
4.2 引入AndroidX
开发过程中,如果想要引入AndroidX的类库,能够参考上面的形式进行引入。
android_app { // 省去其它属性 // 引入AndroidX库下的lib static_libs: [ "androidx.cardview_cardview", "androidx.recyclerview_recyclerview", "androidx-constraintlayout_constraintlayout" ], }
参考:
Soong 编译系统
Android 编译之android.bp