Android कर्नलों के इन-कर्नल एबीआई को स्थिर करने के लिए, ऐप्लिकेशन बाइनरी इंटरफ़ेस (एबीआई) मॉनिटरिंग टूलिंग का इस्तेमाल किया जा सकता है. यह Android 11 और इसके बाद के वर्शन में उपलब्ध है. यह टूल, मौजूदा कर्नेल बाइनरी (vmlinux
+ जीकेआई मॉड्यूल) से एबीआई के डेटा को इकट्ठा करता है और उसकी तुलना करता है. ये ABI, .stg
फ़ाइलें और सिंबल की सूचियां हैं. जिस इंटरफ़ेस पर यह जानकारी दिखती है उसे कर्नेल मॉड्यूल इंटरफ़ेस (केएमआई) कहा जाता है. केएमआई में हुए बदलावों को ट्रैक करने और उन्हें कम करने के लिए, टूलिंग का इस्तेमाल किया जा सकता है.
एबीआई मॉनिटरिंग टूलिंग को AOSP में डेवलप किया गया है. यह टूलिंग, STG (या Android 13 और इससे पहले के वर्शन में libabigail
) का इस्तेमाल करके, अलग-अलग वर्शन जनरेट करती है और उनकी तुलना करती है.
इस पेज पर, टूलिंग, ABI के डेटा को इकट्ठा करने और उसका विश्लेषण करने की प्रोसेस, और कर्नेल में मौजूद ABI को स्टेबल बनाने के लिए, इस तरह के डेटा के इस्तेमाल के बारे में बताया गया है. इस पेज पर, Android कर्नल में बदलाव करने के बारे में भी जानकारी दी गई है.
प्रोसेस
कर्नल के एबीआई का विश्लेषण करने के लिए कई चरणों की ज़रूरत होती है. इनमें से ज़्यादातर चरणों को अपने-आप पूरा किया जा सकता है:
- कर्नल और उसके एबीआई को बनाना.
- बिल्ड और रेफ़रंस के बीच ABI में अंतर का विश्लेषण करें.
- अगर ज़रूरी हो, तो एबीआई का प्रतिनिधित्व अपडेट करें.
- सिंबल वाली सूचियों का इस्तेमाल करना.
यहां दिए गए निर्देश, बनाए जा सकने वाले किसी भी कर्नल के लिए काम करते हैं. इसके लिए, आपको किसी ऐसे टूलचेन का इस्तेमाल करना होगा जो काम करता हो. जैसे, पहले से बना हुआ Clang टूलचेन. repo manifests
ये सभी Android के सामान्य कर्नल ब्रांच और डिवाइस के हिसाब से कई कर्नल के लिए उपलब्ध हैं. ये पुष्टि करते हैं कि विश्लेषण के लिए कर्नल डिस्ट्रिब्यूशन बनाते समय, सही टूलचेन का इस्तेमाल किया गया हो.
सिंबल वाली सूचियां
केएमआई में, कर्नल के सभी सिंबल या एक्सपोर्ट किए गए 30,000 से ज़्यादा सिंबल भी शामिल नहीं होते. इसके बजाय, वेंडर मॉड्यूल के लिए इस्तेमाल किए जा सकने वाले सिंबल, सिंबल की सूची वाली फ़ाइलों के सेट में साफ़ तौर पर दिए गए हैं. इन फ़ाइलों को कर्नल ट्री (Android 15 और इससे पहले के वर्शन में gki/{ARCH}/symbols/*
या android/abi_gki_{ARCH}_*
) में सार्वजनिक तौर पर मैनेज किया जाता है. सिंबल की सूची वाली सभी फ़ाइलों में मौजूद सभी सिंबल का यूनियन, KMI सिंबल के उस सेट को तय करता है जिसे स्थिर रखा जाता है. उदाहरण के लिए, सिंबल की सूची वाली फ़ाइल gki/aarch64/symbols/db845c
है. इसमें DragonBoard 845c के लिए ज़रूरी सिंबल के बारे में बताया गया है.
सिर्फ़ सिंबल की सूची में दिए गए सिंबल और उनसे जुड़े स्ट्रक्चर और परिभाषाओं को केएमआई का हिस्सा माना जाता है. अगर आपको ज़रूरी सिंबल नहीं मिल रहे हैं, तो सिंबल की सूचियों में बदलाव किए जा सकते हैं. सिंबल की सूची में नए इंटरफ़ेस शामिल होने और केएमआई के ब्यौरे का हिस्सा बनने के बाद, उन्हें स्थिर रखा जाता है. साथ ही, ब्रांच फ़्रीज़ होने के बाद, उन्हें सिंबल की सूची से नहीं हटाया जाना चाहिए या उनमें बदलाव नहीं किया जाना चाहिए.
Android Common Kernel (ACK) KMI कर्नल की हर ब्रांच के लिए, सिंबल की अपनी अलग-अलग सूचियां होती हैं. अलग-अलग KMI कर्नल ब्रांच के बीच ABI को स्थिर रखने की कोशिश नहीं की जाती. उदाहरण के लिए, android12-5.10
का केएमआई, android13-5.10
के केएमआई से पूरी तरह अलग होता है.
एबीआई टूल, केएमआई सिंबल की सूचियों का इस्तेमाल करते हैं. इससे यह तय किया जाता है कि स्थिरता के लिए किन इंटरफ़ेस की निगरानी की जानी चाहिए. वेंडर से उम्मीद की जाती है कि वे अपने सिंबल की सूचियां सबमिट करें और उन्हें अपडेट करें. इससे यह पुष्टि की जा सकेगी कि वे जिन इंटरफ़ेस का इस्तेमाल करते हैं वे एबीआई के साथ काम करते हैं. उदाहरण के लिए, android16-6.12
कर्नल के लिए सिंबल की सूचियों की सूची देखने के लिए, https://android.googlesource.com/kernel/common/+/refs/heads/android16-6.12/gki/aarch64/symbols
पर जाएं
सिंबल की सूची में, उन सिंबल के बारे में जानकारी होती है जिनकी ज़रूरत किसी खास वेंडर या डिवाइस के लिए होती है. टूल में इस्तेमाल की गई पूरी सूची, सभी केएमआई सिंबल की सूची वाली फ़ाइलों का यूनियन होती है. एबीआई टूल, हर सिंबल की जानकारी तय करते हैं. इसमें फ़ंक्शन सिग्नेचर और नेस्ट किए गए डेटा स्ट्रक्चर शामिल हैं.
केएमआई फ़्रीज़ होने पर, मौजूदा केएमआई इंटरफ़ेस में कोई बदलाव नहीं किया जा सकता. ये स्थिर होते हैं. हालांकि, वेंडर किसी भी समय KMI में सिंबल जोड़ सकते हैं. हालांकि, यह ज़रूरी है कि सिंबल जोड़ने से मौजूदा ABI की स्थिरता पर असर न पड़े. नए जोड़े गए सिंबल को, KMI सिंबल की सूची में शामिल किए जाने के तुरंत बाद, स्टेबल सिंबल के तौर पर बनाए रखा जाता है. किसी कर्नल के लिए, सूची से सिंबल तब तक नहीं हटाए जाने चाहिए, जब तक यह पुष्टि न हो जाए कि किसी भी डिवाइस को उस सिंबल पर निर्भरता के साथ शिप नहीं किया गया है.
सिंबल की सूचियों का इस्तेमाल कैसे करें में दिए गए निर्देशों का इस्तेमाल करके, किसी डिवाइस के लिए केएमआई सिंबल की सूची जनरेट की जा सकती है. कई पार्टनर, हर ACK के लिए एक सिंबल लिस्ट सबमिट करते हैं. हालांकि, ऐसा करना ज़रूरी नहीं है. अगर इससे रखरखाव में मदद मिलती है, तो एक से ज़्यादा सिंबल लिस्ट सबमिट की जा सकती हैं.
केएमआई को बढ़ाना
केएमआई सिंबल और उनसे जुड़े स्ट्रक्चर को स्थिर रखा जाता है. इसका मतलब है कि फ़्रीज़ किए गए केएमआई वाले कर्नल में, स्थिर इंटरफ़ेस को तोड़ने वाले बदलावों को स्वीकार नहीं किया जा सकता. हालांकि, GKI कर्नल को एक्सटेंशन के लिए खुला रखा जाता है, ताकि साल के आखिर में शिप किए जाने वाले डिवाइसों को केएमआई फ़्रीज़ होने से पहले, अपनी सभी डिपेंडेंसी तय न करनी पड़े. केएमआई को बढ़ाने के लिए, एक्सपोर्ट किए गए नए या मौजूदा कर्नल फ़ंक्शन के लिए केएमआई में नए सिंबल जोड़े जा सकते हैं. भले ही, केएमआई फ़्रीज़ हो गया हो. अगर नए कर्नल पैच, केएमआई को नुकसान नहीं पहुंचाते हैं, तो उन्हें भी स्वीकार किया जा सकता है.
KMI में गड़बड़ियों के बारे में जानकारी
किसी कर्नल में सोर्स होते हैं और बाइनरी उन सोर्स से बनाई जाती हैं.
एबीआई की निगरानी वाली कर्नल ब्रांच में, मौजूदा जीकेआई एबीआई का एबीआई प्रज़ेंटेशन शामिल होता है. यह .stg
फ़ाइल के तौर पर होता है. बाइनरी (vmlinux
, Image
, और कोई भी जीकेआई मॉड्यूल) बनाने के बाद, बाइनरी से एबीआई का प्रतिनिधित्व निकाला जा सकता है. कर्नल सोर्स फ़ाइल में किए गए किसी भी बदलाव से, बाइनरी पर असर पड़ सकता है. इससे निकाले गए .stg
पर भी असर पड़ सकता है. एबीआई कंप्लायंस विश्लेषण, कमिट की गई .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
बिल्ड टाइम में ABI में अंतर का पता चला
गड़बड़ियों की सबसे आम वजह यह है कि जब कोई ड्राइवर, कर्नल से ऐसे नए सिंबल का इस्तेमाल करता है जो किसी भी सिंबल सूची में नहीं है.
अगर यह सिंबल, सिंबल की सूची में शामिल नहीं है, तो आपको पहले यह पुष्टि करनी होगी कि इसे EXPORT_SYMBOL_GPL(symbol_name)
के साथ एक्सपोर्ट किया गया है. इसके बाद, सिंबल की सूची और ABI के बारे में जानकारी अपडेट करें. उदाहरण के लिए, यहां दिए गए बदलावों से 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 सिंबल की सूची अपडेट करें. इसके लिए, एबीआई के बारे में जानकारी अपडेट करना लेख पढ़ें. सिंबल की सूची और ACK में ABI के बारे में जानकारी अपडेट करने के उदाहरण के लिए, aosp/1367601 देखें.
कर्नल के एबीआई में होने वाली गड़बड़ियों को ठीक करना
कर्नल एबीआई के टूटने की समस्या को ठीक करने के लिए, कोड को इस तरह से रीफ़ैक्टर करें कि एबीआई में बदलाव न हो या एबीआई के प्रज़ेंटेशन को अपडेट करें. अपनी स्थिति के हिसाब से सबसे सही तरीका चुनने के लिए, यहां दिया गया चार्ट देखें.
पहली इमेज. एबीआई में गड़बड़ी ठीक करना
एबीआई में बदलाव से बचने के लिए, कोड को फिर से फ़ैक्टर करें
मौजूदा एबीआई में बदलाव करने से बचें. कई मामलों में, एबीआई पर असर डालने वाले बदलावों को हटाने के लिए, कोड को फिर से लिखा जा सकता है.
स्ट्रक्ट फ़ील्ड में किए गए बदलावों को फिर से व्यवस्थित किया गया. अगर किसी बदलाव से डीबग सुविधा के लिए एबीआई में बदलाव होता है, तो फ़ील्ड (स्ट्रक्चर और सोर्स रेफ़रंस में) के चारों ओर
#ifdef
जोड़ें. साथ ही, पक्का करें कि#ifdef
के लिए इस्तेमाल किया गयाCONFIG
, प्रोडक्शन डिफ़ॉल्ट कॉन्फ़िगरेशन औरgki_defconfig
के लिए बंद हो. एबीआई को तोड़े बिना किसी स्ट्रक्चर में debug config जोड़ने के तरीके का उदाहरण देखने के लिए, यह पैचसेट देखें.कोर कर्नल में बदलाव किए बिना, सुविधाओं को फिर से व्यवस्थित किया गया है. अगर पार्टनर मॉड्यूल के साथ काम करने के लिए, ACK में नई सुविधाएं जोड़नी हैं, तो कर्नेल ABI में बदलाव करने से बचने के लिए, बदलाव के ABI वाले हिस्से को फिर से फ़ैक्टर करने की कोशिश करें. कर्नल एबीआई में बदलाव किए बिना, मौजूदा कर्नल एबीआई का इस्तेमाल करके अतिरिक्त सुविधाएं जोड़ने का उदाहरण देखने के लिए, aosp/1312213 पर जाएं.
Android Gerrit पर, टूटे हुए एबीआई को ठीक करना
अगर आपने जान-बूझकर कर्नल एबीआई को नहीं तोड़ा है, तो आपको इसकी जांच करनी होगी. इसके लिए, एबीआई मॉनिटरिंग टूलिंग से मिले दिशा-निर्देशों का इस्तेमाल करें. डेटा स्ट्रक्चर और उससे जुड़े सिंबल के सीआरसी में बदलाव होने या कॉन्फ़िगरेशन के विकल्प में बदलाव होने की वजह से, डेटा में गड़बड़ियां हो सकती हैं. सबसे पहले, टूल से मिली समस्याओं को ठीक करें.
एबीआई से जुड़ी समस्याओं को स्थानीय तौर पर दोहराया जा सकता है. इसके लिए, कर्नल और उसके एबीआई को बनाना लेख पढ़ें.
Lint-1 लेबल के बारे में जानकारी
अगर आपने फ़्रीज़ किए गए या फ़ाइनल किए गए केएमआई वाली किसी ब्रांच में बदलाव अपलोड किए हैं, तो यह ज़रूरी है कि बदलावों के लिए, एबीआई के साथ काम करने और एबीआई के मुताबिक होने की जांच पास की गई हो. इससे यह पक्का किया जा सकेगा कि एबीआई के बदलाव, असल एबीआई को दिखाते हैं और उनमें कोई गड़बड़ी नहीं है. जैसे, सिंबल हटाना या टाइप बदलना.
इनमें से हर एबीआई विश्लेषण, Lint-1 लेबल सेट कर सकता है. साथ ही, सभी समस्याएं हल होने या लेबल को खारिज किए जाने तक, बदलाव सबमिट करने पर रोक लगा सकता है.
कर्नल एबीआई को अपडेट करना
अगर ABI में बदलाव करना ज़रूरी है, तो आपको ACK में कोड में किए गए बदलाव, ABI का प्रतिनिधित्व, और सिंबल की सूची लागू करनी होगी. -1 को हटाने और GKI के साथ काम करने की सुविधा को बनाए रखने के लिए, Lint को इन चरणों का पालन करने दें:
पैचसेट के लिए, कोड की समीक्षा करने वाले दो लोगों से +2 का इंतज़ार करें.
कोड में किए गए बदलावों और एबीआई अपडेट में किए गए बदलावों को मर्ज करें.
ABI कोड में हुए बदलावों को ACK पर अपलोड करें
बदलाव किस तरह का किया जा रहा है, इसके आधार पर ACK ABI को अपडेट किया जाता है.
अगर कोई एबीआई बदलाव ऐसी सुविधा से जुड़ा है जिसका असर सीटीएस या वीटीएस टेस्ट पर पड़ता है, तो आम तौर पर बदलाव को ACK के लिए चुना जा सकता है. उदाहरण के लिए:
- ऑडियो के काम करने के लिए, aosp/1289677 ज़रूरी है.
- यूएसबी के काम करने के लिए, aosp/1295945 ज़रूरी है.
अगर ABI में किया गया बदलाव, ऐसी सुविधा के लिए है जिसे ACK के साथ शेयर किया जा सकता है, तो उस बदलाव को ACK के लिए चुना जा सकता है. उदाहरण के लिए, यहां दिए गए बदलावों की ज़रूरत CTS या VTS टेस्ट के लिए नहीं है, लेकिन इन्हें ACK के साथ शेयर किया जा सकता है:
- aosp/1250412 थर्मल फ़ीचर में बदलाव है.
- aosp/1288857
एक
EXPORT_SYMBOL_GPL
बदलाव है.
अगर किसी एबीआई बदलाव से कोई नई सुविधा मिलती है और उसे ACK में शामिल करने की ज़रूरत नहीं है, तो ACK में सिंबल जोड़ने के लिए स्टब का इस्तेमाल किया जा सकता है. इसके बारे में यहां बताया गया है.
ACK के लिए स्टब का इस्तेमाल करना
स्टब सिर्फ़ कर्नल में किए गए उन मुख्य बदलावों के लिए ज़रूरी होने चाहिए जिनसे ACK को फ़ायदा नहीं मिलता. जैसे, परफ़ॉर्मेंस और पावर में किए गए बदलाव. नीचे दी गई सूची में, GKI के लिए ACK में स्टब और आंशिक रूप से चुने गए कमिट के उदाहरणों के बारे में बताया गया है.
कोर-आइसोलेट सुविधा का स्टब (aosp/1284493). ACK में मौजूद सुविधाओं का इस्तेमाल करना ज़रूरी नहीं है. हालांकि, आपके मॉड्यूल को इन सिंबल का इस्तेमाल करने के लिए, ACK में सिंबल मौजूद होने चाहिए.
वेंडर मॉड्यूल के लिए प्लेसहोल्डर सिंबल (aosp/1288860).
एबीआई के लिए, हर प्रोसेस के हिसाब से
mm
इवेंट ट्रैकिंग सुविधा को सिर्फ़ चुनिंदा तौर पर लागू किया गया है (aosp/1288454). ओरिजनल पैच को ACK के लिए चुना गया था. इसके बाद, इसे छोटा कर दिया गया, ताकि इसमें सिर्फ़task_struct
औरmm_event_count
के लिए, ABI में अंतर को ठीक करने से जुड़े ज़रूरी बदलाव शामिल किए जा सकें. यह पैच,mm_event_type
enum को भी अपडेट करता है, ताकि इसमें फ़ाइनल सदस्य शामिल किए जा सकें.थर्मल स्ट्रक्चर के एबीआई में हुए बदलावों को आंशिक रूप से चुना गया है. इसके लिए, नए एबीआई फ़ील्ड जोड़ने के अलावा और भी काम करने पड़े.
पैच aosp/1255544 ने पार्टनर कर्नल और ACK के बीच ABI के अंतर को ठीक किया.
पैच 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 कर्नल बिल्ड का इस्तेमाल किया जा सकता है. इसमें सिंबल ट्रिमिंग शामिल नहीं होती है. इसका मतलब है कि आम तौर पर एक्सपोर्ट किए गए सभी सिंबल का इस्तेमाल किया जा सकता है. इन बिल्ड का पता लगाने के लिए, 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 के साथ काम न करने वाला मॉड्यूल माना जाता है. मॉड्यूल वर्शनिंग की सुविधा, रन-टाइम के दौरान जांच करती है. इससे गलती से ऐसे मॉड्यूल को लोड होने से रोका जा सकता है जो कर्नेल के साथ केएमआई के मुताबिक काम नहीं करता. इस जांच से, रनटाइम से जुड़ी ऐसी समस्याओं और कर्नल क्रैश को रोकने में मदद मिलती है जिन्हें डीबग करना मुश्किल होता है. ये समस्याएं, केएमआई में मौजूद ऐसी असंगति की वजह से हो सकती हैं जिसका पता नहीं चल पाया है.
मॉड्यूल वर्शनिंग की सुविधा चालू करने से, इन सभी समस्याओं से बचा जा सकता है.
डिवाइस को बूट किए बिना, सीआरसी के मेल न खाने की समस्या की जांच करना
stgdiff
, कर्नल के बीच सीआरसी के न मिलने की तुलना करता है और इसकी रिपोर्ट देता है. साथ ही, यह अन्य एबीआई अंतरों की भी रिपोर्ट देता है.
इसके अलावा, CONFIG_MODVERSIONS
की सुविधा चालू करके पूरा कर्नल बनाने पर, सामान्य बिल्ड प्रोसेस के तहत Module.symvers
फ़ाइल जनरेट होती है. इस फ़ाइल में, कर्नल (vmlinux
) और मॉड्यूल से एक्सपोर्ट किए गए हर सिंबल के लिए एक लाइन होती है. हर लाइन में, सीआरसी वैल्यू, सिंबल का नाम, सिंबल नेमस्पेस, सिंबल को एक्सपोर्ट करने वाले vmlinux
या मॉड्यूल का नाम, और एक्सपोर्ट का टाइप (उदाहरण के लिए, EXPORT_SYMBOL
बनाम EXPORT_SYMBOL_GPL
) शामिल होता है.
GKI बिल्ड और अपने बिल्ड के बीच Module.symvers
फ़ाइलों की तुलना की जा सकती है. इससे यह पता लगाया जा सकता है कि 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 कर्नल और अपने डिवाइस के कर्नल को बनाएं:tools/bazel run --kbuild_symtypes //common:kernel_aarch64_dist
इस कमांड से, हर
.o
फ़ाइल के लिए एक.symtypes
फ़ाइल जनरेट होती है. ज़्यादा जानकारी के लिए, Kleaf मेंKBUILD_SYMTYPES
देखें.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
फ़ाइल ढूंढें. इस फ़ाइल में, सीआरसी मिसमैच वाला सिंबल एक्सपोर्ट किया गया है: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
जनरेट करना सबसे अच्छा होता है. सभी फ़ाइलों को सेव करने का मतलब है कि उनकी तुलना एक साथ की जा सकती है.
जैसे, मुझे पता चला कि
diff -r -N -U0 good bad
इसके अलावा, सिर्फ़ उन फ़ाइलों की तुलना करें जिनमें आपकी दिलचस्पी है.
पहला मामला: डेटा टाइप दिखने की वजह से अंतर
नया #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 कर्नल में .symtypes
में टाइप की पूरी परिभाषा मौजूद नहीं होती. हालांकि, आपके कर्नल में अतिरिक्त #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
की ओर से इस्तेमाल की जाने वाली चीज़ें भी शामिल होती हैं. ऐसा symtype को स्थिर रखने के लिए किया जाता है.
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
की ओर से इस्तेमाल की जाने वाली चीज़ें भी शामिल होती हैं. ऐसा symtype को स्थिर रखने के लिए किया जाता है.
नए सदस्यों के साथ किसी स्ट्रक्चर का एक्सटेंशन
कभी-कभी सदस्यों को स्ट्रक्चर के आखिर में जोड़ा जाता है. इससे मौजूदा सदस्यों के ऑफ़सेट पर कोई असर नहीं पड़ता. साथ ही, इससे स्ट्रक्चर के उन मौजूदा उपयोगकर्ताओं पर भी कोई असर नहीं पड़ता जो सिर्फ़ पॉइंटर से इसे ऐक्सेस करते हैं. स्ट्रक्चर के साइज़ से इसके सीआरसी पर असर पड़ता है. इसमें होने वाले बदलावों को ग्लोबल स्कोप पर अतिरिक्त मैक्रो इनवोकेशन की मदद से रोका जा सकता है. इसके लिए, यह तरीका अपनाएं:
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;
};