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

目录

前言 —— 需求提出

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):

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

# 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",
    ……
}

扩展: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

# 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/

(③ 感谢海思的小抄!

  • 26
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值