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