Pemantauan ABI Kernel Android

Anda dapat menggunakan alat Pemantauan Antarmuka Biner (ABI) aplikasi, tersedia di Android 11 dan lebih tinggi, untuk menstabilkan ABI dalam kernel dari kernel Android. Alat ini mengumpulkan dan membandingkan representasi ABI dari binari kernel yang ada ( vmlinux + modul). Representasi ABI ini adalah file .xml dan daftar simbol. Antarmuka di mana representasi memberikan tampilan disebut Antarmuka Modul Kernel (KMI). Anda dapat menggunakan alat ini untuk melacak dan mengurangi perubahan pada KMI.

Alat pemantauan ABI dikembangkan di AOSP dan menggunakan libabigail untuk menghasilkan dan membandingkan representasi.

Halaman ini menjelaskan perkakas, proses pengumpulan dan analisis representasi ABI, dan penggunaan representasi tersebut untuk memberikan stabilitas pada ABI dalam kernel. Halaman ini juga menyediakan informasi untuk memberikan kontribusi perubahan pada kernel Android.

Direktori ini berisi alat khusus untuk analisis ABI. Gunakan dengan skrip build yang disediakan oleh build_abi.sh .)

Proses

Menganalisis ABI kernel membutuhkan beberapa langkah, yang sebagian besar dapat dilakukan secara otomatis:

  1. Dapatkan rantai alat, skrip build, dan sumber kernel melalui repo .
  2. Berikan prasyarat apa pun (seperti perpustakaan libabigail dan koleksi alat).
  3. Bangun kernel dan representasi ABI-nya .
  4. Analisis perbedaan ABI antara build dan referensi .
  5. Perbarui representasi ABI (jika diperlukan) .
  6. Bekerja dengan daftar simbol .

Instruksi berikut berfungsi untuk kernel apa pun yang dapat Anda buat menggunakan rantai alat yang didukung (seperti rantai alat Clang bawaan). repo manifests tersedia untuk semua cabang kernel umum Android dan untuk beberapa kernel khusus perangkat, manifes tersebut memastikan bahwa rantai alat yang benar digunakan saat Anda membangun distribusi kernel untuk analisis.

Gunakan alat Pemantauan ABI

1. Dapatkan rantai alat, skrip build, dan sumber kernel melalui repo

Anda dapat memperoleh rantai alat, membuat skrip (skrip ini), dan sumber kernel dengan repo . Untuk dokumentasi mendetail, lihat informasi terkait untuk membuat kernel Android .

Untuk mengilustrasikan prosesnya, langkah-langkah berikut menggunakan common-android12-5.10 , cabang kernel Android, yang merupakan kernel GKI terbaru yang dirilis pada saat penulisan ini. Untuk mendapatkan cabang ini melalui repo , jalankan yang berikut:

repo init -u https://android.googlesource.com/kernel/manifest -b common-android12-5.10
repo sync

2. Berikan prasyarat

Alat ABI menggunakan libabigail , perpustakaan dan kumpulan alat, untuk menganalisis binari. Satu set binari prebuilt yang sesuai dilengkapi dengan kernel-build-tools dan secara otomatis digunakan dengan build_abi.sh .

Untuk memanfaatkan perkakas tingkat rendah (seperti dump_abi ), tambahkan alat kernel-build- ke PATH .

3. Bangun kernel dan representasi ABI-nya

Pada titik ini Anda siap membangun kernel dengan rantai alat yang benar dan mengekstrak representasi ABI dari binernya ( vmlinux + modules).

Mirip dengan proses pembuatan kernel Android biasa (menggunakan build.sh ), langkah ini membutuhkan menjalankan build_abi.sh .

BUILD_CONFIG=common/build.config.gki.aarch64 build/build_abi.sh

Itu membangun kernel dan mengekstrak representasi ABI ke dalam subdirektori out_abi . Dalam hal ini out/android12-5.10/dist/abi.xml adalah tautan simbolis ke out_abi/android12-5.10/dist/abi-<id>.xml . < id> dihitung dengan mengeksekusi git describe terhadap pohon sumber kernel.

4. Analisis perbedaan ABI antara build dan representasi referensi

build_abi.sh menganalisis dan melaporkan setiap perbedaan ABI ketika referensi diberikan melalui variabel lingkungan ABI_DEFINITION . ABI_DEFINITION harus menunjuk ke file referensi relatif terhadap pohon sumber kernel, dan dapat ditentukan pada baris perintah atau, lebih umum, sebagai nilai dalam build.config . Berikut ini memberikan contoh:

BUILD_CONFIG=common/build.config.gki.aarch64 build/build_abi.sh

Pada perintah di atas, build.config.gki.aarch64 mendefinisikan file referensi (sebagai ABI_DEFINITION=android/abi_gki_aarch64.xml ), dan diff_abi memanggil abidiff untuk membandingkan representasi ABI yang baru dibuat dengan file referensi. build_abi.sh mencetak lokasi laporan dan mengeluarkan laporan singkat untuk setiap kerusakan ABI. Jika kerusakan terdeteksi, build_abi.sh berhenti dan mengembalikan kode keluar yang bukan nol.

5. Perbarui representasi ABI (jika diperlukan)

Untuk memperbarui representasi ABI, aktifkan build_abi.sh dengan flag --update . Ini memperbarui file abi.xml yang sesuai yang ditentukan oleh build.config . Untuk mencetak perbedaan ABI karena pembaruan, aktifkan skrip dengan --print-report . Pastikan untuk menyertakan laporan dalam pesan komit saat memperbarui file abi.xml .

6. Bekerja dengan daftar simbol

Parameterisasi build_abi.sh dengan daftar simbol KMI untuk memfilter simbol selama ekstraksi ABI. Ini adalah file teks biasa yang mencantumkan simbol kernel ABI yang relevan. Misalnya, file daftar simbol dengan konten berikut membatasi analisis ABI ke simbol ELF dengan nama symbol1 dan symbol2 :

[abi_symbol_list]
   symbol1
   symbol2

Perubahan pada simbol ELF lainnya tidak dipertimbangkan. File daftar simbol dapat ditentukan dalam file konfigurasi build.config yang sesuai dengan build.config KMI_SYMBOL_LIST= sebagai file yang relatif terhadap direktori sumber kernel ( $KERNEL_DIR ). Untuk memberikan tingkat organisasi, Anda dapat menentukan file daftar simbol tambahan dengan menggunakan ADDITIONAL_KMI_SYMBOL_LISTS= dalam file build.config . Ini menentukan file daftar simbol lebih lanjut, relatif terhadap $KERNEL_DIR ; pisahkan beberapa nama file dengan spasi.

Untuk membuat daftar simbol awal atau memperbarui yang sudah ada , Anda harus menggunakan skrip build_abi.sh dengan parameter --update-symbol-list .

Ketika skrip dijalankan dengan konfigurasi yang sesuai, skrip akan membangun kernel dan mengekstrak simbol yang diekspor dari modul vmlinux dan GKI dan yang diperlukan oleh modul lain di pohon.

Pertimbangkan vmlinux mengekspor simbol berikut (biasanya dilakukan melalui makro EXPORT_SYMBOL* ):

  func1
  func2
  func3

Juga, bayangkan ada dua modul vendor, modA.ko dan modB.ko , yang memerlukan simbol berikut (dengan kata lain, mereka mencantumkan entri simbol yang undefined dalam tabel simbol mereka):

 modA.ko:    func1 func2
 modB.ko:    func2

Dari sudut pandang stabilitas ABI, func1 dan func2 harus tetap stabil, karena digunakan oleh modul eksternal. Sebaliknya, ketika func3 diekspor, func3 tidak digunakan secara aktif (dengan kata lain, tidak diperlukan) oleh modul apa pun. Jadi, daftar simbol hanya berisi func1 dan func2 .

Untuk membuat atau memperbarui daftar simbol yang ada, build_abi.sh harus dijalankan sebagai berikut:

BUILD_CONFIG=path/to/build.config.device build/build_abi.sh --update-symbol-list

Dalam contoh ini, build.config.device harus menyertakan beberapa opsi konfigurasi:

  • vmlinux harus ada dalam daftar FILES .
  • KMI_SYMBOL_LIST harus disetel dan diarahkan ke daftar simbol KMI untuk diperbarui.
  • GKI_MODULES_LIST harus disetel dan diarahkan ke daftar modul GKI. Jalur ini biasanya android/gki_aarch64_modules .

Bekerja dengan alat ABI tingkat lebih rendah

Sebagian besar pengguna hanya perlu menggunakan build_abi.sh . Dalam beberapa kasus, bekerja secara langsung dengan perangkat ABI tingkat lebih rendah mungkin diperlukan. Dua perintah yang digunakan oleh build_abi.sh , dump_abi dan diff_abi , tersedia untuk mengekstrak dan membandingkan file ABI. Lihat bagian berikut untuk penggunaannya.

Buat representasi ABI dari pohon kernel

Disediakan pohon kernel linux dengan vmlinux dan modul kernel yang dibangun, alat dump_abi membuat representasi ABI menggunakan alat ABI yang dipilih. Contoh permintaan terlihat seperti ini:

dump_abi --linux-tree path/to/out --out-file /path/to/abi.xml

File abi.xml berisi representasi ABI tekstual dari gabungan, ABI yang dapat diamati dari vmlinux dan modul kernel di direktori yang diberikan. File ini dapat digunakan untuk inspeksi manual, analisis lebih lanjut, atau sebagai file referensi untuk menegakkan stabilitas ABI.

Bandingkan representasi ABI

Representasi ABI yang dibuat oleh dump_abi dapat dibandingkan dengan diff_abi . Gunakan alat-abi yang sama untuk dump_abi dan diff_abi . Contoh permintaan terlihat seperti ini:

diff_abi --baseline abi1.xml --new abi2.xml --report report.out

Daftar laporan yang dihasilkan mendeteksi perubahan ABI yang memengaruhi KMI. File yang ditentukan sebagai baseline dan new adalah representasi ABI yang dikumpulkan dengan dump_abi . diff_abi menyebarkan kode keluar dari alat yang mendasarinya dan oleh karena itu mengembalikan nilai bukan nol ketika ABI yang dibandingkan tidak kompatibel.

Filter representasi dan simbol KMI

Untuk memfilter representasi yang dibuat dengan dump_abi atau untuk memfilter simbol yang dibandingkan dengan diff_abi , gunakan parameter --kmi-symbol-list , yang mengambil jalur ke file daftar simbol KMI:

dump_abi --linux-tree path/to/out --out-file /path/to/abi.xml --kmi-symbol-list /path/to/symbol_list_file

Bekerja dengan daftar simbol

KMI tidak menyertakan semua simbol di kernel atau bahkan semua dari 30.000+ simbol yang diekspor. Sebagai gantinya, simbol yang dapat digunakan oleh modul secara eksplisit terdaftar dalam satu set file daftar simbol yang dikelola secara publik di akar pohon kernel. Penyatuan semua simbol di semua file daftar simbol mendefinisikan kumpulan simbol KMI yang dipertahankan sebagai stabil. Contoh file daftar simbol adalah abi_gki_aarch64_db845c , yang menyatakan simbol yang diperlukan untuk DragonBoard 845c .

Hanya simbol yang tercantum dalam daftar simbol dan struktur serta definisi terkait yang dianggap sebagai bagian dari KMI. Anda dapat memposting perubahan ke daftar simbol Anda jika simbol yang Anda butuhkan tidak ada. Setelah antarmuka baru berada dalam daftar simbol, dan merupakan bagian dari deskripsi KMI, antarmuka tersebut dipertahankan sebagai stabil dan tidak boleh dihapus dari daftar simbol atau dimodifikasi setelah cabang dibekukan.

Setiap cabang kernel KMI Android Common Kernel (ACK) memiliki kumpulan daftar simbolnya sendiri. Tidak ada upaya yang dilakukan 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 mana yang harus dipantau stabilitasnya. Daftar simbol utama berisi simbol-simbol yang diperlukan oleh modul kernel GKI. Vendor diharapkan mengirimkan dan memperbarui daftar simbol tambahan untuk memastikan bahwa antarmuka yang mereka andalkan menjaga kompatibilitas ABI. Misalnya, untuk melihat daftar daftar simbol untuk android13-5.15 , lihat https://android.googlesource.com/kernel/common/+/refs/heads/android13-5.15/android

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 bersarang.

Saat KMI dibekukan, tidak ada perubahan yang diizinkan pada antarmuka KMI yang ada; mereka stabil. Namun, vendor bebas menambahkan simbol ke KMI kapan saja selama penambahan tersebut tidak mempengaruhi stabilitas ABI yang ada. Simbol yang baru ditambahkan dipertahankan stabil segera setelah dikutip oleh daftar simbol KMI. Simbol tidak boleh dihapus dari daftar kernel kecuali dapat dipastikan bahwa tidak ada perangkat yang pernah dikirimkan dengan ketergantungan pada simbol itu.

Anda dapat membuat daftar simbol KMI untuk perangkat menggunakan utilitas build/abi/extract_symbols , yang mengekstrak dependensi simbol dari artefak build *.ko . Utilitas ini menambahkan anotasi ke output dalam bentuk komentar, yang berguna dalam mengidentifikasi pengguna simbol. Saat mengirimkan daftar simbol ke ACK, menyimpan komentar ini sangat dianjurkan untuk memudahkan proses peninjauan. Untuk menghilangkan komentar, berikan --skip-module-grouping saat menjalankan skrip extract_symbols . Banyak mitra mengirimkan satu daftar simbol per ACK, tetapi ini bukan persyaratan yang sulit. Jika ini membantu pemeliharaan, Anda dapat mengirimkan beberapa daftar simbol.

Untuk bantuan dalam menyesuaikan daftar simbol dan menggunakan alat ABI tingkat tinggi dan rendah untuk debugging dan analisis mendetail, lihat Pemantauan ABI untuk Kernel Android .

Perpanjang KMI

Sementara simbol KMI dan struktur terkait dipertahankan sebagai stabil (berarti perubahan yang merusak antarmuka stabil dalam kernel dengan KMI beku tidak dapat diterima), kernel GKI tetap terbuka untuk ekstensi sehingga perangkat yang dikirim di akhir tahun tidak perlu tentukan semua dependensinya sebelum KMI dibekukan. Untuk memperluas KMI, Anda dapat menambahkan simbol baru ke KMI untuk fungsi kernel baru atau yang sudah ada, meskipun KMI dibekukan. Patch kernel baru juga diterima jika tidak merusak KMI.

Tentang kerusakan KMI

Kernel memiliki sumber dan biner dibangun berdasarkan sumber tersebut. Cabang kernel yang dipantau ABI termasuk abi.xml yang merupakan representasi dari GKI ABI saat ini. Setelah biner dibangun (biner kernel, vmlinux , Image plus modul kernel), file abi.xml dapat diekstraksi dari biner. Setiap perubahan yang dilakukan pada sumber kernel dapat mengubah biner dan mungkin juga mengubah abi.xml yang diekstraksi (file yang diekstraksi setelah menerapkan perubahan dan membangun kernel). Penganalisis AbiAnalyzer membandingkan dua file abi.xml semantik dan menetapkan label Lint-1 pada perubahan jika menemukan masalah.

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 5ed8f6292a53..f2ecb34c7645 100644
  --- a/include/linux/mm_types.h
  +++ b/include/linux/mm_types.h
  @@ -339,6 +339,7 @@ struct core_state {
   struct kioctx_table;
   struct mm_struct {
      struct {
  +       int dummy;
          struct vm_area_struct *mmap;            /* list of VMAs */
          struct rb_root mm_rb;
          u64 vmacache_seqnum;                   /* per-thread vmacache */

Saat Anda menjalankan build_abi.sh lagi dengan tambalan ini diterapkan, perkakas keluar dengan kode kesalahan bukan nol dan melaporkan perbedaan ABI yang mirip dengan ini:

 Leaf changes summary: 1 artifact changed
  Changed leaf types summary: 1 leaf type changed
  Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
  Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable

  'struct mm_struct at mm_types.h:372:1' changed:
    type size changed from 6848 to 6912 (in bits)
    there are data member changes:
  [...]

Perbedaan ABI terdeteksi pada waktu pembuatan

Alasan paling umum untuk kesalahan adalah ketika driver menggunakan simbol baru dari kernel yang tidak ada dalam daftar simbol mana pun.

Jika simbol tidak disertakan dalam daftar simbol ( android/abi_gki_aarch64 ), maka Anda harus terlebih dahulu memverifikasi bahwa itu diekspor dengan EXPORT_SYMBOL_GPL( symbol_name ) dan kemudian memperbarui representasi XML ABI dan daftar simbol. Misalnya, perubahan berikut menambahkan fitur FS Inkremental baru ke cabang android-12-5.10 , yang mencakup pembaruan daftar simbol dan representasi XML ABI.

Jika simbol diekspor (baik oleh Anda atau sebelumnya diekspor) tetapi tidak ada driver lain yang sedang menggunakannya, Anda mungkin mendapatkan kesalahan 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 Anda (lihat Memperbarui representasi ABI ). Untuk contoh memperbarui ABI XML dan daftar simbol di ACK, lihat aosp/1367601 .

Mengatasi kerusakan kernel ABI

Anda dapat menangani kerusakan ABI kernel dengan memfaktorkan ulang kode agar tidak mengubah ABI atau memperbarui representasi ABI . Gunakan bagan berikut untuk menentukan pendekatan terbaik untuk situasi Anda.

Bagan Alur Kerusakan ABI

Gambar 1. Resolusi kerusakan ABI

Refactor kode untuk menghindari perubahan ABI

Lakukan segala upaya untuk menghindari modifikasi ABI yang ada. Dalam banyak kasus, Anda dapat memfaktorkan ulang kode Anda untuk menghapus perubahan yang memengaruhi ABI.

  • Memfaktorkan ulang perubahan bidang struct. Jika perubahan mengubah ABI untuk fitur debug, tambahkan #ifdef di sekitar bidang (di struct dan referensi sumber) dan pastikan CONFIG yang digunakan untuk #ifdef dinonaktifkan untuk defconfig produksi dan gki_defconfig . Untuk contoh bagaimana konfigurasi debug dapat ditambahkan ke struct tanpa merusak ABI, lihat patchset ini .

  • Fitur refactoring untuk tidak mengubah kernel inti. Jika fitur baru perlu ditambahkan ke ACK untuk mendukung modul mitra, coba refactor bagian ABI dari perubahan untuk menghindari modifikasi kernel ABI. Untuk contoh penggunaan ABI kernel yang ada untuk menambahkan fungsionalitas tambahan tanpa mengubah ABI kernel, lihat aosp/1312213 .

Perbaiki ABI yang rusak di Android Gerrit

Jika Anda tidak dengan sengaja merusak kernel ABI, maka Anda perlu menyelidikinya, menggunakan panduan yang disediakan oleh alat pemantauan ABI. Penyebab paling umum kerusakan adalah fungsi yang ditambahkan atau dihapus, struktur data yang diubah, atau perubahan pada ABI yang disebabkan oleh penambahan opsi konfigurasi yang mengarah ke salah satu dari yang disebutkan di atas. Mulailah dengan mengatasi masalah yang ditemukan oleh alat.

Anda dapat mereproduksi pengujian ABI secara lokal dengan menjalankan perintah berikut dengan argumen yang sama yang akan Anda gunakan untuk menjalankan build/build.sh :

Ini adalah contoh perintah untuk kernel GKI:

BUILD_CONFIG=common/build.config.gki.aarch64 build/build_abi.sh

Tentang label Lint-1

Jika Anda mengunggah perubahan ke cabang yang berisi KMI yang dibekukan atau diselesaikan, perubahan tersebut harus melewati ABIAnalyzer untuk memastikan perubahan tidak memengaruhi ABI stabil dengan cara yang tidak kompatibel. Selama proses ini, ABIAnalyzer mencari laporan ABI yang dibuat selama build (build diperpanjang yang menjalankan build normal dan kemudian beberapa langkah ekstraksi dan perbandingan ABI. Jika ABIAnalyzer menemukan laporan yang tidak kosong, ia menetapkan label Lint-1 dan perubahan diblokir dari pengiriman hingga diselesaikan; hingga patchset menerima label Lint+1.

Perbarui ABI Kernel

Jika Anda perlu memperbarui representasi ABI kernel, maka Anda harus memperbarui file abi.xml yang sesuai di pohon sumber kernel. Cara paling mudah untuk melakukan ini adalah dengan menggunakan build/build_abi.sh seperti:

build/build_abi.sh --update --print-report

Gunakan argumen yang sama dengan yang Anda gunakan untuk menjalankan build/build.sh . Ini memperbarui abi.xml yang benar di pohon sumber dan mencetak perbedaan yang terdeteksi. Sebagai praktik, sertakan laporan tercetak (pendek) dalam pesan komit (setidaknya sebagian).

Perbarui representasi ABI

Jika memodifikasi ABI tidak dapat dihindari, maka kode Anda berubah dan XML ABI serta daftar simbol perlu diterapkan ke ACK. Agar Lint menghapus -1 dan tidak merusak kompatibilitas GKI, lakukan langkah-langkah berikut:

  1. Unggah perubahan kode ABI ke ACK .

  2. Perbarui file ACK ABI .

  3. Gabungkan perubahan kode Anda dan perubahan pembaruan ABI.

Unggah perubahan kode ABI ke ACK

Memperbarui ACK ABI tergantung pada jenis perubahan yang dilakukan.

  • Jika perubahan ABI terkait dengan fitur yang memengaruhi pengujian CTS atau VTS, perubahan tersebut biasanya dapat dipilih menjadi ACK apa adanya. Sebagai contoh:

  • Jika perubahan ABI adalah untuk fitur yang dapat dibagikan dengan ACK, perubahan itu dapat dipilih secara cermat menjadi ACK apa adanya. Misalnya, perubahan berikut tidak diperlukan untuk pengujian CTS atau VTS tetapi boleh dibagikan dengan ACK:

  • Jika perubahan ABI memperkenalkan fitur baru yang tidak perlu disertakan dalam ACK, Anda dapat memperkenalkan simbol ke ACK menggunakan rintisan seperti yang dijelaskan di bagian berikut.

Gunakan rintisan untuk ACK

Rintisan harus diperlukan hanya untuk perubahan kernel inti yang tidak menguntungkan ACK, seperti perubahan kinerja dan daya. Daftar berikut ini merinci contoh stub dan sebagian cherry-picks di ACK untuk GKI.

  • Rintisan fitur isolasi inti ( aosp/1284493 ). Fungsionalitas di ACK tidak diperlukan, tetapi simbol harus ada di ACK agar modul Anda dapat menggunakan simbol ini.

  • Simbol placeholder untuk modul vendor ( aosp/1288860 ).

  • Fitur pelacakan peristiwa mm per proses khusus ABI ( aosp/1288454 ). Patch asli dipilih untuk ACK dan kemudian dipangkas untuk menyertakan hanya perubahan yang diperlukan untuk menyelesaikan perbedaan ABI untuk task_struct dan mm_event_count . Tambalan ini juga memperbarui enum mm_event_type untuk memuat anggota terakhir.

  • Pilihan ceri parsial dari perubahan ABI struct termal yang membutuhkan lebih dari sekadar menambahkan bidang ABI baru.

    • Patch aosp/1255544 menyelesaikan perbedaan ABI antara kernel mitra dan ACK.

    • Patch aosp/1291018 memperbaiki masalah fungsional yang ditemukan selama pengujian GKI dari tambalan sebelumnya. Perbaikannya termasuk menginisialisasi struct parameter sensor untuk mendaftarkan beberapa zona termal ke satu sensor.

  • CONFIG_NL80211_TESTMODE Perubahan ABI ( aosp/1344321 ). Patch ini menambahkan perubahan struct yang diperlukan untuk ABI dan memastikan kolom tambahan tidak menyebabkan perbedaan fungsional, memungkinkan mitra untuk menyertakan CONFIG_NL80211_TESTMODE dalam kernel produksi mereka dan tetap mempertahankan kepatuhan GKI.

Perbarui file ACK ABI

Untuk memperbarui file ACK ABI:

  1. Unggah perubahan ABI dan tunggu untuk menerima Code-Review +2 untuk patchset.

  2. Perbarui file ACK ABI.

    cp partner kernel/android/abi_gki_aarch64_partner ACK kernel/abi_gki_aarch64_partner
    BUILD_CONFIG=common/build.config.gki.aarch64 build/build_abi.sh --update
    
  3. Lakukan pembaruan ABI:

    cd common
    git add android/abi*
    git commit -s -F $DIST_DIR/abi.report.short
    <push to gerrit>
    

    $DIST_DIR/abi.report.short berisi laporan singkat tentang perubahan. Menggunakan flag -F dengan git commit secara otomatis menggunakan laporan untuk teks komit, yang kemudian dapat Anda edit untuk menambahkan baris subjek (atau potong jika pesannya terlalu panjang).

Cabang Kernel Android dengan ABI yang telah ditentukan sebelumnya

Beberapa cabang kernel hadir dengan representasi ABI yang telah ditentukan sebelumnya untuk Android sebagai bagian dari distribusi sumbernya. Representasi ABI ini dimaksudkan agar akurat, dan untuk mencerminkan hasil build_abi.sh seolah-olah Anda akan menjalankannya sendiri. Karena ABI sangat dipengaruhi oleh berbagai opsi konfigurasi kernel, file .xml ini biasanya termasuk dalam konfigurasi tertentu. Misalnya, cabang common-android12-5.10 berisi abi_gki_aarch64.xml yang sesuai dengan hasil build saat menggunakan build.config.gki.aarch64 . Secara khusus, build.config.gki.aarch64 juga merujuk ke file ini melalui ABI_DEFINITION .

Representasi ABI yang telah ditentukan sebelumnya digunakan sebagai definisi dasar saat membandingkan dengan diff_abi . Misalnya, untuk memvalidasi patch kernel terkait perubahan apa pun pada ABI, buat representasi ABI dengan patch yang diterapkan dan gunakan diff_abi untuk membandingkannya dengan ABI yang diharapkan untuk struktur atau konfigurasi sumber tertentu. Jika ABI_DEFINITION disetel, menjalankan build_abi.sh akan berhasil.

Terapkan KMI saat runtime

Kernel GKI menggunakan opsi 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 yang terdaftar di daftar simbol. Semua simbol lain tidak diekspor, dan memuat modul yang membutuhkan simbol yang tidak diekspor ditolak. Pembatasan ini diberlakukan pada waktu pembuatan dan entri yang hilang ditandai.

Untuk tujuan pengembangan, Anda dapat menggunakan build kernel GKI yang tidak menyertakan pemangkasan simbol (artinya semua simbol yang biasanya diekspor dapat digunakan). Untuk menemukan build ini, cari build kernel_debug_aarch64 di ci.android.com .

Terapkan KMI menggunakan versi modul

Kernel Generic Kernel Image (GKI) menggunakan pembuatan versi modul ( CONFIG_MODVERSIONS ) sebagai tindakan tambahan untuk menerapkan kepatuhan KMI saat runtime. Pembuatan versi modul dapat menyebabkan kegagalan ketidakcocokan pemeriksaan redundansi siklik (CRC) pada waktu muat modul jika KMI modul yang diharapkan tidak cocok dengan KMI vmlinux . Misalnya, berikut ini adalah kegagalan umum yang terjadi pada waktu muat 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 versi modul

Pembuatan versi modul berguna karena alasan berikut:

  • Pembuatan versi modul menangkap 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, perhatikan bidang fwnode di struct device . Bidang ini HARUS buram untuk modul sehingga mereka tidak dapat membuat perubahan pada bidang device->fw_node atau membuat asumsi tentang ukurannya.

    Namun, jika sebuah modul menyertakan <linux/fwnode.h> (secara langsung atau tidak langsung), maka bidang fwnode di struct device tidak lagi buram. Modul kemudian dapat membuat perubahan pada device->fwnode->dev atau device->fwnode->ops . Skenario ini bermasalah karena beberapa alasan, dinyatakan sebagai berikut:

    • Itu dapat mematahkan asumsi yang dibuat oleh kode kernel inti tentang struktur data internalnya.

    • Jika pembaruan kernel di masa mendatang mengubah struct fwnode_handle (tipe data fwnode ), maka modul tidak lagi berfungsi dengan kernel baru. Selain itu, abidiff tidak akan menunjukkan perbedaan apa pun karena modul memecah 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 ketika dimuat di kemudian hari oleh kernel baru yang tidak kompatibel. Pembuatan versi modul menambahkan pemeriksaan waktu proses untuk menghindari secara tidak sengaja memuat modul yang tidak kompatibel dengan KMI dengan kernel. Pemeriksaan ini mencegah masalah runtime yang sulit di-debug dan crash kernel yang mungkin diakibatkan oleh ketidakcocokan yang tidak terdeteksi di KMI.

  • abidiff memiliki keterbatasan dalam mengidentifikasi perbedaan ABI dalam kasus berbelit-belit tertentu yang dapat ditangkap oleh CONFIG_MODVERSIONS .

Mengaktifkan pembuatan versi modul mencegah semua masalah ini.

Periksa ketidakcocokan CRC tanpa mem-boot perangkat

abidiff membandingkan dan melaporkan ketidakcocokan CRC antar kernel. Alat ini memungkinkan Anda untuk menangkap ketidakcocokan CRC pada saat yang sama dengan perbedaan ABI lainnya.

Selain itu, build kernel lengkap dengan CONFIG_MODVERSIONS diaktifkan 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, ruang nama 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 perbedaan CRC dalam simbol yang diekspor oleh vmlinux . Jika ada perbedaan nilai CRC dalam simbol apa pun yang diekspor oleh vmlinux dan simbol itu digunakan oleh salah satu modul yang Anda muat di perangkat Anda, modul tidak 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 pada kedua kernel dan membandingkan hasilnya:

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

Selesaikan ketidakcocokan CRC

Gunakan langkah-langkah berikut untuk mengatasi ketidakcocokan CRC saat memuat modul:

  1. Bangun kernel GKI dan kernel perangkat Anda dengan menambahkan KBUILD_SYMTYPES=1 ke perintah yang Anda gunakan untuk membangun kernel, seperti yang ditunjukkan pada perintah berikut:

    KBUILD_SYMTYPES=1 BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
    

    Perintah ini menghasilkan file .symtypes untuk setiap file .o . Saat menggunakan build_abi.sh, KBUILD_SYMTYPES=1 sudah ditetapkan secara implisit.

  2. Temukan file .c yang mengekspor simbol dengan ketidakcocokan CRC, menggunakan perintah berikut:

    cd common && git grep EXPORT_SYMBOL.*module_layout
    kernel/module.c:EXPORT_SYMBOL(module_layout);
    
  3. File .c memiliki file .symtypes yang sesuai di GKI, dan artefak build kernel perangkat Anda. Temukan file .c menggunakan perintah berikut:

    cd out/$BRANCH/common && ls -1 kernel/module.*
    kernel/module.o
    kernel/module.o.symversions
    kernel/module.symtypes
    

    Berikut ini adalah ciri-ciri file .c :

    • Format file .c adalah satu (berpotensi sangat panjang) baris per simbol.

    • [s|u|e|etc]# di awal baris berarti simbol bertipe data [struct|union|enum|etc] . Sebagai contoh:

      t#bool typedef _Bool bool
      
    • Awalan # yang hilang di awal baris menunjukkan bahwa simbol adalah fungsi. Sebagai contoh:

      find_module s#module * find_module ( const char * )
      
  4. Bandingkan kedua file dan perbaiki semua perbedaannya.

Kasus 1: Perbedaan karena visibilitas tipe data

Jika satu kernel menyimpan simbol atau tipe data buram ke modul dan kernel lainnya tidak, perbedaan itu muncul di antara file .symtypes dari dua kernel. File .symtypes dari salah satu kernel memiliki UNKNOWN untuk simbol dan file .symtypes dari kernel lain memiliki tampilan simbol atau tipe data yang diperluas.

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.symtypes untuk simbol itu, memperlihatkan perbedaan berikut:

 $ diff -u <GKI>/kernel/module.symtypes <your kernel>/kernel/module.symtypes
  --- <GKI>/kernel/module.symtypes
  +++ <your kernel>/kernel/module.symtypes
  @@ -334,12 +334,15 @@
  ...
  -s#fwnode_handle struct fwnode_handle { UNKNOWN }
  +s#fwnode_reference_args struct fwnode_reference_args { s#fwnode_handle * fwnode ; unsigned int nargs ; t#u64 args [ 8 ] ; }
  ...

Jika kernel Anda memiliki nilai UNKNOWN dan kernel GKI memiliki tampilan simbol yang diperluas (sangat tidak mungkin), maka gabungkan Kernel Umum Android terbaru ke dalam kernel Anda sehingga Anda menggunakan basis kernel GKI terbaru.

Dalam kebanyakan kasus, kernel GKI memiliki nilai UNKNOWN , tetapi kernel Anda memiliki detail simbol internal karena perubahan yang dilakukan pada kernel Anda. Ini karena salah satu file di kernel Anda menambahkan #include yang tidak ada di kernel GKI.

Untuk mengidentifikasi #include yang menyebabkan perbedaan, ikuti langkah-langkah berikut:

  1. Buka file header yang mendefinisikan simbol atau tipe data yang memiliki perbedaan ini. Misalnya, edit include/linux/fwnode.h untuk struct fwnode_handle .

  2. Tambahkan kode berikut di bagian atas file header:

    #ifdef CRC_CATCH
    #error "Included from here"
    #endif
    
  3. Dalam file .c modul yang memiliki ketidakcocokan CRC, tambahkan baris berikut sebagai baris pertama sebelum salah satu dari baris #include .

    #define CRC_CATCH 1
    
  4. Kompilasi modul Anda. Kesalahan waktu pembuatan yang dihasilkan menunjukkan rantai file header #include yang menyebabkan ketidakcocokan CRC ini. Sebagai 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 tautan dalam rantai #include ini disebabkan oleh perubahan yang dibuat di kernel Anda, yang tidak ada di kernel GKI.

  5. Identifikasi perubahannya, kembalikan ke kernel Anda atau unggah ke ACK dan gabungkan .

Kasus 2: Perbedaan karena perubahan tipe data

Jika ketidakcocokan CRC untuk simbol atau tipe data bukan karena perbedaan visibilitas, itu karena perubahan aktual (penambahan, penghapusan, atau perubahan) pada tipe data itu sendiri. Biasanya, abidiff menangkap ini, tetapi jika salah karena celah deteksi yang diketahui, mekanisme MODVERSIONS dapat menangkapnya.

Misalnya, membuat 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 itu, 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 struct 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 struct 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:

  1. Temukan definisi simbol dalam kode sumber (biasanya dalam file .h ).

    • Untuk perbedaan simbol sederhana antara kernel Anda dan kernel GKI, temukan komit dengan menjalankan perintah berikut:
    git blame
    
    • Untuk simbol yang dihapus (di mana simbol dihapus di pohon dan Anda juga ingin menghapusnya di pohon lain), Anda perlu menemukan perubahan yang menghapus baris. Gunakan perintah berikut di pohon tempat baris dihapus:
    git log -S "copy paste of deleted line/word" -- <file where it was deleted>
    
  2. Tinjau daftar komit yang dikembalikan untuk menemukan perubahan atau penghapusan. Komit pertama mungkin yang Anda cari. Jika tidak, buka daftar sampai Anda menemukan komit.

  3. Setelah Anda mengidentifikasi perubahan, kembalikan ke kernel Anda atau unggah ke ACK dan gabungkan .