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

يعد استقرار الواجهة الثنائية للتطبيق (ABI) شرطًا أساسيًا لتحديثات إطار العمل فقط لأن وحدات البائع قد تعتمد على المكتبات المشتركة Vendor Native Development Kit (VNDK) الموجودة في قسم النظام. ضمن إصدار Android، يجب أن تكون مكتبات VNDK المشتركة المبنية حديثًا متوافقة مع ABI لمكتبات VNDK المشتركة التي تم إصدارها مسبقًا حتى تتمكن وحدات البائع من العمل مع تلك المكتبات دون إعادة الترجمة ودون أخطاء وقت التشغيل. بين إصدارات Android، يمكن تغيير مكتبات VNDK ولا توجد ضمانات لـ ABI.

للمساعدة في ضمان توافق ABI، يتضمن Android 9 مدقق ABI للرأس، كما هو موضح في الأقسام التالية.

حول امتثال VNDK وABI

VNDK عبارة عن مجموعة مقيدة من المكتبات التي قد ترتبط بها وحدات البائع والتي تتيح تحديثات إطار العمل فقط. يشير توافق ABI إلى قدرة الإصدار الأحدث من المكتبة المشتركة على العمل كما هو متوقع مع وحدة مرتبطة به ديناميكيًا (أي يعمل كإصدار أقدم من المكتبة).

حول الرموز المصدرة

يشير الرمز الذي تم تصديره (المعروف أيضًا بالرمز العالمي ) إلى رمز يلبي جميع ما يلي:

  • تم التصدير بواسطة الرؤوس العامة للمكتبة المشتركة.
  • يظهر في جدول .dynsym لملف .so المطابق للمكتبة المشتركة.
  • لديه ربط ضعيف أو عالمي.
  • الرؤية افتراضية أو محمية.
  • فهرس القسم ليس غير محدد.
  • النوع إما 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"
  ],
}
.جدول الديناميكية
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، يعرض سجل البناء تحذيرات بنوع التحذير ومسارًا إلى تقرير abi-diff. على سبيل المثال، إذا كان لدى واجهة برمجة التطبيقات الخاصة بـ libbinder تغيير غير متوافق، فسيقوم نظام الإنشاء بإلقاء خطأ مع رسالة مشابهة لما يلي:

*****************************************************
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 creation
    الشكل 1. إنشاء ملفات .sdump
  2. يقوم header-abi-linker بعد ذلك بمعالجة ملفات .sdump (باستخدام إما برنامج نصي للإصدار المقدم له أو ملف .so المطابق للمكتبة المشتركة) لإنتاج ملف .lsdump الذي يسجل جميع معلومات ABI المقابلة للمكتبة المشتركة.
    lsdump creation
    الشكل 2. إنشاء ملف .lsdump
  3. يقارن header-abi-diff ملف .lsdump بملف .lsdump مرجعي لإنتاج تقرير فرق يوضح الاختلافات في واجهات ABI للمكتبتين.
    abi diff creation
    الشكل 3. إنشاء تقرير الفرق

رأس أبي قلابة

تقوم أداة header-abi-dumper بتوزيع ملف مصدر C/C++ وتفريغ ABI المستنتج من هذا الملف المصدر إلى ملف وسيط. يقوم نظام البناء بتشغيل header-abi-dumper على جميع ملفات المصدر المترجمة بينما يقوم أيضًا ببناء مكتبة تتضمن الملفات المصدر من التبعيات المتعدية.

المدخلات
  • الملف المصدر AC/C++
  • تصديرها تشمل الدلائل
  • أعلام المترجم
انتاج | ملف يصف ABI للملف المصدر (على سبيل المثال، foo.sdump يمثل foo.cpp 's ABI).

تتوفر حاليًا ملفات .sdump بتنسيق JSON، وهو أمر غير مضمون أن يكون مستقرًا عبر الإصدارات المستقبلية. على هذا النحو، ينبغي اعتبار تنسيق الملف .sdump أحد تفاصيل تنفيذ نظام البناء.

على سبيل المثال، يحتوي 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-dumper كمدخلات ثم تربط تلك الملفات:

المدخلات
  • الملفات الوسيطة التي تنتجها header-abi-dumper
  • الإصدار النصي/ملف الخريطة (اختياري)
  • .so ملف المكتبة المشتركة
  • تصديرها تشمل الدلائل
انتاج | ملف يصف ABI لمكتبة مشتركة (على سبيل المثال، libfoo.so.lsdump يمثل libfoo 's ABI).

تقوم الأداة بدمج الرسوم البيانية للنوع في جميع الملفات الوسيطة المعطاة لها، مع الأخذ في الاعتبار اختلافات التعريف الواحد (الأنواع المحددة بواسطة المستخدم في وحدات ترجمة مختلفة بنفس الاسم المؤهل بالكامل، قد تكون مختلفة لغويًا) عبر وحدات الترجمة. تقوم الأداة بعد ذلك بتوزيع البرنامج النصي للإصدار أو جدول .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 .

رأس أبي فرق

تقوم أداة header-abi-diff بمقارنة ملفين .lsdump يمثلان واجهة التطبيق الثنائية (ABI) لمكتبتين وتنتج تقريرًا مختلفًا يوضح الاختلافات بين واجهتي ABI.

المدخلات
  • يمثل ملف .lsdump واجهة ABI لمكتبة مشتركة قديمة.
  • يمثل ملف .lsdump واجهة ABI لمكتبة مشتركة جديدة.
انتاج | تقرير فرق يوضح الاختلافات في واجهات التطبيقات الثنائية التي تقدمها المكتبتان المشتركتان مقارنة.

ملف ABI diff موجود بتنسيق نص 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 * (يتم تجريد كافة أنواع typedefs).

يشير الحقل 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 يؤدي الآن إلى خطأ في البناء.

لتحديث مراجع 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