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

يعد استقرار الواجهة الثنائية (ABI) من المتطلبات الأساسية التحديثات على إطار العمل فقط لأنّ وحدات الموردين قد تعتمد على سمة Vendor Native المكتبات المشتركة لحزمة تطوير البرامج (VNDK) المتوفرة في قسم النظام يجب أن تكون مكتبات VNDK المشتركة المنشأة حديثًا ضمن إصدار Android متوافقة مع واجهة التطبيق الثنائية (ABI) مع مكتبات VNDK المشتركة التي تم إصدارها سابقًا وبالتالي يمكن للمورّدين يمكن العمل مع هذه المكتبات بدون التحويل البرمجي وبدون أخطاء في وقت التشغيل. يمكن تغيير مكتبات VNDK في الفترة بين إصدارات Android ولا تتوفّر واجهة 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++ أو من تحديد المستخدم ويكون يمكن الوصول إليها بشكل مباشر أو غير مباشر من خلال الرمز الذي تم تصديره AND من خلال العناوين العامة على سبيل المثال، 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 على مستوى واجهة برمجة التطبيقات 27، تتم مقارنة واجهة التطبيق الثنائية (ABI) المستنتَجة من libfoo بمرجعها على:

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

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

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

رأس الصفحة-abi-dumper

تُحلّل أداة header-abi-dumper ملف المصدر C/C++ وتجمع البيانات. واجهة التطبيق الثنائية (ABI) المستنتَجة من ملف المصدر هذا إلى ملف وسيط. التصميم يشغِّل النظام header-abi-dumper على كل ملفات المصدر المجمّعة أثناء وكذلك إنشاء مكتبة تتضمن الملفات المصدر من مصادر متعددة والتبعيات لديك.

مداخل
  • ملف المصدر C/C++
  • أدلة التضمين التي تم تصديرها
  • علامات التجميع
الإخراج يشير هذا المصطلح إلى ملف يصف واجهة التطبيق الثنائية (ABI) للملف المصدر (على سبيل المثال، foo.sdump يمثل واجهة التطبيق الثنائية (ABI) لـ foo.cpp).

حاليًا .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 تمثيل الدوال التي تم تصديرها من خلال العناوين العامة كما أن لديهم معلومات عن الاسم المشوه للدالة ونوع الإرجاع وأنواع المعلمات ومحدد الوصول والسمات الأخرى.

رابط رأس الصفحة في واجهة برمجة التطبيقات Abi

تستخدم أداة 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

اختلاف رأس الصفحة

تقارن أداة 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 * (يتم إزالة جميع تعريفات الكتابة)

ويشير الحقل type_stack إلى كيفية استخدام header-abi-diff وصلت إلى النوع الذي تغيّر (bar). قد يكون هذا الحقل أن Foo هي دالة مصدَّرة تأخذ bar * كمعلمة، التي تشير إلى bar، والتي كانت وتصديرها وتغييرها.

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

لفرض واجهة التطبيق الثنائية (ABI) وواجهة برمجة التطبيقات (API) لمكتبات VNDK المشتركة، يجب أن تتضمن مراجع ABI مراجعي 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