為 GKI 開發核心程式碼

通用核心映像檔 (GKI) 會與上游 Linux 核心緊密配合,藉此減少核心分散現象。不過,有些修補程式無法接受上游更新,而且必須遵守產品時間表,因此有些修補程式會在 Android 通用核心 (ACK) 來源中維護,而 GKI 就是從中建構。

開發人員必須使用 Linux 核心郵件在上游提交程式碼變更 列出 (LKML) 做為第一個選項,然後將程式碼變更提交至 ACK 只有在有充分原因導致上游沒有使用時,才會出現 android-mainline 分支 以及有效原因和處理方式的範例如下所示。

  • 修補程式已提交至 LKML,但未在產品發布時接受。如要處理這個修補程式:

    • 提供證據證明修補程式已提交至 LKML 和註解 或修補程式預估時間 提交了上游。
    • 決定採取實際行動,將修補程式送到 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-mainlineandroid12-5.4),則必須為所有修補程式例項使用相同的 Change-Id

請先將修補程式提交至 LKML,以便進行上游審查。如果修補程式:

  • 已接受上游,會自動合併至 android-mainline
  • 不接受上游,請以下列指示提交給「android-mainline」: 提及上游提交內容,或是無法說明原因 已提交至 LKML

在上游或 android-mainline 中接受修補程式後,即可 移植到適當的 LTS 型 ACK (例如 android12-5.4android11-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 中建立問題,以便討論變更。任何在凍結後影響核心模組介面 (KMI) 的 CONFIG 變更都會遭到拒絕。如果合作夥伴針對單一設定要求互相衝突的設定,我們會討論相關錯誤,解決衝突問題。

程式碼不存在於上游

您無法將已針對 Android 進行修改的程式碼傳送至上游。舉例來說,即使繫結器驅動程式是在上游維護,但繫結器驅動程式的優先順序繼承功能修改內容仍無法傳送至上游,因為這些功能是 Android 專屬。明確表現出錯誤,並修補 無法將代碼傳送到上游可以的話,請將修補程式分割成 無法提交上游和 Android 專屬作品 來盡量減少在 ACK 中維護的樹狀結構外程式碼數量。

這個類別的其他變更包括 KMI 表示檔、KMI 符號清單、gki_defconfig、建構指令碼或設定,或是其他不在上游的程式碼。

樹狀結構外模組

上游 Linux 主動禁止建構外流模組。 由於 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),您必須 可覆寫預設主機 (例如 cpufreqschedutil 主機)。適用對象 不支援可載入管理器的架構 (例如熱架構) 或驅動程式,但仍須導入特定供應商,請建立問題 ,並洽詢 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>

如要將供應商掛鉤所需的介面例項化,請新增標頭檔案 將 hook 宣告傳遞至 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 中的檔案不應含有 類型定義,以避免因 CRC 變更而破壞 KMI。改為轉寄 宣告類型

附加至供應商鉤子

如要使用廠商掛鉤,供應商模組需要為掛鉤註冊處理常式 (通常在模組初始化期間執行)。例如,下列程式碼 會顯示 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 節點請勿在 GKI 核心中新增 sysfs 節點 (這類新增項目僅適用於供應商模組)。由 SoC 和裝置無關的程式庫使用的 sysfs 節點,以及組成 Android 架構的 Java 程式碼,只能以相容的方式變更,且如果不是 Android 專屬的 sysfs 節點,則必須在上游變更。您可以建立 供應商專屬的 sysfs 節點,供供應商使用者空間使用。根據預設,使用者空間會透過 SELinux 拒絕存取 sysfs 節點。供應商必須自行新增適當的 SELinux 標籤,以便授權供應商軟體存取。
  • DebugFS 節點。供應商模組可定義 debugfs 中的節點: 僅供偵錯 (因為 debugfs 並未在 裝置)。