[實戰筆記]系統編譯——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/

(③ 感謝海思的小抄!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章