एंड्रॉइड कर्नेल एबीआई मॉनिटरिंग

आप एंड्रॉइड कर्नेल के इन-कर्नेल एबीआई को स्थिर करने के लिए एंड्रॉइड 11 और उच्चतर में उपलब्ध एप्लिकेशन बाइनरी इंटरफ़ेस (एबीआई) मॉनिटरिंग टूलिंग का उपयोग कर सकते हैं। टूलींग मौजूदा कर्नेल बायनेरिज़ ( vmlinux + GKI मॉड्यूल) से ABI अभ्यावेदन एकत्र करता है और तुलना करता है। ये ABI अभ्यावेदन .stg फ़ाइलें और प्रतीक सूचियाँ हैं। वह इंटरफ़ेस जिस पर प्रतिनिधित्व एक दृश्य देता है उसे कर्नेल मॉड्यूल इंटरफ़ेस (KMI) कहा जाता है। आप KMI में परिवर्तनों को ट्रैक करने और कम करने के लिए टूलींग का उपयोग कर सकते हैं।

एबीआई मॉनिटरिंग टूलिंग एओएसपी में विकसित की गई है और अभ्यावेदन उत्पन्न करने और तुलना करने के लिए एसटीजी (या एंड्रॉइड 13 और उससे कम में libabigail ) का उपयोग करती है।

यह पृष्ठ टूलिंग, एबीआई अभ्यावेदन को इकट्ठा करने और उसका विश्लेषण करने की प्रक्रिया और इन-कर्नेल एबीआई को स्थिरता प्रदान करने के लिए ऐसे अभ्यावेदन के उपयोग का वर्णन करता है। यह पृष्ठ एंड्रॉइड कर्नेल में परिवर्तन योगदान के लिए जानकारी भी प्रदान करता है।

प्रक्रिया

कर्नेल के एबीआई का विश्लेषण करने के लिए कई चरण अपनाए जाते हैं, जिनमें से अधिकांश को स्वचालित किया जा सकता है:

  1. कर्नेल और उसके ABI प्रतिनिधित्व का निर्माण करें
  2. बिल्ड और संदर्भ के बीच एबीआई अंतर का विश्लेषण करें
  3. एबीआई प्रतिनिधित्व को अद्यतन करें (यदि आवश्यक हो)
  4. प्रतीक सूचियों के साथ कार्य करें .

निम्नलिखित निर्देश किसी भी कर्नेल के लिए काम करते हैं जिसे आप समर्थित टूलचेन (जैसे प्रीबिल्ट क्लैंग टूलचेन) का उपयोग करके बना सकते हैंrepo manifests सभी एंड्रॉइड सामान्य कर्नेल शाखाओं और कई डिवाइस-विशिष्ट कर्नेल के लिए उपलब्ध हैं, वे सुनिश्चित करते हैं कि जब आप विश्लेषण के लिए कर्नेल वितरण बनाते हैं तो सही टूलचेन का उपयोग किया जाता है।

प्रतीक सूचियाँ

KMI में कर्नेल के सभी प्रतीक या यहां तक ​​कि सभी 30,000+ निर्यातित प्रतीक शामिल नहीं हैं। इसके बजाय, विक्रेता मॉड्यूल द्वारा उपयोग किए जा सकने वाले प्रतीकों को कर्नेल ट्री की जड़ में सार्वजनिक रूप से बनाए गए प्रतीक सूची फ़ाइलों के एक सेट में स्पष्ट रूप से सूचीबद्ध किया गया है। सभी प्रतीक सूची फ़ाइलों में सभी प्रतीकों का मिलन KMI प्रतीकों के सेट को स्थिर के रूप में परिभाषित करता है। एक उदाहरण प्रतीक सूची फ़ाइल abi_gki_aarch64_db845c है, जो ड्रैगनबोर्ड 845c के लिए आवश्यक प्रतीकों की घोषणा करती है।

केवल प्रतीक सूची में सूचीबद्ध प्रतीकों और उनकी संबंधित संरचनाओं और परिभाषाओं को KMI का हिस्सा माना जाता है। यदि आपके लिए आवश्यक प्रतीक मौजूद नहीं हैं तो आप अपनी प्रतीक सूचियों में परिवर्तन पोस्ट कर सकते हैं। नए इंटरफ़ेस प्रतीक सूची में होने और KMI विवरण का हिस्सा होने के बाद, उन्हें स्थिर बनाए रखा जाता है और शाखा के फ़्रीज़ होने के बाद उन्हें प्रतीक सूची से हटाया नहीं जाना चाहिए या संशोधित नहीं किया जाना चाहिए।

प्रत्येक एंड्रॉइड कॉमन कर्नेल (एसीके) केएमआई कर्नेल शाखा में प्रतीक सूचियों का अपना सेट होता है। विभिन्न KMI कर्नेल शाखाओं के बीच ABI स्थिरता प्रदान करने का कोई प्रयास नहीं किया गया है। उदाहरण के लिए, android12-5.10 के लिए KMI android13-5.10 के KMI से पूरी तरह स्वतंत्र है।

एबीआई उपकरण केएमआई प्रतीक सूचियों का उपयोग यह सीमित करने के लिए करते हैं कि स्थिरता के लिए किन इंटरफेस की निगरानी की जानी चाहिए। मुख्य प्रतीक सूची में वे प्रतीक शामिल हैं जो GKI कर्नेल मॉड्यूल के लिए आवश्यक हैं। विक्रेताओं से यह सुनिश्चित करने के लिए अतिरिक्त प्रतीक सूचियाँ जमा करने और अद्यतन करने की अपेक्षा की जाती है कि जिन इंटरफेस पर वे भरोसा करते हैं वे एबीआई अनुकूलता बनाए रखें। उदाहरण के लिए, android13-5.15 के लिए प्रतीक सूचियों की सूची देखने के लिए, https://android.googlesource.com/kernel/common/+/refs/heads/android13-5.15/android देखें

एक प्रतीक सूची में वे प्रतीक शामिल होते हैं जिनकी विशेष विक्रेता या डिवाइस के लिए आवश्यकता बताई गई है। टूल द्वारा उपयोग की जाने वाली पूरी सूची सभी KMI प्रतीक सूची फ़ाइलों का संघ है। एबीआई उपकरण फ़ंक्शन हस्ताक्षर और नेस्टेड डेटा संरचनाओं सहित प्रत्येक प्रतीक का विवरण निर्धारित करते हैं।

जब KMI फ़्रीज़ हो जाता है, तो मौजूदा KMI इंटरफ़ेस में कोई बदलाव की अनुमति नहीं होती है; वे स्थिर हैं. हालाँकि, विक्रेता किसी भी समय KMI में प्रतीक जोड़ने के लिए स्वतंत्र हैं, जब तक कि जोड़ मौजूदा ABI की स्थिरता को प्रभावित न करें। जैसे ही नए जोड़े गए प्रतीकों को KMI प्रतीक सूची द्वारा उद्धृत किया जाता है, उन्हें स्थिर बनाए रखा जाता है। प्रतीकों को कर्नेल की सूची से तब तक नहीं हटाया जाना चाहिए जब तक कि यह पुष्टि न हो जाए कि किसी भी उपकरण को उस प्रतीक पर निर्भरता के साथ कभी नहीं भेजा गया है।

आप प्रतीक सूचियों के साथ कैसे काम करें के निर्देशों का उपयोग करके किसी डिवाइस के लिए KMI प्रतीक सूची तैयार कर सकते हैं। कई भागीदार प्रति एसीके एक प्रतीक सूची जमा करते हैं, लेकिन यह कोई कठिन आवश्यकता नहीं है। यदि यह रखरखाव में मदद करता है, तो आप एकाधिक प्रतीक सूचियाँ सबमिट कर सकते हैं।

KMI बढ़ाएँ

जबकि KMI प्रतीकों और संबंधित संरचनाओं को स्थिर बनाए रखा जाता है (मतलब जमे हुए KMI के साथ कर्नेल में स्थिर इंटरफेस को तोड़ने वाले परिवर्तनों को स्वीकार नहीं किया जा सकता है) GKI कर्नेल एक्सटेंशन के लिए खुला रहता है ताकि वर्ष में बाद में शिपिंग करने वाले उपकरणों को सभी को परिभाषित करने की आवश्यकता न हो KMI से पहले उनकी निर्भरता समाप्त हो गई है। KMI का विस्तार करने के लिए, आप नए या मौजूदा निर्यातित कर्नेल फ़ंक्शंस के लिए KMI में नए प्रतीक जोड़ सकते हैं, भले ही KMI फ़्रीज़ हो गया हो। नए कर्नेल पैच भी स्वीकार किए जा सकते हैं यदि वे KMI को नहीं तोड़ते हैं।

KMI टूटने के बारे में

कर्नेल में स्रोत होते हैं और उन स्रोतों से बायनेरिज़ बनाए जाते हैं। एबीआई-निगरानी वाली कर्नेल शाखाओं में वर्तमान जीकेआई एबीआई ( .stg फ़ाइल के रूप में) का एबीआई प्रतिनिधित्व शामिल है। बायनेरिज़ ( vmlinux , Image और कोई भी GKI मॉड्यूल) बनने के बाद, बायनेरिज़ से ABI प्रतिनिधित्व निकाला जा सकता है। कर्नेल स्रोत फ़ाइल में किया गया कोई भी परिवर्तन बायनेरिज़ को प्रभावित कर सकता है और बदले में निकाले गए .stg भी प्रभावित कर सकता है। AbiAnalyzer विश्लेषक प्रतिबद्ध .stg फ़ाइल की तुलना बिल्ड कलाकृतियों से निकाली गई फ़ाइल से करता है और यदि कोई अर्थ संबंधी अंतर पाता है तो गेरिट में परिवर्तन पर एक लिंट-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

निर्माण के समय एबीआई अंतर का पता चला

त्रुटियों का सबसे आम कारण तब होता है जब कोई ड्राइवर कर्नेल से एक नए प्रतीक का उपयोग करता है जो किसी भी प्रतीक सूची में नहीं है।

यदि प्रतीक प्रतीक सूची ( android/abi_gki_aarch64 ) में शामिल नहीं है, तो आपको पहले यह सत्यापित करना होगा कि यह EXPORT_SYMBOL_GPL( symbol_name ) के साथ निर्यात किया गया है और फिर ABI XML प्रतिनिधित्व और प्रतीक सूची को अपडेट करें। उदाहरण के लिए, निम्नलिखित परिवर्तन android-12-5.10 शाखा में नई वृद्धिशील एफएस सुविधा जोड़ते हैं, जिसमें प्रतीक सूची और एबीआई एक्सएमएल प्रतिनिधित्व को अपडेट करना शामिल है।

  • सुविधा परिवर्तन का उदाहरण aosp/1345659 में है।
  • प्रतीक सूची उदाहरण aosp/1346742 में है।
  • ABI XML परिवर्तन का उदाहरण 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 प्रतीक सूची को अद्यतन करें ( ABI प्रतिनिधित्व अद्यतन करें देखें)। ACK में ABI XML और प्रतीक सूची को अपडेट करने के उदाहरण के लिए, aosp/1367601 देखें।

कर्नेल एबीआई टूटन का समाधान करें

आप एबीआई को न बदलने या एबीआई प्रतिनिधित्व को अद्यतन करने के लिए कोड को दोबारा तैयार करके कर्नेल एबीआई टूटने को संभाल सकते हैं। अपनी स्थिति के लिए सर्वोत्तम दृष्टिकोण निर्धारित करने के लिए निम्नलिखित चार्ट का उपयोग करें।

एबीआई ब्रेकेज फ्लो चार्ट

चित्र 1. एबीआई टूटना समाधान

एबीआई परिवर्तनों से बचने के लिए रिफैक्टर कोड

मौजूदा एबीआई को संशोधित करने से बचने के लिए हर संभव प्रयास करें। कई मामलों में, आप एबीआई को प्रभावित करने वाले परिवर्तनों को हटाने के लिए अपने कोड को दोबारा तैयार कर सकते हैं।

  • रिफैक्टरिंग संरचना क्षेत्र परिवर्तन। यदि कोई परिवर्तन डिबग सुविधा के लिए ABI को संशोधित करता है, तो फ़ील्ड के चारों ओर एक #ifdef जोड़ें (structs और स्रोत संदर्भों में) और सुनिश्चित करें कि #ifdef के लिए उपयोग किया जाने वाला CONFIG उत्पादन defconfig और gki_defconfig के लिए अक्षम है। एबीआई को तोड़े बिना किसी संरचना में डिबग कॉन्फिगरेशन को कैसे जोड़ा जा सकता है, इसके उदाहरण के लिए, इस पैचसेट को देखें।

  • कोर कर्नेल को न बदलने के लिए रीफैक्टरिंग सुविधाएँ। यदि भागीदार मॉड्यूल का समर्थन करने के लिए ACK में नई सुविधाएँ जोड़ने की आवश्यकता है, तो कर्नेल ABI को संशोधित करने से बचने के लिए परिवर्तन के ABI भाग को दोबारा करने का प्रयास करें। कर्नेल एबीआई को बदले बिना अतिरिक्त कार्यक्षमता जोड़ने के लिए मौजूदा कर्नेल एबीआई का उपयोग करने के उदाहरण के लिए aosp/1312213 देखें।

Android Gerrit पर टूटे हुए ABI को ठीक करें

यदि आपने जानबूझकर कर्नेल एबीआई को नहीं तोड़ा है, तो आपको एबीआई निगरानी टूलिंग द्वारा प्रदान किए गए मार्गदर्शन का उपयोग करके जांच करने की आवश्यकता है। टूट-फूट का सबसे आम कारण बदली हुई डेटा संरचनाएं और संबंधित प्रतीक सीआरसी परिवर्तन हैं, या कॉन्फ़िगरेशन विकल्प परिवर्तनों के कारण जो उपरोक्त में से किसी एक का कारण बनते हैं। टूल द्वारा पाए गए मुद्दों को संबोधित करके शुरुआत करें।

आप एबीआई निष्कर्षों को स्थानीय रूप से पुन: प्रस्तुत कर सकते हैं, कर्नेल और उसके एबीआई प्रतिनिधित्व का निर्माण देखें।

लिंट-1 लेबल के बारे में

यदि आप जमे हुए या अंतिम KMI वाली किसी शाखा में परिवर्तन अपलोड करते हैं, तो परिवर्तनों को AbiAnalyzer से गुजरना होगा ताकि यह सुनिश्चित किया जा सके कि परिवर्तन असंगत तरीके से स्थिर ABI को प्रभावित न करें। इस प्रक्रिया के दौरान, AbiAnalyzer बिल्ड के दौरान बनाई गई ABI रिपोर्ट की तलाश करता है (एक विस्तारित बिल्ड जो सामान्य बिल्ड करता है और फिर कुछ ABI निष्कर्षण और तुलना चरण करता है।

यदि AbiAnalyzer एक गैर-रिक्त रिपोर्ट मिलती है तो यह लिंट-1 लेबल सेट करता है और परिवर्तन को हल होने तक सबमिटल से अवरुद्ध कर दिया जाता है; जब तक पैचसेट को लिंट+1 लेबल प्राप्त नहीं हो जाता।

कर्नेल एबीआई को अद्यतन करें

यदि एबीआई को संशोधित करना अपरिहार्य है, तो आपको अपने कोड परिवर्तन, एबीआई प्रतिनिधित्व और प्रतीक सूची को एसीके पर लागू करना होगा। लिंट को -1 हटाने और जीकेआई संगतता को न तोड़ने के लिए, इन चरणों का पालन करें:

  1. ACK में कोड परिवर्तन अपलोड करें

  2. पैचसेट के लिए कोड-समीक्षा +2 प्राप्त करने की प्रतीक्षा करें।

  3. संदर्भ एबीआई प्रतिनिधित्व अद्यतन करें

  4. अपने कोड परिवर्तन और ABI अद्यतन परिवर्तन को मर्ज करें।

ACK में ABI कोड परिवर्तन अपलोड करें

ACK ABI को अद्यतन करना किए जा रहे परिवर्तन के प्रकार पर निर्भर करता है।

  • यदि एबीआई परिवर्तन किसी ऐसी सुविधा से संबंधित है जो सीटीएस या वीटीएस परीक्षणों को प्रभावित करता है, तो परिवर्तन को आमतौर पर एसीके में चेरी-पिक किया जा सकता है। उदाहरण के लिए:

    • ऑडियो के काम करने के लिए aosp/1289677 की आवश्यकता है।
    • USB के कार्य करने के लिए aosp/1295945 की आवश्यकता है।
  • यदि ABI परिवर्तन किसी ऐसी सुविधा के लिए है जिसे ACK के साथ साझा किया जा सकता है, तो उस परिवर्तन को ACK में चेरी-पिक किया जा सकता है। उदाहरण के लिए, सीटीएस या वीटीएस परीक्षण के लिए निम्नलिखित परिवर्तनों की आवश्यकता नहीं है, लेकिन ACK के साथ साझा करना ठीक है:

    • aosp/1250412 एक थर्मल फीचर परिवर्तन है।
    • aosp/1288857 एक EXPORT_SYMBOL_GPL परिवर्तन है।
  • यदि ABI परिवर्तन एक नई सुविधा प्रस्तुत करता है जिसे ACK में शामिल करने की आवश्यकता नहीं है, तो आप एक स्टब का उपयोग करके ACK में प्रतीकों को प्रस्तुत कर सकते हैं जैसा कि निम्नलिखित अनुभाग में बताया गया है।

एसीके के लिए स्टब्स का प्रयोग करें

स्टब्स केवल कोर कर्नेल परिवर्तनों के लिए आवश्यक होना चाहिए जो ACK को लाभ नहीं पहुंचाते हैं, जैसे प्रदर्शन और पावर परिवर्तन। निम्नलिखित सूची में GKI के लिए ACK में स्टब्स और आंशिक चेरी-पिक्स के उदाहरणों का विवरण दिया गया है।

  • कोर-आइसोलेट फीचर स्टब ( एओएसपी/1284493 )। ACK में कार्यक्षमता आवश्यक नहीं है, लेकिन इन प्रतीकों का उपयोग करने के लिए आपके मॉड्यूल के लिए ACK में प्रतीकों का मौजूद होना आवश्यक है।

  • विक्रेता मॉड्यूल के लिए प्लेसहोल्डर प्रतीक ( एओएसपी/1288860 )।

  • प्रति-प्रक्रिया mm ईवेंट ट्रैकिंग सुविधा ( एओएसपी/1288454 ) का एबीआई-केवल चेरी-पिक। मूल पैच को ACK के लिए चेरी-पिक किया गया था और फिर task_struct और mm_event_count के लिए ABI अंतर को हल करने के लिए केवल आवश्यक परिवर्तनों को शामिल करने के लिए ट्रिम किया गया था। यह पैच अंतिम सदस्यों को शामिल करने के लिए mm_event_type एनम को भी अपडेट करता है।

  • थर्मल संरचना एबीआई परिवर्तनों का आंशिक चेरी-चयन जिसके लिए नए एबीआई फ़ील्ड जोड़ने से कहीं अधिक की आवश्यकता है।

    • पैच एओएसपी/1255544 ने पार्टनर कर्नेल और एसीके के बीच एबीआई मतभेदों को हल किया।

    • पैच एओएसपी/1291018 ने पिछले पैच के जीकेआई परीक्षण के दौरान पाए गए कार्यात्मक मुद्दों को ठीक किया। फिक्स में एक ही सेंसर में कई थर्मल ज़ोन को पंजीकृत करने के लिए सेंसर पैरामीटर संरचना को आरंभ करना शामिल था।

  • 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 बिल्ड देखें।

मॉड्यूल संस्करण का उपयोग करके KMI लागू करें

जेनेरिक कर्नेल इमेज (जीकेआई) कर्नेल रनटाइम पर केएमआई अनुपालन को लागू करने के लिए एक अतिरिक्त उपाय के रूप में मॉड्यूल वर्जनिंग ( CONFIG_MODVERSIONS ) का उपयोग करते हैं। यदि मॉड्यूल की अपेक्षित 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 का हिस्सा नहीं हैं, तो वे संरचना में भविष्य में बदलाव के बाद टूट जाती हैं।

    उदाहरण के तौर पर, 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-असंगत माना जाता है जब इसे बाद की तारीख में एक नए कर्नेल द्वारा लोड किया जाता है जो असंगत है। मॉड्यूल संस्करण गलती से ऐसे मॉड्यूल को लोड करने से बचने के लिए रन-टाइम चेक जोड़ता है जो कर्नेल के साथ KMI-संगत नहीं है। यह जाँच हार्ड-टू-डिबग रनटाइम समस्याओं और कर्नेल क्रैश को रोकती है जो KMI में अज्ञात असंगतता के परिणामस्वरूप हो सकते हैं।

मॉड्यूल संस्करण सक्षम करने से इन सभी समस्याओं से बचाव होता है।

डिवाइस को बूट किए बिना सीआरसी बेमेल की जाँच करें

stgdiff अन्य ABI अंतरों के साथ कर्नेल के बीच CRC बेमेल की तुलना और रिपोर्ट करता है।

इसके अलावा, CONFIG_MODVERSIONS सक्षम पूर्ण कर्नेल बिल्ड सामान्य बिल्ड प्रक्रिया के भाग के रूप में एक Module.symvers फ़ाइल उत्पन्न करता है। इस फ़ाइल में कर्नेल ( vmlinux ) और मॉड्यूल द्वारा निर्यात किए गए प्रत्येक प्रतीक के लिए एक पंक्ति है। प्रत्येक पंक्ति में CRC मान, प्रतीक नाम, प्रतीक नामस्थान, vmlinux या मॉड्यूल नाम जो प्रतीक को निर्यात कर रहा है, और निर्यात प्रकार (उदाहरण के लिए, EXPORT_SYMBOL बनाम EXPORT_SYMBOL_GPL ) शामिल हैं।

आप vmlinux द्वारा निर्यात किए गए प्रतीकों में किसी भी CRC अंतर की जांच के लिए GKI बिल्ड और अपने बिल्ड के बीच Module.symvers फ़ाइलों की तुलना कर सकते हैं। यदि vmlinux द्वारा निर्यात किए गए किसी प्रतीक में CRC मान में अंतर है और उस प्रतीक का उपयोग आपके डिवाइस में लोड किए गए मॉड्यूल में से एक द्वारा किया जाता है, तो मॉड्यूल लोड नहीं होता है।

यदि आपके पास सभी बिल्ड कलाकृतियाँ नहीं हैं, लेकिन GKI कर्नेल और आपके कर्नेल की vmlinux फ़ाइलें हैं, तो आप दोनों कर्नेल पर निम्नलिखित कमांड चलाकर और आउटपुट की तुलना करके एक विशिष्ट प्रतीक के लिए CRC मानों की तुलना कर सकते हैं:

nm <path to vmlinux>/vmlinux | grep __crc_<symbol name>

उदाहरण के लिए, निम्न आदेश module_layout प्रतीक के लिए सीआरसी मान की जांच करता है:

nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout

सीआरसी विसंगतियों का समाधान करें

मॉड्यूल लोड करते समय सीआरसी बेमेल को हल करने के लिए निम्नलिखित चरणों का उपयोग करें:

  1. निम्नलिखित कमांड में दिखाए अनुसार --kbuild_symtypes विकल्प का उपयोग करके GKI कर्नेल और अपने डिवाइस कर्नेल का निर्माण करें:

    tools/bazel run --kbuild_symtypes //common:kernel_aarch64_dist
    

    यह कमांड प्रत्येक .o फ़ाइल के लिए एक .symtypes फ़ाइल उत्पन्न करता है। विवरण के लिए क्लीफ़ में 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 ध्वज पहले से ही अंतर्निहित रूप से सेट होता है।

  2. निम्न आदेश का उपयोग करके .c फ़ाइल ढूंढें जिसमें CRC बेमेल प्रतीक निर्यात किया गया है:

    cd common && git grep EXPORT_SYMBOL.*module_layout
    kernel/module.c:EXPORT_SYMBOL(module_layout);
    
  3. .c फ़ाइल में GKI में एक संगत .symtypes फ़ाइल होती है, और आपका डिवाइस कर्नेल कलाकृतियों का निर्माण करता है। निम्नलिखित आदेशों का उपयोग करके .c फ़ाइल का पता लगाएँ:

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

    .c फ़ाइल की विशेषताएँ निम्नलिखित हैं:

    • .c फ़ाइल का प्रारूप प्रति प्रतीक एक (संभावित रूप से बहुत लंबी) पंक्ति है।

    • [s|u|e|etc]# लाइन की शुरुआत में इसका मतलब है कि प्रतीक डेटा प्रकार का है [struct|union|enum|etc] । उदाहरण के लिए:

      t#bool typedef _Bool bool
      
    • पंक्ति की शुरुआत में एक लुप्त # उपसर्ग इंगित करता है कि प्रतीक एक फ़ंक्शन है। उदाहरण के लिए:

      find_module s#module * find_module ( const char * )
      
  4. दो फ़ाइलों की तुलना करें और सभी अंतरों को ठीक करें।

केस 1: डेटा प्रकार दृश्यता के कारण अंतर

यदि एक कर्नेल किसी प्रतीक या डेटा प्रकार को मॉड्यूल के लिए अपारदर्शी रखता है और दूसरा कर्नेल नहीं रखता है, तो वह अंतर दो कर्नेल की .symtypes फ़ाइलों के बीच दिखाई देता है। एक कर्नेल से .symtypes फ़ाइल में एक प्रतीक UNKNOWN है और दूसरे कर्नेल से .symtypes फ़ाइल में प्रतीक या डेटा प्रकार का एक विस्तारित दृश्य है।

उदाहरण के लिए, आपके कर्नेल में include/linux/device.h फ़ाइल में निम्न पंक्ति जोड़ने से CRC बेमेल हो जाता है, जिनमें से एक module_layout() के लिए है:

 #include <linux/fwnode.h>

उस प्रतीक के लिए module.symtypes की तुलना करने से निम्नलिखित अंतर उजागर होते हैं:

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

यदि आपके कर्नेल का मान UNKNOWN है और GKI कर्नेल में प्रतीक का विस्तारित दृश्य है (बहुत असंभावित), तो नवीनतम एंड्रॉइड कॉमन कर्नेल को अपने कर्नेल में मर्ज करें ताकि आप नवीनतम GKI कर्नेल बेस का उपयोग कर सकें।

अधिकांश मामलों में, GKI कर्नेल का मान UNKNOWN होता है, लेकिन आपके कर्नेल में किए गए परिवर्तनों के कारण आपके कर्नेल में प्रतीक का आंतरिक विवरण होता है। ऐसा इसलिए है क्योंकि आपके कर्नेल की फ़ाइलों में से एक ने #include जोड़ा है जो GKI कर्नेल में मौजूद नहीं है।

अक्सर, समाधान genksyms से नए #include छिपाने जितना आसान होता है।

#ifndef __GENKSYMS__
#include <linux/fwnode.h>
#endif

अन्यथा, उस #include पहचान करने के लिए जो अंतर का कारण बनता है, इन चरणों का पालन करें:

  1. वह हेडर फ़ाइल खोलें जो इस अंतर वाले प्रतीक या डेटा प्रकार को परिभाषित करती है। उदाहरण के लिए, struct fwnode_handle के लिए include/linux/fwnode.h संपादित करें।

  2. हेडर फ़ाइल के शीर्ष पर निम्नलिखित कोड जोड़ें:

    #ifdef CRC_CATCH
    #error "Included from here"
    #endif
    
  3. मॉड्यूल की .c फ़ाइल में जिसमें CRC बेमेल है, किसी भी #include लाइन से पहले पहली पंक्ति के रूप में निम्नलिखित जोड़ें।

    #define CRC_CATCH 1
    
  4. अपना मॉड्यूल संकलित करें. परिणामी बिल्ड-टाइम त्रुटि हेडर फ़ाइल #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 कर्नेल में गायब है।

  5. परिवर्तन को पहचानें, इसे अपने कर्नेल में वापस लाएं या इसे ACK पर अपलोड करें और इसे मर्ज करें

केस 2: डेटा प्रकार में परिवर्तन के कारण अंतर

यदि किसी प्रतीक या डेटा प्रकार के लिए सीआरसी बेमेल दृश्यता में अंतर के कारण नहीं है, तो यह डेटा प्रकार में वास्तविक परिवर्तनों (परिवर्धन, निष्कासन या परिवर्तन) के कारण है।

उदाहरण के लिए, आपके कर्नेल में निम्नलिखित परिवर्तन करने से कई सीआरसी बेमेल हो जाते हैं क्योंकि इस प्रकार के परिवर्तन से कई प्रतीक अप्रत्यक्ष रूप से प्रभावित होते हैं:

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 struct iommu_ops { ... ; t#phy
  s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t ) ; int
    ( * add_device ) ( s#device * ) ; ...
  +s#iommu_ops struct iommu_ops { ... ; t#phy
  s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t , unsigned long ) ; int ( * add_device ) ( s#device * ) ; ...

बदले हुए प्रकार की पहचान करने के लिए, इन चरणों का पालन करें:

  1. स्रोत कोड में प्रतीक की परिभाषा ढूंढें (आमतौर पर .h फ़ाइलों में)।

    • आपके कर्नेल और GKI कर्नेल के बीच सरल प्रतीक अंतर के लिए, निम्न कमांड चलाकर कमिट ढूंढें:
    git blame
    
    • हटाए गए प्रतीकों के लिए (जहां एक पेड़ में एक प्रतीक हटा दिया गया है और आप इसे दूसरे पेड़ में भी हटाना चाहते हैं), आपको उस परिवर्तन को ढूंढना होगा जिसने लाइन को हटा दिया है। उस पेड़ पर निम्नलिखित कमांड का उपयोग करें जहां लाइन हटा दी गई थी:
    git log -S "copy paste of deleted line/word" -- <file where it was deleted>
    
  2. परिवर्तन या विलोपन का पता लगाने के लिए प्रतिबद्धताओं की लौटाई गई सूची की समीक्षा करें। पहली प्रतिबद्धता शायद वह है जिसे आप खोज रहे हैं। यदि ऐसा नहीं है, तो सूची को तब तक देखें जब तक आपको प्रतिबद्धता न मिल जाए।

  3. परिवर्तन की पहचान करने के बाद, या तो इसे अपने कर्नेल में वापस लाएँ या इसे ACK पर अपलोड करें और इसे मर्ज कर दें