ניטור ABI של ליבת אנדרואיד

אתה יכול להשתמש בכלי ניטור ממשק בינארי (ABI) של יישומים, הזמינים באנדרואיד 11 ומעלה, כדי לייצב את ה-ABI בתוך הליבה של גרעיני אנדרואיד. הכלי אוסף ומשווה ייצוגי ABI מקבצים בינאריים קיימים של ליבה (מודולי vmlinux + GKI). ייצוגי ABI אלה הם קובצי .stg ורשימות הסמלים. הממשק עליו הייצוג נותן תצוגה נקרא ממשק מודול ליבה (KMI). אתה יכול להשתמש בכלים כדי לעקוב ולהפחית שינויים ב-KMI.

כלי הניטור של ABI פותח ב-AOSP ומשתמש ב-STG (או libabigail באנדרואיד 13 ומטה) כדי ליצור ולהשוות ייצוגים.

דף זה מתאר את הכלים, תהליך האיסוף והניתוח של ייצוגי ABI, והשימוש בייצוגים כאלה כדי לספק יציבות ל-ABI בתוך הליבה. דף זה מספק גם מידע לתרומת שינויים לגרעיני האנדרואיד.

תהליך

ניתוח ה-ABI של הקרנל לוקח מספר שלבים, רובם ניתנים לאוטומטיים:

  1. בנה את הליבה ואת ייצוג ה-ABI שלו .
  2. נתח הבדלי ABI בין ה-build להפניה .
  3. עדכן את ייצוג ABI (אם נדרש) .
  4. עבודה עם רשימות סמלים .

ההוראות הבאות פועלות עבור כל ליבה שתוכל לבנות באמצעות שרשרת כלים נתמכת (כגון שרשרת הכלים Clang שנבנתה מראש). repo manifests זמינים עבור כל ענפי הליבה הנפוצים של אנדרואיד ועבור מספר גרעינים ספציפיים למכשיר, הם מבטיחים כי נעשה שימוש בשרשרת הכלים הנכונה כאשר אתה בונה הפצת ליבה לניתוח.

רשימות סמלים

ה-KMI אינו כולל את כל הסמלים בקרנל או אפילו את כל 30,000+ הסמלים המיוצאים. במקום זאת, הסמלים שניתן להשתמש בהם על ידי מודולי הספק רשומים במפורש בקבוצה של קבצי רשימת סמלים המתוחזקים באופן ציבורי בשורש עץ הליבה. האיחוד של כל הסמלים בכל קבצי רשימת הסמלים מגדיר את קבוצת סמלי ה-KMI הנשמרת כיציבה. קובץ רשימת סמלים לדוגמה הוא abi_gki_aarch64_db845c , המצהיר על הסמלים הנדרשים עבור ה- DragonBoard 845c .

רק הסמלים הרשומים ברשימת סמלים והמבנים וההגדרות הקשורים אליהם נחשבים לחלק מה-KMI. אתה יכול לפרסם שינויים ברשימות הסמלים שלך אם הסמלים שאתה צריך אינם קיימים. לאחר שממשקים חדשים נמצאים ברשימת סמלים, והם חלק מתיאור ה-KMI, הם נשמרים כיציבים ואין להסירם מרשימת הסמלים או לשנותם לאחר הקפאת הסניף.

לכל ענף ליבת KMI של Android Common Kernel (ACK) יש סט רשימות סמלים משלו. לא נעשה ניסיון לספק יציבות ABI בין ענפי ליבת 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. אין להסיר סמלים מרשימה עבור ליבה אלא אם כן ניתן לאשר שאף מכשיר לא נשלח מעולם עם תלות בסמל זה.

אתה יכול ליצור רשימת סמלים של KMI עבור מכשיר באמצעות ההוראות מאיך לעבוד עם רשימות סמלים . שותפים רבים מגישים רשימת סמלים אחת לכל ACK, אך זו לא דרישה קשה. אם זה עוזר בתחזוקה, אתה יכול לשלוח רשימות סמלים מרובות.

הארך את ה-KMI

בעוד שסמלי KMI ומבנים קשורים נשמרים כיציבים (כלומר לא ניתן לקבל שינויים השוברים ממשקים יציבים בליבה עם KMI קפוא), ליבת ה-GKI נשארת פתוחה להרחבות כך שמכשירים המשלוחים מאוחר יותר בשנה אינם צריכים להגדיר את כל התלות שלהם לפני הקפאת ה-KMI. כדי להרחיב את ה-KMI, אתה יכול להוסיף סמלים חדשים ל-KMI עבור פונקציות ליבה מיוצאות חדשות או קיימות, גם אם ה-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 של build עם תיקון זה מוחל, הכלי יוצא עם קוד שגיאה שאינו אפס ומדווח על הבדל 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 ) ולאחר מכן לעדכן את ייצוג ה-ABI XML ורשימת הסמלים. לדוגמה, השינויים הבאים מוסיפים את תכונת ה-Incremental FS החדשה לסניף android-12-5.10 , הכוללת עדכון רשימת הסמלים וייצוג ABI XML.

  • דוגמה לשינוי תכונה נמצאת ב- 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 גם בליבה וגם ב-ACK (ראה עדכון ייצוג ABI ). לדוגמא לעדכון רשימת ה-ABI XML והסמלים ב-ACK, עיין ב- aosp/1367601 .

פתור שברי ABI של ליבה

אתה יכול לטפל בשבירת ABI של ליבה על ידי עיבוד מחדש של הקוד כדי לא לשנות את ה-ABI או עדכון ייצוג ABI . השתמש בתרשים הבא כדי לקבוע את הגישה הטובה ביותר למצבך.

תרשים זרימת שבירה של ABI

איור 1. רזולוציית שבירה של ABI

Refactor קוד כדי למנוע שינויים ABI

עשה כל מאמץ כדי להימנע משינוי ה-ABI הקיים. במקרים רבים, אתה יכול לשנות את הקוד שלך כדי להסיר שינויים המשפיעים על ה-ABI.

  • שחזור שינויים בשדה מבנה. אם שינוי משנה את ה-ABI עבור תכונת ניפוי באגים, הוסף #ifdef סביב השדות (במבנים ובהפניות למקור) וודא שה- CONFIG המשמש עבור #ifdef מושבת עבור ה-production defconfig ו- gki_defconfig . לדוגמא כיצד ניתן להוסיף תצורת באגים למבנה מבלי לשבור את ה-ABI, עיין בערכת תיקונים זו .

  • שחזור תכונות כדי לא לשנות את ליבת הליבה. אם יש צורך להוסיף תכונות חדשות ל-ACK כדי לתמוך במודולים של השותפים, נסה לשחזר את חלק ה-ABI של השינוי כדי להימנע משינוי ה-ABI של הליבה. לדוגמא לשימוש ב-ABI הקיים של הליבה כדי להוסיף פונקציונליות נוספת מבלי לשנות את ה-ABI של הליבה, עיין ב- aosp/1312213 .

תקן ABI שבור באנדרואיד Gerrit

אם לא שברת בכוונה את ה-ABI של הליבה, אז אתה צריך לחקור, באמצעות ההדרכה שמספקת כלי הניטור של ABI. הגורמים הנפוצים ביותר לשברים הם מבני נתונים שהשתנו ושינויי הסמל המשויכים ל-CRC, או עקב שינויים באפשרויות התצורה שמובילים לכל אחד מהדברים האמורים. התחל בטיפול בבעיות שמצא הכלי.

אתה יכול לשחזר את ממצאי ABI באופן מקומי, ראה בניית הליבה וייצוג ה-ABI שלו .

לגבי תוויות Lint-1

אם אתה מעלה שינויים לסניף המכיל KMI קפוא או סופי, השינויים חייבים לעבור את AbiAnalyzer כדי להבטיח שהשינויים לא ישפיעו על ה-ABI היציב בצורה לא תואמת. במהלך תהליך זה, ה- AbiAnalyzer מחפש את דוח ה-ABI שנוצר במהלך הבנייה (מבנה מורחב שמבצע את הבנייה הרגילה ולאחר מכן כמה שלבי חילוץ והשוואה של ABI.

אם ה- AbiAnalyzer מוצא דוח לא ריק הוא מגדיר את תווית Lint-1 והשינוי נחסם להגשה עד לפתרון; עד שסט הטלאים יקבל תווית Lint+1.

עדכן את ה-Kernel ABI

אם שינוי ה-ABI הוא בלתי נמנע, עליך להחיל את שינויי הקוד שלך, ייצוג ABI ורשימת הסמלים על ה-ACK. כדי לגרום ל-Lint להסיר את -1 ולא לשבור את תאימות GKI, בצע את השלבים הבאים:

  1. העלה שינויים בקוד ל-ACK .

  2. המתן לקבלת קוד סקירת +2 עבור ערכת התיקון.

  3. עדכן את ייצוג ה-ABI הייחוס .

  4. מזג את השינויים בקוד שלך ושינוי עדכון ABI.

העלה שינויים בקוד ABI ל-ACK

עדכון ה-ACK ABI תלוי בסוג השינוי שמתבצע.

  • אם שינוי ABI קשור לתכונה המשפיעה על בדיקות CTS או VTS, בדרך כלל ניתן לבחור את השינוי ל-ACK כפי שהוא. לדוגמה:

  • אם שינוי ABI מיועד לתכונה שניתן לשתף עם ה-ACK, ניתן לבחור את השינוי הזה ל-ACK כפי שהוא. לדוגמה, השינויים הבאים אינם נחוצים עבור בדיקת CTS או VTS, אך ניתן לשתף אותם עם ACK:

  • אם שינוי ABI מציג תכונה חדשה שאינה צריכה להיכלל ב-ACK, אתה יכול להציג את הסמלים ל-ACK באמצעות בדל כמתואר בסעיף הבא.

השתמש בסתימות עבור ACK

Stubs חייבים להיות נחוצים רק עבור שינויים בליבת הליבה שאינם מועילים ל-ACK, כגון שינויים בביצועים ובכוח. הרשימה הבאה מפרטת דוגמאות של בדלי וקטיף דובדבנים חלקיים ב-ACK עבור GKI.

  • בדל תכונה מבודד ליבות ( aosp/1284493 ). הפונקציונליות ב-ACK אינה הכרחית, אבל הסמלים צריכים להיות נוכחים ב-ACK כדי שהמודולים שלך ישתמשו בסמלים אלה.

  • סמל מציין מיקום עבור מודול ספק ( aosp/1288860 ).

  • בחירת דובדבן בלבד של ABI של תכונת מעקב אחר אירועים mm לכל תהליך ( aosp/1288454 ). התיקון המקורי נבחר ל-ACK ולאחר מכן נחתך כך שיכלול רק את השינויים הדרושים כדי לפתור את ההבדל ב-ABI עבור task_struct ו- mm_event_count . תיקון זה גם מעדכן את ה- mm_event_type enum כך שיכיל את האיברים הסופיים.

  • בחירת דובדבן חלקית של שינויי ABI במבנה תרמי שדרשו יותר מסתם הוספת שדות ABI החדשים.

    • תיקון aosp/1255544 פתר הבדלי ABI בין ליבת השותף ל-ACK.

    • תיקון aosp/1291018 תיקן את הבעיות התפקודיות שנמצאו במהלך בדיקת GKI של התיקון הקודם. התיקון כלל אתחול מבנה פרמטר החיישן כדי לרשום מספר אזורים תרמיים לחיישן בודד.

  • CONFIG_NL80211_TESTMODE שינויים ב-ABI ( aosp/1344321 ). תיקון זה הוסיף את שינויי המבנה הדרושים עבור ABI ודאג שהשדות הנוספים לא יגרמו להבדלים תפקודיים, מה שאיפשר לשותפים לכלול CONFIG_NL80211_TESTMODE בליבת הייצור שלהם ועדיין לשמור על תאימות ל-GKI.

אכוף את ה-KMI בזמן ריצה

ליבות ה-GKI משתמשות באפשרויות התצורה TRIM_UNUSED_KSYMS=y ו- UNUSED_KSYMS_WHITELIST=<union of all symbol lists> , המגבילות את הסמלים המיוצאים (כגון סמלים המיוצאים באמצעות EXPORT_SYMBOL_GPL() ) לאלה הרשומים ברשימת סמלים. כל שאר הסמלים אינם מיוצאים, וטעינת מודול הדורש סמל לא מיוצא נדחית. הגבלה זו נאכפת בזמן הבנייה וערכים חסרים מסומנים.

למטרות פיתוח, אתה יכול להשתמש במבנה ליבת GKI שאינו כולל חיתוך סמלים (כלומר ניתן להשתמש בכל הסמלים המיוצאים בדרך כלל). כדי לאתר את ה-builds האלה, חפש את ה- kernel_debug_aarch64 ב- ci.android.com .

אכוף את ה-KMI באמצעות ניהול גרסאות של מודול

ליבות תמונת ליבה כללית (GKI) משתמשות בגירסאות מודול ( CONFIG_MODVERSIONS ) כאמצעי נוסף לאכיפת תאימות ל-KMI בזמן ריצה. ניהול גרסאות של מודול יכול לגרום לכשלים בבדיקת יתירות מחזורית (CRC) בזמן טעינת המודול אם ה-KMI הצפוי של מודול אינו תואם ל- vmlinux KMI. לדוגמה, להלן כשל טיפוסי המתרחש בזמן טעינת המודול עקב אי-התאמה של CRC עבור הסמל module_layout() :

init: Loading module /lib/modules/kernel/.../XXX.ko with args ""
XXX: disagrees about version of symbol module_layout
init: Failed to insmod '/lib/modules/kernel/.../XXX.ko' with args ''

שימושים בניהול גרסאות מודול

ניהול גרסאות מודול שימושי מהסיבות הבאות:

  • ניהול גרסאות של מודול קולט שינויים בנראות מבנה הנתונים. אם מודולים משנים מבני נתונים אטומים, כלומר מבני נתונים שאינם חלק מה-KMI, הם נשברים לאחר שינויים עתידיים במבנה.

    כדוגמה, שקול את השדה fwnode ב- struct device . שדה זה חייב להיות אטום למודולים כדי שלא יוכלו לבצע שינויים בשדות של device->fw_node או להניח הנחות לגבי הגודל שלו.

    עם זאת, אם מודול כולל <linux/fwnode.h> (באופן ישיר או עקיף), אז השדה fwnode struct device כבר לא אטום עבורו. לאחר מכן, המודול יכול לבצע שינויים device->fwnode->dev או device->fwnode->ops . תרחיש זה בעייתי מכמה סיבות, המפורטות כדלקמן:

    • זה יכול לשבור הנחות שקוד הליבה עושה לגבי מבני הנתונים הפנימיים שלו.

    • אם עדכון ליבה עתידי משנה את ה- struct fwnode_handle (סוג הנתונים של fwnode ), אז המודול כבר לא עובד עם הקרנל החדש. יתרה מכך, stgdiff לא יציג שום הבדלים מכיוון שהמודול שובר את ה-KMI על ידי מניפולציה ישירה של מבני נתונים פנימיים בדרכים שלא ניתן ללכוד רק על ידי בדיקת הייצוג הבינארי.

  • מודול נוכחי נחשב כבלתי תואם KMI כאשר הוא נטען במועד מאוחר יותר על ידי ליבה חדשה שאינה תואמת. ניהול גרסאות של מודול מוסיף בדיקת זמן ריצה כדי למנוע טעינה בטעות של מודול שאינו תואם KMI עם הליבה. בדיקה זו מונעת בעיות בזמן ריצה שקשה לאפות באגים וקריסות ליבה שעלולות לנבוע מאי תאימות לא מזוהה ב-KMI.

הפעלת ניהול גרסאות מודול מונעת את כל הבעיות הללו.

בדוק אם יש אי התאמה של CRC מבלי לאתחל את המכשיר

stgdiff משווה ומדווח על אי התאמה של CRC בין ליבות יחד עם הבדלי ABI אחרים.

בנוסף, בניית ליבה מלאה עם CONFIG_MODVERSIONS מופעלת מייצרת קובץ Module.symvers כחלק מתהליך הבנייה הרגיל. לקובץ זה יש שורה אחת לכל סמל המיוצא על ידי הקרנל ( vmlinux ) והמודולים. כל שורה מורכבת מערך ה-CRC, שם הסמל, מרחב השמות של הסמל, שם ה- vmlinux או המודול שמייצא את הסמל וסוג הייצוא (לדוגמה, EXPORT_SYMBOL לעומת EXPORT_SYMBOL_GPL ).

אתה יכול להשוות את קבצי Module.symvers בין ה-GKI build ל-build שלך כדי לבדוק אם יש הבדלים ב-CRC בסמלים המיוצאים על ידי vmlinux . אם יש הבדל בערך CRC בסמל כלשהו שמיוצא על ידי vmlinux והסמל הזה משמש את אחד מהמודולים שאתה טוען במכשיר שלך, המודול לא נטען.

אם אין לך את כל חפצי הבנייה, אבל יש לך את קבצי vmlinux של ליבת GKI והקרנל שלך, אתה יכול להשוות את ערכי ה-CRC עבור סמל מסוים על ידי הפעלת הפקודה הבאה על שני הגרעינים והשוואת הפלט:

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 ומטה בנה את ליבת ה-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, וחפצי בניית ליבת המכשיר שלך. אתר את קובץ .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 יש את התצוגה המורחבת של הסמל (מאוד לא סביר), אז מיזוג את ה- Android Common Kernel העדכני ביותר לתוך הליבה שלך כך שאתה משתמש בבסיס ליבת GKI העדכני ביותר.

ברוב המקרים, לליבה של 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 שהובילה לאי-התאמה של ה-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: הבדלים עקב שינויים בסוג הנתונים

אם חוסר ההתאמה של ה-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 ).

    • עבור הבדלי סמלים פשוטים בין הליבה שלך ל-GKI, מצא את ה-commit על ידי הפעלת הפקודה הבאה:
    git blame
    
    • עבור סמלים שנמחקו (כאשר סמל נמחק בעץ וברצונך למחוק אותו גם בעץ השני), עליך למצוא את השינוי שמחק את השורה. השתמש בפקודה הבאה בעץ שבו נמחקה השורה:
    git log -S "copy paste of deleted line/word" -- <file where it was deleted>
    
  2. עיין ברשימת ההתחייבויות שהוחזרו כדי לאתר את השינוי או המחיקה. ההתחייבות הראשונה היא כנראה זו שאתה מחפש. אם לא, עברו על הרשימה עד שתמצאו את ה-commit.

  3. לאחר שתזהה את השינוי, החזר אותו בקרנל שלך או העלה אותו ל-ACK ותמזג אותו .