Anda dapat menggunakan alat pemantauan antarmuka biner aplikasi (ABI), yang tersedia di
Android 11 dan yang lebih tinggi, untuk menstabilkan ABI dalam kernel
kernel Android. Alat ini mengumpulkan dan membandingkan representasi ABI
dari biner kernel yang ada (modul GKI vmlinux
+). Representasi ABI ini adalah file .stg
dan daftar simbol. Antarmuka tempat representasi memberikan tampilan disebut Kernel Module Interface
(KMI). Anda dapat menggunakan alat ini untuk melacak dan memitigasi perubahan pada KMI.
Alat pemantauan ABI
dikembangkan di AOSP
dan menggunakan
STG (atau
libabigail
di
Android 13 dan yang lebih rendah) untuk membuat dan membandingkan
representasi.
Halaman ini menjelaskan alat, proses pengumpulan dan analisis representasi ABI, serta penggunaan representasi tersebut untuk memberikan stabilitas pada ABI dalam kernel. Halaman ini juga memberikan informasi untuk berkontribusi dalam melakukan perubahan pada kernel Android.
Proses
Menganalisis ABI kernel memerlukan beberapa langkah, yang sebagian besar dapat diotomatiskan:
- Bangun kernel dan representasi ABI-nya.
- Menganalisis perbedaan ABI antara build dan referensi.
- Perbarui representasi ABI (jika diperlukan).
- Bekerja dengan daftar simbol.
Petunjuk berikut berfungsi untuk kernel yang dapat Anda bangun menggunakan toolchain yang didukung (seperti toolchain Clang yang telah dibuat sebelumnya). repo manifests
tersedia untuk semua cabang kernel umum Android dan untuk beberapa
kernel khusus perangkat, yang memverifikasi bahwa toolchain yang benar digunakan saat Anda
membuat distribusi kernel untuk analisis.
Daftar simbol
KMI tidak menyertakan semua simbol dalam kernel atau bahkan semua simbol yang diekspor yang berjumlah lebih dari 30.000. Sebagai gantinya, simbol yang dapat digunakan oleh modul vendor dicantumkan secara eksplisit dalam serangkaian file daftar simbol yang dikelola secara publik di struktur kernel (gki/{ARCH}/symbols/*
atau android/abi_gki_{ARCH}_*
di Android 15 dan yang lebih lama). Gabungan semua simbol dalam semua file daftar simbol
menentukan kumpulan simbol KMI yang dipertahankan sebagai stabil. Contoh file daftar simbol
adalah
gki/aarch64/symbols/db845c
,
yang mendeklarasikan simbol yang diperlukan untuk
DragonBoard 845c.
Hanya simbol yang tercantum dalam daftar simbol serta struktur dan definisi terkaitnya yang dianggap sebagai bagian dari KMI. Anda dapat memposting perubahan pada daftar simbol jika simbol yang Anda butuhkan tidak ada. Setelah antarmuka baru berada dalam daftar simbol, dan menjadi bagian dari deskripsi KMI, antarmuka tersebut akan dipertahankan sebagai stabil dan tidak boleh dihapus dari daftar simbol atau diubah setelah cabang dibekukan.
Setiap cabang kernel KMI Android Common Kernel (ACK) memiliki kumpulan daftar simbolnya sendiri. Tidak ada upaya untuk memberikan stabilitas ABI antara cabang kernel KMI yang berbeda. Misalnya, KMI untuk android12-5.10
sepenuhnya independen dari
KMI untuk android13-5.10
.
Alat ABI menggunakan daftar simbol KMI untuk membatasi antarmuka yang harus dipantau stabilitasnya. Vendor diharapkan mengirimkan dan memperbarui daftar simbol mereka sendiri untuk memverifikasi bahwa antarmuka yang mereka andalkan mempertahankan kompatibilitas ABI. Misalnya, untuk melihat daftar daftar simbol untuk kernel android16-6.12
, lihat https://android.googlesource.com/kernel/common/+/refs/heads/android16-6.12/gki/aarch64/symbols
Daftar simbol berisi simbol yang dilaporkan diperlukan untuk vendor atau perangkat tertentu. Daftar lengkap yang digunakan oleh alat ini adalah gabungan dari semua file daftar simbol KMI. Alat ABI menentukan detail setiap simbol, termasuk tanda tangan fungsi dan struktur data bertingkat.
Saat KMI dibekukan, tidak ada perubahan yang diizinkan pada antarmuka KMI yang ada; antarmuka tersebut stabil. Namun, vendor bebas menambahkan simbol ke KMI kapan saja selama penambahan tidak memengaruhi stabilitas ABI yang ada. Simbol yang baru ditambahkan dipertahankan kestabilannya segera setelah dikutip oleh daftar simbol KMI. Simbol tidak boleh dihapus dari daftar untuk kernel kecuali jika dapat dikonfirmasi bahwa tidak ada perangkat yang pernah dikirim dengan dependensi pada simbol tersebut.
Anda dapat membuat daftar simbol KMI untuk perangkat menggunakan petunjuk dari Cara menggunakan daftar simbol. Banyak partner mengirimkan satu daftar simbol per ACK, tetapi ini bukan persyaratan yang ketat. Jika membantu pemeliharaan, Anda dapat mengirimkan beberapa daftar simbol.
Memperpanjang KMI
Meskipun simbol KMI dan struktur terkait dipertahankan sebagai stabil (artinya perubahan yang merusak antarmuka stabil di kernel dengan KMI yang dibekukan tidak dapat diterima), kernel GKI tetap terbuka untuk ekstensi sehingga perangkat yang diluncurkan pada tahun ini tidak perlu menentukan semua dependensinya sebelum KMI dibekukan. Untuk memperluas KMI, Anda dapat menambahkan simbol baru ke KMI untuk fungsi kernel yang diekspor baru atau yang sudah ada, meskipun KMI dibekukan. Patch kernel baru juga dapat diterima jika tidak merusak KMI.
Tentang gangguan KMI
Kernel memiliki sumber dan biner dibuat dari sumber tersebut.
Cabang kernel yang dipantau ABI mencakup representasi ABI GKI saat ini (dalam bentuk file .stg
). Setelah biner (vmlinux
, Image
, dan
modul GKI apa pun) dibuat, representasi ABI dapat diekstrak dari
biner. Setiap perubahan yang dilakukan pada file sumber kernel dapat memengaruhi biner dan pada gilirannya juga memengaruhi .stg
yang diekstrak. Analisis Kepatuhan ABI membandingkan file .stg
yang di-commit dengan file yang diekstrak dari artefak build dan menetapkan label Lint-1 pada perubahan di Gerrit jika menemukan perbedaan semantik.
Menangani kerusakan ABI
Sebagai contoh, patch berikut memperkenalkan kerusakan ABI yang sangat jelas:
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 42786e6364ef..e15f1d0f137b 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -657,6 +657,7 @@ struct mm_struct {
ANDROID_KABI_RESERVE(1);
} __randomize_layout;
+ int tickle_count;
/*
* The mm_cpumask needs to be at the end of mm_struct, because it
* is dynamically sized based on nr_cpu_ids.
Saat Anda menjalankan build ABI dengan patch ini diterapkan, alat akan keluar dengan kode error bukan nol dan melaporkan perbedaan ABI yang mirip dengan ini:
function symbol 'struct block_device* I_BDEV(struct inode*)' changed
CRC changed from 0x8d400dbd to 0xabfc92ad
function symbol 'void* PDE_DATA(const struct inode*)' changed
CRC changed from 0xc3c38b5c to 0x7ad96c0d
function symbol 'void __ClearPageMovable(struct page*)' changed
CRC changed from 0xf489e5e8 to 0x92bd005e
... 4492 omitted; 4495 symbols have only CRC changes
type 'struct mm_struct' changed
byte size changed from 992 to 1000
member 'int tickle_count' was added
member 'unsigned long cpu_bitmap[0]' changed
offset changed by 64
Perbedaan ABI terdeteksi pada waktu build
Penyebab paling umum terjadinya error adalah saat driver menggunakan simbol baru dari kernel yang tidak ada dalam daftar simbol mana pun.
Jika simbol tidak disertakan dalam daftar simbol, Anda harus memverifikasi terlebih dahulu
bahwa simbol diekspor dengan
EXPORT_SYMBOL_GPL(symbol_name)
, lalu perbarui
daftar simbol dan representasi ABI. Misalnya, perubahan berikut menambahkan fitur FS Inkremental baru ke cabang android-12-5.10
, yang mencakup pembaruan daftar simbol dan representasi ABI.
- Contoh perubahan fitur ada di aosp/1345659.
- Contoh daftar simbol ada di aosp/1346742.
- Contoh perubahan representasi ABI ada di aosp/1349377.
Jika simbol diekspor (baik oleh Anda atau diekspor sebelumnya) tetapi tidak ada driver lain yang menggunakannya, Anda mungkin mendapatkan error build yang mirip dengan berikut ini.
Comparing the KMI and the symbol lists:
+ build/abi/compare_to_symbol_list out/$BRANCH/common/Module.symvers out/$BRANCH/common/abi_symbollist.raw
ERROR: Differences between ksymtab and symbol list detected!
Symbols missing from ksymtab:
Symbols missing from symbol list:
- simple_strtoull
Untuk mengatasinya, perbarui daftar simbol KMI di kernel dan ACK (lihat Memperbarui representasi ABI). Untuk contoh memperbarui daftar simbol dan representasi ABI di ACK, lihat aosp/1367601.
Mengatasi kerusakan ABI kernel
Anda dapat menangani kerusakan ABI kernel dengan memfaktorkan ulang kode agar tidak mengubah ABI atau memperbarui representasi ABI. Gunakan diagram berikut untuk menentukan pendekatan terbaik untuk situasi Anda.
Gambar 1. Penyelesaian kerusakan ABI
Memfaktorkan ulang kode untuk menghindari perubahan ABI
Lakukan segala upaya untuk menghindari modifikasi ABI yang ada. Dalam banyak kasus, Anda dapat memfaktorkan ulang kode untuk menghapus perubahan yang memengaruhi ABI.
Memfaktorkan ulang perubahan kolom struct. Jika perubahan memodifikasi ABI untuk fitur debug, tambahkan
#ifdef
di sekitar kolom (dalam struct dan referensi sumber) dan pastikanCONFIG
yang digunakan untuk#ifdef
dinonaktifkan untuk defconfig produksi dangki_defconfig
. Untuk contoh cara menambahkan konfigurasi debug ke struct tanpa merusak ABI, lihat patchset ini.Memfaktorkan ulang fitur agar tidak mengubah kernel inti. Jika fitur baru perlu ditambahkan ke ACK untuk mendukung modul partner, coba refaktor bagian ABI dari perubahan untuk menghindari modifikasi ABI kernel. Untuk contoh penggunaan ABI kernel yang ada untuk menambahkan kemampuan tambahan tanpa mengubah ABI kernel, lihat aosp/1312213.
Memperbaiki ABI yang rusak di Android Gerrit
Jika Anda tidak sengaja merusak ABI kernel, Anda perlu menyelidikinya menggunakan panduan yang diberikan oleh alat pemantauan ABI. Penyebab paling umum kerusakan adalah perubahan struktur data dan perubahan CRC simbol terkait, atau karena perubahan opsi konfigurasi yang menyebabkan salah satu hal di atas. Mulailah dengan mengatasi masalah yang ditemukan oleh alat.
Anda dapat mereproduksi temuan ABI secara lokal, lihat Membangun kernel dan representasi ABI-nya.
Tentang label Lint-1
Jika Anda mengupload perubahan ke cabang yang berisi KMI yang dibekukan atau difinalisasi, perubahan harus lulus analisis Kepatuhan dan Kompatibilitas ABI untuk memastikan perubahan pada representasi ABI mencerminkan ABI sebenarnya dan tidak berisi ketidakcocokan (penghapusan simbol atau perubahan jenis).
Setiap analisis ABI ini dapat menetapkan label Lint-1 dan memblokir pengiriman perubahan hingga semua masalah diselesaikan atau label diganti.
Memperbarui ABI kernel
Jika modifikasi ABI tidak dapat dihindari, Anda harus menerapkan perubahan kode, representasi ABI, dan daftar simbol ke ACK. Untuk membuat Lint menghapus -1 dan tidak merusak kompatibilitas GKI, ikuti langkah-langkah berikut:
Tunggu hingga Anda menerima Code-Review +2 untuk patchset.
Gabungkan perubahan kode dan perubahan update ABI Anda.
Mengupload perubahan kode ABI ke ACK
Memperbarui ABI ACK bergantung pada jenis perubahan yang dilakukan.
Jika perubahan ABI terkait dengan fitur yang memengaruhi pengujian CTS atau VTS, perubahan biasanya dapat dipilih untuk ACK apa adanya. Misalnya:
- aosp/1289677 diperlukan agar audio berfungsi.
- aosp/1295945 diperlukan agar USB dapat berfungsi.
Jika perubahan ABI ditujukan untuk fitur yang dapat dibagikan dengan ACK, perubahan tersebut dapat dipilih ke ACK apa adanya. Misalnya, perubahan berikut tidak diperlukan untuk pengujian CTS atau VTS, tetapi dapat dibagikan dengan ACK:
- aosp/1250412 adalah perubahan fitur termal.
- aosp/1288857
adalah perubahan
EXPORT_SYMBOL_GPL
.
Jika perubahan ABI memperkenalkan fitur baru yang tidak perlu disertakan dalam ACK, Anda dapat memperkenalkan simbol ke ACK menggunakan stub seperti yang dijelaskan di bagian berikut.
Menggunakan stub untuk ACK
Stub hanya diperlukan untuk perubahan kernel inti yang tidak mendapatkan manfaat dari ACK, seperti perubahan performa dan daya. Daftar berikut menjelaskan contoh stub dan cherry-pick parsial di ACK untuk GKI.
Stub fitur isolasi inti (aosp/1284493). Kemampuan di ACK tidak diperlukan, tetapi simbol harus ada di ACK agar modul Anda dapat menggunakan simbol ini.
Simbol placeholder untuk modul vendor (aosp/1288860).
Pilihan cherry-pick khusus ABI untuk fitur pelacakan peristiwa
mm
per proses (aosp/1288454). Patch asli dipilih ke ACK, lalu dipangkas agar hanya menyertakan perubahan yang diperlukan untuk menyelesaikan perbedaan ABI untuktask_struct
danmm_event_count
. Patch ini juga mengupdate enummm_event_type
untuk berisi anggota akhir.Cherry-pick parsial perubahan ABI struktur termal yang memerlukan lebih dari sekadar menambahkan kolom ABI baru.
Patch aosp/1255544 menyelesaikan perbedaan ABI antara kernel partner dan ACK.
Patch aosp/1291018 memperbaiki masalah fungsional yang ditemukan selama pengujian GKI pada patch sebelumnya. Perbaikan ini mencakup inisialisasi struct parameter sensor untuk mendaftarkan beberapa zona termal ke satu sensor.
Perubahan ABI
CONFIG_NL80211_TESTMODE
(aosp/1344321). Patch ini menambahkan perubahan struct yang diperlukan untuk ABI dan memastikan kolom tambahan tidak menyebabkan perbedaan fungsional, sehingga memungkinkan partner menyertakanCONFIG_NL80211_TESTMODE
dalam kernel produksi mereka dan tetap mempertahankan kepatuhan GKI.
Menerapkan KMI saat runtime
Kernel GKI menggunakan opsi konfigurasi TRIM_UNUSED_KSYMS=y
dan UNUSED_KSYMS_WHITELIST=<union
of all symbol lists>
, yang membatasi simbol yang diekspor
(seperti simbol yang diekspor menggunakan EXPORT_SYMBOL_GPL()
) ke simbol yang tercantum dalam
daftar simbol. Semua simbol lainnya tidak diekspor, dan pemuatan modul yang memerlukan simbol yang tidak diekspor akan ditolak. Pembatasan ini diterapkan pada waktu build dan entri yang tidak ada akan ditandai.
Untuk tujuan pengembangan, Anda dapat menggunakan build kernel GKI yang tidak menyertakan penghapusan simbol (artinya semua simbol yang biasanya diekspor dapat digunakan). Untuk menemukan build ini, cari build kernel_debug_aarch64
di ci.android.com.
Menerapkan KMI menggunakan pembuatan versi modul
Kernel Generic Kernel Image (GKI) menggunakan pembuatan versi modul
(CONFIG_MODVERSIONS
) sebagai langkah tambahan untuk menerapkan kepatuhan KMI saat
runtime. Pemberian versi modul dapat menyebabkan kegagalan ketidakcocokan pemeriksaan redundansi siklik (CRC) pada waktu pemuatan modul jika KMI yang diharapkan dari modul tidak cocok dengan KMI vmlinux
. Misalnya, berikut adalah kegagalan umum yang terjadi pada waktu pemuatan modul karena ketidakcocokan CRC untuk simbol module_layout()
:
init: Loading module /lib/modules/kernel/.../XXX.ko with args ""
XXX: disagrees about version of symbol module_layout
init: Failed to insmod '/lib/modules/kernel/.../XXX.ko' with args ''
Penggunaan pembuatan versi modul
Pembuatan versi modul berguna karena alasan berikut:
Pembuatan versi modul mencatat perubahan dalam visibilitas struktur data. Jika modul mengubah struktur data buram, yaitu struktur data yang bukan bagian dari KMI, modul tersebut akan rusak setelah perubahan struktur di masa mendatang.
Sebagai contoh, pertimbangkan kolom
fwnode
distruct device
. Kolom ini HARUS buram bagi modul sehingga modul tidak dapat melakukan perubahan pada kolomdevice->fw_node
atau membuat asumsi tentang ukurannya.Namun, jika modul menyertakan
<linux/fwnode.h>
(secara langsung atau tidak langsung), maka kolomfwnode
distruct device
tidak lagi buram baginya. Modul kemudian dapat membuat perubahan padadevice->fwnode->dev
ataudevice->fwnode->ops
. Skenario ini bermasalah karena beberapa alasan, seperti yang dinyatakan berikut:Hal ini dapat melanggar asumsi yang dibuat oleh kode kernel inti tentang struktur data internalnya.
Jika update kernel mendatang mengubah
struct fwnode_handle
(jenis datafwnode
), maka modul tidak lagi berfungsi dengan kernel baru. Selain itu,stgdiff
tidak akan menunjukkan perbedaan apa pun karena modul melanggar KMI dengan memanipulasi struktur data internal secara langsung dengan cara yang tidak dapat ditangkap hanya dengan memeriksa representasi biner.
Modul saat ini dianggap tidak kompatibel dengan KMI jika dimuat di kemudian hari oleh kernel baru yang tidak kompatibel. Pemberian versi modul menambahkan pemeriksaan run-time untuk menghindari pemuatan modul yang tidak kompatibel dengan KMI secara tidak sengaja dengan kernel. Pemeriksaan ini mencegah masalah runtime yang sulit di-debug dan error kernel yang mungkin diakibatkan oleh ketidakcocokan yang tidak terdeteksi dalam KMI.
Mengaktifkan pembuatan versi modul akan mencegah semua masalah ini.
Memeriksa ketidakcocokan CRC tanpa melakukan booting perangkat
stgdiff
membandingkan dan melaporkan ketidakcocokan CRC antar-kernel bersama dengan perbedaan ABI lainnya.
Selain itu, build kernel lengkap dengan CONFIG_MODVERSIONS
yang diaktifkan akan menghasilkan file Module.symvers
sebagai bagian dari proses build normal. File ini memiliki satu
baris untuk setiap simbol yang diekspor oleh kernel (vmlinux
) dan modul. Setiap
baris terdiri dari nilai CRC, nama simbol, namespace simbol, vmlinux
atau
nama modul yang mengekspor simbol, dan jenis ekspor (misalnya,
EXPORT_SYMBOL
versus EXPORT_SYMBOL_GPL
).
Anda dapat membandingkan file Module.symvers
antara build GKI dan build Anda
untuk memeriksa apakah ada perbedaan CRC dalam simbol yang diekspor oleh vmlinux
. Jika ada perbedaan nilai CRC dalam simbol apa pun yang diekspor oleh vmlinux
dan, dan simbol tersebut digunakan oleh salah satu modul yang Anda muat di perangkat, modul tidak akan dimuat.
Jika Anda tidak memiliki semua artefak build, tetapi memiliki file vmlinux
dari kernel GKI dan kernel Anda, Anda dapat membandingkan nilai CRC untuk simbol tertentu dengan menjalankan perintah berikut di kedua kernel dan membandingkan outputnya:
nm <path to vmlinux>/vmlinux | grep __crc_<symbol name>
Misalnya, perintah berikut memeriksa nilai CRC untuk simbol module_layout
:
nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout
Mengatasi ketidakcocokan CRC
Gunakan langkah-langkah berikut untuk menyelesaikan ketidakcocokan CRC saat memuat modul:
Bangun kernel GKI dan kernel perangkat Anda menggunakan opsi
--kbuild_symtypes
seperti yang ditunjukkan dalam perintah berikut:tools/bazel run --kbuild_symtypes //common:kernel_aarch64_dist
Perintah ini akan menghasilkan file
.symtypes
untuk setiap file.o
. LihatKBUILD_SYMTYPES
di Kleaf untuk mengetahui detailnya.Untuk Android 13 dan yang lebih lama, bangun kernel GKI dan kernel perangkat Anda dengan menambahkan
KBUILD_SYMTYPES=1
ke perintah yang Anda gunakan untuk membangun kernel, seperti yang ditunjukkan dalam perintah berikut:KBUILD_SYMTYPES=1 BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
Saat menggunakan
build_abi.sh,
, flagKBUILD_SYMTYPES=1
sudah ditetapkan secara implisit.Temukan file
.c
tempat simbol dengan CRC tidak cocok diekspor, menggunakan perintah berikut:git -C common grep EXPORT_SYMBOL.*module_layout kernel/module/version.c:EXPORT_SYMBOL(module_layout);
File
.c
memiliki file.symtypes
yang sesuai di GKI, dan artefak build kernel perangkat Anda. Temukan file.symtypes
menggunakan perintah berikut:cd bazel-bin/common/kernel_aarch64/symtypes ls -1 kernel/module/version.symtypes
Di Android 13 dan yang lebih rendah, menggunakan skrip build lama, lokasinya kemungkinan adalah
out/$BRANCH/common
atauout_abi/$BRANCH/common
.Setiap file
.symtypes
adalah file teks biasa yang terdiri dari deskripsi jenis dan simbol:Setiap baris memiliki bentuk
key description
dengan deskripsi yang dapat merujuk ke kunci lain dalam file yang sama.Tombol seperti
[s|u|e|t]#foo
merujuk ke[struct|union|enum|typedef] foo
. Contoh:t#bool typedef _Bool bool
Kunci tanpa awalan
x#
hanyalah nama simbol. Contoh:find_module s#module * find_module ( const char * )
Bandingkan kedua file dan perbaiki semua perbedaannya.
Sebaiknya buat symtypes
dengan build tepat sebelum perubahan yang bermasalah dan kemudian pada perubahan yang bermasalah. Menyimpan semua file berarti file tersebut dapat dibandingkan secara massal.
Misalnya,
for f in $(find good bad -name '*.symtypes' | sed -r 's;^(good|bad)/;;' | LANG=C sort -u); do
diff -N -U0 --label good/"$f" --label bad/"$f" <(LANG=C sort good/"$f") <(LANG=C sort bad/"$f")
done
Jika tidak, cukup bandingkan file tertentu yang diinginkan.
Kasus 1: Perbedaan karena visibilitas jenis data
#include
baru dapat menarik definisi jenis baru (misalnya struct foo
) ke dalam
file sumber. Dalam kasus ini, deskripsinya dalam file .symtypes
yang sesuai akan berubah dari structure_type foo { }
kosong menjadi definisi lengkap.
Hal ini akan memengaruhi semua CRC dari semua simbol dalam file .symtypes
yang deskripsinya bergantung secara langsung atau tidak langsung pada definisi jenis.
Misalnya, menambahkan baris berikut ke file
include/linux/device.h
di kernel Anda menyebabkan ketidakcocokan CRC, salah satunya
adalah untuk module_layout()
:
#include <linux/fwnode.h>
Membandingkan module/version.symtypes
untuk simbol tersebut akan menunjukkan perbedaan berikut:
$ diff -u <GKI>/kernel/module/version.symtypes <your kernel>/kernel/module/version.symtypes
--- <GKI>/kernel/module/version.symtypes
+++ <your kernel>/kernel/module/version.symtypes
@@ -334,12 +334,15 @@
...
-s#fwnode_handle structure_type fwnode_handle { }
+s#fwnode_reference_args structure_type fwnode_reference_args { s#fwnode_handle * fwnode ; unsigned int nargs ; t#u64 args [ 8 ] ; }
...
Jika kernel GKI memiliki definisi jenis lengkap, tetapi kernel Anda tidak memilikinya (sangat tidak mungkin), gabungkan Android Common Kernel terbaru ke kernel Anda sehingga Anda menggunakan basis kernel GKI terbaru.
Dalam sebagian besar kasus, kernel GKI tidak memiliki definisi jenis lengkap di
.symtypes
, tetapi kernel Anda memilikinya karena adanya direktif #include
tambahan.
Resolusi untuk Android 16 dan yang lebih tinggi
Pastikan file sumber yang terpengaruh menyertakan header stabilisasi KABI Android:
#include <linux/android_kabi.h>
Untuk setiap jenis yang terpengaruh, tambahkan ANDROID_KABI_DECLONLY(name);
pada cakupan global ke
file sumber yang terpengaruh.
Misalnya, jika perbedaan symtypes
adalah ini:
--- good/drivers/android/vendor_hooks.symtypes
+++ bad/drivers/android/vendor_hooks.symtypes
@@ -1051 +1051,2 @@
-s#ubuf_info structure_type ubuf_info { }
+s#ubuf_info structure_type ubuf_info { member pointer_type { const_type { s#ubuf_info_ops } } ops data_member_location(0) , member t#refcount_t refcnt data_member_location(8) , member t#u8 flags data_member_location(12) } byte_size(16)
+s#ubuf_info_ops structure_type ubuf_info_ops { member pointer_type { subroutine_type ( formal_parameter pointer_type { s#sk_buff } , formal_parameter pointer_type { s#ubuf_info } , formal_parameter t#bool ) -> base_type void } complete data_member_location(0) , member pointer_type { subroutine_type ( formal_parameter pointer_type { s#sk_buff } , formal_parameter pointer_type { s#ubuf_info } ) -> base_type int byte_size(4) encoding(5) } link_skb data_member_location(8) } byte_size(16)
Kemudian, masalahnya adalah struct ubuf_info
kini memiliki definisi lengkap di
symtypes
. Solusinya adalah menambahkan baris ke drivers/android/vendor_hooks.c
:
ANDROID_KABI_DECLONLY(ubuf_info);
Hal ini menginstruksikan gendwarfksyms
untuk memperlakukan jenis bernama sebagai tidak ditentukan dalam file.
Kemungkinan yang lebih rumit adalah bahwa #include
baru itu sendiri ada dalam file header. Dalam hal ini, Anda mungkin perlu mendistribusikan berbagai set pemanggilan makro ANDROID_KABI_DECLONLY
di seluruh file sumber yang secara tidak langsung menarik definisi jenis tambahan karena beberapa di antaranya mungkin sudah memiliki beberapa definisi jenis.
Agar mudah dibaca, tempatkan pemanggilan makro tersebut di dekat awal file sumber.
Resolusi untuk Android 15 dan yang lebih rendah
Sering kali, perbaikannya hanya menyembunyikan #include
baru dari genksyms
.
#ifndef __GENKSYMS__
#include <linux/fwnode.h>
#endif
Jika tidak, untuk mengidentifikasi #include
yang menyebabkan perbedaan, ikuti langkah-langkah berikut:
Buka file header yang menentukan simbol atau jenis data yang memiliki perbedaan ini. Misalnya, edit
include/linux/fwnode.h
untukstruct fwnode_handle
.Tambahkan kode berikut di bagian atas file header:
#ifdef CRC_CATCH #error "Included from here" #endif
Dalam file
.c
modul yang memiliki ketidakcocokan CRC, tambahkan berikut sebagai baris pertama sebelum baris#include
.#define CRC_CATCH 1
Kompilasi modul Anda. Error waktu build yang dihasilkan menunjukkan rangkaian file header
#include
yang menyebabkan ketidakcocokan CRC ini. Contoh:In file included from .../drivers/clk/XXX.c:16:` In file included from .../include/linux/of_device.h:5: In file included from .../include/linux/cpu.h:17: In file included from .../include/linux/node.h:18: .../include/linux/device.h:16:2: error: "Included from here" #error "Included from here"
Salah satu link dalam rangkaian
#include
ini disebabkan oleh perubahan yang dilakukan di kernel Anda, yang tidak ada di kernel GKI.
Kasus 2: Perbedaan karena perubahan jenis data
Jika ketidakcocokan CRC untuk simbol atau jenis data bukan karena perbedaan visibilitas, maka hal itu disebabkan oleh perubahan aktual (penambahan, penghapusan, atau perubahan) dalam jenis data itu sendiri.
Misalnya, melakukan perubahan berikut di kernel Anda menyebabkan beberapa ketidakcocokan CRC karena banyak simbol yang terpengaruh secara tidak langsung oleh jenis perubahan ini:
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -259,7 +259,7 @@ struct iommu_ops {
void (*iotlb_sync)(struct iommu_domain *domain);
phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova);
phys_addr_t (*iova_to_phys_hard)(struct iommu_domain *domain,
- dma_addr_t iova);
+ dma_addr_t iova, unsigned long trans_flag);
int (*add_device)(struct device *dev);
void (*remove_device)(struct device *dev);
struct iommu_group *(*device_group)(struct device *dev);
Satu ketidakcocokan CRC adalah untuk devm_of_platform_populate()
.
Jika Anda membandingkan file .symtypes
untuk simbol tersebut, file tersebut mungkin terlihat seperti ini:
$ diff -u <GKI>/drivers/of/platform.symtypes <your kernel>/drivers/of/platform.symtypes
--- <GKI>/drivers/of/platform.symtypes
+++ <your kernel>/drivers/of/platform.symtypes
@@ -399,7 +399,7 @@
...
-s#iommu_ops structure_type iommu_ops { ... ; t#phy
s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t ) ; int
( * add_device ) ( s#device * ) ; ...
+s#iommu_ops structure_type iommu_ops { ... ; t#phy
s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t , unsigned long ) ; int ( * add_device ) ( s#device * ) ; ...
Untuk mengidentifikasi jenis yang diubah, ikuti langkah-langkah berikut:
Temukan definisi simbol dalam kode sumber (biasanya dalam file
.h
).- Untuk mengetahui perbedaan simbol antara kernel Anda dan kernel GKI, temukan commit dengan menjalankan perintah berikut:
git blame
- Untuk simbol yang dihapus (jika simbol dihapus di satu pohon dan Anda juga ingin menghapusnya di pohon lain), Anda harus menemukan perubahan yang menghapus baris. Gunakan perintah berikut pada pohon tempat baris dihapus:
git log -S "copy paste of deleted line/word" -- <file where it was deleted>
Tinjau daftar commit yang ditampilkan untuk menemukan perubahan atau penghapusan. Commit pertama mungkin adalah commit yang Anda cari. Jika tidak, lihat daftar hingga Anda menemukan commit.
Setelah mengidentifikasi commit, batalkan perubahannya di kernel atau perbarui untuk menekan perubahan CRC dan upload ke ACK dan gabungkan. Setiap jeda ABI residual harus ditinjau keamanannya dan jika perlu, jeda yang diizinkan dapat dicatat.
Lebih memilih untuk menggunakan padding yang ada
Beberapa struktur di GKI diisi untuk memungkinkan ekstensinya tanpa merusak modul vendor yang ada. Jika commit upstream (misalnya) menambahkan anggota ke struktur tersebut, maka commit tersebut dapat diubah untuk menggunakan beberapa padding. Kemudian, perubahan ini disembunyikan dari penghitungan CRC.
Makro yang distandardisasi dan mendokumentasikan dirinya sendiri ANDROID_KABI_RESERVE
mencadangkan ruang (yang disejajarkan) senilai u64
. Pernyataan ini digunakan sebagai pengganti pernyataan anggota.
Contoh:
struct data {
u64 handle;
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
};
Padding dapat digunakan, tanpa memengaruhi CRC simbol, dengan ANDROID_KABI_USE
(atau ANDROID_KABI_USE2
atau varian lain yang dapat ditentukan).
Anggota sekret
tersedia seolah-olah dideklarasikan secara langsung, tetapi makro sebenarnya diperluas ke anggota gabungan anonim yang berisi sekret
serta hal-hal yang digunakan oleh gendwarfksyms
untuk mempertahankan stabilitas symtype.
struct data {
u64 handle;
ANDROID_KABI_USE(1, void *sekret);
ANDROID_KABI_RESERVE(2);
};
Resolusi untuk Android 16 dan yang lebih tinggi
CRC dihitung oleh gendwarfksyms
yang menggunakan informasi debug DWARF, sehingga mendukung jenis C dan Rust. Resolusi bervariasi menurut jenis perubahan huruf. Berikut ini beberapa contohnya.
Enumerator baru atau yang diubah
Terkadang enumerator baru ditambahkan dan sesekali nilai enumerator MAX
atau yang serupa juga terpengaruh. Perubahan ini aman jika tidak "keluar" dari GKI atau jika kita dapat memastikan bahwa modul vendor tidak dapat memedulikan nilainya.
Contoh:
enum outcome {
SUCCESS,
FAILURE,
RETRY,
+ TRY_HARDER,
OUTCOME_LIMIT
};
Penambahan TRY_HARDER
dan perubahan pada OUTCOME_LIMIT
dapat disembunyikan dari
penghitungan CRC dengan pemanggilan makro pada cakupan global:
ANDROID_KABI_ENUMERATOR_IGNORE(outcome, TRY_HARDER);
ANDROID_KABI_ENUMERATOR_VALUE(outcome, OUTCOME_LIMIT, 3);
Agar mudah dibaca, tempatkan tepat setelah definisi enum
.
Anggota struktur baru yang menempati lubang yang ada
Karena penyelarasan, akan ada byte yang tidak digunakan antara urgent
dan scratch
.
void *data;
bool urgent;
+ bool retry;
void *scratch;
Tidak ada offset anggota yang ada atau ukuran struktur yang terpengaruh oleh
penambahan retry
. Namun, hal ini dapat memengaruhi CRC simbol atau representasi ABI atau keduanya.
Tindakan ini akan menyembunyikannya dari perhitungan CRC:
void *data;
bool urgent;
+ ANDROID_KABI_IGNORE(1, bool retry);
void *scratch_space;
Anggota retry
tersedia seolah-olah dideklarasikan secara langsung, tetapi makro sebenarnya diperluas ke anggota gabungan anonim yang berisi retry
serta hal-hal yang digunakan oleh gendwarfksyms
untuk mempertahankan stabilitas symtype.
Perluasan struktur dengan anggota baru
Anggota terkadang ditambahkan di akhir struktur. Hal ini tidak memengaruhi offset anggota yang ada atau memengaruhi pengguna struktur yang ada yang hanya mengaksesnya dengan pointer. Ukuran struktur memengaruhi CRC-nya dan perubahan pada CRC ini dapat dihentikan dengan pemanggilan makro tambahan pada cakupan global, sebagai berikut:
struct data {
u64 handle;
u64 counter;
ANDROID_KABI_IGNORE(1, void *sekret);
};
ANDROID_KABI_BYTE_SIZE(data, 16);
Agar mudah dibaca, tempatkan ini tepat setelah definisi struct
.
Semua perubahan lain pada jenis atau jenis simbol
Terkadang, ada perubahan yang tidak termasuk dalam salah satu kategori sebelumnya, sehingga menyebabkan perubahan CRC yang tidak dapat dihentikan menggunakan makro sebelumnya.
Dalam kasus ini, deskripsi symtypes
asli dari jenis atau simbol dapat
disediakan dengan pemanggilan ANDROID_KABI_TYPE_STRING
pada cakupan global.
struct data {
/* extensive changes */
};
ANDROID_KABI_TYPE_STRING("s#data", "original s#data symtypes definition");
Agar mudah dibaca, tempatkan tepat setelah definisi jenis atau simbol.
Resolusi untuk Android 15 dan yang lebih rendah
Perubahan jenis dan jenis simbol harus disembunyikan dari genksyms
. Hal ini dapat dilakukan
dengan mengontrol praproses menggunakan __GENKSYMS__
.
Transformasi kode arbitrer dapat dinyatakan dengan cara ini.
Misalnya, untuk menyembunyikan anggota baru yang menempati lubang dalam struktur yang ada:
struct parcel {
void *data;
bool urgent;
#ifndef __GENKSYMS__
bool retry;
#endif
void *scratch_space;
};