Generic Kernel Image (GKI) mengurangi fragmentasi kernel dengan menyelaraskan secara ketat dengan kernel Linux upstream. Namun, ada alasan yang valid mengapa beberapa patch tidak dapat diterima di upstream, dan ada jadwal produk yang harus dipenuhi, sehingga beberapa patch dipertahankan di sumber Android Common Kernel (ACK) yang digunakan untuk membangun GKI.
Developer harus mengirimkan perubahan kode ke upstream menggunakan Linux Kernel Mailing List (LKML) sebagai pilihan pertama, dan mengirimkan perubahan kode ke cabang ACK android-mainline
hanya jika ada alasan kuat mengapa upstream tidak layak. Contoh alasan yang valid dan cara menanganinya tercantum sebagai berikut.
Patch dikirimkan ke LKML, tetapi tidak diterima tepat waktu untuk rilis produk. Untuk menangani patch ini:
- Berikan bukti bahwa patch telah dikirimkan ke LKML dan komentar yang diterima untuk patch tersebut, atau perkiraan waktu patch dikirimkan ke upstream.
- Tentukan tindakan yang akan dilakukan untuk menerapkan patch di ACK, mendapatkan persetujuan di upstream, lalu menghapusnya dari ACK saat versi upstream final digabungkan ke ACK.
Patch menentukan
EXPORT_SYMBOLS_GPL()
untuk modul vendor, tetapi tidak dapat dikirimkan ke upstream karena tidak ada modul dalam struktur yang menggunakan simbol tersebut. Untuk menangani patch ini, berikan detail tentang alasan modul Anda tidak dapat dikirimkan ke upstream dan alternatif yang Anda pertimbangkan sebelum membuat permintaan ini.Patch tidak cukup generik untuk upstream dan tidak ada waktu untuk memfaktorkannya ulang sebelum rilis produk. Untuk menangani patch ini, berikan perkiraan waktu saat patch yang difaktorkan ulang dikirimkan ke upstream (patch tidak akan diterima di ACK tanpa rencana untuk mengirimkan patch yang difaktorkan ulang ke upstream untuk ditinjau).
Patch tidak dapat diterima oleh upstream karena... <insert reason here>. Untuk menangani patch ini, hubungi tim kernel Android dan bekerja samalah dengan kami untuk mencari opsi guna memfaktorkan ulang patch agar dapat dikirim untuk ditinjau dan diterima di upstream.
Ada banyak lagi potensi justifikasi. Saat Anda mengirimkan bug atau patch, sertakan justifikasi yang valid dan bersiaplah untuk beberapa iterasi dan diskusi. Kami menyadari bahwa ACK membawa beberapa patch, terutama pada tahap awal GKI saat semua orang mempelajari cara bekerja di upstream, tetapi tidak dapat menunda jadwal produk untuk melakukannya. Harapkan persyaratan upstreaming menjadi lebih ketat dari waktu ke waktu.
Persyaratan patch
Patch harus sesuai dengan standar coding kernel Linux yang dijelaskan dalam
hierarki sumber Linux,
baik dikirimkan ke upstream maupun ke ACK. Skrip scripts/checkpatch.pl
dijalankan sebagai bagian dari pengujian pra-kirim Gerrit, jadi jalankan terlebih dahulu untuk memastikan lulus. Untuk menjalankan skrip checkpatch dengan konfigurasi yang sama seperti
pengujian pra-kirim, gunakan //build/kernel/static_analysis:checkpatch_presubmit
.
Untuk mengetahui detailnya, lihat
build/kernel/kleaf/docs/checkpatch.md.
Patch ACK
Patch yang dikirimkan ke ACK harus sesuai dengan standar coding kernel Linux dan
pedoman kontribusi.
Anda harus menyertakan tag Change-Id
dalam pesan commit; jika Anda mengirimkan patch ke beberapa cabang (misalnya, android-mainline
dan android12-5.4
), Anda harus menggunakan
Change-Id
yang sama untuk semua instance patch.
Kirim patch ke LKML terlebih dahulu untuk peninjauan upstream. Jika patch:
- Diterima di upstream, secara otomatis digabungkan ke
android-mainline
. - Tidak diterima di upstream, kirimkan ke
android-mainline
dengan referensi ke pengiriman upstream atau penjelasan mengapa tidak dikirimkan ke LKML.
Setelah patch diterima di upstream atau di android-mainline
, patch tersebut dapat di-backport ke ACK berbasis LTS yang sesuai (seperti android12-5.4
dan android11-5.4
untuk patch yang memperbaiki kode khusus Android). Pengiriman ke
android-mainline
memungkinkan pengujian dengan kandidat rilis upstream baru dan
menjamin bahwa patch ada di ACK berbasis LTS berikutnya. Pengecualian mencakup kasus
ketika patch upstream di-backport ke android12-5.4
(karena patch kemungkinan
sudah ada di android-mainline
).
Patch upstream
Seperti yang ditentukan dalam pedoman kontribusi, patch upstream yang ditujukan untuk kernel ACK termasuk dalam grup berikut (dicantumkan dalam urutan kemungkinan diterima).
UPSTREAM:
- Patch yang dipilih dari 'android-mainline` kemungkinan akan diterima di ACK jika ada kasus penggunaan yang wajar.BACKPORT:
- Patch dari upstream yang tidak dapat di-cherrypick dengan baik dan perlu dimodifikasi juga cenderung diterima jika ada kasus penggunaan yang wajar.FROMGIT:
- Patch yang dipilih dari cabang pengelola sebagai persiapan untuk dikirimkan ke mainline Linux dapat diterima jika ada batas waktu yang akan datang. Hal ini harus dibenarkan baik untuk konten maupun jadwal.FROMLIST:
- Patch yang telah dikirimkan ke LKML, tetapi belum diterima ke cabang pengelola, kemungkinan tidak akan diterima, kecuali jika justifikasinya cukup kuat sehingga patch akan diterima, terlepas dari apakah patch tersebut masuk ke Linux upstream atau tidak (kami mengasumsikan bahwa patch tersebut tidak akan masuk). Harus ada masalah yang terkait dengan patchFROMLIST
untuk memfasilitasi diskusi dengan tim kernel Android.
Patch khusus Android
Jika Anda tidak dapat menerapkan perubahan yang diperlukan di upstream, Anda dapat mencoba mengirimkan patch di luar struktur ke ACK secara langsung. Pengiriman patch di luar pohon memerlukan
Anda membuat masalah di IT yang mengutip patch dan alasan mengapa
patch tidak dapat dikirimkan ke upstream (lihat daftar sebelumnya untuk contoh).
Namun, ada beberapa kasus saat kode tidak dapat dikirimkan ke upstream. Kasus ini tercakup sebagai berikut dan harus mengikuti panduan kontribusi untuk patch khusus Android dan diberi tag dengan awalan ANDROID:
di subjek.
Perubahan pada gki_defconfig
Semua perubahan CONFIG
pada gki_defconfig
harus diterapkan ke versi arm64 dan
x86 kecuali jika CONFIG
khusus untuk arsitektur. Untuk meminta perubahan
pada setelan CONFIG
, buat masalah di IT untuk mendiskusikan perubahan tersebut. Setiap perubahan CONFIG
yang memengaruhi Kernel Module Interface (KMI) setelah dibekukan akan ditolak. Jika partner meminta setelan yang bertentangan untuk satu konfigurasi, kami menyelesaikan konflik melalui diskusi tentang bug terkait.
Kode yang tidak ada di upstream
Modifikasi pada kode yang sudah khusus Android tidak dapat dikirim ke upstream. Misalnya, meskipun driver binder dikelola di upstream, modifikasi pada fitur pewarisan prioritas driver binder tidak dapat dikirim ke upstream karena khusus untuk Android. Jelaskan secara eksplisit dalam bug dan patch Anda mengapa kode tidak dapat dikirim ke upstream. Jika memungkinkan, pisahkan patch menjadi bagian yang dapat dikirimkan ke upstream dan bagian khusus Android yang tidak dapat dikirimkan ke upstream untuk meminimalkan jumlah kode di luar pohon yang dipertahankan di ACK.
Perubahan lain dalam kategori ini adalah update pada file representasi KMI, daftar simbol KMI, gki_defconfig
, skrip atau konfigurasi build, atau skrip lain yang tidak ada di upstream.
Modul di luar pohon
Linux upstream secara aktif tidak menganjurkan dukungan untuk membangun modul di luar pohon. Ini adalah posisi yang wajar mengingat bahwa pengelola Linux tidak memberikan jaminan tentang kompatibilitas biner atau sumber dalam kernel dan tidak ingin mendukung kode yang tidak ada di tree. Namun, GKI memang memberikan jaminan ABI untuk modul vendor, sehingga memastikan bahwa antarmuka KMI stabil selama masa aktif kernel yang didukung. Oleh karena itu, ada serangkaian perubahan untuk mendukung modul vendor yang dapat diterima untuk ACK, tetapi tidak dapat diterima untuk upstream.
Misalnya, pertimbangkan patch yang menambahkan makro EXPORT_SYMBOL_GPL()
saat
modul yang menggunakan ekspor tidak ada di pohon sumber. Meskipun Anda harus mencoba
meminta EXPORT_SYMBOL_GPL()
di upstream dan menyediakan modul yang menggunakan
simbol yang baru diekspor, jika ada justifikasi yang valid mengapa modul
tidak dikirimkan ke upstream, Anda dapat mengirimkan patch ke ACK. Anda
harus menyertakan alasan mengapa modul tidak dapat di-upstream dalam
masalah tersebut. (Jangan meminta varian non-GPL, EXPORT_SYMBOL()
.)
Konfigurasi tersembunyi
Beberapa modul dalam pohon otomatis memilih konfigurasi tersembunyi yang tidak dapat ditentukan
dalam gki_defconfig
. Misalnya, CONFIG_SND_SOC_TOPOLOGY
dipilih
secara otomatis saat CONFIG_SND_SOC_SOF=y
dikonfigurasi. Untuk mengakomodasi pembuatan modul di luar pohon, GKI menyertakan mekanisme untuk mengaktifkan konfigurasi tersembunyi.
Untuk mengaktifkan konfigurasi tersembunyi, tambahkan pernyataan select
di init/Kconfig.gki
sehingga
konfigurasi tersebut otomatis dipilih berdasarkan konfigurasi kernel CONFIG_GKI_HACKS_TO_FIX
,
yang diaktifkan di gki_defconfig
. Gunakan mekanisme ini hanya untuk konfigurasi tersembunyi;
jika konfigurasi tidak tersembunyi, konfigurasi harus ditentukan di gki_defconfig
baik secara eksplisit maupun sebagai dependensi.
Governor yang dapat dimuat
Untuk framework kernel (seperti cpufreq
) yang mendukung governor yang dapat dimuat, Anda
dapat mengganti governor default (seperti governor schedutil
cpufreq
. Untuk framework (seperti framework termal) yang tidak mendukung governor atau driver yang dapat dimuat, tetapi tetap memerlukan penerapan khusus vendor, buat masalah di IT dan berkonsultasilah dengan tim kernel Android.
Kami akan bekerja sama dengan Anda dan pengelola upstream untuk menambahkan dukungan yang diperlukan.
Hook vendor
Pada rilis sebelumnya, Anda dapat menambahkan modifikasi khusus vendor langsung ke kernel inti. Hal ini tidak mungkin dilakukan dengan GKI 2.0 karena kode khusus produk harus diimplementasikan dalam modul dan tidak akan diterima di kernel inti upstream atau di ACK. Untuk mengaktifkan fitur bernilai tambah yang diandalkan partner dengan dampak minimal pada kode kernel inti, GKI menerima hook vendor yang memungkinkan modul dipanggil dari kode kernel inti. Selain itu, struktur data utama dapat diisi dengan kolom data vendor yang tersedia untuk menyimpan data khusus vendor guna menerapkan fitur ini.
Hook vendor hadir dalam dua varian (normal dan terbatas) yang didasarkan pada titik rekaman aktivitas (bukan peristiwa rekaman aktivitas) yang dapat dilampirkan oleh modul vendor. Misalnya,
daripada menambahkan fungsi sched_exit()
baru untuk melakukan tugas akuntansi saat
keluar, vendor dapat menambahkan hook di do_exit()
yang dapat dilampirkan oleh modul vendor
untuk diproses. Contoh implementasi mencakup hook vendor berikut.
- Hook vendor normal menggunakan
DECLARE_HOOK()
untuk membuat fungsi titik rekaman aktivitas dengan namatrace_name
di mananame
adalah ID unik untuk rekaman aktivitas. Menurut konvensi, nama hook vendor normal dimulai denganandroid_vh
, sehingga nama untuk hooksched_exit()
adalahandroid_vh_sched_exit
. - Hook vendor terbatas diperlukan untuk kasus seperti hook penjadwal yang fungsi terlampirnya harus dipanggil meskipun CPU sedang offline atau memerlukan konteks non-atomik. Hook vendor terbatas tidak dapat dilepas, sehingga modul yang terpasang ke hook terbatas tidak akan pernah dibongkar. Nama hook vendor yang dibatasi dimulai dengan
android_rvh
.
Untuk menambahkan hook vendor, ajukan masalah di IT dan kirimkan patch (seperti semua patch khusus Android, masalah harus ada dan Anda harus memberikan justifikasi). Dukungan untuk hook vendor hanya ada di ACK, jadi jangan kirim patch ini ke Linux upstream.
Menambahkan kolom vendor ke struktur
Anda dapat mengaitkan data vendor dengan struktur data utama dengan menambahkan kolom android_vendor_data
menggunakan makro ANDROID_VENDOR_DATA()
. Misalnya, untuk mendukung fitur bernilai tambah, tambahkan kolom ke struktur seperti yang ditunjukkan dalam contoh kode berikut.
Untuk menghindari potensi konflik antara kolom yang diperlukan oleh vendor dan kolom yang diperlukan oleh OEM, OEM tidak boleh menggunakan kolom yang dideklarasikan menggunakan makro ANDROID_VENDOR_DATA()
. Sebagai gantinya, OEM harus menggunakan ANDROID_OEM_DATA()
untuk mendeklarasikan kolom 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 */
}
Menentukan hook vendor
Tambahkan hook vendor ke kode kernel sebagai titik rekaman aktivitas dengan mendeklarasikannya menggunakan
DECLARE_HOOK()
atau DECLARE_RESTRICTED_HOOK()
, lalu menambahkannya ke kode sebagai
titik rekaman aktivitas. Misalnya, untuk menambahkan trace_android_vh_sched_exit()
ke
fungsi kernel do_exit()
yang ada:
#include <trace/hooks/exit.h>
void do_exit(long code)
{
struct task_struct *tsk = current;
...
trace_android_vh_sched_exit(tsk);
...
}
Fungsi trace_android_vh_sched_exit()
awalnya hanya memeriksa apakah ada sesuatu yang dilampirkan. Namun, jika modul vendor mendaftarkan pengendali menggunakan
register_trace_android_vh_sched_exit()
, fungsi yang terdaftar akan dipanggil. Handler harus mengetahui konteks terkait kunci yang ditahan, status RCS, dan faktor lainnya. Hook harus ditentukan dalam file header di
direktori include/trace/hooks
.
Misalnya, kode berikut memberikan kemungkinan deklarasi untuk
trace_android_vh_sched_exit()
dalam file include/trace/hooks/exit.h
.
/* 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>
Untuk membuat instance antarmuka yang diperlukan untuk hook vendor, tambahkan file header
dengan deklarasi hook ke drivers/android/vendor_hooks.c
dan ekspor
simbol. Misalnya, kode berikut melengkapi deklarasi hook
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);
CATATAN: Struktur data yang digunakan dalam deklarasi hook harus ditentukan sepenuhnya untuk menjamin stabilitas ABI. Jika tidak, tidak aman untuk
melakukan dereferensi pointer buram atau menggunakan struct dalam konteks berukuran. Include yang memberikan definisi lengkap struktur data tersebut harus berada di dalam
bagian #ifndef __GENKSYMS__
dari drivers/android/vendor_hooks.c
. File header di include/trace/hooks
tidak boleh menyertakan file header kernel dengan definisi jenis untuk menghindari perubahan CRC yang merusak KMI. Sebagai gantinya, teruskan
deklarasi jenis.
Melampirkan ke hook vendor
Untuk menggunakan hook vendor, modul vendor perlu mendaftarkan pengendali untuk hook
(biasanya dilakukan selama inisialisasi modul). Misalnya, kode berikut menunjukkan pengendali modul foo.ko
untuk trace_android_vh_sched_exit()
.
#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);
...
}
Menggunakan hook vendor dari file header
Untuk menggunakan hook vendor dari file header, Anda mungkin perlu memperbarui file header hook vendor untuk membatalkan definisi TRACE_INCLUDE_PATH
guna menghindari error build yang menunjukkan bahwa file header titik rekaman aktivitas tidak dapat ditemukan. Misalnya,
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.
Untuk memperbaiki jenis error build ini, terapkan perbaikan yang setara ke file header hook vendor yang Anda sertakan. Untuk mengetahui informasi tambahan, lihat 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
Menentukan UNDEF_TRACE_INCLUDE_PATH
memberi tahu include/trace/define_trace.h
untuk
membatalkan definisi TRACE_INCLUDE_PATH
setelah membuat titik rekaman aktivitas.
Fitur kernel inti
Jika tidak ada teknik sebelumnya yang memungkinkan Anda menerapkan fitur dari modul, Anda harus menambahkan fitur sebagai modifikasi khusus Android ke kernel inti. Buat masalah di pelacak masalah (IT) untuk memulai percakapan.
User application programming interface (UAPI)
- File header UAPI. Perubahan pada file header UAPI harus dilakukan di upstream kecuali jika perubahan tersebut ditujukan untuk antarmuka khusus Android. Gunakan file header khusus vendor untuk menentukan antarmuka antara modul vendor dan kode ruang pengguna vendor.
- node sysfs. Jangan menambahkan node sysfs baru ke kernel GKI (penambahan tersebut hanya valid di modul vendor). Node sysfs yang digunakan oleh library dan kode Java yang tidak bergantung pada SoC dan perangkat yang terdiri dari framework Android hanya dapat diubah dengan cara yang kompatibel dan harus diubah di upstream jika bukan node sysfs khusus Android. Anda dapat membuat node sysfs khusus vendor untuk digunakan oleh userspace vendor. Secara default, akses ke node sysfs oleh userspace ditolak menggunakan SELinux. Vendor bertanggung jawab untuk menambahkan label SELinux yang sesuai agar software vendor yang sah dapat mengaksesnya.
- Node DebugFS. Modul vendor dapat menentukan node di
debugfs
hanya untuk proses debug (karenadebugfs
tidak di-mount selama operasi normal perangkat).