汎用カーネル イメージ (GKI) は、アップストリームの Linux カーネルと緊密に連携することで、カーネルの断片化を軽減します。ただし、一部のパッチがアップストリームで受け入れられない正当な理由があり、満たさなければならない製品スケジュールがあるため、一部のパッチは GKI の構築元となる Android Common Kernel (ACK) ソースで維持されます。
開発者は、Linux カーネル メーリング リスト (LKML) を第一の選択肢として使用して、コード変更をアップストリームに送信する必要があります。また、アップストリームが実行できない強い理由がある場合にのみ、コード変更を ACK android-mainline
ブランチに送信する必要があります。正当な理由の例とその対処方法は次のとおりです。
パッチは LKML に提出されましたが、製品リリースまでに受け入れられませんでした。このパッチを処理するには:
- パッチが LKML に送信されたという証拠と、パッチに対して受け取ったコメント、またはパッチがアップストリームに送信されるまでの推定時間を提供します。
- パッチを ACK に登録し、アップストリームで承認を得て、最終的なアップストリーム バージョンが ACK にマージされるときに ACK から削除するという一連の行動を決定します。
このパッチはベンダー モジュールの
EXPORT_SYMBOLS_GPL()
を定義していますが、そのシンボルを使用するツリー内モジュールがないため、アップストリームに送信できませんでした。このパッチを処理するには、モジュールをアップストリームに送信できない理由と、このリクエストを行う前に検討した代替案の詳細を提供してください。このパッチはアップストリーム向けに十分汎用的ではないため、製品リリース前にリファクタリングする時間がありません。このパッチを処理するには、リファクタリングされたパッチがアップストリームに送信されるまでの推定時間を提供します (レビューのためにリファクタリングされたパッチをアップストリームに送信する計画がなければ、パッチは ACK で受け入れられません)。
このパッチはアップストリームによって受け入れられません。理由は... <ここに理由を挿入> です。このパッチを処理するには、Android カーネル チームに連絡し、レビューのために提出してアップストリームで受け入れられるように、パッチをリファクタリングするオプションについて協力してください。
正当化できる可能性は他にもたくさんあります。バグやパッチを送信するときは、有効な理由を含めて、反復と議論を期待してください。特に GKI の初期段階では、誰もが上流での作業方法を学習しているものの、そのために製品スケジュールを緩めることができないため、ACK にはいくつかのパッチが含まれることを認識しています。アップストリームの要件は時間の経過とともにさらに厳しくなることが予想されます。
パッチの要件
パッチは、アップストリームに送信されるか ACK に送信されるかに関係なく、 Linux ソース ツリーに記載されている Linux カーネルのコーディング標準に準拠する必要があります。 scripts/checkpatch.pl
スクリプトは、Gerrit の事前送信テストの一部として実行されるため、事前に実行して、合格することを確認してください。 repo
送信テストと同じ構成で checkpatch スクリプトを実行するには、リポジトリのチェックアウトからbuild/static_analysis/checkpatch_presubmit.sh
を使用します。
ACKパッチ
ACK に提出されるパッチは、Linux カーネルのコーディング標準とコントリビューション ガイドラインに準拠する必要があります。コミット メッセージにはChange-Id
タグを含める必要があります。パッチを複数のブランチ (たとえば、 android-mainline
とandroid12-5.4
) に送信する場合は、パッチのすべてのインスタンスに同じChange-Id
を使用する必要があります。
まずアップストリームのレビューのためにパッチを LKML に送信します。パッチが次の場合:
- アップストリームで受け入れられ、自動的に
android-mainline
にマージされます。 - アップストリームで受け入れられませんでした。アップストリームの送信への参照または LKML に送信されなかった理由の説明を添えて、
android-mainline
に送信してください。
パッチがアップストリームまたはandroid-mainline
で受け入れられた後、適切な LTS ベースの ACK (Android 固有のコードを修正するパッチのandroid12-5.4
およびandroid11-5.4
など) にバックポートできます。 android-mainline
に送信すると、新しいアップストリーム リリース候補を使用したテストが可能になり、次の LTS ベースの ACK にパッチが含まれることが保証されます。例外には、アップストリーム パッチがandroid12-5.4
にバックポートされる場合が含まれます (パッチはすでにandroid-mainline
にある可能性が高いため)。
アップストリームパッチ
貢献ガイドラインで指定されているように、ACK カーネル向けのアップストリーム パッチは次のグループに分類されます (受け入れられる可能性の高い順にリストされています)。
-
UPSTREAM:
- 合理的な使用例がある場合、「android-mainline」から厳選されたパッチは ACK に受け入れられる可能性があります。 -
BACKPORT:
- 適切な使用例があれば、アップストリームからのパッチが適切に選択されず、修正が必要な場合も受け入れられる可能性があります。 -
FROMGIT:
- Linux メインラインへの提出に備えてメンテナー ブランチから厳選されたパッチは、期限が迫っている場合には受け入れられる可能性があります。これらは内容とスケジュールの両方で正当化される必要があります。 -
FROMLIST:
- LKML に送信されたものの、まだメンテナ ブランチに受け入れられていないパッチは、上流の Linux に到達するかどうかに関係なく、そのパッチが受け入れられるほど説得力のある正当な理由がない限り、受け入れられる可能性は低いです (私たちはそう想定しています)そうはならないだろう)。 Android カーネル チームとの議論を促進するには、FROMLIST
パッチに関連する問題が必要です。
Android 固有のパッチ
必要な変更をアップストリームに反映できない場合は、ツリー外のパッチを ACK に直接送信してみることができます。ツリー外のパッチを送信するには、そのパッチと、そのパッチを上流に送信できない理由を引用する問題を IT 部門で作成する必要があります (例については、前のリストを参照してください)。ただし、コードを上流に送信できない場合がいくつかあります。これらのケースは次のようにカバーされており、Android 固有のパッチの貢献ガイドラインに従い、件名にANDROID:
プレフィックスを付けてタグ付けする必要があります。
gki_defconfig への変更
CONFIG
アーキテクチャ固有のものでない限り、 gki_defconfig
に対するすべてのCONFIG
変更は arm64 バージョンと x86 バージョンの両方に適用する必要があります。 CONFIG
設定の変更をリクエストするには、IT 内で問題を作成し、変更について話し合ってください。カーネル モジュール インターフェイス (KMI) がフリーズされた後に影響を与えるCONFIG
変更はすべて拒否されます。パートナーが 1 つの構成に対して競合する設定を要求した場合、関連するバグについての議論を通じて競合を解決します。
上流に存在しないコード
すでに 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 はコア カーネル コードからモジュールを呼び出すことができるベンダー フックを受け入れます。さらに、これらの機能を実装するためにベンダー固有のデータを保存するために使用できるベンダー データ フィールドを主要なデータ構造に埋め込むことができます。
ベンダー フックには、ベンダー モジュールが接続できるトレースポイント (トレース イベントではない) に基づく 2 つのバリアント (通常と制限付き) があります。たとえば、タスクの終了時にアカウンティングを行う新しいsched_exit()
関数を追加する代わりに、ベンダーは、ベンダー モジュールが処理のために接続できるフックをdo_exit()
に追加できます。実装例には次のベンダー フックが含まれています。
- 通常のベンダー フックは
DECLARE_HOOK()
を使用して、trace_ name
のトレースポイント関数を作成します。namename
トレースの一意の識別子です。慣例により、通常のベンダー フック名はandroid_vh
で始まるため、sched_exit()
フックの名前はandroid_vh_sched_exit
になります。 - 制限されたベンダー フックは、CPU がオフラインであるか非アトミック コンテキストを必要とする場合でも、添付された関数を呼び出す必要があるスケジューラー フックなどの場合に必要です。制限されたベンダー フックはデタッチできないため、制限されたフックにアタッチされたモジュールはアンロードできません。許可される添付ファイルは 1 つだけであるため、他の添付試行は
-EBUSY
で失敗します。制限されたベンダー フック名はandroid_rvh
で始まります。
ベンダー フックを追加するには、IT 部門に問題を報告し、パッチを送信します (Android 固有のすべてのパッチと同様、問題が存在する必要があり、その理由を提供する必要があります)。ベンダー フックのサポートは ACK でのみサポートされているため、これらのパッチを上流の Linux に送信しないでください。
ベンダーフィールドを構造に追加する
ANDROID_VENDOR_DATA()
マクロを使用してandroid_vendor_data
フィールドを追加することで、ベンダー データを主要なデータ構造に関連付けることができます。たとえば、付加価値機能をサポートするには、次のコード サンプルに示すように構造体にフィールドを追加します。
ベンダーが必要とするフィールドと OEM が必要とするフィールド間の潜在的な競合を回避するために、OEM はANDROID_VENDOR_DATA()
マクロを使用して宣言されたフィールドを決して使用してはなりません。代わりに、OEM は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 の安定性を保証するには、フック宣言内で使用されるデータ構造を完全に定義する必要があります。そうしないと、不透明なポインターを逆参照したり、サイズ指定されたコンテキストで構造体を使用したりするのは安全ではありません。このようなデータ構造の完全な定義を提供するインクルードはdrivers/android/vendor_hooks.c
の#ifndef __GENKSYMS__
セクション内に含める必要があります。 KMI を破壊する CRC 変更を避けるためにinclude/trace/hooks
ヘッダー ファイルには型定義を含むカーネル ヘッダー ファイルを含めないでください。代わりに型を前方宣言します。
ベンダーフックに取り付ける
ベンダー フックを使用するには、ベンダー モジュールはフックのハンドラーを登録する必要があります (通常はモジュールの初期化中に行われます)。たとえば、次のコードは、 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);
...
}
コアカーネル機能
上記のどの手法でもモジュールから機能を実装できない場合は、その機能を Android 固有の変更としてコア カーネルに追加する必要があります。問題トラッカー (IT) で問題を作成して、会話を開始します。
ユーザー アプリケーション プログラミング インターフェイス (UAPI)
- UAPI ヘッダー ファイル。 Android 固有のインターフェイスに対する変更でない限り、 UAPI ヘッダー ファイルへの変更はアップストリームで行う必要があります。ベンダー固有のヘッダー ファイルを使用して、ベンダー モジュールとベンダー ユーザー空間コード間のインターフェイスを定義します。
- sysfs ノード。新しい sysfs ノードを GKI カーネルに追加しないでください (そのような追加はベンダー モジュールでのみ有効です)。 SoC およびデバイスに依存しないライブラリと、Android フレームワークを構成する Java コードによって使用される sysfs ノードは、互換性のある方法でのみ変更でき、Android 固有の sysfs ノードでない場合はアップストリームで変更する必要があります。ベンダーのユーザー空間で使用されるベンダー固有の sysfs ノードを作成できます。デフォルトでは、SELinux を使用したユーザースペースによる sysfs ノードへのアクセスは拒否されます。認可されたベンダー ソフトウェアによるアクセスを許可するために適切な SELinux ラベルを追加するかどうかは、ベンダーの責任です。
- FS ノードをデバッグします。ベンダー モジュールは、デバッグのみを目的として
debugfs
にノードを定義できます (debugfs
はデバイスの通常の動作中にマウントされないため)。