คุณสามารถใช้เครื่องมือตรวจสอบอินเทอร์เฟซแบบไบนารีของแอปพลิเคชัน (ABI) ซึ่งมีอยู่ใน Android 11 ขึ้นไป เพื่อรักษาความเสถียรของ ABI ในเคอร์เนล
ของเคอร์เนล Android เครื่องมือจะรวบรวมและเปรียบเทียบการแสดง ABI
จากไบนารีของเคอร์เนลที่มีอยู่ (vmlinux
+ โมดูล GKI) การแสดง ABI เหล่านี้คือไฟล์ .stg
และรายการสัญลักษณ์ อินเทอร์เฟซที่การแสดงผลให้มุมมองเรียกว่าอินเทอร์เฟซโมดูลเคอร์เนล (KMI)
คุณสามารถใช้เครื่องมือเพื่อติดตามและลดผลกระทบจากการเปลี่ยนแปลง KMI ได้
เครื่องมือตรวจสอบ ABI ได้รับการพัฒนาใน AOSP
และใช้ STG (หรือ libabigail
ใน Android 13 และต่ำกว่า) เพื่อสร้างและเปรียบเทียบการแสดง
หน้านี้อธิบายเครื่องมือ กระบวนการรวบรวมและวิเคราะห์การแสดง ABI และการใช้การแสดงดังกล่าวเพื่อมอบความเสถียรให้กับ ABI ในเคอร์เนล หน้านี้ยังมีข้อมูลสำหรับการมีส่วนร่วมในการเปลี่ยนแปลง เคอร์เนลของ Android ด้วย
กระบวนการ
การวิเคราะห์ ABI ของเคอร์เนลต้องใช้หลายขั้นตอน ซึ่งส่วนใหญ่สามารถทำให้เป็นอัตโนมัติได้ ดังนี้
- สร้างเคอร์เนลและการแสดง ABI
- วิเคราะห์ความแตกต่างของ ABI ระหว่างบิลด์กับข้อมูลอ้างอิง
- อัปเดตการแสดง ABI (หากจำเป็น)
- ทำงานกับรายการสัญลักษณ์
วิธีการต่อไปนี้ใช้ได้กับเคอร์เนลที่คุณสร้างได้โดยใช้
เครื่องมือเชนที่รองรับ (เช่น เครื่องมือเชน Clang ที่สร้างไว้ล่วงหน้า) repo manifests
พร้อมใช้งานสำหรับสาขาเคอร์เนลทั่วไปของ Android ทั้งหมดและสำหรับเคอร์เนลเฉพาะอุปกรณ์หลายรายการ
โดยจะยืนยันว่ามีการใช้เครื่องมือที่ถูกต้องเมื่อคุณ
สร้างการกระจายเคอร์เนลเพื่อการวิเคราะห์
รายการสัญลักษณ์
KMI ไม่ได้รวมสัญลักษณ์ทั้งหมดในเคอร์เนล หรือแม้แต่สัญลักษณ์ที่ส่งออกทั้งหมดกว่า 30,000 รายการ
แต่สัญลักษณ์ที่โมดูลของผู้ให้บริการใช้ได้จะแสดงอย่างชัดเจนในชุดไฟล์รายการสัญลักษณ์ที่ดูแลจัดการแบบสาธารณะใน
โครงสร้างเคอร์เนล (gki/{ARCH}/symbols/*
หรือ android/abi_gki_{ARCH}_*
ใน Android 15
และเวอร์ชันที่ต่ำกว่า) การรวมสัญลักษณ์ทั้งหมดในไฟล์รายการสัญลักษณ์ทั้งหมด
จะกำหนดชุดสัญลักษณ์ KMI ที่ถือว่าเสถียร ตัวอย่างไฟล์รายการสัญลักษณ์
คือ
gki/aarch64/symbols/db845c
ซึ่งประกาศสัญลักษณ์ที่จำเป็นสำหรับ
DragonBoard 845c
เฉพาะสัญลักษณ์ที่แสดงในรายการสัญลักษณ์ รวมถึงโครงสร้างและคำจำกัดความที่เกี่ยวข้องเท่านั้นที่จะถือเป็นส่วนหนึ่งของ KMI คุณโพสต์การเปลี่ยนแปลงใน รายการสัญลักษณ์ได้หากไม่มีสัญลักษณ์ที่ต้องการ หลังจากที่อินเทอร์เฟซใหม่ปรากฏใน รายการสัญลักษณ์และเป็นส่วนหนึ่งของคำอธิบาย KMI แล้ว อินเทอร์เฟซเหล่านั้นจะได้รับการดูแลให้มีความเสถียร และต้องไม่ถูกนำออกจากรายการสัญลักษณ์หรือแก้ไขหลังจากที่สาขาถูก ตรึงไว้
แต่ละสาขาเคอร์เนล KMI ของ Android Common Kernel (ACK) จะมีชุดรายการสัญลักษณ์ของตัวเอง
ไม่มีการพยายามให้ความเสถียรของ ABI ระหว่างสาขาเคอร์เนล KMI ที่แตกต่างกัน
เช่น KMI สำหรับ android12-5.10
จะไม่ขึ้นอยู่กับ
KMI สำหรับ android13-5.10
เครื่องมือ ABI ใช้รายการสัญลักษณ์ KMI เพื่อจำกัดอินเทอร์เฟซที่ต้องตรวจสอบเพื่อ
ความเสถียร ผู้ให้บริการควรส่งและอัปเดตรายการสัญลักษณ์ของตนเองเพื่อ
ยืนยันว่าอินเทอร์เฟซที่ใช้ยังคงมีความเข้ากันได้ของ ABI เช่น หากต้องการดูรายการรายการสัญลักษณ์สำหรับเคอร์เนล android16-6.12
โปรดดูที่
https://android.googlesource.com/kernel/common/+/refs/heads/android16-6.12/gki/aarch64/symbols
รายการสัญลักษณ์ประกอบด้วยสัญลักษณ์ที่รายงานว่าจำเป็นสำหรับผู้ให้บริการหรืออุปกรณ์นั้นๆ รายการที่สมบูรณ์ซึ่งเครื่องมือใช้คือการรวมไฟล์รายการสัญลักษณ์ KMI ทั้งหมด เครื่องมือ ABI จะกำหนดรายละเอียดของแต่ละสัญลักษณ์ ซึ่งรวมถึง ลายเซ็นฟังก์ชันและโครงสร้างข้อมูลที่ซ้อนกัน
เมื่อ KMI หยุดทำงาน จะไม่อนุญาตให้เปลี่ยนแปลงอินเทอร์เฟซ KMI ที่มีอยู่ ซึ่งจะมีความเสถียร อย่างไรก็ตาม ผู้ให้บริการสามารถเพิ่มสัญลักษณ์ลงใน KMI ได้ทุกเมื่อ ตราบใดที่การเพิ่มดังกล่าวไม่ส่งผลต่อความเสถียรของ ABI ที่มีอยู่ ระบบจะรักษาความเสถียรของสัญลักษณ์ที่เพิ่มเข้ามาใหม่ ทันทีที่รายการสัญลักษณ์ KMI อ้างอิงถึง ไม่ควรนำสัญลักษณ์ออกจากรายการสำหรับเคอร์เนล เว้นแต่จะยืนยันได้ว่า ไม่มีอุปกรณ์ใดที่จัดส่งโดยมีสัญลักษณ์นั้นเป็นทรัพยากร Dependency
คุณสร้างรายการสัญลักษณ์ KMI สำหรับอุปกรณ์ได้โดยใช้คำสั่งจากวิธีทำงานกับรายการสัญลักษณ์ พาร์ทเนอร์หลายรายส่งรายการสัญลักษณ์ 1 รายการต่อ ACK แต่ก็ไม่ได้เป็นข้อกำหนดที่เข้มงวด หากช่วยในการบำรุงรักษา คุณสามารถส่งรายการสัญลักษณ์หลายรายการได้
ขยาย KMI
แม้ว่าสัญลักษณ์ KMI และโครงสร้างที่เกี่ยวข้องจะได้รับการดูแลให้มีความเสถียร (หมายความว่า การเปลี่ยนแปลงที่ทำให้อินเทอร์เฟซที่มีเสถียรภาพในเคอร์เนลที่มี KMI ที่หยุดการเปลี่ยนแปลงไม่สามารถ ยอมรับได้) แต่เคอร์เนล GKI ยังคงเปิดให้ขยายได้ เพื่อให้อุปกรณ์ที่จัดส่ง ในภายหลังของปีนี้ไม่จำเป็นต้องกำหนดการขึ้นต่อทั้งหมดก่อนที่ KMI จะ หยุดการเปลี่ยนแปลง หากต้องการขยาย KMI คุณสามารถเพิ่มสัญลักษณ์ใหม่ลงใน KMI สำหรับฟังก์ชันเคอร์เนลใหม่หรือฟังก์ชันเคอร์เนลที่มีอยู่ได้ แม้ว่า KMI จะถูกระงับก็ตาม นอกจากนี้ เราอาจยอมรับแพตช์เคอร์เนลใหม่ หากแพตช์ดังกล่าวไม่ทำให้ KMI เสียหาย
เกี่ยวกับการหยุดทำงานของ KMI
เคอร์เนลมีแหล่งที่มาและไบนารีสร้างขึ้นจากแหล่งที่มาเหล่านั้น
สาขาเคอร์เนลที่ ABI ตรวจสอบจะมีตัวแทน ABI ของ GKI ปัจจุบัน
ABI (ในรูปแบบของไฟล์ .stg
) หลังจากสร้างไบนารี (vmlinux
, Image
และ
โมดูล GKI) แล้ว คุณจะแยกการแสดง ABI ออกจาก
ไบนารีได้ การเปลี่ยนแปลงใดๆ ที่ทำกับไฟล์แหล่งที่มาของเคอร์เนลอาจส่งผลต่อไบนารี และส่งผลต่อ .stg
ที่แยกออกมาด้วย การวิเคราะห์การปฏิบัติตามข้อกำหนดของ ABI จะเปรียบเทียบไฟล์ที่คอมมิต .stg
กับไฟล์ที่แยกจากอาร์ติแฟกต์ของบิลด์ และติดป้ายกำกับ Lint-1 ให้กับการเปลี่ยนแปลงใน Gerrit หากพบความแตกต่างทางความหมาย
จัดการการหยุดทำงานของ ABI
ตัวอย่างเช่น แพตช์ต่อไปนี้ทำให้ ABI เสียหายอย่างเห็นได้ชัด
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.
เมื่อเรียกใช้ ABI ของบิลด์โดยใช้แพตช์นี้ เครื่องมือจะออกโดยมี รหัสข้อผิดพลาดที่ไม่ใช่ 0 และรายงานความแตกต่างของ ABI ที่คล้ายกับตัวอย่างต่อไปนี้
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
ตรวจพบความแตกต่างของ ABI ในเวลาบิลด์
สาเหตุที่พบบ่อยที่สุดของข้อผิดพลาดคือเมื่อไดรเวอร์ใช้สัญลักษณ์ใหม่จาก เคอร์เนลที่ไม่ได้อยู่ในรายการสัญลักษณ์ใดๆ
หากสัญลักษณ์ไม่ได้รวมอยู่ในรายการสัญลักษณ์ คุณต้องตรวจสอบก่อน
ว่าได้ส่งออกด้วย
EXPORT_SYMBOL_GPL(symbol_name)
แล้วจึงอัปเดต
รายการสัญลักษณ์และการแสดง ABI ตัวอย่างเช่น การเปลี่ยนแปลงต่อไปนี้จะเพิ่มฟีเจอร์ FS แบบเพิ่มใหม่ไปยังกิ่ง android-12-5.10
ซึ่งรวมถึงการอัปเดตรายการสัญลักษณ์และการแสดง ABI
- ตัวอย่างการเปลี่ยนแปลงฟีเจอร์อยู่ใน aosp/1345659
- ตัวอย่างรายการสัญลักษณ์อยู่ใน aosp/1346742
- ตัวอย่างการเปลี่ยนแปลงการแสดง ABI อยู่ใน aosp/1349377
หากส่งออกสัญลักษณ์ (ไม่ว่าคุณจะเป็นผู้ส่งออกหรือมีการส่งออกก่อนหน้านี้) แต่ไม่มี ไดรเวอร์อื่นใช้สัญลักษณ์ดังกล่าว คุณอาจได้รับข้อผิดพลาดในการสร้างที่คล้ายกับข้อความต่อไปนี้
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
หากต้องการแก้ไข ให้อัปเดตรายการสัญลักษณ์ KMI ทั้งในเคอร์เนลและ ACK (ดูอัปเดตการแสดง ABI) ดูตัวอย่าง การอัปเดตรายการสัญลักษณ์และการแสดง ABI ใน ACK ได้ที่ aosp/1367601
แก้ไขการหยุดทำงานของ ABI ของเคอร์เนล
คุณสามารถจัดการการหยุดทำงานของ ABI ของเคอร์เนลได้โดยปรับโครงสร้างโค้ดเพื่อไม่ให้เปลี่ยน ABI หรืออัปเดตการแสดง ABI ใช้แผนภูมิต่อไปนี้เพื่อกำหนดแนวทางที่ดีที่สุดสำหรับสถานการณ์ของคุณ
รูปที่ 1 การแก้ไขการหยุดทำงานของ ABI
ปรับโครงสร้างโค้ดเพื่อหลีกเลี่ยงการเปลี่ยนแปลง ABI
พยายามอย่างเต็มที่เพื่อหลีกเลี่ยงการแก้ไข ABI ที่มีอยู่ ในหลายกรณี คุณสามารถ ปรับโครงสร้างโค้ดเพื่อนำการเปลี่ยนแปลงที่ส่งผลต่อ ABI ออกได้
การปรับโครงสร้างการเปลี่ยนแปลงฟิลด์ struct หากการเปลี่ยนแปลงแก้ไข ABI สำหรับฟีเจอร์การแก้ไขข้อบกพร่อง ให้เพิ่ม
#ifdef
รอบฟิลด์ (ในโครงสร้างและแหล่งข้อมูลอ้างอิง) และตรวจสอบว่าได้ปิดใช้CONFIG
ที่ใช้สำหรับ#ifdef
สำหรับ defconfig ที่ใช้งานจริงและgki_defconfig
แล้ว ดูตัวอย่างวิธีเพิ่มการกำหนดค่าการแก้ไขข้อบกพร่อง ลงในโครงสร้างโดยไม่ทําให้ ABI เสียหายได้ที่ชุดแพตช์นี้การปรับโครงสร้างฟีเจอร์เพื่อไม่ให้เปลี่ยนแปลงเคอร์เนลหลัก หากต้องเพิ่มฟีเจอร์ใหม่ลงใน ACK เพื่อรองรับโมดูลพาร์ทเนอร์ ให้ลองรีแฟกเตอร์ส่วน ABI ของการเปลี่ยนแปลงเพื่อหลีกเลี่ยงการแก้ไข ABI ของเคอร์เนล ดูตัวอย่างการใช้ ABI ของเคอร์เนลที่มีอยู่เพื่อเพิ่มความสามารถโดยไม่ต้องเปลี่ยน ABI ของเคอร์เนลได้ที่ aosp/1312213
แก้ไข ABI ที่ใช้งานไม่ได้ใน Android Gerrit
หากไม่ได้ตั้งใจทำให้ ABI ของเคอร์เนลใช้งานไม่ได้ คุณจะต้องตรวจสอบ โดยใช้คำแนะนำที่ได้รับจากเครื่องมือตรวจสอบ ABI สาเหตุที่พบบ่อยที่สุด ที่ทำให้เกิดการหยุดทำงานคือโครงสร้างข้อมูลที่เปลี่ยนแปลงและการเปลี่ยนแปลง CRC ของสัญลักษณ์ที่เกี่ยวข้อง หรือเกิดจากการเปลี่ยนแปลงตัวเลือกการกำหนดค่าที่นำไปสู่สาเหตุที่กล่าวมาข้างต้น เริ่มต้นด้วยการแก้ไขปัญหาที่เครื่องมือพบ
คุณสามารถสร้างผลการค้นหา ABI ในเครื่องได้ โปรดดูสร้างเคอร์เนลและการแสดง ABI
เกี่ยวกับป้ายกำกับ Lint-1
หากคุณอัปโหลดการเปลี่ยนแปลงไปยังสาขาที่มี KMI ที่หยุดใช้งานหรือ KMI ที่เสร็จสมบูรณ์แล้ว การเปลี่ยนแปลงจะต้องผ่านการวิเคราะห์การปฏิบัติตามข้อกำหนดและความเข้ากันได้ของ ABI เพื่อให้มั่นใจว่าการเปลี่ยนแปลงในการแสดง ABI จะแสดงถึง ABI จริงและไม่มีความไม่เข้ากัน (การนำสัญลักษณ์ออกหรือการเปลี่ยนแปลงประเภท)
การวิเคราะห์ ABI แต่ละรายการเหล่านี้อาจตั้งป้ายกำกับ Lint-1 และการส่งการเปลี่ยนแปลงที่ถูกบล็อก จนกว่าปัญหาทั้งหมดจะได้รับการแก้ไขหรือมีการลบล้างป้ายกำกับ
อัปเดต ABI ของเคอร์เนล
หากหลีกเลี่ยงการแก้ไข ABI ไม่ได้ คุณต้องใช้การเปลี่ยนแปลงโค้ด การแสดง ABI และรายการสัญลักษณ์กับ ACK หากต้องการให้ Lint นำ -1 ออกและไม่ทำให้ความเข้ากันได้ของ GKI เสียหาย ให้ทำตามขั้นตอนต่อไปนี้
รอรับ Code-Review +2 สำหรับชุดแพตช์
ผสานรวมการเปลี่ยนแปลงโค้ดและการเปลี่ยนแปลงการอัปเดต ABI
อัปโหลดการเปลี่ยนแปลงโค้ด ABI ไปยัง ACK
การอัปเดต ACK ABI จะขึ้นอยู่กับประเภทของการเปลี่ยนแปลงที่ทำ
หากการเปลี่ยนแปลง ABI เกี่ยวข้องกับฟีเจอร์ที่ส่งผลต่อการทดสอบ CTS หรือ VTS โดยปกติแล้ว คุณสามารถเลือกการเปลี่ยนแปลงเพื่อ ACK ได้ตามเดิม ตัวอย่างเช่น
- aosp/1289677 จำเป็นต่อการทำงานของเสียง
- aosp/1295945 จำเป็นต่อการทำงานของ USB
หากการเปลี่ยนแปลง ABI เป็นฟีเจอร์ที่แชร์กับ ACK ได้ คุณสามารถเลือกการเปลี่ยนแปลงนั้นเพื่อนำไปใช้กับ ACK ได้โดยตรง ตัวอย่างเช่น การเปลี่ยนแปลงต่อไปนี้ไม่จำเป็นสำหรับการทดสอบ CTS หรือ VTS แต่แชร์กับ ACK ได้
- aosp/1250412 เป็นการเปลี่ยนแปลงฟีเจอร์ด้านความร้อน
- aosp/1288857
คือการเปลี่ยนแปลง
EXPORT_SYMBOL_GPL
หากการเปลี่ยนแปลง ABI ทำให้เกิดฟีเจอร์ใหม่ที่ไม่จำเป็นต้องรวมไว้ใน ACK คุณสามารถแนะนำสัญลักษณ์ไปยัง ACK โดยใช้ Stub ตามที่อธิบายไว้ในส่วนต่อไปนี้
ใช้ Stub สำหรับ ACK
โดยสแต็บจะต้องจำเป็นสำหรับการเปลี่ยนแปลงเคอร์เนลหลักเท่านั้น ซึ่งไม่เป็นประโยชน์ต่อ ACK เช่น การเปลี่ยนแปลงด้านประสิทธิภาพและพลังงาน รายการต่อไปนี้แสดงรายละเอียดตัวอย่าง ของ Stub และ Cherry-Pick บางส่วนใน ACK สำหรับ GKI
ฟีเจอร์ Core-isolate (aosp/1284493) ความสามารถใน ACK ไม่จำเป็น แต่ต้องมีสัญลักษณ์ใน ACK เพื่อให้โมดูลใช้สัญลักษณ์เหล่านี้ได้
สัญลักษณ์ตัวยึดตำแหน่งสำหรับโมดูลผู้ให้บริการ (aosp/1288860)
การเลือกเฉพาะ ABI ของ
mm
ฟีเจอร์การติดตามเหตุการณ์ (aosp/1288454) ต่อกระบวนการ เราได้เลือกแพตช์ต้นฉบับเพื่อ ACK แล้วตัดทอนให้เหลือเฉพาะ การเปลี่ยนแปลงที่จำเป็นเพื่อแก้ไขความแตกต่างของ ABI สำหรับtask_struct
และmm_event_count
นอกจากนี้ แพตช์นี้ยังอัปเดต enummm_event_type
ให้มีสมาชิกสุดท้ายด้วยการเลือกบางส่วนของการเปลี่ยนแปลง ABI โครงสร้างความร้อนที่ต้องใช้มากกว่าแค่ การเพิ่มฟิลด์ ABI ใหม่
แพตช์ aosp/1255544 แก้ไขความแตกต่างของ ABI ระหว่างเคอร์เนลของพาร์ทเนอร์กับ ACK
แพตช์ aosp/1291018 แก้ไขปัญหาด้านฟังก์ชันที่พบระหว่างการทดสอบ GKI ของแพตช์ก่อนหน้า การแก้ไขนี้รวมถึงการเริ่มต้นโครงสร้างพารามิเตอร์ของเซ็นเซอร์เพื่อลงทะเบียน โซนความร้อนหลายโซนกับเซ็นเซอร์เดียว
CONFIG_NL80211_TESTMODE
การเปลี่ยนแปลง ABI (aosp/1344321) แพตช์นี้ได้เพิ่มการเปลี่ยนแปลงโครงสร้างที่จำเป็นสำหรับ ABI และตรวจสอบว่าฟิลด์เพิ่มเติมไม่ได้ทำให้เกิดความแตกต่างในการทำงาน ซึ่งช่วยให้พาร์ทเนอร์สามารถรวมCONFIG_NL80211_TESTMODE
ไว้ในเคอร์เนลการผลิตและยังคงรักษาการปฏิบัติตามข้อกำหนดของ GKI ได้
บังคับใช้ KMI ที่รันไทม์
เคอร์เนล GKI ใช้ตัวเลือกการกำหนดค่า TRIM_UNUSED_KSYMS=y
และ UNUSED_KSYMS_WHITELIST=<union
of all symbol lists>
ซึ่งจำกัดสัญลักษณ์ที่ส่งออก
(เช่น สัญลักษณ์ที่ส่งออกโดยใช้ EXPORT_SYMBOL_GPL()
) ให้เฉพาะสัญลักษณ์ที่แสดงใน
รายการสัญลักษณ์ ส่วนสัญลักษณ์อื่นๆ ทั้งหมดจะไม่ได้ส่งออก และระบบจะปฏิเสธการโหลดโมดูลที่ต้องใช้สัญลักษณ์ที่ไม่ได้ส่งออก ข้อจำกัดนี้จะบังคับใช้ในเวลาที่สร้างและ
มีการแจ้งว่าไม่มีรายการ
เพื่อวัตถุประสงค์ในการพัฒนา คุณสามารถใช้บิลด์เคอร์เนล GKI ที่ไม่มีการ
ตัดแต่งสัญลักษณ์ (หมายความว่าสามารถใช้สัญลักษณ์ที่มักจะส่งออกทั้งหมดได้) หากต้องการค้นหา
บิลด์เหล่านี้ ให้มองหาบิลด์ kernel_debug_aarch64
ใน
ci.android.com
บังคับใช้ KMI โดยใช้การกำหนดเวอร์ชันของโมดูล
เคอร์เนล Generic Kernel Image (GKI) ใช้การกำหนดเวอร์ชันของโมดูล
(CONFIG_MODVERSIONS
) เป็นมาตรการเพิ่มเติมในการบังคับใช้การปฏิบัติตามข้อกำหนด KMI ที่
รันไทม์ การกำหนดเวอร์ชันของโมดูลอาจทำให้การตรวจสอบความซ้ำซ้อนแบบวนรอบ (CRC) ไม่ตรงกัน
ล้มเหลวในเวลาที่โหลดโมดูล หาก KMI ที่คาดไว้ของโมดูลไม่ตรงกับ
vmlinux
KMI ตัวอย่างเช่น ข้อผิดพลาดทั่วไปต่อไปนี้เกิดขึ้นในเวลาโหลดโมดูลเนื่องจาก CRC ไม่ตรงกันสำหรับสัญลักษณ์ 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 ''
การใช้การกำหนดเวอร์ชันโมดูล
การกำหนดเวอร์ชันของโมดูลมีประโยชน์ด้วยเหตุผลต่อไปนี้
การกำหนดเวอร์ชันของโมดูลจะตรวจจับการเปลี่ยนแปลงในระดับการมองเห็นของโครงสร้างข้อมูล หากโมดูล เปลี่ยนโครงสร้างข้อมูลแบบทึบ นั่นคือโครงสร้างข้อมูลที่ไม่ได้เป็นส่วนหนึ่งของ KMI โมดูลจะหยุดทำงานหลังจากการเปลี่ยนแปลงโครงสร้างในอนาคต
ตัวอย่างเช่น ลองพิจารณาฟิลด์
fwnode
ในstruct device
ฟิลด์นี้ต้องไม่โปร่งใสต่อโมดูลเพื่อไม่ให้โมดูลทำการเปลี่ยนแปลงฟิลด์ของdevice->fw_node
หรือคาดเดาขนาดของฟิลด์ได้อย่างไรก็ตาม หากโมดูลมี
<linux/fwnode.h>
(ทั้งทางตรงและทางอ้อม) ฟิลด์fwnode
ในstruct device
จะไม่ทึบแสงอีกต่อไป จากนั้นโมดูลจะทำการเปลี่ยนแปลงในdevice->fwnode->dev
หรือdevice->fwnode->ops
ได้ สถานการณ์นี้มีปัญหาด้วยเหตุผลหลายประการ ดังนี้ซึ่งอาจทำให้การคาดการณ์ของโค้ดเคอร์เนลหลักเกี่ยวกับโครงสร้างข้อมูลภายใน ไม่ถูกต้อง
หากการอัปเดตเคอร์เนลในอนาคตเปลี่ยน
struct fwnode_handle
(ประเภทข้อมูลของfwnode
) โมดูลจะใช้กับเคอร์เนลใหม่ไม่ได้อีกต่อไป นอกจากนี้stgdiff
จะไม่แสดงความแตกต่างใดๆ เนื่องจากโมดูลจะทําลาย KMI โดยการจัดการโครงสร้างข้อมูลภายในโดยตรงในลักษณะที่ ไม่สามารถจับได้โดยการตรวจสอบการแสดงไบนารีเท่านั้น
โมดูลปัจจุบันจะถือว่าไม่รองรับ KMI เมื่อมีการโหลดในภายหลัง โดยเคอร์เนลใหม่ที่ไม่รองรับ การกำหนดเวอร์ชันของโมดูลจะเพิ่มการตรวจสอบรันไทม์เพื่อ หลีกเลี่ยงการโหลดโมดูลที่ไม่ใช่ KMI โดยไม่ตั้งใจด้วยเคอร์เนล การตรวจสอบนี้ช่วยป้องกันปัญหาที่รันไทม์ซึ่งแก้ไขข้อบกพร่องได้ยากและเคอร์เนลขัดข้องที่อาจ เกิดจากความไม่เข้ากันใน KMI ที่ตรวจไม่พบ
การเปิดใช้การควบคุมเวอร์ชันของโมดูลจะช่วยป้องกันปัญหาเหล่านี้ทั้งหมด
ตรวจสอบ CRC ที่ไม่ตรงกันโดยไม่ต้องบูตอุปกรณ์
stgdiff
จะเปรียบเทียบและรายงานความไม่ตรงกันของ CRC ระหว่างเคอร์เนลพร้อมกับความแตกต่างอื่นๆ ของ
ABI
นอกจากนี้ การสร้างเคอร์เนลแบบเต็มที่เปิดใช้ CONFIG_MODVERSIONS
จะสร้างไฟล์
Module.symvers
เป็นส่วนหนึ่งของกระบวนการสร้างปกติ ไฟล์นี้มีบรรทัดเดียวสำหรับทุกสัญลักษณ์ที่เคอร์เนล (vmlinux
) และโมดูลส่งออก แต่ละบรรทัดประกอบด้วยค่า CRC, ชื่อสัญลักษณ์, เนมสเปซของสัญลักษณ์, vmlinux
หรือ
ชื่อโมดูลที่ส่งออกสัญลักษณ์ และประเภทการส่งออก (เช่น
EXPORT_SYMBOL
กับ EXPORT_SYMBOL_GPL
)
คุณสามารถเปรียบเทียบไฟล์ Module.symvers
ระหว่างบิลด์ GKI กับบิลด์ของคุณ
เพื่อตรวจสอบความแตกต่างของ CRC ในสัญลักษณ์ที่ส่งออกโดย vmlinux
หากค่า CRC ในสัญลักษณ์ใดก็ตามที่ส่งออกโดย vmlinux
และแตกต่างกัน และโมดูลที่คุณโหลดในอุปกรณ์ใช้สัญลักษณ์ดังกล่าว โมดูลจะไม่โหลด
หากไม่มีอาร์ติแฟกต์การสร้างทั้งหมด แต่มีไฟล์ vmlinux
ของ
เคอร์เนล GKI และเคอร์เนลของคุณ คุณสามารถเปรียบเทียบค่า CRC สำหรับสัญลักษณ์
ที่เฉพาะเจาะจงได้โดยการเรียกใช้คำสั่งต่อไปนี้ในทั้ง 2 เคอร์เนลและเปรียบเทียบ
เอาต์พุต
nm <path to vmlinux>/vmlinux | grep __crc_<symbol name>
ตัวอย่างเช่น คำสั่งต่อไปนี้จะตรวจสอบค่า CRC สำหรับสัญลักษณ์ module_layout
nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout
แก้ไข CRC ที่ไม่ตรงกัน
ทำตามขั้นตอนต่อไปนี้เพื่อแก้ไข CRC ไม่ตรงกันเมื่อโหลดโมดูล
สร้างเคอร์เนล GKI และเคอร์เนลของอุปกรณ์โดยใช้
--kbuild_symtypes
ตัวเลือกตามที่แสดงในคำสั่งต่อไปนี้tools/bazel run --kbuild_symtypes //common:kernel_aarch64_dist
คำสั่งนี้จะสร้างไฟล์
.symtypes
สำหรับไฟล์.o
แต่ละไฟล์ ดูรายละเอียดได้ที่KBUILD_SYMTYPES
ใน Kleafสำหรับ Android 13 และต่ำกว่า ให้สร้างเคอร์เนล GKI และเคอร์เนลของอุปกรณ์โดยการเพิ่ม
KBUILD_SYMTYPES=1
ไว้หน้าคำสั่งที่คุณ ใช้สร้างเคอร์เนล ดังที่แสดงในคำสั่งต่อไปนี้KBUILD_SYMTYPES=1 BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
เมื่อใช้
build_abi.sh,
ระบบจะตั้งค่าสถานะKBUILD_SYMTYPES=1
โดยปริยาย อยู่แล้วค้นหาไฟล์
.c
ที่ส่งออกสัญลักษณ์ที่มี CRC ไม่ตรงกันโดยใช้คำสั่งต่อไปนี้git -C common grep EXPORT_SYMBOL.*module_layout kernel/module/version.c:EXPORT_SYMBOL(module_layout);
ไฟล์
.c
มีไฟล์.symtypes
ที่เกี่ยวข้องใน GKI และ อาร์ติแฟกต์การสร้างเคอร์เนลของอุปกรณ์ ค้นหาไฟล์.symtypes
โดยใช้คำสั่งต่อไปนี้cd bazel-bin/common/kernel_aarch64/symtypes ls -1 kernel/module/version.symtypes
ใน Android 13 และต่ำกว่า เมื่อใช้สคริปต์บิลด์เดิม ตำแหน่งน่าจะอยู่ที่
out/$BRANCH/common
หรือout_abi/$BRANCH/common
.symtypes
ไฟล์แต่ละไฟล์เป็นไฟล์ข้อความธรรมดาที่ประกอบด้วยประเภทและคำอธิบายสัญลักษณ์แต่ละบรรทัดจะมีรูปแบบ
key description
โดยคำอธิบายสามารถ อ้างอิงคีย์อื่นๆ ในไฟล์เดียวกันได้คีย์ เช่น
[s|u|e|t]#foo
จะอ้างอิงถึง[struct|union|enum|typedef] foo
เช่นt#bool typedef _Bool bool
คีย์ที่ไม่มีคำนำหน้า
x#
จะเป็นเพียงชื่อสัญลักษณ์ เช่นfind_module s#module * find_module ( const char * )
เปรียบเทียบไฟล์ทั้ง 2 ไฟล์และแก้ไขความแตกต่างทั้งหมด
เราขอแนะนำให้สร้าง symtypes
ด้วยบิลด์ก่อนการเปลี่ยนแปลงที่ทำให้เกิดปัญหา
และในการเปลี่ยนแปลงที่ทำให้เกิดปัญหา การบันทึกไฟล์ทั้งหมดหมายความว่าคุณจะเปรียบเทียบไฟล์หลายไฟล์พร้อมกันได้
ตัวอย่างเช่น
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
หรือจะเปรียบเทียบเฉพาะไฟล์ที่สนใจก็ได้
กรณีที่ 1: ความแตกต่างเนื่องจากระดับการมองเห็นของประเภทข้อมูล
#include
ใหม่สามารถดึงคำจำกัดความประเภทใหม่ (เช่น ของ struct foo
) ลงในไฟล์ต้นฉบับได้ ในกรณีเหล่านี้ คำอธิบายในไฟล์ .symtypes
ที่เกี่ยวข้อง
จะเปลี่ยนจาก structure_type foo { }
ที่ว่างเปล่าเป็นคำจำกัดความแบบเต็ม
ซึ่งจะส่งผลต่อ CRC ทั้งหมดของสัญลักษณ์ทั้งหมดในไฟล์ .symtypes
ซึ่งคำอธิบาย
ขึ้นอยู่กับคำจำกัดความของประเภทโดยตรงหรือโดยอ้อม
เช่น การเพิ่มบรรทัดต่อไปนี้ลงในไฟล์
include/linux/device.h
ในเคอร์เนลจะทำให้เกิดความไม่ตรงกันของ CRC ซึ่งหนึ่งในนั้น
คือสำหรับ module_layout()
#include <linux/fwnode.h>
การเปรียบเทียบ module/version.symtypes
สำหรับสัญลักษณ์นั้นจะแสดงความแตกต่างต่อไปนี้
$ 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 ] ; }
...
หากเคอร์เนล GKI มีคำจำกัดความประเภทแบบเต็ม แต่เคอร์เนลของคุณไม่มีคำจำกัดความดังกล่าว (ไม่น่าเป็นไปได้) ให้ผสานรวม Android Common Kernel เวอร์ชันล่าสุดเข้ากับเคอร์เนลของคุณเพื่อให้ คุณใช้ฐานเคอร์เนล GKI เวอร์ชันล่าสุด
ในกรณีส่วนใหญ่ เคอร์เนล GKI จะไม่มีคำจำกัดความประเภทแบบเต็มใน
.symtypes
แต่เคอร์เนลของคุณมีเนื่องจากมีคำสั่ง #include
เพิ่มเติม
ความละเอียดสำหรับ Android 16 ขึ้นไป
ตรวจสอบว่าไฟล์ต้นทางที่ได้รับผลกระทบมีส่วนหัวการคงที่ของ KABI ของ Android
#include <linux/android_kabi.h>
สำหรับแต่ละประเภทที่ได้รับผลกระทบ ให้เพิ่ม ANDROID_KABI_DECLONLY(name);
ที่ขอบเขตส่วนกลางลงใน
ไฟล์ต้นฉบับที่ได้รับผลกระทบ
เช่น หากsymtypes
Diff เป็นดังนี้
--- 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)
จากนั้นปัญหาคือตอนนี้ struct ubuf_info
มีคำจำกัดความที่สมบูรณ์ใน
symtypes
วิธีแก้ปัญหาคือการเพิ่มบรรทัดใน drivers/android/vendor_hooks.c
ดังนี้
ANDROID_KABI_DECLONLY(ubuf_info);
ซึ่งจะสั่งให้ gendwarfksyms
ถือว่าประเภทที่ระบุชื่อเป็นประเภทที่ไม่ได้กำหนดไว้ในไฟล์
ความเป็นไปได้ที่ซับซ้อนกว่านั้นคือ #include
ใหม่เองอยู่ในไฟล์ส่วนหัว ในกรณีนี้ คุณอาจต้องกระจายชุดการเรียกใช้มาโคร ANDROID_KABI_DECLONLY
ที่แตกต่างกันในไฟล์ต้นฉบับที่ดึงคำจำกัดความของประเภทเพิ่มเติมโดยอ้อม เนื่องจากบางไฟล์อาจมีคำจำกัดความของประเภทอยู่แล้ว
วางการเรียกใช้มาโครดังกล่าวไว้ใกล้กับจุดเริ่มต้นของไฟล์ต้นฉบับเพื่อให้อ่านง่าย
ความละเอียดสำหรับ Android 15 และต่ำกว่า
โดยส่วนใหญ่แล้ว วิธีแก้ปัญหาคือการซ่อน #include
ใหม่จาก genksyms
#ifndef __GENKSYMS__
#include <linux/fwnode.h>
#endif
หรือหากต้องการระบุ #include
ที่ทำให้เกิดความแตกต่าง ให้ทำตามขั้นตอนต่อไปนี้
เปิดไฟล์ส่วนหัวที่กำหนดสัญลักษณ์หรือประเภทข้อมูลที่มีความแตกต่างนี้ เช่น แก้ไข
include/linux/fwnode.h
สำหรับstruct fwnode_handle
เพิ่มโค้ดต่อไปนี้ที่ด้านบนของไฟล์ส่วนหัว
#ifdef CRC_CATCH #error "Included from here" #endif
ในไฟล์
.c
ของโมดูลที่มี CRC ไม่ตรงกัน ให้เพิ่ม รายการต่อไปนี้เป็นบรรทัดแรกก่อนบรรทัด#include
ใดๆ#define CRC_CATCH 1
คอมไพล์โมดูล ข้อผิดพลาดที่เกิดขึ้นในเวลาบิลด์จะแสดงห่วงโซ่ของ ไฟล์ส่วนหัว
#include
ที่ทำให้เกิด CRC ไม่ตรงกันนี้ เช่น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"
ลิงก์หนึ่งในเชนของ
#include
เกิดจากการเปลี่ยนแปลงในเคอร์เนลของคุณ ซึ่งไม่มีในเคอร์เนล GKI
กรณีที่ 2: ความแตกต่างเนื่องจากการเปลี่ยนแปลงประเภทข้อมูล
หาก CRC ไม่ตรงกันสำหรับสัญลักษณ์หรือประเภทข้อมูลไม่ได้เกิดจากความแตกต่างใน ระดับการมองเห็น แสดงว่าเกิดจากการเปลี่ยนแปลงจริง (การเพิ่ม การนำออก หรือการเปลี่ยนแปลง) ใน ประเภทข้อมูลนั้นๆ
ตัวอย่างเช่น การเปลี่ยนแปลงต่อไปนี้ในเคอร์เนลจะทำให้เกิดความไม่ตรงกันของ CRC หลายรายการ เนื่องจากสัญลักษณ์จำนวนมากได้รับผลกระทบทางอ้อมจากการเปลี่ยนแปลงประเภทนี้
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);
CRC ที่ไม่ตรงกัน 1 รายการคือ devm_of_platform_populate()
หากคุณเปรียบเทียบไฟล์ .symtypes
สำหรับสัญลักษณ์นั้น อาจมีลักษณะดังนี้
$ 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 * ) ; ...
หากต้องการระบุประเภทที่เปลี่ยนแปลง ให้ทำตามขั้นตอนต่อไปนี้
ค้นหาคำจำกัดความของสัญลักษณ์ในซอร์สโค้ด (มักอยู่ในไฟล์
.h
)- หากต้องการดูความแตกต่างของสัญลักษณ์ระหว่างเคอร์เนลของคุณกับเคอร์เนล GKI ให้ค้นหาคอมมิตโดยเรียกใช้คำสั่งต่อไปนี้
git blame
- สำหรับสัญลักษณ์ที่ถูกลบ (ในกรณีที่สัญลักษณ์ถูกลบในแผนผังหนึ่งและคุณต้องการลบสัญลักษณ์นั้นในแผนผังอื่นด้วย) คุณต้องค้นหาการเปลี่ยนแปลงที่ลบบรรทัด ใช้คำสั่งต่อไปนี้ในทรีที่บรรทัด ถูกลบ
git log -S "copy paste of deleted line/word" -- <file where it was deleted>
ตรวจสอบรายการคอมมิตที่แสดงเพื่อค้นหาการเปลี่ยนแปลงหรือการลบ คอมมิตแรกอาจเป็นคอมมิตที่คุณกำลังค้นหา หากไม่พบ ให้เลื่อนดูรายการจนกว่าจะพบคอมมิต
หลังจากระบุการคอมมิตแล้ว ให้ย้อนกลับในเคอร์เนลหรืออัปเดต เพื่อไม่ให้มีการเปลี่ยนแปลง CRC แล้วอัปโหลดไปยัง ACK และรับการผสาน การเปลี่ยนแปลง ABI ที่เหลือแต่ละรายการจะต้องได้รับการตรวจสอบเพื่อความปลอดภัย และหากจำเป็น จะบันทึกการเปลี่ยนแปลงที่อนุญาตได้
ต้องการใช้ระยะเว้นที่มีอยู่
โครงสร้างบางอย่างใน GKI มีการเพิ่มพื้นที่ว่างเพื่อให้ขยายได้โดยไม่ทำให้โมดูลของผู้ให้บริการที่มีอยู่เสียหาย หากคอมมิตต้นทาง (เช่น) เพิ่มสมาชิกไปยัง โครงสร้างดังกล่าว คุณอาจเปลี่ยนให้ใช้ การเว้นวรรคแทนได้ จากนั้นระบบจะซ่อนการเปลี่ยนแปลงนี้จากการคำนวณ CRC
มาโครที่ได้มาตรฐานและสร้างเอกสารด้วยตนเอง ANDROID_KABI_RESERVE
จะจองพื้นที่ (ที่สอดคล้องกัน) มูลค่า u64
โดยใช้แทนการประกาศความเป็นสมาชิก
เช่น
struct data {
u64 handle;
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
};
สามารถใช้ Padding ได้โดยไม่ส่งผลต่อ CRC ของสัญลักษณ์ด้วย ANDROID_KABI_USE
(หรือ ANDROID_KABI_USE2
หรือตัวแปรอื่นๆ ที่อาจกำหนดไว้)
สมาชิก sekret
จะพร้อมใช้งานราวกับว่ามีการประกาศโดยตรง แต่มาโครจะขยายเป็นสมาชิกสหภาพที่ไม่ระบุชื่อซึ่งมี sekret
รวมถึง
สิ่งต่างๆ ที่ gendwarfksyms
ใช้เพื่อรักษาความเสถียรของ symtype
struct data {
u64 handle;
ANDROID_KABI_USE(1, void *sekret);
ANDROID_KABI_RESERVE(2);
};
ความละเอียดสำหรับ Android 16 ขึ้นไป
gendwarfksyms
จะคำนวณ CRC โดยใช้ข้อมูลการแก้ไขข้อบกพร่อง DWARF
จึงรองรับทั้งประเภท C และ Rust ความละเอียดจะแตกต่างกันไปตามประเภท
ของการเปลี่ยนแปลง ต่อไปนี้เป็นตัวอย่างบางส่วน
ผู้แจงนับใหม่หรือผู้แจงนับที่แก้ไข
บางครั้งระบบจะเพิ่มค่าแจงนับใหม่ และบางครั้งค่าแจงนับ MAX
หรือค่าที่คล้ายกัน
ก็จะได้รับผลกระทบด้วย การเปลี่ยนแปลงเหล่านี้จะปลอดภัยหากไม่ได้ "หลุด"
ออกจาก GKI หรือหากเรามั่นใจว่าโมดูลของผู้ให้บริการจะไม่สนใจค่าของโมดูล
เช่น
enum outcome {
SUCCESS,
FAILURE,
RETRY,
+ TRY_HARDER,
OUTCOME_LIMIT
};
การเพิ่ม TRY_HARDER
และการเปลี่ยนเป็น OUTCOME_LIMIT
สามารถซ่อนจากการคำนวณ CRC ด้วยการเรียกใช้มาโครที่ขอบเขตส่วนกลางได้โดยทำดังนี้
ANDROID_KABI_ENUMERATOR_IGNORE(outcome, TRY_HARDER);
ANDROID_KABI_ENUMERATOR_VALUE(outcome, OUTCOME_LIMIT, 3);
เพื่อให้อ่านง่าย ให้วางไว้หลังคำจำกัดความของ enum
สมาชิกโครงสร้างใหม่ที่เข้ามาแทนที่ตำแหน่งเดิม
เนื่องจากการจัดแนว จะมีไบต์ที่ไม่ได้ใช้ระหว่าง urgent
กับ scratch
void *data;
bool urgent;
+ bool retry;
void *scratch;
การเพิ่ม retry
จะไม่ส่งผลต่อออฟเซ็ตของสมาชิกที่มีอยู่หรือขนาดของโครงสร้าง แต่การดำเนินการนี้อาจส่งผลต่อ CRC ของสัญลักษณ์หรือการแสดง ABI หรือทั้ง 2 อย่าง
การดำเนินการนี้จะซ่อนจาก CRC Calculation
void *data;
bool urgent;
+ ANDROID_KABI_IGNORE(1, bool retry);
void *scratch_space;
สมาชิก retry
จะพร้อมใช้งานราวกับว่ามีการประกาศโดยตรง แต่มาโครจะขยายเป็นสมาชิกสหภาพที่ไม่ระบุชื่อซึ่งมี retry
รวมถึง
สิ่งต่างๆ ที่ gendwarfksyms
ใช้เพื่อรักษาความเสถียรของ symtype
การขยายโครงสร้างด้วยสมาชิกใหม่
บางครั้งระบบจะเพิ่มสมาชิกไว้ท้ายโครงสร้าง การดำเนินการนี้จะไม่ส่งผลต่อ ออฟเซ็ตของสมาชิกที่มีอยู่ หรือส่งผลต่อผู้ใช้ที่มีอยู่ของโครงสร้างที่ เข้าถึงได้โดยใช้พอยน์เตอร์เท่านั้น ขนาดของโครงสร้างมีผลต่อ CRC และการเปลี่ยนแปลงใน ส่วนนี้สามารถระงับได้ด้วยการเรียกใช้มาโครเพิ่มเติมที่ขอบเขตส่วนกลาง ดังนี้
struct data {
u64 handle;
u64 counter;
ANDROID_KABI_IGNORE(1, void *sekret);
};
ANDROID_KABI_BYTE_SIZE(data, 16);
เพื่อให้อ่านง่าย ให้วางไว้หลังคำจำกัดความ struct
การเปลี่ยนแปลงอื่นๆ ทั้งหมดในประเภทหรือประเภทของสัญลักษณ์
ในบางครั้งอาจมีการเปลี่ยนแปลงที่ไม่ได้อยู่ในหมวดหมู่ใดหมวดหมู่หนึ่งก่อนหน้า ซึ่งส่งผลให้เกิดการเปลี่ยนแปลง CRC ที่ไม่สามารถระงับได้โดยใช้ มาโครก่อนหน้า
ในกรณีเหล่านี้ คุณสามารถระบุsymtypes
คำอธิบายเดิมของประเภทหรือสัญลักษณ์ANDROID_KABI_TYPE_STRING
พร้อมการเรียกใช้ที่ขอบเขตส่วนกลางได้
struct data {
/* extensive changes */
};
ANDROID_KABI_TYPE_STRING("s#data", "original s#data symtypes definition");
เพื่อให้อ่านง่าย ให้วางไว้หลังคำจำกัดความประเภทหรือสัญลักษณ์
ความละเอียดสำหรับ Android 15 และต่ำกว่า
การเปลี่ยนแปลงประเภทและประเภทสัญลักษณ์ต้องซ่อนจาก genksyms
ซึ่งทำได้โดย
ควบคุมการประมวลผลล่วงหน้าด้วย __GENKSYMS__
การแปลงโค้ดที่กำหนดเองสามารถแสดงได้ด้วยวิธีนี้
ตัวอย่างเช่น หากต้องการซ่อนสมาชิกใหม่ที่เข้ามาแทนที่ตำแหน่งที่ว่างในโครงสร้างที่มีอยู่ ให้ทำดังนี้
struct parcel {
void *data;
bool urgent;
#ifndef __GENKSYMS__
bool retry;
#endif
void *scratch_space;
};