当前位置:   article > 正文

[实战笔记]系统编译——Android.mk / Android.bp 条件编译实现指南_android mk 条件编译

android mk 条件编译

目录

前言 —— 需求提出

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中完成条件编译。   ——  兼容不同版本系统平台,根据条件快速切换优化方案。

下面就想方法解决这个问题吧!

Android 8.0-  —— Android.mk实现条件编译

先给出一份8.0系统framework下的mk文件(framework/base/service/core):

  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_MODULE := services.core
  4. ……
  5. LOCAL_SRC_FILES += \
  6. $(call all-java-files-under,java) \
  7. java/com/android/server/EventLogTags.logtags \
  8. java/com/android/server/am/EventLogTags.logtags \
  9. ../../../../system/netd/server/binder/android/net/INetd.aidl \
  10. ../../../../system/netd/server/binder/android/net/metrics/INetdEventListener.aidl \
  11. ../../../native/cmds/installd/binder/android/os/IInstalld.aidl \
  12. # patch start
  13. $(custom_module_files) \
  14. # patch end
  15. ……
  16. include $(BUILD_STATIC_JAVA_LIBRARY)

在源码中mk中加入 $(module_files),在自定义系统模块的mk中完成 module_files 的定义,将改动尽量放到系统自定义模块下。

Android.mk不必多说,通过在mk里设立变量,即可使用ifeq、ifdef等判断值,进行条件编译。如定义:

OPTIMIZE := true

 随后修改mk参与编译的文件,如下:

  1. custom_module_files := \
  2. ……
  3. # patch start
  4. ifeq ($(OPTIMIZE),true)
  5. custom_module_files += \
  6. (custom_module_path)/audio/services/core/java/com/android/server/policy/HotKey.java
  7. else
  8. custom_module_files += \
  9. (custom_module_path)/hotkey/services/core/java/com/android/server/policy/HotKey.java
  10. endif
  11. # patch end

其中audio目录下的HotKey.java是优化后待测试的代码,而policy目录下的HotKey则是未优化的稳定代码。通过定义mk中的变量,就可以完成mk文件的条件编译了。

Android 9.0+ —— Android.bp实现条件编译

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定义两个方案(优化和未优化),如:

  1. # patch start
  2. filegroup {
  3. name: "custom_optimize",
  4. srcs: [
  5. "audio/services/core/java/com/android/server/policy/HotKey.java",
  6. ],
  7. }
  8. filegroup {
  9. name: "custom_origin",
  10. srcs: [
  11. "hotkey/services/core/java/com/android/server/policy/HotKey.java",
  12. ],
  13. }
  14. # patch end

2.添加用于自定义系统模块条件编译的Go文件。如在自定义模块名字为customsystem,则在customsystem目录下创建customsystem.go,内容如下:

  1. package customsystem
  2. import (
  3. "android/soong/android"
  4. "android/soong/java"
  5. "fmt"
  6. )
  7. //注册module模板,存放默认属性
  8. func init() {
  9. android.RegisterModuleType("custom_optimize_default", custom_optimize_go)
  10. }
  11. func custom_optimize_go() android.Module {
  12. module := java.DefaultsFactory()
  13. android.AddLoadHook(module, custom_optimize_append_properties)
  14. return module
  15. }
  16. func custom_optimize_append_properties(ctx android.LoadHookContext) {
  17. type props struct {
  18. Srcs []string
  19. }
  20. p := &props{}
  21. sdkVersion := ctx.AConfig().PlatformSdkVersionInt()
  22. fmt.Println("sdkVersion:", sdkVersion)
  23. if sdkVersion >=28 { //after P
  24. p.Srcs = append(p.Srcs, ":custom_optimize")
  25. } else {
  26. p.Srcs = append(p.Srcs, ":custom_origin")
  27. }
  28. ctx.AppendProperties(p)
  29. }

3.framework下Android.bp加入自定义模块声明(framework/base/service/core/Android.bp):

  1. # patch start
  2. custom_optimize_default{
  3. name: "custom_optimize_default",
  4. }
  5. # patch end
  6. java_library_static {
  7. name: "services.core.unboosted",
  8. # patch start
  9. defaults: [
  10. "custom_optimize_default",
  11. ],
  12. # patch end
  13. aidl: {
  14. ……
  15. },
  16. srcs: [
  17. ……
  18. ],
  19. ……
  20. }

 这样子就完成了一次条件编译,此处使用的条件是Android版本。如果需要其他变量作为判断条件,可以查看out/soong/soong.variables文件,里面是系统中提供的所有环境变量,如当前系统Android版本、是否调试版本、架构、路径等等:

  1. {
  2. "Platform_version_name": "9",
  3. "Platform_sdk_version": 28,
  4. "Platform_sdk_codename": "REL",
  5. "Platform_sdk_final": true,
  6. "Allow_missing_dependencies": false,
  7. "Debuggable": false,
  8. "Eng": false,
  9. "DeviceArch": "arm",
  10. "DeviceArchVariant": "armv7-a-neon",
  11. "DeviceCpuVariant": "cortex-a9",
  12. "DeviceAbi": ["armeabi-v7a","armeabi"],
  13. "DeviceSecondaryArchVariant": "",
  14. "DeviceSecondaryCpuVariant": "",
  15. "HostArch": "x86_64",
  16. "HostSecondaryArch": "x86",
  17. "HostStaticBinaries": false,
  18. "CrossHost": "windows",
  19. "CrossHostArch": "x86",
  20. "CrossHostSecondaryArch": "x86_64",
  21. ……
  22. }

扩展:Android 9.0+ —— Android.bp实现自定义条件编译

上一部分做了一个用系统内环境变量条件编译的实例,不过等等,好像和一开头的需求不是很符合?

想一想,仅用sdkVersion进行判断,那么对于所有Android9.0的平台来说只能做统一处理,连区分平台都做不到,更何况区分同code的不同平台了。

那么扩展场景来了:如何打入一个系统环境变量,并通过mk文件赋值,让我们的条件编译真正按照平台生效呢?

翻了资料,全程耗时一周,打通了一条路,原理剖析后续补上,直接上code。(具体可以戳传送门瞅瞅这位大大写出来的通路图 --> https://blog.csdn.net/u012188065/article/details/89352166

1.在平台mk中,定义mk变量。(此处平台mk选择的是BoardConfig.mk, 路劲device/(厂商)/(平台)/BoardConfig.mk

  1. # patch start
  2. OPTIMIZE := true
  3. # patch end

2.新增bool类型go变量。路径build/soong/android/variable.go

  1. type productVariables struct {
  2. ……
  3. // patch start
  4. Optimize *bool `json:",omitempty"`
  5. // patch end
  6. }

3.建立go变量和mk变量的json映射关系,让go变量可以获取到mk中定义的变量值。路径build/make/core/soong_config.mk

  1. ……
  2. # patch start
  3. $(call add_json_bool, Optimize, $(filter true, $(OPTIMIZE)))
  4. # patch end
  5. # 这句等同于:
  6. # bool Optimize = (OPTIMIZE == true)
  7. ……

4.定义go方法,返回go变量的值。路径:build/soong/android/config.go

  1. ……
  2. # patch start
  3. func (c *deviceConfig) Optimize() bool {
  4. return Bool(c.config.productVariables.Optimize)
  5. }
  6. # patch end
  7. ……

完成了以上四步后,mk变量就成功映射到go文件中,并生成系统环境变量。

在编译之后可以查看out/soong/soong.variables文件,确认是否生成环境变量,赋值是否正确。

基于上一部分的成果,我们来修改一下实现,完成我们的需求:

修改customsystem.go,如下:

  1. ……
  2. func custom_optimize_append_properties(ctx android.LoadHookContext) {
  3. type props struct {
  4. Srcs []string
  5. }
  6. p := &props{}
  7. // 修改成自定义条件
  8. optimize := ctx.DeviceConfig().Optimize()
  9. fmt.Println("mk OPTIMIZE:", optimize)
  10. if optimize {
  11. p.Srcs = append(p.Srcs, ":custom_optimize")
  12. } else {
  13. p.Srcs = append(p.Srcs, ":custom_origin")
  14. }
  15. ctx.AppendProperties(p)
  16. }
  17. ……

修改到这里,就完全结束了。现在只需要编译看看,验证效果。

相关原理剖析会另起一篇,未完待续……

——————————————————————————————————————

参考资料:

① 少侠的崛起 - 产品.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/

(③ 感谢海思的小抄!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/255759
推荐阅读
相关标签
  

闽ICP备14008679号