Android के कर्नेल में मौजूद एबीआई को स्थिर करने के लिए, ऐप्लिकेशन बाइनरी इंटरफ़ेस (एबीआई) मॉनिटरिंग टूल का इस्तेमाल किया जा सकता है. यह टूल, Android 11 और इसके बाद के वर्शन में उपलब्ध है. टूल, मौजूदा कर्नेल बाइनरी (vmlinux
+ GKI मॉड्यूल) से एबीआई के रिप्रज़ेंटेशन इकट्ठा करता है और उनकी तुलना करता है. एबीआई के ये प्रतिनिधित्व, .stg
फ़ाइलें और सिंबल की सूचियां हैं. जिस इंटरफ़ेस पर डेटा दिखाया जाता है उसे कर्नेल मॉड्यूल इंटरफ़ेस (केएमआई) कहा जाता है. KMI में होने वाले बदलावों को ट्रैक करने और उन्हें कम करने के लिए, टूल का इस्तेमाल किया जा सकता है.
एबीआई मॉनिटरिंग टूल को AOSP में डेवलप किया गया है. साथ ही, यह STG (या Android 13 और उससे पहले के वर्शन में libabigail
) का इस्तेमाल करके, रिप्रज़ेंटेशन जनरेट करता है और उनकी तुलना करता है.
इस पेज पर टूल, एबीआई के रिप्रज़ेंटेशन को इकट्ठा करने और उनका विश्लेषण करने की प्रोसेस, और इन-कर्नल एबीआई को स्थिरता देने के लिए, ऐसे रिप्रज़ेंटेशन के इस्तेमाल के बारे में बताया गया है. इस पेज पर, Android के कर्नेल में बदलाव करने के बारे में भी जानकारी दी गई है.
प्रोसेस
कर्नेल के एबीआई का विश्लेषण करने के लिए कई चरण पूरे करने होते हैं. इनमें से ज़्यादातर चरण अपने-आप पूरे हो सकते हैं:
- कर्नल और उसके एबीआई का प्रतिनिधित्व बनाएं.
- बिल्ड और रेफ़रंस के बीच एबीआई के अंतर का विश्लेषण करें.
- अगर ज़रूरी हो, तो एबीआई का प्रतिनिधित्व अपडेट करें.
- सिंबल की सूचियों के साथ काम करना.
नीचे दिए गए निर्देश, काम करने वाले टूलचेन का इस्तेमाल करके, बिल्ड किए जा सकने वाले किसी भी कर्नेल के लिए काम करते हैं. जैसे, पहले से बने Clang टूलचेन. repo manifests
सभी Android सामान्य कर्नेल ब्रांच और कई डिवाइस के हिसाब से बने कर्नेल के लिए उपलब्ध हैं. इनसे यह पक्का होता है कि विश्लेषण के लिए कर्नेल डिस्ट्रिब्यूशन बनाते समय, सही टूलचेन का इस्तेमाल किया जाए.
सिंबल की सूचियां
KMI में, कर्नेल के सभी सिंबल या एक्सपोर्ट किए गए 30,000 से ज़्यादा सिंबल शामिल नहीं होते. इसके बजाय, वेंडर मॉड्यूल के ज़रिए इस्तेमाल किए जा सकने वाले सिंबल, सिंबल की सूची वाली फ़ाइलों के सेट में साफ़ तौर पर शामिल किए जाते हैं. इन फ़ाइलों को कर्नेल ट्री (Android 15 और उससे पहले के वर्शन में gki/{ARCH}/symbols/*
या android/abi_gki_{ARCH}_*
) में सार्वजनिक तौर पर रखा जाता है. सभी सिंबल की सूची वाली फ़ाइलों में मौजूद सभी सिंबल का यूनियन, स्थिर के तौर पर बनाए गए KMI सिंबल के सेट को तय करता है. सिंबल की सूची वाली फ़ाइल का उदाहरण, gki/aarch64/symbols/db845c
है. इसमें DragonBoard 845c के लिए ज़रूरी सिंबल की जानकारी दी गई है.
सिर्फ़ सिंबल की सूची में शामिल सिंबल और उनसे जुड़े स्ट्रक्चर और परिभाषाओं को केएमआई का हिस्सा माना जाता है. अगर आपको ज़रूरी सिंबल नहीं मिल रहे हैं, तो अपनी सिंबल सूचियों में बदलाव किए जा सकते हैं. नए इंटरफ़ेस, सिंबल की सूची में शामिल होने और केएमआई के ब्यौरे का हिस्सा बनने के बाद, उन्हें स्थिर के तौर पर बनाए रखा जाता है. साथ ही, शाखा को फ़्रीज़ करने के बाद, उन्हें सिंबल की सूची से नहीं हटाया जाना चाहिए या उनमें बदलाव नहीं किया जाना चाहिए.
Android Common Kernel (ACK) KMI kernel की हर शाखा में, सिंबल सूचियों का अपना सेट होता है. अलग-अलग KMI कर्नेल ब्रैंच के बीच एबीआई को स्थिर रखने की कोशिश नहीं की जाती. उदाहरण के लिए, android12-5.10
के लिए केएमआई, android13-5.10
के लिए केएमआई से पूरी तरह अलग होता है.
ABI टूल, KMI सिंबल की सूचियों का इस्तेमाल करके यह तय करते हैं कि किन इंटरफ़ेस को स्थिरता के लिए मॉनिटर किया जाना चाहिए. वेंडर को अपनी सिंबल सूचियां सबमिट और अपडेट करनी चाहिए, ताकि यह पक्का किया जा सके कि वे इंटरफ़ेस जिन पर वे भरोसा करते हैं वे एबीआई के साथ काम करते रहें. उदाहरण के लिए, android16-6.12
कर्नेल के लिए सिंबल की सूची देखने के लिए, https://android.googlesource.com/kernel/common/+/refs/heads/android16-6.12/gki/aarch64/symbols
देखें
सिंबल की सूची में वे सिंबल शामिल होते हैं जिनकी किसी खास वेंडर या डिवाइस के लिए ज़रूरत होती है. टूल में इस्तेमाल की जाने वाली पूरी सूची, सभी के यूनियन के तौर पर काम करती है KMI सिंबल की सूची वाली फ़ाइलें. एबीआई टूल, हर सिंबल की जानकारी तय करते हैं. इसमें फ़ंक्शन हस्ताक्षर और नेस्ट किए गए डेटा स्ट्रक्चर भी शामिल हैं.
KMI फ़्रीज़ होने पर, मौजूदा KMI इंटरफ़ेस में कोई बदलाव नहीं किया जा सकता. ये इंटरफ़ेस स्थिर होते हैं. हालांकि, वेंडर के पास किसी भी समय केएमआई में सिंबल जोड़ने का विकल्प होता है. ऐसा तब तक किया जा सकता है, जब तक कि इससे मौजूदा एबीआई की स्थिरता पर असर न पड़े. जोड़े गए नए चिह्नों को, KMI के चिह्न की सूची में शामिल करने के बाद, स्थिर माना जाता है. किसी कर्नेल की सूची से सिंबल तब तक नहीं हटाए जाने चाहिए, जब तक यह पुष्टि न हो जाए कि किसी भी डिवाइस को कभी भी उस सिंबल पर निर्भर करके शिप नहीं किया गया है.
सिंबल की सूचियों के साथ काम करने का तरीका में दिए गए निर्देशों का इस्तेमाल करके, किसी डिवाइस के लिए केएमआई सिंबल की सूची जनरेट की जा सकती है. कई पार्टनर हर ACK के लिए एक सिंबल सूची सबमिट करते हैं, लेकिन यह ज़रूरी नहीं है. अगर इससे रखरखाव में मदद मिलती है, तो एक से ज़्यादा सिंबल की सूचियां सबमिट की जा सकती हैं.
केएमआई को बढ़ाना
KMI सिंबल और उससे जुड़े स्ट्रक्चर को स्थिर रखा जाता है. इसका मतलब है कि फ़्रीज़ किए गए KMI वाले कर्नेल में, स्थिर इंटरफ़ेस को तोड़ने वाले बदलावों को स्वीकार नहीं किया जा सकता. हालांकि, GKI कर्नेल में एक्सटेंशन जोड़े जा सकते हैं, ताकि साल के आखिर में शिप होने वाले डिवाइसों को KMI के फ़्रीज़ होने से पहले, अपनी सभी डिपेंडेंसी तय करने की ज़रूरत न पड़े. KMI को बड़ा करने के लिए, नए या मौजूदा एक्सपोर्ट किए गए कर्नेल फ़ंक्शन के लिए, KMI में नए सिंबल जोड़े जा सकते हैं. भले ही, KMI फ़्रीज़ हो. अगर नए कर्नेल पैच, केएमआई का उल्लंघन नहीं करते हैं, तो उन्हें भी स्वीकार किया जा सकता है.
KMI के काम न करने के बारे में जानकारी
किसी कर्नेल में सोर्स होते हैं और बाइनरी उन सोर्स से बनाई जाती हैं.
एबीआई की निगरानी वाली कर्नेल शाखाओं में, मौजूदा GKI एबीआई (.stg
फ़ाइल के तौर पर) का एबीआई दिखाया जाता है. बाइनरी (vmlinux
, Image
, और किसी भी GKI मॉड्यूल) बनने के बाद, बाइनरी से एबीआई का प्रतिनिधित्व निकाला जा सकता है. किसी भी कर्नेल सोर्स फ़ाइल में किए गए बदलाव से, बाइनरी पर असर पड़ सकता है. साथ ही, इससे निकाले गए .stg
पर भी असर पड़ सकता है. AbiAnalyzer
विश्लेषक, कमिट की गई .stg
फ़ाइल की तुलना, बिल्ड आर्टफ़ैक्ट से निकाली गई फ़ाइल से करता है. अगर उसे सेमेटिक फ़र्क़ मिलता है, तो वह Gerrit में किए गए बदलाव पर, Lint-1 लेबल सेट करता है.
एबीआई (ऐप्लिकेशन बाइनरी इंटरफ़ेस) से जुड़ी गड़बड़ियों को ठीक करना
उदाहरण के लिए, नीचे दिए गए पैच में एबीआई के काम न करने की समस्या का पता चलता है:
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.
इस पैच को लागू करके एबीआई को बिल्ड करने पर, टूल गड़बड़ी का कोड दिखाकर बंद हो जाता है. साथ ही, एबीआई में इस तरह का अंतर दिखता है:
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
बिल्ड के समय एबीआई में अंतर का पता चलना
गड़बड़ियों की सबसे आम वजह यह होती है कि कोई ड्राइवर, कर्नेल से किसी ऐसे नए सिंबल का इस्तेमाल करता है जो किसी भी सिंबल की सूची में नहीं है.
अगर सिंबल आपकी सिंबल सूची में शामिल नहीं है, तो आपको पहले यह पुष्टि करनी होगी कि इसे EXPORT_SYMBOL_GPL(symbol_name)
के साथ एक्सपोर्ट किया गया है. इसके बाद, सिंबल सूची और एबीआई के रिप्रज़ेंटेशन को अपडेट करें. उदाहरण के लिए, इन बदलावों से android-12-5.10
शाखा में, इंक्रीमेंटल एफ़एस की नई सुविधा जोड़ी जाती है. इसमें, सिंबल की सूची और एबीआई के प्रतिनिधित्व को अपडेट करना शामिल है.
- सुविधा में हुए बदलाव का उदाहरण, aosp/1345659 में दिया गया है.
- सिंबल की सूची का उदाहरण, aosp/1346742 में दिया गया है.
- एबीआई के दिखाए जाने के तरीके में हुए बदलाव का उदाहरण, 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
इसे ठीक करने के लिए, अपने कर्नेल और ACK, दोनों में KMI सिंबल की सूची अपडेट करें (एबीआई का प्रतिनिधित्व अपडेट करें देखें). एसीएम में सिंबल की सूची और एबीआई के रिप्रज़ेंटेशन को अपडेट करने का उदाहरण पाने के लिए, aosp/1367601 देखें.
कर्नेल एबीआई के गड़बड़ियों को ठीक करना
कोड को फिर से लिखकर, एबीआई में बदलाव न करने या एबीआई के रिप्रज़ेंटेशन को अपडेट करके, कर्नेल एबीआई के गड़बड़ियों को ठीक किया जा सकता है. अपनी स्थिति के हिसाब से सबसे सही तरीका तय करने के लिए, नीचे दिए गए चार्ट का इस्तेमाल करें.
पहली इमेज. एबीआई के उल्लंघन को ठीक करना
एबीआई में बदलावों से बचने के लिए, कोड को फिर से लिखना
मौजूदा एबीआई में बदलाव करने से बचने की पूरी कोशिश करें. कई मामलों में, एबीआई पर असर डालने वाले बदलावों को हटाने के लिए, अपने कोड को फिर से तैयार किया जा सकता है.
स्ट्रक्चर फ़ील्ड में बदलावों को फिर से तैयार करना. अगर किसी बदलाव से डीबग करने की सुविधा के लिए एबीआई में बदलाव होता है, तो फ़ील्ड के आस-पास (स्ट्रक्चर और सोर्स रेफ़रंस में)
#ifdef
जोड़ें. साथ ही, पक्का करें कि#ifdef
के लिए इस्तेमाल किया गयाCONFIG
, प्रोडक्शन defconfig औरgki_defconfig
के लिए बंद हो. एबीआई को बदले बिना, किसी स्ट्रक्चर में डीबग कॉन्फ़िगरेशन जोड़ने का उदाहरण देखने के लिए, इस पैच सेट को देखें.कोर कर्नेल में बदलाव न करने के लिए, सुविधाओं को फिर से तैयार करना. अगर पार्टनर मॉड्यूल के साथ काम करने के लिए, ACK में नई सुविधाएं जोड़नी हैं, तो बदलाव के एबीआई हिस्से को फिर से लिखने की कोशिश करें, ताकि कर्नेल एबीआई में बदलाव न करना पड़े. मौजूदा कर्नेल एबीआई का इस्तेमाल करके, कर्नेल एबीआई में बदलाव किए बिना अतिरिक्त सुविधाएं जोड़ने का उदाहरण देखने के लिए, aosp/1312213 देखें.
Android Gerrit पर, काम न करने वाले एबीआई को ठीक करना
अगर आपने जान-बूझकर कर्नेल एबीआई को नहीं तोड़ा है, तो आपको एबीआई मॉनिटरिंग टूल से मिले दिशा-निर्देशों का इस्तेमाल करके, इसकी जांच करनी होगी. डेटा स्ट्रक्चर और उससे जुड़े सिंबल सीआरसी में बदलाव होने की वजह से, आम तौर पर डेटा फ़ाइलें नहीं खुलती हैं. इसके अलावा, कॉन्फ़िगरेशन के विकल्प में बदलाव होने की वजह से भी ऐसा हो सकता है. टूल से मिली समस्याओं को ठीक करके शुरुआत करें.
एबीआई से जुड़ी समस्याओं को स्थानीय तौर पर दोहराया जा सकता है. इसके लिए, कर्नल और उसके एबीआई का प्रतिनिधित्व बनाएं लेख पढ़ें.
Lint-1 लेबल के बारे में जानकारी
अगर किसी ऐसी शाखा में बदलाव अपलोड किए जाते हैं जिसमें फ़्रीज़ किया गया या फ़ाइनल किया गया केएमआई शामिल है, तो बदलावों को AbiAnalyzer
से पास करना होगा. इससे यह पक्का किया जा सकेगा कि बदलावों का, काम करने वाले एबीआई पर गलत तरीके से असर न पड़े. इस प्रोसेस के दौरान, AbiAnalyzer
उस एबीआई रिपोर्ट को खोजता है जो बिल्ड के दौरान बनाई गई है. यह एक एक्सटेंडेड बिल्ड है, जो सामान्य बिल्ड के बाद, एबीआई को निकालने और तुलना करने के कुछ चरणों को पूरा करता है.
अगर AbiAnalyzer
को कोई रिपोर्ट मिलती है, तो वह Lint-1 लेबल सेट करता है. साथ ही, जब तक समस्या हल नहीं हो जाती, तब तक बदलाव को सबमिट करने से रोक दिया जाता है. ऐसा तब तक किया जाता है, जब तक पैचसेट को Lint+1 लेबल नहीं मिल जाता.
कर्नेल एबीआई को अपडेट करना
अगर एबीआई में बदलाव करना ज़रूरी है, तो आपको कोड में किए गए बदलावों, एबीआई के रेप्रज़ेंटेशन, और सिंबल की सूची को ACK में लागू करना होगा. Lint को -1 हटाने और GKI के साथ काम करने की सुविधा को बनाए रखने के लिए, यह तरीका अपनाएं:
पैचसेट के लिए, कोड की समीक्षा +2 स्टेटस मिलने का इंतज़ार करें.
अपने कोड में किए गए बदलावों और एबीआई अपडेट में किए गए बदलावों को मर्ज करें.
ACK में ABI कोड में किए गए बदलाव अपलोड करना
ACK ABI को अपडेट करने का तरीका, किए जा रहे बदलाव के टाइप पर निर्भर करता है.
अगर एबीआई में किया गया बदलाव, किसी ऐसी सुविधा से जुड़ा है जिसका असर CTS या VTS टेस्ट पर पड़ता है, तो आम तौर पर बदलाव को स्वीकार करने के लिए, उसे चुन लिया जा सकता है. उदाहरण के लिए:
- ऑडियो की सुविधा काम करने के लिए, aosp/1289677 की ज़रूरत होती है.
- यूएसबी के काम करने के लिए, aosp/1295945 की ज़रूरत होती है.
अगर एबीआई में किया गया बदलाव किसी ऐसी सुविधा के लिए है जिसे ACK के साथ शेयर किया जा सकता है, तो उस बदलाव को ACK के साथ शेयर किया जा सकता है. उदाहरण के लिए, नीचे दिए गए बदलावों की ज़रूरत सीटीएस या वीटीएस टेस्ट के लिए नहीं है, लेकिन इन्हें ACK के साथ शेयर किया जा सकता है:
- aosp/1250412, डिवाइस के तापमान से जुड़ी सुविधा में बदलाव है.
- aosp/1288857
EXPORT_SYMBOL_GPL
बदलाव है.
अगर एबीआई में हुए बदलाव से कोई नई सुविधा मिलती है, जिसे ACK में शामिल करने की ज़रूरत नहीं है, तो स्टब का इस्तेमाल करके ACK में सिंबल जोड़े जा सकते हैं. इसके बारे में अगले सेक्शन में बताया गया है.
ACK के लिए स्टब का इस्तेमाल करना
स्टब सिर्फ़ मुख्य कर्नेल में किए गए उन बदलावों के लिए ज़रूरी हैं जिनसे ACK को फ़ायदा नहीं मिलता. जैसे, परफ़ॉर्मेंस और पावर में हुए बदलाव. नीचे दी गई सूची में, GKI के लिए ACK में स्टब और कुछ हिस्सों को चुनकर शामिल करने के उदाहरण दिए गए हैं.
Core-isolate सुविधा का स्टब (aosp/1284493). ACK में ये सुविधाएं होना ज़रूरी नहीं है. हालांकि, आपके मॉड्यूल में इन सिंबल का इस्तेमाल करने के लिए, ACK में ये सिंबल मौजूद होने चाहिए.
वेंडर मॉड्यूल के लिए प्लेसहोल्डर सिंबल (aosp/1288860).
हर प्रोसेस के लिए
mm
इवेंट ट्रैकिंग की सुविधा को सिर्फ़ एबीआई के लिए चुना गया है (aosp/1288454). ओरिजनल पैच को स्वीकार करने के लिए चुना गया था. इसके बाद,task_struct
औरmm_event_count
के लिए एबीआई के अंतर को हल करने के लिए, सिर्फ़ ज़रूरी बदलावों को शामिल करने के लिए पैच को छोटा किया गया था. इस पैच सेmm_event_type
enum को भी अपडेट किया जाता है, ताकि उसमें आखिरी सदस्य शामिल किए जा सकें.थर्मल स्ट्रक्चर एबीआई में किए गए कुछ बदलावों को चुना गया है. इन बदलावों के लिए, एबीआई के नए फ़ील्ड जोड़ने के अलावा और भी काम करने पड़े.
पैच aosp/1255544 ने पार्टनर कर्नेल और ACK के बीच एबीआई के अंतर को ठीक किया.
पैच aosp/1291018 ने, पिछले पैच की GKI जांच के दौरान मिली फ़ंक्शनल समस्याओं को ठीक किया है. इस सुधार में, सेंसर पैरामीटर स्ट्रक्चर को शुरू करना शामिल है, ताकि एक सेंसर में कई थर्मल ज़ोन रजिस्टर किए जा सकें.
CONFIG_NL80211_TESTMODE
एबीआई में बदलाव (aosp/1344321). इस पैच में, एबीआई के लिए ज़रूरी स्ट्रक्चर में बदलाव किए गए हैं. साथ ही, यह पक्का किया गया है कि अतिरिक्त फ़ील्ड की वजह से फ़ंक्शन में कोई अंतर न आए. इससे पार्टनर, अपने प्रॉडक्शन कर्नेल मेंCONFIG_NL80211_TESTMODE
को शामिल कर पाएंगे और जीकेआई का पालन भी कर पाएंगे.
रनटाइम के दौरान KMI लागू करना
GKI केर्नेल, TRIM_UNUSED_KSYMS=y
और UNUSED_KSYMS_WHITELIST=<union
of all symbol lists>
कॉन्फ़िगरेशन विकल्पों का इस्तेमाल करते हैं. इनकी मदद से, एक्सपोर्ट किए गए सिंबल (जैसे, EXPORT_SYMBOL_GPL()
का इस्तेमाल करके एक्सपोर्ट किए गए सिंबल) को सिंबल की सूची में शामिल सिंबल तक सीमित किया जा सकता है. अन्य सभी सिंबल एक्सपोर्ट नहीं किए जाते. साथ ही, ऐसे मॉड्यूल को लोड करने की अनुमति नहीं है जिसमें एक्सपोर्ट नहीं किए गए सिंबल की ज़रूरत होती है. यह पाबंदी, बिल्ड के समय लागू होती है और मौजूद न होने वाली एंट्री को फ़्लैग किया जाता है.
डेवलपमेंट के लिए, GKI के ऐसे कर्नेल बिल्ड का इस्तेमाल किया जा सकता है जिसमें सिंबल ट्रिमिंग शामिल न हो. इसका मतलब है कि आम तौर पर एक्सपोर्ट किए गए सभी सिंबल का इस्तेमाल किया जा सकता है. इन बिल्ड को ढूंढने के लिए, ci.android.com पर kernel_debug_aarch64
बिल्ड खोजें.
मॉड्यूल के वर्शन का इस्तेमाल करके, केएमआई लागू करना
सामान्य कर्नेल इमेज (जीकेआई) के कर्नेल, रनटाइम पर केएमआई के अनुपालन को लागू करने के लिए, मॉड्यूल वर्शनिंग (CONFIG_MODVERSIONS
) का इस्तेमाल एक अतिरिक्त उपाय के तौर पर करते हैं. मॉड्यूल के वर्शन की वजह से, मॉड्यूल लोड होने के समय साइक्लिक रेडंडेंसी जांच (सीआरसी) में गड़बड़ी हो सकती है. ऐसा तब होता है, जब किसी मॉड्यूल का अनुमानित केएमआई, vmlinux
केएमआई से मेल न खाता हो. उदाहरण के लिए, 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 ''
मॉड्यूल वर्शनिंग के इस्तेमाल
मॉड्यूल का वर्शन इन वजहों से काम का होता है:
मॉड्यूल के वर्शन से, डेटा स्ट्रक्चर की दिखने की सेटिंग में हुए बदलावों का पता चलता है. अगर मॉड्यूल, ऐसे डेटा स्ट्रक्चर में बदलाव करते हैं जो पारदर्शी नहीं हैं, यानी ऐसे डेटा स्ट्रक्चर जो केएमआई का हिस्सा नहीं हैं, तो स्ट्रक्चर में आने वाले बदलावों के बाद वे काम नहीं करते.
उदाहरण के लिए,
struct device
में मौजूदfwnode
फ़ील्ड को देखें. यह ज़रूरी है कि मॉड्यूल के लिए यह फ़ील्ड ऐपैरेंट न हो, ताकि वेdevice->fw_node
के फ़ील्ड में बदलाव न कर सकें या उसके साइज़ के बारे में अनुमान न लगा सकें.हालांकि, अगर किसी मॉड्यूल में सीधे या किसी दूसरे तरीके से
<linux/fwnode.h>
शामिल है, तोstruct device
में मौजूदfwnode
फ़ील्ड अब उसके लिए पारदर्शी नहीं होगा. इसके बाद, मॉड्यूलdevice->fwnode->dev
याdevice->fwnode->ops
में बदलाव कर सकता है. इस स्थिति में कई समस्याएं आ सकती हैं. इनके बारे में यहां बताया गया है:इससे, कोर कर्नेल कोड के अपने इंटरनल डेटा स्ट्रक्चर के बारे में की गई अनुमानित गलतियां ठीक हो सकती हैं.
अगर आने वाले समय में, किसी कर्नेल अपडेट में
struct fwnode_handle
(fwnode
का डेटा टाइप) में बदलाव होता है, तो मॉड्यूल नए कर्नेल के साथ काम नहीं करेगा. इसके अलावा,stgdiff
में कोई अंतर नहीं दिखेगा, क्योंकि मॉड्यूल सीधे तौर पर इंटरनल डेटा स्ट्रक्चर में बदलाव करके, केएमआई को तोड़ रहा है. इन बदलावों को सिर्फ़ बाइनरी रिप्रज़ेंटेशन की जांच करके कैप्चर नहीं किया जा सकता.
किसी मौजूदा मॉड्यूल को तब KMI के साथ काम न करने वाला माना जाता है, जब उसे बाद में किसी ऐसे नए कर्नेल से लोड किया जाता है जो काम नहीं करता. मॉड्यूल के वर्शन की सुविधा, रनटाइम की जांच जोड़ती है. इससे, गलती से ऐसा मॉड्यूल लोड होने से बचा जा सकता है जो कर्नेल के साथ केएमआई के मुताबिक न हो. इस जांच से, रनटाइम की उन समस्याओं और कर्नेल क्रैश को रोका जा सकता है जिन्हें डीबग करना मुश्किल होता है. ये समस्याएं, KMI में किसी ऐसे कॉम्पोनेंट के इस्तेमाल से हो सकती हैं जो काम नहीं करता.
मॉड्यूल वर्शनिंग की सुविधा चालू करने से, इन सभी समस्याओं से बचा जा सकता है.
डिवाइस को बूट किए बिना सीआरसी मेल न खाने की जांच करना
stgdiff
, अन्य एबीआई के अंतर के साथ-साथ, कर्नेल के बीच सीआरसी मैच न होने की तुलना करता है और उसकी शिकायत करता है.
इसके अलावा, CONFIG_MODVERSIONS
चालू होने पर पूरा कर्नेल बिल्ड करने पर, सामान्य बिल्ड प्रोसेस के हिस्से के तौर पर Module.symvers
फ़ाइल जनरेट होती है. इस फ़ाइल में, कर्नेल (vmlinux
) और मॉड्यूल से एक्सपोर्ट किए गए हर सिंबल के लिए एक लाइन होती है. हर लाइन में सीआरसी वैल्यू, सिंबल का नाम, सिंबल नेमस्पेस, सिंबल को एक्सपोर्ट करने वाले vmlinux
या मॉड्यूल का नाम, और एक्सपोर्ट टाइप (उदाहरण के लिए, EXPORT_SYMBOL
बनाम EXPORT_SYMBOL_GPL
) शामिल होता है.
GKI बिल्ड और अपने बिल्ड के बीच Module.symvers
फ़ाइलों की तुलना की जा सकती है, ताकि vmlinux
से एक्सपोर्ट किए गए सिंबल में सीआरसी के अंतर की जांच की जा सके. अगर vmlinux
से एक्सपोर्ट किए गए किसी सिंबल में सीआरसी वैल्यू का अंतर है और उस सिंबल का इस्तेमाल आपके डिवाइस में लोड किए गए किसी मॉड्यूल में किया जाता है, तो मॉड्यूल लोड नहीं होता.
अगर आपके पास सभी बिल्ड आर्टफ़ैक्ट नहीं हैं, लेकिन आपके पास GKI कर्नेल और आपके कर्नेल की vmlinux
फ़ाइलें हैं, तो किसी खास सिंबल के लिए सीआरसी वैल्यू की तुलना की जा सकती है. इसके लिए, दोनों कर्नेल पर यह कमांड चलाएं और आउटपुट की तुलना करें:
nm <path to vmlinux>/vmlinux | grep __crc_<symbol name>
उदाहरण के लिए, यह कमांड module_layout
सिंबल के लिए सीआरसी वैल्यू की जांच करता है:
nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout
सीआरसी मैच न होने की समस्या हल करना
मॉड्यूल लोड करते समय सीआरसी मैच न होने की समस्या को हल करने के लिए, यह तरीका अपनाएं:
--kbuild_symtypes
विकल्प का इस्तेमाल करके, GKI kernel और अपने डिवाइस का kernel बनाएं, जैसा कि इस कमांड में दिखाया गया है:tools/bazel run --kbuild_symtypes //common:kernel_aarch64_dist
यह कमांड, हर
.o
फ़ाइल के लिए एक.symtypes
फ़ाइल जनरेट करता है. ज़्यादा जानकारी के लिए, Kleaf मेंKBUILD_SYMTYPES
देखें.Android 13 और उससे पहले के वर्शन के लिए, GKI kernel और अपने डिवाइस के kernel को इकट्ठा करें. इसके लिए, kernel को इकट्ठा करने के लिए इस्तेमाल किए जाने वाले कमांड के आगे
KBUILD_SYMTYPES=1
जोड़ें, जैसा कि इस कमांड में दिखाया गया है:KBUILD_SYMTYPES=1 BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
build_abi.sh,
का इस्तेमाल करने पर,KBUILD_SYMTYPES=1
फ़्लैग पहले से ही सेट होता है.नीचे दिए गए निर्देश का इस्तेमाल करके, वह
.c
फ़ाइल ढूंढें जिसमें सीआरसी मैच न करने वाला सिंबल एक्सपोर्ट किया गया है: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 * )
दोनों फ़ाइलों की तुलना करें और उनमें मौजूद अंतरों को ठीक करें.
समस्या वाले बदलाव से ठीक पहले और फिर समस्या वाले बदलाव के बाद, किसी बिल्ड के साथ 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
इसके अलावा, सिर्फ़ अपनी पसंद की फ़ाइलों की तुलना करें.
पहला उदाहरण: डेटा टाइप दिखने की सेटिंग की वजह से अंतर
कोई नया #include
, सोर्स फ़ाइल में किसी नए टाइप की परिभाषा (जैसे, struct foo
) को शामिल कर सकता है. इन मामलों में, उससे जुड़ी .symtypes
फ़ाइल में मौजूद उसका ब्यौरा, खाली structure_type foo { }
से पूरी परिभाषा में बदल जाएगा.
इससे .symtypes
फ़ाइल में मौजूद उन सभी सिंबल के सीआरसी पर असर पड़ेगा जिनके ब्यौरे, सीधे या अप्रत्यक्ष रूप से टाइप की परिभाषा पर निर्भर करते हैं.
उदाहरण के लिए, अपने कर्नेल में include/linux/device.h
फ़ाइल में यह लाइन जोड़ने पर, सीआरसी मैच नहीं होता. इनमें से एक 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 के kernel में .symtypes
में पूरी तरह से टाइप की परिभाषा मौजूद नहीं होती. हालांकि, आपके kernel में #include
निर्देशों की वजह से यह मौजूद होती है.
Android 16 और उसके बाद के वर्शन के लिए रिज़ॉल्यूशन
पक्का करें कि जिस सोर्स फ़ाइल पर असर पड़ा है उसमें Android KABI स्टैबिलाइज़ेशन हेडर शामिल हो:
#include <linux/android_kabi.h>
जिन फ़ाइलों पर असर पड़ा है उनके लिए, ग्लोबल स्कोप में ANDROID_KABI_DECLONLY(name);
जोड़ें.
उदाहरण के लिए, अगर symtypes
का अंतर यह था:
--- 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 और इससे पहले के वर्शन के लिए रिज़ॉल्यूशन
अक्सर, genksyms
से नया #include
छिपाकर ही समस्या को ठीक किया जाता है.
#ifndef __GENKSYMS__
#include <linux/fwnode.h>
#endif
इसके अलावा, अंतर की वजह बनने वाले #include
की पहचान करने के लिए, यह तरीका अपनाएं:
वह हेडर फ़ाइल खोलें जिसमें इस अंतर वाले सिंबल या डेटा टाइप के बारे में बताया गया है. उदाहरण के लिए,
struct fwnode_handle
के लिएinclude/linux/fwnode.h
में बदलाव करें.हेडर फ़ाइल में सबसे ऊपर यह कोड जोड़ें:
#ifdef CRC_CATCH #error "Included from here" #endif
जिस मॉड्यूल की
.c
फ़ाइल में सीआरसी मेल नहीं खाता है उसमें,#include
लाइनों से पहले पहली लाइन के तौर पर यह जोड़ें.#define CRC_CATCH 1
अपना मॉड्यूल कंपाइल करें. बिल्ड के समय मिलने वाली गड़बड़ी से, हेडर फ़ाइल
#include
की चेन दिखती है, जिसकी वजह से सीआरसी मेल नहीं खाता. उदाहरण के लिए: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 कोर में मौजूद नहीं है.
दूसरा मामला: डेटा टाइप में बदलाव की वजह से अंतर
अगर किसी सिंबल या डेटा टाइप के लिए सीआरसी मैच नहीं होता है, तो इसका मतलब है कि डेटा टाइप में कोई बदलाव हुआ है. जैसे, डेटा टाइप में कुछ जोड़ा गया है, कुछ हटाया गया है या उसमें बदलाव किया गया है.
उदाहरण के लिए, अपने कर्नेल में यह बदलाव करने से कई सीआरसी मैच नहीं होते, क्योंकि इस तरह के बदलाव से कई सिंबल पर अप्रत्यक्ष रूप से असर पड़ता है:
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);
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>
बदलाव या मिटाए गए डेटा का पता लगाने के लिए, कमिट की गई फ़ाइलों की सूची देखें. शायद आपको पहला कमिट ही चाहिए. अगर ऐसा नहीं है, तो सूची में तब तक जाएं, जब तक आपको वह कमिट नहीं मिल जाता.
कमिट की पहचान करने के बाद, उसे अपने कर्नेल में वापस लाएं या सीआरसी में हुए बदलाव को रोकने के लिए उसे अपडेट करें. इसके बाद, उसे ACK पर अपलोड करें और उसे मर्ज कराएं. सुरक्षा के लिहाज़ से, हर बचे हुए एबीआई ब्रेक की समीक्षा की जाएगी. अगर ज़रूरी हो, तो अनुमति वाला ब्रेक रिकॉर्ड किया जा सकता है.
मौजूदा पैडिंग का इस्तेमाल करना
GKI में कुछ स्ट्रक्चर को पैड किया जाता है, ताकि वे मौजूदा वेंडर मॉड्यूल को तोड़े बिना ही, अपने दायरे को बढ़ा सकें. अगर कोई अपस्ट्रीम कमिट (उदाहरण के लिए) इस तरह के स्ट्रक्चर में कोई सदस्य जोड़ता है, तो हो सकता है कि उसे बदलकर पैडिंग का कुछ हिस्सा इस्तेमाल किया जाए. इसके बाद, इस बदलाव को सीआरसी के हिसाब से नहीं गिना जाता.
स्टैंडर्ड और अपने-आप दस्तावेज़ बनाने वाला मैक्रो ANDROID_KABI_RESERVE
, अलाइन किए गए u64
के बराबर स्पेस रिज़र्व करता है. इसका इस्तेमाल, सदस्य के एलान के बजाय किया जाता है.
उदाहरण के लिए:
struct data {
u64 handle;
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
};
ANDROID_KABI_USE
(या ANDROID_KABI_USE2
या ऐसे अन्य वैरिएंट जिन्हें तय किया जा सकता है) की मदद से, पैडिंग का इस्तेमाल किया जा सकता है. इससे सिंबल सीआरसी पर कोई असर नहीं पड़ता.
सदस्य sekret
वैसे ही उपलब्ध है जैसे कि उसे सीधे तौर पर एलान किया गया हो. हालांकि, मैक्रो असल में एक ऐसे यूनियन मेंबर में बदल जाता है जिसमें sekret
के साथ-साथ, gendwarfksyms
के इस्तेमाल की गई चीज़ें भी शामिल होती हैं, ताकि सिमटाइप को स्थिर रखा जा सके.
struct data {
u64 handle;
ANDROID_KABI_USE(1, void *sekret);
ANDROID_KABI_RESERVE(2);
};
Android 16 और उसके बाद के वर्शन के लिए रिज़ॉल्यूशन
सीआरसी का हिसाब gendwarfksyms
लगाता है. यह DWARF डीबगिंग की जानकारी का इस्तेमाल करता है. इसलिए, यह C और Rust, दोनों टाइप के साथ काम करता है. बदलाव के टाइप के हिसाब से, रिज़ॉल्यूशन अलग-अलग होता है. यहां कुछ उदाहरण दिए गए हैं.
नए या बदले गए एनोमेरेटर
कभी-कभी नए एनोमेरेटर जोड़े जाते हैं और कभी-कभी MAX
या मिलती-जुलती एनोमेरेटर वैल्यू पर भी असर पड़ता है. ये बदलाव तब सुरक्षित होते हैं, जब वे GKI से "एस्केप" न करते हों या जब हम यह पक्का कर लें कि वेंडर मॉड्यूल उनकी वैल्यू का इस्तेमाल न कर सकें.
उदाहरण के लिए:
enum outcome {
SUCCESS,
FAILURE,
RETRY,
+ TRY_HARDER,
OUTCOME_LIMIT
};
TRY_HARDER
जोड़ने और OUTCOME_LIMIT
में बदलाव करने पर, वैश्विक दायरे में मैक्रो को कॉल करने पर, सीआरसी कैलकुलेशन से छिपाया जा सकता है:
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
जोड़ने से, किसी भी मौजूदा सदस्य के ऑफ़सेट या स्ट्रक्चर के साइज़ पर असर नहीं पड़ता. हालांकि, इससे सिंबल सीआरसी या एबीआई के प्रतिनिधित्व या दोनों पर असर पड़ सकता है.
ऐसा करने पर, यह सीआरसी के हिसाब से नहीं दिखेगा:
void *data;
bool urgent;
+ ANDROID_KABI_IGNORE(1, bool retry);
void *scratch_space;
सदस्य retry
वैसे ही उपलब्ध है जैसे कि उसे सीधे तौर पर एलान किया गया हो. हालांकि, मैक्रो असल में एक ऐसे यूनियन मेंबर में बदल जाता है जिसमें retry
के साथ-साथ, gendwarfksyms
के इस्तेमाल की जाने वाली चीज़ें भी शामिल होती हैं. ऐसा, सिमटाइप के स्टेबिलिटी को बनाए रखने के लिए किया जाता है.
नए सदस्यों के साथ स्ट्रक्चर का एक्सटेंशन
कभी-कभी सदस्यों को स्ट्रक्चर के आखिर में जोड़ा जाता है. इससे, मौजूदा सदस्यों के ऑफ़सेट पर कोई असर नहीं पड़ता. इसके अलावा, स्ट्रक्चर के उन मौजूदा उपयोगकर्ताओं पर भी कोई असर नहीं पड़ता जो सिर्फ़ पॉइंटर से इसे ऐक्सेस करते हैं. स्ट्रक्चर के साइज़ का असर उसके सीआरसी पर पड़ता है. इसमें बदलाव करने के लिए, ग्लोबल स्कोप में अतिरिक्त मैक्रो का इस्तेमाल किया जा सकता है. इसके लिए, यह तरीका अपनाएं:
struct data {
u64 handle;
u64 counter;
ANDROID_KABI_IGNORE(1, void *sekret);
};
ANDROID_KABI_BYTE_SIZE(data, 16);
आसानी से पढ़ने के लिए, इसे struct
की परिभाषा के ठीक बाद रखें.
किसी टाइप या किसी सिंबल के टाइप में किए गए अन्य सभी बदलाव
ऐसा बहुत कम होता है कि कोई बदलाव, पिछली कैटगरी में न आता हो. इस वजह से, सीआरसी में ऐसे बदलाव हो सकते हैं जिन्हें पिछले मैक्रो का इस्तेमाल करके नहीं रोका जा सकता.
इन मामलों में, किसी टाइप या सिंबल के मूल 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;
};