一般核心映像檔 (GKI) 與上游 Linux 核心緊密整合,以減少核心分段的情況。不過,基於某些正當理由,部分修補程式無法接受上游,而且必須遵循產品時間表,因此部分修補程式會在建構 GKI 的 Android 通用核心 (ACK) 來源中維護。
開發人員必須以 Linux Kernel Mailing List (LKML) 做為首選,將程式碼變更提交至上游,並且只有在有充分理由認為上游無法運作時,才將程式碼變更提交至 ACK android-mainline
分支。有效原因和處理方式示例如下。
修補程式已提交至 LKML,但在產品發布時未及時接受。如要處理這個修補程式:
- 提供證明,證明您已將修補程式提交至 LKML,並收到修補程式的意見回饋,或是預估提交至上游的時間。
- 決定在 ACK 中發布修補程的行動方針,並讓修補程在上游獲得核准,然後在最終上游版本合併至 ACK 時,將其從 ACK 中移除。
修補程式為供應商模組定義了
EXPORT_SYMBOLS_GPL()
,但無法提交上游,因為所有樹狀模組內沒有使用該符號的模組。如要處理這個修補程式,請詳細說明模組無法提交上游的原因,以及提出這項要求前考慮的替代方案。這個修補程式不夠通用,無法用於上游,而且在產品發布前也沒有時間進行重構。如要處理這個修補程式,請提供預估時間,說明何時會將重構的修補程式提交至上游 (如果沒有計畫將重構的修補程式提交至上游供審查,則 ACK 不會接受修補程式)。
修補程式無法接受上游,因為... <插入原因>。如要處理這個修補程式,請與 Android 核心團隊聯絡,並與我們合作,選擇重構修補程式的選項,以便提交供上游審查及接受。
還有許多其他可能的理由。提交錯誤或修補程式時,請附上有效的理由,並預期會進行一些重複作業和討論。我們瞭解 ACK 有某些修補程式,特別是在 GKI 的早期階段,而所有人都在學習如何上游,但是無法放鬆產品排程。
修補需求
無論是提交至上游還是 ACK,修補程式都必須符合 Linux 來源樹狀結構中所述的 Linux kernel 程式碼標準。scripts/checkpatch.pl
指令碼作為 Gerrit 預先提交測試的一部分執行,因此請事先執行,以確保可通過測試。如要執行 checkpatch 指令碼,並使用與提交前測試相同的設定,請使用 //build/kernel/static_analysis:checkpatch_presubmit
。詳情請參閱 build/kernel/kleaf/docs/checkpatch.md。
ACK 修補程式
提交至 ACK 的修補程式必須符合 Linux 核心程式碼設計標準和貢獻指南。您必須在修訂版本訊息中加入 Change-Id
標記;如果您將修補程式提交至多個分支 (例如 android-mainline
和 android12-5.4
),則必須為所有修補程式例項使用相同的 Change-Id
。
請先將修補程式提交至 LKML,以便進行上游審查。如果修補程式是:
- 已接受上游,會自動合併至
android-mainline
。 - 上游不接受,請將其提交至
android-mainline
,並附上上游提交內容的參照資料,或說明為何未提交至 LKML。
在上游或 android-mainline
中接受修補程式後,便可將其移植至適當的 LTS 型 ACK (例如,android12-5.4
和 android11-5.4
則用於修正 Android 特定程式碼的修補程式)。提交至 android-mainline
可使用新的上游候選版本進行測試,並保證修補程式會納入下一個以 LTS 為基礎的 ACK。例外狀況包括上游修補程式已回移至 android12-5.4
的情況 (因為修補程式可能已在 android-mainline
中)。
上游修補程式
如貢獻指南所述,專為 ACK 核心設計的上游修補程式可分為以下幾類 (依接受機率排序)。
UPSTREAM:
- 如果有合理的用途,從「android-mainline」中精選的修補程式很可能會納入 ACK。BACKPORT:
- 如果有合理的用途,來自上游的修補程式即使無法精準挑選,且需要修改,也可能會獲得核准。FROMGIT:
- 如果有即將到來的截止日期,我們可能會接受從維護者分支中挑選出來的修補程式,以便提交至 Linux 主線。內容和時間表都必須符合規定。FROMLIST:
- 已提交至 LKML 但尚未獲準加入維護器分支的修補程式,可能還不太可能被接受,除非理由足夠充分,是能接受修補程式是否位於上游 Linux (我們假設並不適用)。必須與FROMLIST
修補程式相關聯的問題,才能與 Android 核心團隊進行討論。
Android 專屬修補程式
如果您無法將必要的變更送入上游,可以嘗試將樹狀結構外修補程式直接提交 ACK。如要提交樹狀結構外修補程式,您必須在 IT 中建立問題,並在其中引用修補程式,以及為何無法將修補程式提交至上游的理由 (請參閱上一個清單中的範例)。不過在某些情況下,也無法在上游提交代碼。這些情況的處理方式如下,且必須遵循 Android 專屬修補程式的貢獻規範,並在主旨中加上 ANDROID:
前置字元。
gki_defconfig 的變更
除非 CONFIG
是特定架構,否則 gki_defconfig
的所有 CONFIG
變更都必須套用至 arm64 和 x86 版本。如需要求變更 CONFIG
設定,請在 IT 中建立一個問題討論變更。任何 CONFIG
變更,如果會影響凍結後的核心模組介面 (KMI),都會遭到拒絕。如果合作夥伴要求單一設定相互衝突的設定,我們會透過相關錯誤討論來解決衝突。
上游不存在的程式碼
您無法將已針對 Android 進行修改的程式碼傳送至上游。舉例來說,即使繫結器驅動程式是在上游維護,但繫結器驅動程式的優先順序繼承功能修改內容仍無法傳送至上游,因為這些功能是 Android 專屬。明確地在錯誤中清楚說明,並修補無法上游傳送程式碼的原因。盡可能將修補程式分割成可提交至上游的部分,以及無法提交至上游的 Android 專屬部分,以便盡量減少 ACK 中維護的樹外程式碼數量。
這個類別的其他變更包括 KMI 表示檔、KMI 符號清單、gki_defconfig
、建構指令碼或設定,或是其他不在上游的程式碼。
樹狀結構外模組
上游 Linux 積極不鼓勵支援建構樹狀結構外模組。這是合理的做法,因為 Linux 維護人員不會保證核心內的來源或二進位相容性,也不想支援不在樹狀結構中的程式碼。不過,GKI 會為供應商模組提供 ABI 保證,確保 KMI 介面在核心的支援生命週期內保持穩定。因此,我們有一系列變更可支援供應商模組,這些變更可接受 ACK,但不接受上游。
舉例來說,假設有個修補程式會在來源樹狀結構中新增使用匯出模組的 EXPORT_SYMBOL_GPL()
巨集。雖然您必須嘗試要求上游 EXPORT_SYMBOL_GPL()
,並提供使用新匯出的符號的模組,但如果有充分理由說明為何不將模組提交至上游,您可以改為將修補程式提交至 ACK。您必須加入原因,說明模組無法在問題中向上游的原因。(請勿要求非 GPL 變體 EXPORT_SYMBOL()
)。
隱藏設定
樹狀結構中的部分模組會自動選取無法在 gki_defconfig
中指定的隱藏設定。舉例來說,如果您設定 CONFIG_SND_SOC_SOF=y
,系統會自動選取 CONFIG_SND_SOC_TOPOLOGY
。為了支援樹狀結構外模組建構作業,GKI 包含啟用隱藏設定的機制。
如要啟用隱藏的設定,請在 init/Kconfig.gki
中新增 select
陳述式,讓系統根據 gki_defconfig
中啟用的 CONFIG_GKI_HACKS_TO_FIX
核心設定,自動選取該設定。請僅針對隱藏的設定使用此機制;如果設定未隱藏,則必須在 gki_defconfig
中明確指定,或設為依附元件。
可載入的調節器
如果是支援可載入的調節器的核心架構 (例如 cpufreq
),您可以覆寫預設調節器 (例如 cpufreq
的 schedutil
調節器)。如果架構 (例如熱架構) 不支援可載入管理器或驅動程式,但仍需要特定廠商的實作,請在 IT 建立問題,並洽詢 Android 核心團隊。
我們會與您和上游維護人員合作,新增必要的支援。
供應商掛鉤
在先前的版本中,您可以直接將供應商專屬修改內容新增至核心核心。但在 GKI 2.0 中無法實現這項功能,因為產品專屬程式碼必須在模組中實作,且無法在核心核心或 ACK 中接受。為在對核心核心程式碼影響降到最低的情況下,啟用合作夥伴所需的加值功能,GKI 會接受供應商鉤子,讓您可從核心核心程式碼叫用模組。此外,您也可以在主要資料結構中填入供應商資料欄位,用於儲存供應商專屬資料,以便實作這些功能。
供應商掛鉤有兩種變化版本 (正常和受限),這些版本是根據供應商模組可附加的追蹤點 (而非追蹤事件) 而定。舉例來說,供應商可以選擇在 do_exit()
中新增鉤子,讓供應商模組可附加至該鉤子進行處理,而非新增新的 sched_exit()
函式來執行工作結束時的計算。以下是實作範例,其中包含下列供應商掛鉤。
- 一般供應商鉤子會使用
DECLARE_HOOK()
建立名稱為trace_name
的追蹤點函式,其中name
是追蹤的專屬 ID。按照慣例,一般供應商鉤子名稱會以android_vh
開頭,因此sched_exit()
鉤子的名稱會是android_vh_sched_exit
。 - 在某些情況下,例如排程器掛鉤,就需要使用受限制的供應商掛鉤,因為在這些情況下,即使 CPU 處於離線狀態或需要非原子化內容,也必須呼叫已附加的函式。受限制的供應商掛鉤無法解除連結,因此連結至受限制掛鉤的模組永遠無法卸載。受限制的供應商鉤子名稱開頭為
android_rvh
。
如要新增廠商掛鉤,請在 IT 中回報錯誤並提交修補程式 (如同所有 Android 專用修補程式,問題必須存在,且必須提供原因)。供應商鉤子的支援功能僅在 ACK 中提供,因此請勿將這些修補程式傳送至上游 Linux。
在結構中新增供應商欄位
您可以使用 ANDROID_VENDOR_DATA()
巨集新增 android_vendor_data
欄位,將供應商資料與主要資料結構建立關聯。舉例來說,如要支援附加價值功能,請在結構體中附加欄位,如以下程式碼範例所示。
為避免供應商所需的欄位與原始設備製造商 (OEM) 所需的欄位之間發生衝突,OEM 不得使用以 ANDROID_VENDOR_DATA()
巨集宣告的欄位。相反地,原始設備製造商必須使用 ANDROID_OEM_DATA()
來宣告 android_oem_data
欄位。
#include <linux/android_vendor.h>
...
struct important_kernel_data {
[all the standard fields];
/* Create vendor data for use by hook implementations. The
* size of vendor data is based on vendor input. Vendor data
* can be defined as single u64 fields like the following that
* declares a single u64 field named "android_vendor_data1" :
*/
ANDROID_VENDOR_DATA(1);
/*
* ...or an array can be declared. The following is equivalent to
* u64 android_vendor_data2[20]:
*/
ANDROID_VENDOR_DATA_ARRAY(2, 20);
/*
* SoC vendors must not use fields declared for OEMs and
* OEMs must not use fields declared for SoC vendors.
*/
ANDROID_OEM_DATA(1);
/* no further fields */
}
定義供應商掛鉤
使用 DECLARE_HOOK()
或 DECLARE_RESTRICTED_HOOK()
宣告供應商掛鉤,然後將其加入程式碼中做為追蹤點,即可將供應商掛鉤新增至核心程式碼中做為追蹤點。例如,如要將 trace_android_vh_sched_exit()
新增至現有的 do_exit()
核心函式:
#include <trace/hooks/exit.h>
void do_exit(long code)
{
struct task_struct *tsk = current;
...
trace_android_vh_sched_exit(tsk);
...
}
trace_android_vh_sched_exit()
函式一開始只會檢查是否有附加項目。不過,如果供應商模組使用 register_trace_android_vh_sched_exit()
註冊處理常式,系統會呼叫已註冊的函式。處理程序必須瞭解與已保留鎖定、RCS 狀態和其他因素相關的內容。鉤子必須在 include/trace/hooks
目錄的標頭檔案中定義。
例如,下列程式碼會在 include/trace/hooks/exit.h
檔案中提供 trace_android_vh_sched_exit()
的可能宣告。
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM sched
#define TRACE_INCLUDE_PATH trace/hooks
#if !defined(_TRACE_HOOK_SCHED_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HOOK_SCHED_H
#include <trace/hooks/vendor_hooks.h>
/*
* Following tracepoints are not exported in tracefs and provide a
* mechanism for vendor modules to hook and extend functionality
*/
struct task_struct;
DECLARE_HOOK(android_vh_sched_exit,
TP_PROTO(struct task_struct *p),
TP_ARGS(p));
#endif /* _TRACE_HOOK_SCHED_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
如要將供應商鉤子所需的介面例項化,請將含有鉤子宣告的標頭檔案新增至 drivers/android/vendor_hooks.c
,然後匯出符號。例如,下列程式碼會完成 android_vh_sched_exit()
鉤子的宣告。
#ifndef __GENKSYMS__
/* struct task_struct */
#include <linux/sched.h>
#endif
#define CREATE_TRACE_POINTS
#include <trace/hooks/vendor_hooks.h>
#include <trace/hooks/exit.h>
/*
* Export tracepoints that act as a bare tracehook (i.e. have no trace
* event associated with them) to allow external modules to probe
* them.
*/
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sched_exit);
注意:為了確保 ABI 穩定性,您必須完整定義在掛鉤宣告中使用的資料結構。否則,要解除參照不透明指標或在大小環境中使用結構是不安全的做法。提供這類資料結構完整定義的 include 應放在 drivers/android/vendor_hooks.c
的 #ifndef __GENKSYMS__
部分。include/trace/hooks
中的標頭檔案不應包含含有類型定義的核心標頭檔案,以免發生會破壞 KMI 的 CRC 變更。請改為宣告類型。
附加至廠商掛鉤
如要使用供應商掛鉤,供應商模組需要為掛鉤註冊處理常式 (通常是在模組初始化期間完成)。舉例來說,以下程式碼顯示 trace_android_vh_sched_exit()
的模組 foo.ko
處理常式。
#include <trace/hooks/sched.h>
...
static void foo_sched_exit_handler(void *data, struct task_struct *p)
{
foo_do_exit_accounting(p);
}
...
static int foo_probe(..)
{
...
rc = register_trace_android_vh_sched_exit(foo_sched_exit_handler, NULL);
...
}
從標頭檔案中使用廠商掛鉤
如要使用標頭檔案中的供應商掛鉤,您可能需要更新供應商掛鉤標頭檔案,以便取消定義 TRACE_INCLUDE_PATH
,避免發生指出找不到追蹤點標頭檔案的建構錯誤。例如:
In file included from .../common/init/main.c:111:
In file included from .../common/include/trace/events/initcall.h:74:
.../common/include/trace/define_trace.h:95:10: fatal error: 'trace/hooks/initcall.h' file not found
95 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../common/include/trace/define_trace.h:90:32: note: expanded from macro 'TRACE_INCLUDE'
90 | # define TRACE_INCLUDE(system) __TRACE_INCLUDE(system)
| ^~~~~~~~~~~~~~~~~~~~~~~
.../common/include/trace/define_trace.h:87:34: note: expanded from macro '__TRACE_INCLUDE'
87 | # define __TRACE_INCLUDE(system) __stringify(TRACE_INCLUDE_PATH/system.h)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../common/include/linux/stringify.h:10:27: note: expanded from macro '__stringify'
10 | #define __stringify(x...) __stringify_1(x)
| ^~~~~~~~~~~~~~~~
.../common/include/linux/stringify.h:9:29: note: expanded from macro '__stringify_1'
9 | #define __stringify_1(x...) #x
| ^~
<scratch space>:14:1: note: expanded from here
14 | "trace/hooks/initcall.h"
| ^~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
如要修正這類建構錯誤,請將同等修正項目套用至您要加入的供應商掛鉤標頭檔案。詳情請參閱 https://r.android.com/3066703。
diff --git a/include/trace/hooks/mm.h b/include/trace/hooks/mm.h
index bc6de7e53d66..039926f7701d 100644
--- a/include/trace/hooks/mm.h
+++ b/include/trace/hooks/mm.h
@@ -2,7 +2,10 @@
#undef TRACE_SYSTEM
#define TRACE_SYSTEM mm
+#ifdef CREATE_TRACE_POINTS
#define TRACE_INCLUDE_PATH trace/hooks
+#define UNDEF_TRACE_INCLUDE_PATH
+#endif
定義 UNDEF_TRACE_INCLUDE_PATH
會告知 include/trace/define_trace.h
在建立追蹤點後取消定義 TRACE_INCLUDE_PATH
。
核心核心功能
如果上述技術都無法讓您透過模組實作功能,則必須將該功能設為 Android 專屬的核心核心修改項目。在問題追蹤器 (IT) 中建立問題,即可開始對話。
使用者應用程式設計介面 (UAPI)
- UAPI 標頭檔案。除非變更為 Android 專屬介面,否則必須在上游變更 UAPI 標頭檔案。使用廠商專屬的標頭檔案,定義廠商模組和廠商使用者空間程式碼之間的介面。
- sysfs 節點。請勿將新的 sysfs 節點新增至 GKI 核心 (此類新增功能僅在供應商模組中有效)。由 SoC 和各裝置通用程式庫使用的 sysfs 節點和構成 Android 架構的 Java 程式碼只能透過相容方式變更,且若非 Android 專屬 sysf 節點,則必須變更上游。您「可以」建立供應商專屬的 sysfs 節點,供供應商使用者空間使用。根據預設,使用者空間會透過 SELinux 拒絕存取 sysfs 節點。供應商必須自行新增適當的 SELinux 標籤,以便授權供應商軟體存取。
- DebugFS 節點。供應商模組可在
debugfs
中定義節點,但僅限於偵錯 (因為debugfs
不會在裝置的正常運作期間掛載)。