تتبُّع واجهة التطبيق الثنائية (ABI) بنواة Android

يمكنك استخدام أدوات مراقبة واجهة التطبيق الثنائية (ABI)، المتوفّرة في Android 11 والإصدارات الأحدث، لتحسين استقرار واجهة التطبيق الثنائية (ABI) المضمّنة في نواة نظام التشغيل Android. تجمع الأدوات تمثيلات ABI من ملفات ثنائية النواة الحالية (vmlinux+ وحدات GKI) وتقارن بينها. تمثيلات ABI هذه هي ملفات .stg وقوائم الرموز. تُعرف الواجهة التي يعرض عليها التمثيل عرضًا باسم واجهة وحدة النواة (KMI). يمكنك استخدام الأدوات لتتبُّع التغييرات التي تطرأ على مؤشر KMI والحدّ منها.

تم تطوير أدوات مراقبة ABI في AOSP وتستخدم STG (أو libabigail في Android 13 والإصدارات الأقدم) لإنشاء نماذج مقارنة.

توضّح هذه الصفحة الأدوات وعملية جمع تمثيلات ABI وتحليلها واستخدام هذه التمثيلات لتوفير ثبات لـ ABI داخل النواة. توفر هذه الصفحة أيضًا معلومات للمساهمة بالتغييرات في نواة Android.

معالجة

يتطلّب تحليل ABI للنواة خطوات متعدّدة، يمكن تنفيذ معظمها تلقائيًا:

  1. إنشاء النواة وتمثيل واجهة ABI
  2. تحليل الاختلافات في ABI بين الإصدار والمرجع
  3. عدِّل تمثيل ABI (إذا لزم الأمر).
  4. استخدام قوائم الرموز

يمكن تطبيق التعليمات التالية على أي نواة يمكنك إنشاؤها باستخدام مجموعة أدوات متوافقة (مثل مجموعة أدوات Clang المُنشأة مسبقًا). تتوفر repo manifests لجميع فروع نواة Android الشائعة ولعدة ملفّات نواة تتعلّق بالأجهزة، وهي تضمن استخدام مجموعة الأدوات الصحيحة عند إنشاء إصدار نواة للتحليل.

قوائم الرموز

لا يتضمّن ملف KMI جميع الرموز في النواة أو حتى كل الرموز التي تم تصديرها والتي تزيد عن 30,000 رمز. بدلاً من ذلك، يتم إدراج الرموز التي يمكن أن تستخدمها وحدات المورّدين بشكل صريح في مجموعة من ملفات قائمة الرموز التي يتم الاحتفاظ بها بشكل علني في جذر شجرة النواة. يعمل اتحاد جميع الرموز في جميع ملفات قائمة الرموز على تحديد مجموعة رموز KMI التي يتم الحفاظ عليها كثابتة. مثال على ملف قائمة الرموز هو abi_gki_aarch64_db845c، الذي يعرِض الرموز المطلوبة لجهاز DragonBoard 845c.

فقط الرموز المدرجة في قائمة الرموز والبنيات والتعريفات المرتبطة بها هي جزء من KMI. يمكنك نشر التغييرات على قوائم الرموز إذا لم تكن الرموز التي تحتاج إليها متوفّرة. بعد إدراج الواجهات الجديدة في قائمة رموز وعلى أنها جزء من وصف خوارزمية KMI، يتم الحفاظ على هذه الواجهات كثابتة ويجب عدم إزالتها من قائمة الرموز أو تعديلها بعد تجميد الفرع.

يحتوي كل فرع من فروع "النواة الشائعة لنظام التشغيل Android" (ACK) على مجموعة خاصة به من قوائم الرموز. لا يتمّ إجراء أيّ محاولة لتوفير ثبات ABI بين مشاريع kernel KMI المختلفة. على سبيل المثال، تعتبر KMI لـ android12-5.10 مستقلة تمامًا عن KMI لـ android13-5.10.

تستخدِم أدوات ABI قوائم رموز KMI للحدّ من الواجهات التي يجب مراقبتها من أجل الثبات. تحتوي قائمة الرموز الرئيسية على الرموز المطلوبة من وحدات نواة GKI. ويُتوقّع من المورّدين إرسال قوائم رموز إضافية وتعديلها لضمان أنّ الواجهات التي يعتمدون عليها تحافظ على توافقها مع واجهة التطبيق الثنائية (ABI). على سبيل المثال، للاطّلاع على قائمة بقوائم الرموز الخاصة بـ android13-5.15، يُرجى الرجوع إلى https://android.googlesource.com/kernel/common/+/refs/heads/android13-5.15/android.

تحتوي قائمة الرموز على الرموز التي تم الإبلاغ عن أنّها مطلوبة لجهة التصنيع أو الجهاز المعيّنين. القائمة الكاملة التي تستخدمها الأدوات هي اتحاد جميع ملفات قائمة رموز KMI. تحدِّد أدوات ABI تفاصيل كل رمز، بما في ذلك توقيع الدالة وبنى البيانات المتداخلة.

عند تجميد KMI، لا يُسمح بإجراء أي تغييرات على واجهات KMI الحالية، فهي مستقرة. ومع ذلك، يُتاح للمورّدين إضافة رموز إلى قاعدة بيانات KMI في أي وقت ما دامت الإضافات لا تؤثّر في استقرار ABI الحالي. يتم الحفاظ على ثبات العلامات المُضافة حديثًا فور الإشارة إليها في قائمة رموز KMI. يجب عدم إزالة الرموز من قائمة النواة (kernel) ما لم يتم التأكد من أنه لم يتم شحن أي جهاز من قبل وكان يعتمد على هذا الرمز.

يمكنك إنشاء قائمة رموز KMI لجهاز باستخدام التعليمات الواردة في مقالة كيفية التعامل مع قوائم الرموز. يرسل العديد من الشركاء قائمة رموز واحدة لكلّ رسالة تأكيد، ولكنّ هذا ليس شرطًا صارمًا. وإذا كان ذلك يساعد في الصيانة، يمكنك إرسال قوائم رموز متعددة.

توسيع نطاق نموذج KMI

يتم الحفاظ على استقرار رموز KMI والبُنى ذات الصلة (أي التغييرات التي تؤدي إلى كسر الواجهات الثابتة في النواة ذات الخوارزمية KMI المجمّدة)، تبقى نواة GKI متاحة للإضافات كي لا تحتاج الأجهزة التي يتم شحنها لاحقًا في العام إلى تحديد جميع تبعياتها قبل تجميد KMI. لتوسيع نطاق KMI، يمكنك إضافة رموز جديدة إلى KMI لدوالّ kernel الجديدة أو الحالية التي تم تصديرها، حتى إذا تم تجميد KMI. قد يتم أيضًا قبول تصحيحات ملف التمهيد الجديدة إذا كانت لا تؤدي إلى إيقاف KMI.

لمحة عن حالات تعطُّل واجهة برمجة التطبيقات KMI

تحتوي النواة على مصادر ويتم إنشاء الملفات الثنائية من هذه المصادر. تشمل فروع النواة التي تراقبها واجهة التطبيق الثنائية (ABI) تمثيل ABI لـ GKI ABI الحالي (في شكل ملف .stg). بعد إنشاء الملفات الثنائية (vmlinux وImage و أي وحدات GKI)، يمكن استخراج تمثيل ABI من الملفات الثنائية. يمكن أن يؤثر أي تغيير يتم إجراؤه على ملف مصدر نواة النظام في الملفات الثنائية، وبالتالي في .stg المستخرَج. يقارن محلّل AbiAnalyzerملف .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) للإصدار مع تطبيق هذا الإصلاح، تنتهي الأداة مع رمز خطأ غير صفري وتُبلغ عن اختلاف في واجهة برمجة التطبيقات (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) في وقت الإصدار

إنّ السبب الأكثر شيوعًا للأخطاء هو استخدام برنامج تشغيل رمزًا جديدًا من ملف ‎"النواة" ليس مُدرَجًا في أي من قوائم الرموز.

إذا لم يكن الرمز مُدرَجًا في قائمة الرموز (android/abi_gki_aarch64)، عليك أولاً التأكّد من تصديره باستخدام EXPORT_SYMBOL_GPL(symbol_name) ثم تعديل تمثيل XML ورمز ABI وقائمة الرموز. على سبيل المثال، تضيف التغييرات التالية ميزة FS الإضافية الجديدة إلى فرع android-12-5.10، والتي تشمل تعديل قائمة الرموز وتمثيل XML الخاص بـ ABI.

  • يمكنك الاطّلاع على مثال على تغيير الميزة في aosp/1345659.
  • يمكنك العثور على مثال لقائمة الرموز فيملف aosp/1346742.
  • يتوفّر مثال على تغيير XML الخاص بـ 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 في كل من kernel وACK (يُرجى الاطّلاع على تعديل تمثيل ABI). للحصول على مثال على تعديل ملف ABI XML وقائمة الرموز في ACK، يُرجى الرجوع إلى aosp/1367601.

حلّ مشاكل تعذُّر استخدام واجهة برمجة التطبيقات للنواة

يمكنك التعامل مع حالات تعطُّل ABI للنواة من خلال إعادة صياغة الرمز لتجنُّب تغيير IDE أو تعديل تمثيل ABI. استخدِم الرسم البياني التالي لتحديد أفضل نهج لحالتك.

رسم بياني انسيابي لحالات كسر ABI

الشكل 1. حلّ مشكلة عدم توافق واجهة ABI

إعادة صياغة الرمز لتجنُّب تغييرات ABI

ابذل قصارى جهدك لتجنُّب تعديل ABI الحالي. في كثير من الحالات، يمكنك إعادة صياغة الرمز البرمجي لإزالة التغييرات التي تؤثّر في ABI.

  • إعادة بناء حقل البنية: إذا أدّى تغيير إلى تعديل واجهة التطبيق الثنائية (ABI) لميزة تصحيح الأخطاء، أضِف #ifdef حول الحقول (في البُنى ومراجع المصدر) وتأكَّد من إيقاف CONFIG المستخدَم في #ifdef لإعدادات الإنتاج وgki_defconfig. للحصول على مثال على كيفية إضافة ملف برمجة debugging config إلى بنية بدون إيقاف ABI، يُرجى الرجوع إلى مجموعة التعديلات هذه.

  • إعادة صياغة الميزات لتجنُّب تغيير النواة الأساسية إذا كان يجب إضافة ميزات جديدة إلى ACK لتتوافق مع وحدات الشركاء، حاوِل إعادة صياغة ABI كجزء من التغيير لتجنُّب تعديل ABI للنواة. للحصول على مثال على استخدام واجهة تطبيقات ثنائية (ABI) الحالية للنواة لإضافة إمكانات إضافية بدون تغيير واجهة تطبيقات ثنائية (ABI) للنواة، يُرجى الرجوع إلى aosp/1312213.

إصلاح واجهة برمجة تطبيقات معطّلة على Android Gerrit

إذا لم تكن قد اخترقت ABI للنواة عن قصد، عليك التحقيق في الأمر، باستخدام الإرشادات المقدَّمة من خلال أدوات مراقبة ABI. إنّ الأسباب الأكثر شيوعًا للحدوث الأعطال هي تغييرات في بنية البيانات والرموز المرتبطة بها المتعلّقة بـ CRC ، أو بسبب تغييرات في خيارات الضبط تؤدي إلى أيّ من الأسباب المذكورة أعلاه. ابدأ بمعالجة المشاكل التي عثرت عليها الأداة.

يمكنك إعادة إنتاج نتائج ABI محليًا، اطّلِع على إنشاء النواة وتمثيل ABI.

لمحة عن تصنيفات Lint-1

في حال تحميل تغييرات إلى فرع يتضمّن ملف KMI مجمّدًا أو نهائيًا، يجب أن تمرّ التغييرات بالاختبار AbiAnalyzer لضمان عدم تأثُّر ABI الثابت بطريقة غير متوافقة. خلال هذه العملية، يبحث AbiAnalyzer عن تقرير ABI الذي تم إنشاؤه أثناء عملية الإنشاء (عملية إنشاء موسّعة تُجري عملية الإنشاء العادية ثم بعض خطوات استخراج ABI ومقارنتها).

إذا عثرت أداة AbiAnalyzer على تقرير غير فارغ، يتم ضبط التصنيف Lint-1 ويتم حظر إرسال المحتوى المتغيّر إلى أن يتم حلّ المشكلة، إلى أن تتلقّى مجموعة التصحيحات تصنيف Lint+1.

تعديل واجهة برمجة التطبيقات للنواة

إذا كان لا مفر من تعديل ABI، عليك تطبيق تغييرات الرمز و تمثيل ABI وقائمة الرموز على ACK. لإزالة القيمة -1 من خلال Lint وعدم إيقاف توافق GKI، اتّبِع الخطوات التالية:

  1. حمِّل التغييرات في الرمز إلى الإشعار بتلقّي الرسالة.

  2. انتظِر تلقّي مراجعة للرمز البرمجي و+2 لمجموعة التصحيحات.

  3. تعديل تمثيل ABI المرجعي

  4. دمج تغييرات الرمز البرمجي وتغيير تحديث ABI

تحميل التغييرات في رمز ABI إلى ACK

يعتمد تعديل ABI لتطبيق ACK على نوع التغيير الذي يتم إجراؤه.

  • إذا كان تغيير ABI مرتبطًا بميزة تؤثّر في اختبارات CTS أو VTS، يمكن عادةً اختيار التغيير لتأكيده كما هو. على سبيل المثال:

    • يجب توفُّر حزمة aosp/1289677 لكي يعمل الصوت.
    • يجب تثبيت الإصدار aosp/1295945 لكي يعمل منفذ USB.
  • إذا كان تغيير ABI ناتجًا عن ميزة يمكن مشاركتها مع ACK، يمكن اختيار هذا التغيير وإضافته إلى ACK كما هو. على سبيل المثال، التغييرات التالية غير مطلوبة لاختبار CTS أو VTS، ولكن يمكن مشاركتها مع ACK:

    • aosp/1250412 هو تغيير في ميزة قياس الحرارة.
    • aosp/1288857 هو تغيير في EXPORT_SYMBOL_GPL.
  • إذا كان تغيير ABI يقدّم ميزة جديدة لا يلزم تضمينها في ACK، يمكنك إدخال الرموز إلى ACK باستخدام رمز نائب كما هو موضّح في القسم التالي.

استخدام العناصر النائبة لتأكيد الاستلام

يجب أن تكون العناصر الأساسية ضرورية فقط لتغييرات النواة الأساسية التي لا تعود بالفائدة على ACK، مثل التغييرات في الأداء والقوة. توضِّح القائمة التالية أمثلة على العناصر النائبة وعمليات الاختيار الجزئي في ACK لـ GKI.

  • رمز مميز لميزة عزل التطبيقات الأساسية (aosp/1284493). الإمكانات في ACK ليست ضرورية، ولكن يجب أن تكون الرموز موجودة في ACK حتى تتمكن الوحدات من استخدام هذه الرموز.

  • رمز العنصر النائب لمكوّن المورّد (aosp/1288860).

  • اختيار ABI فقط لميزة تتبُّع أحداث mm لكل عملية (aosp/1288454). تم اختيار التصحيح الأصلي للموافقة عليه، ثم تم اقتصاصه ليشمل فقط التغييرات اللازمة لحلّ مشكلة اختلاف ABI في task_struct و mm_event_count. يؤدي رمز التصحيح هذا أيضًا إلى تعديل تعداد mm_event_type ليتضمّن الأعضاء النهائيين.

  • اختيار جزئي لتغييرات ABI في البنية الحرارية التي تتطلّب أكثر من إضافة حقول ABI الجديدة

    • تم حلّ الاختلافات في ABI بين نواة الشريك وACK من خلال التصحيح aosp/1255544.

    • أصلح 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 الذي لا يتضمّن قطعًا للرموز (أي يمكن استخدام جميع الرموز التي يتم تصديرها عادةً). لتحديد موقع هذه الإصدارات، ابحث عن إصدارات kernel_debug_aarch64 على ci.android.com.

فرض نموذج إدارة الهوية (KMI) باستخدام نظام ترقيم الإصدارات للوحدات

تستخدِم نوى "صورة النواة العامة" (GKI) نظام ترقيم الإصدارات للوحدات (CONFIG_MODVERSIONS) كإجراء إضافي لفرض الامتثال لـ KMI أثناء وقت التشغيل. يمكن أن يؤدي إنشاء إصدارات من الوحدة إلى حدوث حالات عدم تطابق في فحص التكرار الدوري (CRC) في وقت تحميل الوحدة إذا كان مقياس KMI المتوقع لإحدى الوحدات لا يتطابق مع مؤشر KMI لـ 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 ''

استخدامات ترقيم إصدارات الوحدات

يكون ترقيم الإصدارات للمكوّنات مفيدًا للأسباب التالية:

  • تلتقط إصدارات الوحدة التغييرات التي تطرأ على رؤية بنية البيانات. إذا غيّرت الوحدات هياكل البيانات المبهمة، أي هياكل البيانات التي ليست جزءًا من 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 مع النواة. وتمنع هذه الفحص مشاكل وقت التشغيل التي يصعب تصحيحها وأعطال kernel التي قد تنتج عن عدم التوافق الذي لم يتم اكتشافه في 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 kernel وkernel، يمكنك مقارنة قيم CRC لرمز معيّن ‎بواسطة تنفيذ الأمر التالي على كل من ملفَّي kernel ومقارنة ‎الإخراج:

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) عند تحميل وحدة:

  1. أنشئ نواة GKI ونواة جهازك باستخدام الخيار --kbuild_symtypes كما هو موضّح في الأمر التالي:

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

    ينشئ هذا الأمر ملف .symtypes لكل ملف .o. اطّلِع على KBUILD_SYMTYPES في Kleaf للحصول على التفاصيل.

    بالنسبة إلى الإصدار 13 من نظام التشغيل Android والإصدارات الأقدم، يمكنك إنشاء نواة 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 على ملف .symtypes مقابل في GKI ومواد عرض إنشاء ملف ‎ kernel للجهاز. حدِّد مكان ملف .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 ] ; }
  ...

إذا كانت قيمة kernel لديك هي UNKNOWN وكانت نواة GKI لديها عرض موسّع للرمز (على الأرجح)، ادمج أحدث نواة Android Kernel في نواة kernel لتتمكّن من استخدام أحدث قاعدة GKI kernel.

في معظم الحالات، تكون قيمة kernel (GKI) هي UNKNOWN، غير أنّ النواة تحتوي على تفاصيل داخلية للرمز بسبب التغييرات التي تم إجراؤها على النواة. ويعود سبب ذلك إلى أنّ أحد الملفات في نواة النظام أضاف #include غير متوفّر في نواة GKI.

غالبًا ما يكفي إخفاء #include الجديد من genksyms لحلّ المشكلة.

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

في الحالات الأخرى، لتحديد عنصر #include الذي يسبّب الفارق، اتّبِع الخطوات التالية:

  1. افتح ملف العنوان الذي يحدد الرمز أو نوع البيانات الذي يحتوي على هذا الفرق. على سبيل المثال، عدِّل include/linux/fwnode.h ليصبح struct fwnode_handle.

  2. أضِف الرمز التالي في أعلى ملف العنوان:

    #ifdef CRC_CATCH
    #error "Included from here"
    #endif
    
  3. في ملف .c الخاص بالوحدة الذي يتضمّن تعارضًا في تسلسل التحقّق من صحة البيانات (CRC)، أضِف السطر التالي كأول سطر قبل أيّ من أسطر #include.

    #define CRC_CATCH 1
    
  4. اجمع الوحدات. يعرض الخطأ الناتج عن وقت الإنشاء سلسلة ملف العنوان #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.

  5. حدِّد التغيير، وألغِه في نواة النظام أو حمِّله إلى ACK واطلب دمجه.

الحالة 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 للسمة 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).

    • للتعرّف على الاختلافات في الرموز بين النواة kernel وGKI، يمكنك البحث عن عملية التنفيذ باستخدام الأمر التالي:
    git blame
    
    • بالنسبة إلى الرموز المحذوفة (حيث يتم حذف رمز في شجرة وأردت أيضًا حذفه في الشجرة الأخرى)، عليك العثور على التغيير الذي أدى إلى حذف السطر. استخدم الأمر التالي في الشجرة التي تم حذف السطر فيها:
    git log -S "copy paste of deleted line/word" -- <file where it was deleted>
    
  2. راجِع قائمة عمليات الإلغاء المعروضة للعثور على التغيير أو الحذف. من المرجّح أنّه التغيير الأول هو التغيير الذي تبحث عنه. إذا لم يكن الأمر كذلك، انتقِل إلى أسفل القائمة للعثور على عملية الربط.

  3. بعد تحديد التغيير، يمكنك إما التراجع عنه في نواة النظام أو تحميله إلى ACK ودمجه.