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:仅供参考,一切以实际情况为准~

相关推荐
阿巴斯甜15 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker15 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952716 小时前
Andorid Google 登录接入文档
android
黄林晴18 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android