יציבות ABI

יציבות Application Binary Interface (ABI) היא דרישה מוקדמת עדכונים של framework בלבד, כי המודולים של הספק עשויים להיות תלויים ב-Native של הספק ספריות משותפות של ערכת פיתוח (VNDK) שנמצאות במחיצת המערכת. בגרסה של Android, ספריות משותפות של VNDK שנוצרו לאחרונה חייבות להיות תואם ל-ABI לספריות משותפות של VNDK שפורסמו בעבר, כך שמודולים של ספקים יכול לפעול עם הספריות האלה ללא אוסף מחדש ובלי שגיאות זמן ריצה. בין הגרסאות של Android, ניתן לשנות ספריות VNDK ואין ממשק ABI באחריות.

כדי להבטיח תאימות ABI, מערכת Android 9 כוללת בודק ABI כותרת, כפי שמתואר בקטעים הבאים.

מידע על תאימות של VNDK ו-ABI

ה-VNDK היא קבוצה מגבילה של ספריות שמודולים של ספקים יכולים לקשר אליהם שמאפשרים עדכונים של framework בלבד. תאימות ל-ABI מתייחסת את היכולת של גרסה חדשה יותר של ספרייה משותפת לפעול כצפוי עם שמקושר אליו באופן דינמי (כלומר פועל כגרסה ישנה יותר של לספרייה).

מידע על סמלים שיוצאו

סמל מיוצא (שנקרא גם סמל גלובלי) מתייחס סמל שעומד בכל התנאים הבאים:

  • מיוצא באמצעות הכותרות הציבוריות של ספרייה משותפת.
  • מופיע בטבלה .dynsym של הקובץ .so שתואם לספרייה המשותפת.
  • יש לו קישור WEAK או GLOBAL.
  • הרשאות הגישה הן ברירת המחדל או ההגנה.
  • אינדקס הקטע לא מוגדר.
  • הסוג הוא FUNC או OBJECT.

הכותרות הציבוריות של ספרייה משותפת מוגדרות ככותרות לספריות/קבצים בינאריים אחרים דרך export_include_dirs, export_header_lib_headers export_static_lib_headers, export_shared_lib_headers, וגם מאפייני export_generated_headers ב-Android.bp ההגדרות של המודול שתואם לספרייה המשותפת.

מידע על סוגים שאפשר להגיע אליהם

סוג נגיש הוא כל סוג מובנה של C/C++ או מוגדר על ידי המשתמש, שניתן להגיע אליו באופן ישיר או עקיף דרך סמל מיוצא, וגם באמצעות כותרות ציבוריות. לדוגמה, ל-libfoo.so יש פונקציה Foo, שהוא סמל מיוצא שנמצא טבלה .dynsym. הספרייה libfoo.so כוללת את הבאים:

foo_exported.h foo.private.h
typedef struct foo_private foo_private_t;

typedef struct foo {
  int m1;
  int *m2;
  foo_private_t *mPfoo;
} foo_t;

typedef struct bar {
  foo_t mfoo;
} bar_t;

bool Foo(int id, bar_t *bar_ptr);
typedef struct foo_private {
  int m1;
  float mbar;
} foo_private_t;
Android.bp
cc_library {
  name : libfoo,
  vendor_available: true,
  vndk {
    enabled : true,
  }
  srcs : ["src/*.cpp"],
  export_include_dirs : [
    "exported"
  ],
}
טבלת .dynsym
Num Value Size Type Bind Vis Ndx Name
1 0 0 FUNC GLOB DEF UND dlerror@libc
2 1ce0 20 FUNC GLOB DEF 12 Foo

על סמך Foo, סוגי האינטראקציות הישירות והעקיפים כוללים:

סוג תיאור
bool סוג ההחזרה: Foo.
int סוג הפרמטר הראשון (Foo).
bar_t * סוג הפרמטר השני של Foo. דרך bar_t *, הייצוא של bar_t מיוצא באמצעות foo_exported.h.

bar_t מכיל חבר mfoo, מסוג foo_t, שמיוצא באמצעות foo_exported.h, כתוצאה מכך, יותר סוגים מיוצאים:
  • int : הוא הסוג של m1.
  • int * : הוא הסוג של m2.
  • foo_private_t * : הוא הסוג של mPfoo.

עם זאת, אי אפשר לגשת אל foo_private_t כי הוא לא הייצוא בוצע דרך foo_exported.h. (foo_private_t *) אטום, ולכן שינויים שבוצעו ב-foo_private_t מותרים.)

אפשר להסביר הסבר דומה לסוגים שאפשר להגיע אליהם דרך מחלקת הבסיס. ואת הפרמטרים של התבניות.

בדיקה של תאימות ל-ABI

יש לוודא תאימות ל-ABI עבור ספריות שמסומנות vendor_available: true וגם vndk.enabled: true Android.bp הקבצים המתאימים. לדוגמה:

cc_library {
    name: "libvndk_example",
    vendor_available: true,
    vndk: {
        enabled: true,
    }
}

לגבי סוגי נתונים שפונקציות מיוצאות יכולים לגשת אליהן באופן ישיר או עקיף, השינויים הבאים בספרייה מסווגים כהפסקות ABI:

סוג נתונים תיאור
מבנים וכיתות
  • אפשר לשנות את הגודל של סוג הכיתה או את סוג המבנה.
  • סיווגי בסיס
    • מוסיפים או מסירים כיתות בסיס.
    • להוסיף או להסיר את מחלקות הבסיס שעברו בירושה וירטואלית.
    • שינוי הסדר של מחלקות הבסיס.
  • פעולות לחברים
    • הסרת פונקציות של חברים*.
    • הוספה או הסרה של ארגומנטים מפונקציות של חברים.
    • שינוי סוגי הארגומנטים או סוגי ההחזרה של החבר פונקציות*.
    • משנים את הפריסה של הטבלה הווירטואלית.
  • חברים בנתונים
    • מסירים חברים של נתונים סטטיים.
    • מוסיפים או מסירים חברים של נתונים לא סטטיים.
    • שינוי הסוגים של החברים בנתונים.
    • משנים את ההיסט לאלה של נתונים לא סטטיים**.
    • לשנות את const, volatile ו/או restricted תוחמים של חברים בנתונים***.
    • שדרוג לאחור של מצייןי הגישה של החברים בנתונים***.
  • משנים את הארגומנטים בתבנית.
איגודים
  • מוסיפים או מסירים חברים בנתונים.
  • שינוי הגודל של סוג האיחוד.
  • שינוי הסוגים של החברים בנתונים.
ערכים של ספירה
  • שינוי הסוג הבסיסי.
  • משנים את שמות הסופרים.
  • שינוי ערכי המונה.
סמלים גלובליים
  • מסירים את הסמלים שיוצאו מכותרות ציבוריות.
  • לסמלים גלובליים מסוג FUNC
    • הוספה או הסרה של ארגומנטים.
    • שינוי סוגי הארגומנטים.
    • שינוי סוג ההחזרה.
    • שדרוג לאחור של מציין הגישה***.
  • לסמלים גלובליים מסוג OBJECT
    • משנים את הסוג המתאים של C/C++.
    • שדרוג לאחור של מציין הגישה***.

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

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

*** אמנם הם לא משנים את פריסת הזיכרון מהסוג הזה, יש הבדלים סמנטיים שעלולים להוביל לכך שלא פועלות כמצופה.

שימוש בכלים לתאימות ל-ABI

בזמן הבנייה של ספריית VNDK, מתבצעת השוואה בין ה-ABI של הספרייה הפניית ABI תואמת לגרסת ה-VNDK שנמצאת בבנייה. אפליקציות עזר קובצי תמונה של ABI נמצאים ב:

${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/<PLATFORM_VNDK_VERSION>/<BINDER_BITNESS>/<ARCH>/source-based

לדוגמה, בפיתוח libfoo ל-x86 ברמת API 27, המערכת משווה בין ה-ABI המשוער של libfoo לבין ההפניה שלו כך:

${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/27/64/x86/source-based/libfoo.so.lsdump

שגיאה בתקלה ב-ABI

כשיש תקלות ב-ABI, ביומן ה-build מוצגות אזהרות עם סוג האזהרה נתיב לדוח ה-Abi-diff. לדוגמה, אם ה-ABI של libbinder כולל שינוי לא תואם, מערכת ה-build גורמת לשגיאה עם הודעה כמו:

*****************************************************
error: VNDK library: libbinder.so's ABI has INCOMPATIBLE CHANGES
Please check compatibility report at:
out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm64_armv8-a_cortex-a73_vendor_shared/libbinder.so.abidiff
******************************************************
---- Please update abi references by running
platform/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l libbinder ----

יצירת בדיקות ABI של ספרייה VNDK

כשיוצרים ספרייה של VNDK:

  1. header-abi-dumper מעבד את קובצי המקור שעברו הידור ליצור את ספריית VNDK (קובצי המקור של הספרייה עצמה וגם קובצי המקור עוברים בירושה דרך יחסי תלות סטטיים, .sdump קבצים שתואמים לכל אחד מהמקורות.
    יצירת קובץ sdump
    איור 1. יצירת .sdump קבצים
  2. לאחר מכן, header-abi-linker מעבד את .sdump קבצים (באמצעות סקריפט הגרסה שסופק לו או באמצעות .so שתואם לספרייה המשותפת) כדי ליצור .lsdump שרושם את כל פרטי ה-ABI שתואמים לספרייה המשותפת.
    יצירת lsdump
    איור 2. יצירת .lsdump קובץ
  3. header-abi-diff משווה את .lsdump עם קובץ עזר של .lsdump כדי להפיק דוח הבדלים שמתארים את ההבדלים בין ממשקי ה-ABI של שתי הספריות.
    יצירה של הבדלי Abi
    איור 3. יוצרים את דוח ההבדלים

כותרת-abi-dumper

הכלי header-abi-dumper מנתח קובץ מקור וקובצי מקור מסוג C/C++ את ה-ABI שהמערכת מסיקה מקובץ המקור הזה לקובץ ביניים. גרסת ה-build המערכת תריץ את header-abi-dumper בכל קובצי המקור שעברו הידור בזמן וגם ליצור ספרייה שכוללת את קובצי המקור של יחסי התלות.

כניסות קלט
  • קובץ מקור מסוג C/C++
  • הושלם הייצוא של ספריות מסוג 'הכללה'
  • דגלים של מהדר
פלט קובץ שמתאר את ה-ABI של קובץ המקור (לדוגמה, foo.sdump היא ה-ABI של foo.cpp).

נכון לעכשיו, .sdump קבצים הם בפורמט JSON, שאינו יציבות בגרסאות עתידיות. לכן, .sdump יש להתייחס לפורמט הקובץ כפרטי ההטמעה של מערכת ה-build.

לדוגמה, libfoo.so מכיל את קובץ המקור הבא foo.cpp:

#include <stdio.h>
#include <foo_exported.h>

bool Foo(int id, bar_t *bar_ptr) {
    if (id > 0 && bar_ptr->mfoo.m1 > 0) {
        return true;
    }
    return false;
}

אפשר להשתמש ב-header-abi-dumper כדי ליצור אמצעי ביניים קובץ .sdump שמייצג את ה-ABI שמוצג על ידי קובץ המקור באמצעות:

$ header-abi-dumper foo.cpp -I exported -o foo.sdump -- -I exported -x c++

הפקודה הזו מנחה את header-abi-dumper לנתח foo.cpp עם דגלי המהדר אחרי --, וגם פולט את פרטי ה-ABI שמיוצאים על ידי הכותרות הציבוריות הספרייה exported. אלה הפרטים foo.sdump נוצר על ידי header-abi-dumper:

{
 "array_types" : [],
 "builtin_types" :
 [
  {
   "alignment" : 4,
   "is_integral" : true,
   "linker_set_key" : "_ZTIi",
   "name" : "int",
   "referenced_type" : "_ZTIi",
   "self_type" : "_ZTIi",
   "size" : 4
  }
 ],
 "elf_functions" : [],
 "elf_objects" : [],
 "enum_types" : [],
 "function_types" : [],
 "functions" :
 [
  {
   "function_name" : "FooBad",
   "linker_set_key" : "_Z6FooBadiP3foo",
   "parameters" :
   [
    {
     "referenced_type" : "_ZTIi"
    },
    {
     "referenced_type" : "_ZTIP3foo"
    }
   ],
   "return_type" : "_ZTI3bar",
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "global_vars" : [],
 "lvalue_reference_types" : [],
 "pointer_types" :
 [
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIP11foo_private",
   "name" : "foo_private *",
   "referenced_type" : "_ZTI11foo_private",
   "self_type" : "_ZTIP11foo_private",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIP3foo",
   "name" : "foo *",
   "referenced_type" : "_ZTI3foo",
   "self_type" : "_ZTIP3foo",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIPi",
   "name" : "int *",
   "referenced_type" : "_ZTIi",
   "self_type" : "_ZTIPi",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "qualified_types" : [],
 "record_types" :
 [
  {
   "alignment" : 8,
   "fields" :
   [
    {
     "field_name" : "mfoo",
     "referenced_type" : "_ZTI3foo"
    }
   ],
   "linker_set_key" : "_ZTI3bar",
   "name" : "bar",
   "referenced_type" : "_ZTI3bar",
   "self_type" : "_ZTI3bar",
   "size" : 24,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "fields" :
   [
    {
     "field_name" : "m1",
     "referenced_type" : "_ZTIi"
    },
    {
     "field_name" : "m2",
     "field_offset" : 64,
     "referenced_type" : "_ZTIPi"
    },
    {
     "field_name" : "mPfoo",
     "field_offset" : 128,
     "referenced_type" : "_ZTIP11foo_private"
    }
   ],
   "linker_set_key" : "_ZTI3foo",
   "name" : "foo",
   "referenced_type" : "_ZTI3foo",
   "self_type" : "_ZTI3foo",
   "size" : 24,
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "rvalue_reference_types" : []
}

foo.sdump מכיל פרטי ABI שיוצאו על ידי קובץ המקור foo.cpp והכותרות הציבוריות, לדוגמה,

  • record_types התייחסות למבנים, לאיחודים או למחלקות שהוגדרו בכותרות הציבוריות. לכל סוג רשומה יש מידע על השדות, גודל, מציין גישה, קובץ הכותרת שבו הוא מוגדר ועוד .
  • pointer_types התייחסות לסוגי המצביע באופן ישיר או עקיף שיש אליהן הפניה מהרשומות/הפונקציות המיוצאות בכותרות הציבוריות, יחד מסוג שמצביע מפנה אליו (באמצעות ה-referenced_type בשדה type_info). מידע דומה נרשם קובץ .sdump לסוגים מתאימים, סוגי C/C++ מובנים, מערך וסוגי הפניות של lvalue ו-rvalue. מידע כזה מאפשר שונות רקורסיביות.
  • functions הציגו פונקציות שיוצאו על ידי כותרות ציבוריות. יש בהם גם מידע על השם הפגום של הפונקציה, סוג ההחזרה, סוגי הפרמטרים, מציין הגישה ומאפיינים אחרים.

header-abi-linker

הכלי header-abi-linker מתייחס לקובצי הביניים שנוצרו על ידי header-abi-dumper כקלט, ואז מקשר את הקבצים האלה:

כניסות קלט
  • קובצי ביניים שנוצרו על ידי header-abi-dumper
  • סקריפט גרסה/קובץ מפה (אופציונלי)
  • קובץ אחד (.so) של הספרייה המשותפת
  • הושלם הייצוא של ספריות מסוג 'הכללה'
פלט קובץ שמתאר את ה-ABI של ספרייה משותפת (לדוגמה, libfoo.so.lsdump היא ה-ABI של libfoo).

הכלי ממזג את תרשימי הסוגים בכל קובצי הביניים שסופקו לו, תוך התייחסות להגדרה אחת (סוגים בהגדרת המשתמש יחידות תרגום עם אותו שם מלא, עשויות להיות סמנטיות שונים) בין יחידות התרגום. לאחר מכן הכלי ינתח סקריפט של גרסה או הטבלה .dynsym של הספרייה המשותפת (קובץ אחד (.so)) כדי ליצור רשימה של הסמלים שיוצאו.

לדוגמה, libfoo מכיל foo.cpp ו bar.cpp. ניתן להפעיל את header-abi-linker ל- יוצרים את תמונת ה-ABI המלאה של libfoo באופן הבא:

header-abi-linker -I exported foo.sdump bar.sdump \
                  -o libfoo.so.lsdump \
                  -so libfoo.so \
                  -arch arm64 -api current

פלט פקודה לדוגמה ב-libfoo.so.lsdump:

{
 "array_types" : [],
 "builtin_types" :
 [
  {
   "alignment" : 1,
   "is_integral" : true,
   "is_unsigned" : true,
   "linker_set_key" : "_ZTIb",
   "name" : "bool",
   "referenced_type" : "_ZTIb",
   "self_type" : "_ZTIb",
   "size" : 1
  },
  {
   "alignment" : 4,
   "is_integral" : true,
   "linker_set_key" : "_ZTIi",
   "name" : "int",
   "referenced_type" : "_ZTIi",
   "self_type" : "_ZTIi",
   "size" : 4
  }
 ],
 "elf_functions" :
 [
  {
   "name" : "_Z3FooiP3bar"
  },
  {
   "name" : "_Z6FooBadiP3foo"
  }
 ],
 "elf_objects" : [],
 "enum_types" : [],
 "function_types" : [],
 "functions" :
 [
  {
   "function_name" : "Foo",
   "linker_set_key" : "_Z3FooiP3bar",
   "parameters" :
   [
    {
     "referenced_type" : "_ZTIi"
    },
    {
     "referenced_type" : "_ZTIP3bar"
    }
   ],
   "return_type" : "_ZTIb",
   "source_file" : "exported/foo_exported.h"
  },
  {
   "function_name" : "FooBad",
   "linker_set_key" : "_Z6FooBadiP3foo",
   "parameters" :
   [
    {
     "referenced_type" : "_ZTIi"
    },
    {
     "referenced_type" : "_ZTIP3foo"
    }
   ],
   "return_type" : "_ZTI3bar",
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "global_vars" : [],
 "lvalue_reference_types" : [],
 "pointer_types" :
 [
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIP11foo_private",
   "name" : "foo_private *",
   "referenced_type" : "_ZTI11foo_private",
   "self_type" : "_ZTIP11foo_private",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIP3bar",
   "name" : "bar *",
   "referenced_type" : "_ZTI3bar",
   "self_type" : "_ZTIP3bar",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIP3foo",
   "name" : "foo *",
   "referenced_type" : "_ZTI3foo",
   "self_type" : "_ZTIP3foo",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIPi",
   "name" : "int *",
   "referenced_type" : "_ZTIi",
   "self_type" : "_ZTIPi",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "qualified_types" : [],
 "record_types" :
 [
  {
   "alignment" : 8,
   "fields" :
   [
    {
     "field_name" : "mfoo",
     "referenced_type" : "_ZTI3foo"
    }
   ],
   "linker_set_key" : "_ZTI3bar",
   "name" : "bar",
   "referenced_type" : "_ZTI3bar",
   "self_type" : "_ZTI3bar",
   "size" : 24,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "fields" :
   [
    {
     "field_name" : "m1",
     "referenced_type" : "_ZTIi"
    },
    {
     "field_name" : "m2",
     "field_offset" : 64,
     "referenced_type" : "_ZTIPi"
    },
    {
     "field_name" : "mPfoo",
     "field_offset" : 128,
     "referenced_type" : "_ZTIP11foo_private"
    }
   ],
   "linker_set_key" : "_ZTI3foo",
   "name" : "foo",
   "referenced_type" : "_ZTI3foo",
   "self_type" : "_ZTI3foo",
   "size" : 24,
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "rvalue_reference_types" : []
}

הכלי header-abi-linker:

  • מקשר אל .sdump הקבצים שסופקו (foo.sdump) ו-bar.sdump), לסינון נתוני ה-ABI שלא נמצאים הכותרות שנמצאות בספרייה: exported.
  • ניתוח של libfoo.so ואיסוף מידע על הסמלים הספרייה ייצאה דרך הטבלה .dynsym.
  • הוספה של _Z3FooiP3bar ושל _Z6FooBadiP3foo.

libfoo.so.lsdump הוא תמונת ה-ABI הסופית שנוצרה libfoo.so.

כותרת-abi-diff

הכלי header-abi-diff משווה בין שני קובצי .lsdump שמייצג את ה-ABI של שתי ספריות ומפיק דוח הבדלים שמציין בין שני ממשקי ה-ABI.

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

קובץ הפרשי ה-ABI נמצא פורמט טקסט של Protobuf. הפורמט עשוי להשתנות בגרסאות עתידיות.

לדוגמה, יש לך שתי גרסאות של libfoo: libfoo_old.so ו libfoo_new.so. בעוד libfoo_new.so, ב- bar_t, בחרת לשנות את הסוג של mfoo מ: foo_t אל foo_t *. מכיוון ש-bar_t הוא סוג נגיש, צריך לסמן את זה כשינוי תוכנה שעלול לגרום לכשל ב-ABI על ידי header-abi-diff.

כדי להריץ את header-abi-diff:

header-abi-diff -old libfoo_old.so.lsdump \
                -new libfoo_new.so.lsdump \
                -arch arm64 \
                -o libfoo.so.abidiff \
                -lib libfoo

פלט פקודה לדוגמה ב-libfoo.so.abidiff:

lib_name: "libfoo"
arch: "arm64"
record_type_diffs {
  name: "bar"
  type_stack: "Foo-> bar *->bar "
  type_info_diff {
    old_type_info {
      size: 24
      alignment: 8
    }
    new_type_info {
      size: 8
      alignment: 8
    }
  }
  fields_diff {
    old_field {
      referenced_type: "foo"
      field_offset: 0
      field_name: "mfoo"
      access: public_access
    }
    new_field {
      referenced_type: "foo *"
      field_offset: 0
      field_name: "mfoo"
      access: public_access
    }
  }
}

השדה libfoo.so.abidiff מכיל דיווח על כל השיבושים ב-ABI שינויים ב-libfoo. ההודעה של record_type_diffs מציין שהרשומה השתנתה ומפרט את השינויים הלא תואמים, כוללים:

  • גודל הרשומה משתנה מ-24 בייטים ל- 8 בייטים.
  • סוג השדה mfoo משתנה מ-foo ל- foo * (כל הגדרות ה-typedef מבוטלות).

השדה type_stack מציין איך header-abi-diff הגיעו לסוג שהשתנה (bar). השדה הזה יכול להיות מפורשת כ-Foo היא פונקציה מיוצאת שמקבלת bar * כפרמטר שמצביע אל bar, ייצוא והשתנה.

אכיפה של ממשק ABI ו-API

כדי לאכוף את ה-ABI וה-API של ספריות משותפות של VNDK, הפניות ל-ABI צריכות לעשות צ'ק-אין אל ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/. כדי ליצור את ההפניות האלה, מריצים את הפקודה הבאה:

${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py

לאחר יצירת ההפניות, כל שינוי שמתבצע בקוד המקור בשינוי לא תואם של ABI/API בספריית VNDK, תופיע עכשיו שגיאת build.

כדי לעדכן הפניות ABI לספריות ספציפיות, מריצים את הפקודה הבאה:

${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l <lib1> -l <lib2>

לדוגמה, כדי לעדכן libbinder הפניות ABI, מריצים את:

${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l libbinder