Android.bp相关知识及条件编译

1. Android.bp 文件介绍

Android.bp 文件是 Android 系统的一种编译配置文件,用来代替原来的 Android.mk 文件。在 Android7.0 以前,Android 使用 make 来组织各模块的编译,对应的编译配置文件是 Android.mk 文件。Android7.0 开始,Google 引入了 Ninja 和 Kati 来编译,Ninja 的配置文件就是 Android.bp,Android 系统使用 Blueprint 和 Soong 工具来解析 Android.bp 转换生成 ninja 文件。为了兼容老的 mk 配置文件,Android 也开发了 Kati 工具来转换 mk 文件生成 ninja。Blueprint 和 Soong 都是由 Golang 写的项目,从 Android 7.0,prebuilts/go/ 目录下新增 Golang 所需的运行环境,在编译时使用。bp 跟 mk 文件不同,它是纯粹的配置,没有分支、循环等流程控制,不能做算数逻辑运算。如果需要控制逻辑,那么只能通过 Go 语言编写。

2. Android.bp 语法规则

Android.bp 示例如下:

/packages/apps/QuickAccessWallet/Android.bp

go 复制代码
android_app {
    name: "QuickAccessWallet",
    srcs: ["src/**/*.java"],
    resource_dirs: ["res"],
    platform_apis: true,
    system_ext_specific: true,
    certificate: "platform",
    privileged: true,
    manifest: "AndroidManifest_App.xml",
    static_libs: [
        "SystemUIPluginLib",
        "androidx.cardview_cardview",
        "androidx.recyclerview_recyclerview",
    ],
    optimize: {
        proguard_flags_files: [
            "proguard.flags",
        ],
    },
}

Android.bp 的语法结构与 JSON 的语法结构相似,都是以键值对的形式编写:

go 复制代码
[module type] {
    name: ["name value"],
    [property1name]: ["property1value"]
    [property2name]: ["property2 value"]
}

常见的 module type 类型

编译成 jar

go 复制代码
Android.bp
java_library {
......
}

编译成 aar

go 复制代码
android_library {
......
}

编译成 apk

go 复制代码
android_app {
......
}

编译成 Native 动态库

go 复制代码
cc_library_shared {
......
}

编译成 Native 静态库

go 复制代码
cc_library_static {
......
}

常见的 property 类型

模块命名(模块命名是唯一的!)

go 复制代码
name: ......

指定当前模块的源码位置,可使用通配符 *

go 复制代码
srcs: [......]

指定当前模块的资源文件位置

go 复制代码
resource_dirs: [......]

指定AndroidManifest.xml文件位置

go 复制代码
manifest: ......

指定 aidl 文件位置

go 复制代码
aidl: {
    local_include_dirs: [......],
}

允许使用系统 API

go 复制代码
platform_apis: true

使用系统签名

go 复制代码
certificate: "platform"

设定 apk 安装路径为 priv-app

go 复制代码
privileged: true

引入依赖库

go 复制代码
static_libs: [
......
]

引入编译时依赖库,依赖仅参与编译,不会被打包

go 复制代码
libs: [
......
]

是否启用代码优化

go 复制代码
optimize: {
    enabled: false,
}

是否预先生成 dex 文件,默认为 true。该属性会影响应用的首次启动速度以及 Android 系统的启动速度

go 复制代码
dex_preopt: {
    enabled: false,
}

注解处理器

go 复制代码
plugins: [
......
]

编译参数

go 复制代码
cflags: [
......
]

cppflags: [
......
]

javacflags: [
......
]

kotlincflags: [
......
]

certificate 用于指定 apk 的签名方式,Android 中共有四中签名方式

  • testkey:普通 apk ,则默认使用该签名
  • platform:如果 apk 需要对系统中存在的文件夹进行访问等,或者需要完成一些系统的核心功能,则使用改签名,这种方式编译出来的 apk 所在进程的 uid 为 system
  • shared:如果 apk 需要和 home/contacts 进程共享数据,则使用该签名
  • media:如果 apk 是 media/download 系统中的一环,则使用该签名

指定源文件位置,可以用通配符指定 src/main/java 目录下,所有后缀是 .java 和 .kt 的文件

go 复制代码
srcs: ["src/main/java/**/*.java", "src/main/java/**/*.kt"],

指定 manifest

go 复制代码
manifest: "src/main/AndroidManifest.xml",

设置允许使用系统 API

go 复制代码
platform_apis: true,

PS:如果想了解更多的模块类型和属性,可以通过out/soong/docs/中的soong_build.html文件来查阅~

3.Androidmk 工具介绍

Androidmk是soong中集成的一个小工具。作用是将android.mk文件转换成android.bp文件。

用法如下:

  1. 整体编译代码
  2. 编译成功后,在out/soong/host/linux-x86/bin/下会有一个androidmk文件(通过它才能进行mk->bp转换)
  3. 把想要转换的.mk文件放到out/soong/host/linux-x86/bin/ 路径下
  4. 输入命令:androidmk Android.mk > Android.bp 其中 Android.mk 是你想要转换的.mk文件。 Android.bp是生成的对应.bp文件

例子:以CarStateService下.mk为例子,给大家排一下槽点..

CarStateService中Android.mk如下:

转换后生成的Android.bp文件如下:

红框圈出来的都是转换过程中androidmk不识别的部分,会自动给注释掉。

总结:
  1. androidmk工具只能转换"较为简单的".mk文件(这里的简单是指:自定义的属性少、没有分支、循环等流程控制)
  2. androidmk工具的使用是依赖out/soong/host/linux-x86/bin/路径下的生成物的(必须要有编译产物androidmk)
我踩过的坑,以及如何规避:

①如果在out/soong/host/linux-x86/bin/路径下执行了转换命令后,Android.bp文件是空的怎么办?

解决方式:建议make clean 重新整编代码。

②转换后部分属性未识别到,被androidmk注释掉了(例如上图中红框圈出的LOCAL_PRIVATE_PLATFORM_APIS),怎么能找到该属性在bp文件中的正确写法?

解决方式:源码查阅网址:aospxref.com/android-12....

这里面记录了.mk文件属性对应在.bp文件中怎么定义,如下图(以.mk中LOCAL_PRIVATE_PLATFORM_APIS属性为例子)

4.格式规范

  • 4个空格缩进。
  • 多元素列表的每个元素后的换行符。
  • 在lists和maps的结尾处始终包含一个逗号。

bpfmt工具:也可以使用bpfmt工具来规范.bp文件的格式。例如:要格式化当前目录中所有Android.bp文件

可以输入

bpfmt -w . (.前边有空格!)

5.条件编译如何添加?-> .go文件

由于Android.bp文件是 纯 配 置 文 件,条件编译控制则依赖.go文件

下面以一例简单的需求,来举例.go文件的编写,及Android.bp文件如何与其建立关系,从而实现条件编译。

需求:根据TARGET_PRODUCT来进行条件编译,如果TARGET_PRODUCT=test那么引入相关宏,否则打印调试信息。

.go文件如下:

go 复制代码
//包名自拟,建议和文件名相同
package testparser

import (
        //引入编译依赖
        "android/soong/android"
        "android/soong/cc"
        //引入调试信息
        "fmt"
)

func init() {
    //输出调试信息
	  fmt.Println("test init ->>>>")
	  //注册模块
    android.RegisterModuleType("linker_test", testDefaultsFactory)
}

func testDefaultsFactory() (android.Module) {
	  //获取模块对象
    fmt.Println("test testDefaultsFactory->>>>")
    module := cc.DefaultsFactory()
    android.AddLoadHook(module, testAndroidDefaults)
    return module
}

func testAndroidDefaults(ctx android.LoadHookContext) {
   fmt.Println("test testAndroidDefaults->>>>")
   type props struct {
        Cflags []string
    }
    p := &props{}
	  //获取差分后的属性
    p.Cflags = globalDefaults(ctx)
    ctx.AppendProperties(p)
}

func globalDefaults(ctx android.BaseContext) ([]string) {
    //声明了一个切片(数组)
    var cppflags []string
	  //条件逻辑在这里
    fmt.Println("test globalDefaults ->>>>")
    if ctx.AConfig().Getenv("TARGET_PRODUCT") == "test" {
        //将属性加入cppflags中
        cppflags = append(cppflags,"相关宏")
    } else {
        fmt.Println("如果项目的target不为test则输出日志")
    }
    //最终cppflags会被 p.Cflags引用,通过ctx.AppendProperties(p)加入到编译环境中
    return cppflags
}

Android.bp文件进行引用:

arduino 复制代码
//模块类型选择bootstrap_go_package,用于编译Go文件资源
bootstrap_go_package {
    name: "soong_testparser_defaults",
    //指定引用路径
    pkgPath:"vendor/fulscience/packages/services/CarStateService/service",
    // 添加你对应的Go 文件资源
    srcs: [
        "testparser.go",
    ],
    //添加编译依赖
    deps:[
        "soong-android",
        "soong-cc",
        "soong",
        "soong-genrule",
        "blueprint",
        "blueprint-pathtools",
    ],
    pluginFor:["soong_build"],
}


//自定义了模块类型,该模块类型会被go文件中的RegisterModuleType注册,从而建立连接关系
linker_test {
    //模块名称
    name :"testparser_defaults",
}


android_app {

    name: "CarStateManagerService",

    srcs: [
        "java/**/*.java"
    ],

    resource_dirs: [
        "res"
    ],

    
    platform_apis:true,

    certificate: "platform",

    privileged:true,
    
    optimize: {
        enabled: false,
    },

    libs: [
        "android.car",
        "dsv-platformadapter",
    ],

    static_libs: [
        "android.hardware.automotive.vehicle-V2.0-java",
        "com.desaysv.vehiclelan.proxy-V1.0-java",
        "android.hardware.dsp-V1.0-java",
        "vehicle-hal-support-lib",
        "androidx.annotation_annotation",
        "android-support-constraint-layout-solver",
        "jsr305",
        "android-support-constraint-layout",
    ],

    //引入自定义模块的名称
    defaults :[
       "testparser_defaults",
    ]

}

到此为止Android.bp文件就已经成功的引用了.go文件。

ps:仅供参考,一切以实际情况为准~

相关推荐
watl022 分钟前
【Android】unzip aar删除冲突classes再zip
android·linux·运维
键盘上的蚂蚁-25 分钟前
PHP爬虫类的并发与多线程处理技巧
android
喜欢猪猪1 小时前
Java技术专家视角解读:SQL优化与批处理在大数据处理中的应用及原理
android·python·adb
JasonYin~3 小时前
HarmonyOS NEXT 实战之元服务:静态案例效果---手机查看电量
android·华为·harmonyos
zhangphil3 小时前
Android adb查看某个进程的总线程数
android·adb
抛空3 小时前
Android14 - SystemServer进程的启动与工作流程分析
android
Gerry_Liang5 小时前
记一次 Android 高内存排查
android·性能优化·内存泄露·mat
天天打码7 小时前
ThinkPHP项目如何关闭runtime下Log日志文件记录
android·java·javascript
工业互联网专业8 小时前
Python毕业设计选题:基于python的酒店推荐系统_django+hadoop
hadoop·python·django·vue·毕业设计·源码·课程设计
爱数学的程序猿9 小时前
Python入门:6.深入解析Python中的序列
android·服务器·python