赞
踩
目录
Android 8.0- —— Android.mk实现条件编译
Android 9.0+ —— Android.bp实现条件编译
扩展:Android 9.0+ —— Android.bp实现自定义条件编译
本人正在学习中。此篇文章如有不正之处,欢迎指正讨论!
最近在协助完成模块优化的时候,有个需求如下:
依赖结构:A B C……等多个平台共用一个自定义系统模块
随后优化此模块中内容,改动需要跟随A平台进行系统迭代测试,但希望BC等其他平台不受此优化内容影响
基于上面的需求,整理了一下条件:
1.平台系统版本包括Android 8.0、9.0。
2.自定义系统模块功能已经在源码打点完毕,尽可能少地改动系统源码(否则要多个平台都修改)。
3.不同平台可快速进行优化方案和非优化方案的切换,便于在不同阶段的各个平台能不受影响快速切换方案。
因此想出了以下做法:
1.保证优化后的类名和包名一致,可以放到包名以上的其他目录中。 —— 确保系统源码中的打点无需改动。
如自定义系统模块中优化前的类和包名为:(module_path)/hotkey/service/core/java/com/android/server/policy/HotKey.java
自定义系统模块中优化后的类和包名为:(module_path)/audio/service/core/java/com/android/server/policy/HotKey.java
如此一来,HotKey的类名和包名与原来一致,系统中引用到HotKey的地方依旧只需要import com.android.server.policy.HotKey; 无需变动。
2.在Android.mk和Android.bp中完成条件编译。 —— 兼容不同版本系统平台,根据条件快速切换优化方案。
下面就想方法解决这个问题吧!
先给出一份8.0系统framework下的mk文件(framework/base/service/core):
- LOCAL_PATH := $(call my-dir)
-
- include $(CLEAR_VARS)
-
- LOCAL_MODULE := services.core
-
- ……
-
- LOCAL_SRC_FILES += \
- $(call all-java-files-under,java) \
- java/com/android/server/EventLogTags.logtags \
- java/com/android/server/am/EventLogTags.logtags \
- ../../../../system/netd/server/binder/android/net/INetd.aidl \
- ../../../../system/netd/server/binder/android/net/metrics/INetdEventListener.aidl \
- ../../../native/cmds/installd/binder/android/os/IInstalld.aidl \
- # patch start
- $(custom_module_files) \
- # patch end
- ……
-
- include $(BUILD_STATIC_JAVA_LIBRARY)

在源码中mk中加入 $(module_files),在自定义系统模块的mk中完成 module_files 的定义,将改动尽量放到系统自定义模块下。
Android.mk不必多说,通过在mk里设立变量,即可使用ifeq、ifdef等判断值,进行条件编译。如定义:
OPTIMIZE := true
随后修改mk参与编译的文件,如下:
- custom_module_files := \
-
- ……
-
- # patch start
- ifeq ($(OPTIMIZE),true)
- custom_module_files += \
- (custom_module_path)/audio/services/core/java/com/android/server/policy/HotKey.java
- else
- custom_module_files += \
- (custom_module_path)/hotkey/services/core/java/com/android/server/policy/HotKey.java
- endif
- # patch end
其中audio目录下的HotKey.java是优化后待测试的代码,而policy目录下的HotKey则是未优化的稳定代码。通过定义mk中的变量,就可以完成mk文件的条件编译了。
Android在7.0引入 ninja 编译系统,8.0引入Android.bp替代Android.mk,9.0强制使用Android.bp作为编译配置。
解决完8.0的编译问题,准备着手9.0的编译问题了。出于一样的想法,在bp里完成条件编译,然后和mk处理方式一样,通过开关决定参与编译的文件,即可解决此问题。但是Android.bp实际上是一个纯粹的json配置文件,没有条件、分支等流程结构,因此即便使用自带的androidmk工具想要将Android.mk快速转成Android.bp,也会发现流程语句并不起效果。为了解决此问题,google将条件编译进行分家,Android.bp负责纯粹配置,引入Go文件负责进行流程结构判断。
这样一来思路就清楚了:
下面用代码实现:
1.自定义模块custommodule下Android.bp定义两个方案(优化和未优化),如:
- # patch start
- filegroup {
- name: "custom_optimize",
- srcs: [
- "audio/services/core/java/com/android/server/policy/HotKey.java",
- ],
- }
-
- filegroup {
- name: "custom_origin",
- srcs: [
- "hotkey/services/core/java/com/android/server/policy/HotKey.java",
- ],
- }
- # patch end
2.添加用于自定义系统模块条件编译的Go文件。如在自定义模块名字为customsystem,则在customsystem目录下创建customsystem.go,内容如下:
- package customsystem
-
- import (
- "android/soong/android"
- "android/soong/java"
- "fmt"
- )
-
- //注册module模板,存放默认属性
- func init() {
- android.RegisterModuleType("custom_optimize_default", custom_optimize_go)
- }
-
- func custom_optimize_go() android.Module {
- module := java.DefaultsFactory()
- android.AddLoadHook(module, custom_optimize_append_properties)
- return module
- }
-
- func custom_optimize_append_properties(ctx android.LoadHookContext) {
- type props struct {
- Srcs []string
- }
- p := &props{}
- sdkVersion := ctx.AConfig().PlatformSdkVersionInt()
- fmt.Println("sdkVersion:", sdkVersion)
- if sdkVersion >=28 { //after P
- p.Srcs = append(p.Srcs, ":custom_optimize")
- } else {
- p.Srcs = append(p.Srcs, ":custom_origin")
- }
- ctx.AppendProperties(p)
- }

3.framework下Android.bp加入自定义模块声明(framework/base/service/core/Android.bp):
- # patch start
- custom_optimize_default{
- name: "custom_optimize_default",
- }
- # patch end
-
- java_library_static {
- name: "services.core.unboosted",
-
- # patch start
- defaults: [
- "custom_optimize_default",
- ],
- # patch end
-
- aidl: {
- ……
- },
- srcs: [
- ……
- ],
-
- ……
-
- }

这样子就完成了一次条件编译,此处使用的条件是Android版本。如果需要其他变量作为判断条件,可以查看out/soong/soong.variables文件,里面是系统中提供的所有环境变量,如当前系统Android版本、是否调试版本、架构、路径等等:
- {
- "Platform_version_name": "9",
- "Platform_sdk_version": 28,
- "Platform_sdk_codename": "REL",
- "Platform_sdk_final": true,
- "Allow_missing_dependencies": false,
- "Debuggable": false,
- "Eng": false,
- "DeviceArch": "arm",
- "DeviceArchVariant": "armv7-a-neon",
- "DeviceCpuVariant": "cortex-a9",
- "DeviceAbi": ["armeabi-v7a","armeabi"],
- "DeviceSecondaryArchVariant": "",
- "DeviceSecondaryCpuVariant": "",
- "HostArch": "x86_64",
- "HostSecondaryArch": "x86",
- "HostStaticBinaries": false,
- "CrossHost": "windows",
- "CrossHostArch": "x86",
- "CrossHostSecondaryArch": "x86_64",
- ……
- }

上一部分做了一个用系统内环境变量条件编译的实例,不过等等,好像和一开头的需求不是很符合?
想一想,仅用sdkVersion进行判断,那么对于所有Android9.0的平台来说只能做统一处理,连区分平台都做不到,更何况区分同code的不同平台了。
那么扩展场景来了:如何打入一个系统环境变量,并通过mk文件赋值,让我们的条件编译真正按照平台生效呢?
翻了资料,全程耗时一周,打通了一条路,原理剖析后续补上,直接上code。(具体可以戳传送门瞅瞅这位大大写出来的通路图 --> https://blog.csdn.net/u012188065/article/details/89352166)
1.在平台mk中,定义mk变量。(此处平台mk选择的是BoardConfig.mk, 路劲device/(厂商)/(平台)/BoardConfig.mk
- # patch start
- OPTIMIZE := true
- # patch end
2.新增bool类型go变量。路径build/soong/android/variable.go
- type productVariables struct {
-
- ……
-
- // patch start
- Optimize *bool `json:",omitempty"`
- // patch end
- }
3.建立go变量和mk变量的json映射关系,让go变量可以获取到mk中定义的变量值。路径build/make/core/soong_config.mk
- ……
-
- # patch start
- $(call add_json_bool, Optimize, $(filter true, $(OPTIMIZE)))
- # patch end
-
- # 这句等同于:
- # bool Optimize = (OPTIMIZE == true)
-
- ……
4.定义go方法,返回go变量的值。路径:build/soong/android/config.go
- ……
-
- # patch start
- func (c *deviceConfig) Optimize() bool {
- return Bool(c.config.productVariables.Optimize)
- }
- # patch end
-
- ……
完成了以上四步后,mk变量就成功映射到go文件中,并生成系统环境变量。
在编译之后可以查看out/soong/soong.variables文件,确认是否生成环境变量,赋值是否正确。
基于上一部分的成果,我们来修改一下实现,完成我们的需求:
修改customsystem.go,如下:
- ……
-
- func custom_optimize_append_properties(ctx android.LoadHookContext) {
- type props struct {
- Srcs []string
- }
- p := &props{}
-
- // 修改成自定义条件
- optimize := ctx.DeviceConfig().Optimize()
- fmt.Println("mk OPTIMIZE:", optimize)
- if optimize {
- p.Srcs = append(p.Srcs, ":custom_optimize")
- } else {
- p.Srcs = append(p.Srcs, ":custom_origin")
- }
-
- ctx.AppendProperties(p)
- }
-
- ……

修改到这里,就完全结束了。现在只需要编译看看,验证效果。
相关原理剖析会另起一篇,未完待续……
——————————————————————————————————————
参考资料:
① 少侠的崛起 - 产品.mk控制android.bp选择性编译 - https://blog.csdn.net/u012188065/article/details/89352166
② 秋少 - Android系统开发进阶-Android编译系统介绍 - https://qiushao.net/2020/02/06/Android%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91%E8%BF%9B%E9%98%B6/Android%E7%BC%96%E8%AF%91%E7%B3%BB%E7%BB%9F%E4%BB%8B%E7%BB%8D/
(③ 感谢海思的小抄!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。