يُعدّ ثبات واجهة التطبيق الثنائية (ABI) متطلبًا أساسيًا لإجراء تحديثات ضمن إطار العمل فقط، لأنّ وحدات المورّدين قد تعتمد على المكتبات المشتركة الخاصة بـ "حزمة تطوير البرامج الأصلية للمورّدين" (VNDK) المتوفّرة في قسم النظام. ضمن إصدار Android، يجب أن تكون المكتبات المشتركة لنظام التشغيل VNDK التي تم إنشاؤها حديثًا متوافقة مع معيار ABI مع المكتبات المشتركة لنظام التشغيل VNDK التي تم إصدارها سابقًا حتى تتمكّن وحدات المورّدين من العمل مع هذه المكتبات بدون إعادة الترجمة وبدون أخطاء وقت التشغيل. يمكن تغيير مكتبات VNDK بين إصدارات Android، ولا تتوفّر أي ضمانات بشأن ABI .
للمساعدة في ضمان التوافق مع واجهات التطبيق الثنائية (ABI)، يتضمّن الإصدار 9 من Android أداة فحص واجهة التطبيق الثنائية (ABI) كما هو موضّح في الأقسام التالية.
لمحة عن امتثال VNDK وABI
VNDK هي مجموعة مفروض عليها قيود من المكتبات التي يمكن أن ترتبط بها وحدات المورّدين، والتي تتيح التحديثات للإطار فقط. يشير التوافق مع 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 ،
ما يؤدي إلى تصدير المزيد من الأنواع:
ومع ذلك، لا يمكن الوصول إلى foo_private_t لأنّه لا يتم تصديره من خلال foo_exported.h . (foo_private_t *
غير شفافة، وبالتالي يُسمح بالتغييرات التي يتم إجراؤها على foo_private_t ).
|
يمكن تقديم تفسير مشابه للأنواع التي يمكن الوصول إليها من خلال محددات الفئة الأساسية ومعاملات النماذج أيضًا.
التأكّد من امتثال واجهة ABI
يجب التأكّد من امتثال ABI للمكتبات التي تم وضع علامة عليها
vendor_available: true
وvndk.enabled: true
فيملفَي Android.bp
corresponding
المعنيَّين. مثلاً:
cc_library { name: "libvndk_example", vendor_available: true, vndk: { enabled: true, } }
بالنسبة إلى أنواع البيانات التي يمكن الوصول إليها بشكل مباشر أو غير مباشر من خلال دالة مصدَّرة، يتم تصنيف التغييرات التالية التي يتم إجراؤها على مكتبة على أنّها إيقاف واجهة ABI:
نوع البيانات | الوصف |
---|---|
الهياكل والفئات |
|
الاتحادات |
|
التعدادات |
|
الرموز العالمية |
|
* يجب عدم تغيير أو إزالة الدالتين العامتين والخاصة، لأنّ الدوال المضمّنة العامة يمكن أن تشير إلى الدوال الأعضاء الخاصة. يمكن الاحتفاظ بمراجع الرموز إلى دوال الأعضاء الخاصة في ملفات الثنائيات للمتصل. إنّ تغيير وظائف الأعضاء الخاصة أو إزالتها من المكتبات المشتركة قد يؤدي إلى إنشاء ملفات ثنائية غير متوافقة مع الإصدارات القديمة.
** يجب عدم تغيير المُعلّقات لعناصر البيانات العامة أو الخاصة لأنّ الدوالّ المضمّنة يمكنها الإشارة إلى عناصر البيانات هذه في نص الدالة. يمكن أن يؤدي تغيير Offsets لأعضاء البيانات إلى توليد ملفَي binary غير متوافقَين مع الإصدارات القديمة.
*** على الرغم من أنّ هذه التغييرات لا تغيّر تنسيق الذاكرة للنوع، إلا أنّ هناك اختلافات دلالية قد تؤدي إلى عدم عمل المكتبات على النحو المتوقّع.
استخدام أدوات الامتثال لـ 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. إنشاء تقرير الاختلافات
header-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 التي تصدّرها الرؤوس العامة في directory
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
كإدخال، ثم تربط هذه الملفات:
مداخل |
|
---|---|
الإخراج | ملف يصف واجهة برمجة التطبيقات لنظام التشغيل لإحدى المكتبات المشتركة (على سبيل المثال، يمثّل
libfoo.so.lsdump واجهة برمجة التطبيقات لنظام التشغيل 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
تقارن أداة 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 وواجهة برمجة التطبيقات لمكتبات 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