Stabilitas Antarmuka Biner Aplikasi (ABI) adalah prasyarat untuk update khusus framework karena modul vendor mungkin bergantung pada library bersama Vendor Native Development Kit (VNDK) yang berada di partisi sistem. Dalam rilis Android, library bersama VNDK yang baru dibuat harus kompatibel dengan ABI library bersama VNDK yang dirilis sebelumnya sehingga modul vendor dapat berfungsi dengan library tersebut tanpa kompilasi ulang dan tanpa error runtime. Di antara rilis Android, library VNDK dapat diubah dan tidak ada jaminan ABI.
Untuk membantu memastikan kompatibilitas ABI, Android 9 menyertakan pemeriksa ABI header, seperti yang dijelaskan di bagian berikut.
Tentang VNDK dan kepatuhan ABI
VNDK adalah serangkaian library ketat yang dapat ditautkan oleh modul vendor dan yang memungkinkan update khusus framework. Kepatuhan ABI mengacu pada kemampuan library bersama versi yang lebih baru untuk berfungsi seperti yang diharapkan dengan modul yang ditautkan secara dinamis ke library tersebut (yaitu berfungsi seperti versi library yang lebih lama).
Tentang simbol yang diekspor
Simbol yang diekspor (juga dikenal sebagai simbol global) merujuk pada simbol yang memenuhi semua hal berikut:
- Diekspor oleh header publik library bersama.
- Muncul di tabel .dynsympada file.soyang sesuai dengan library bersama.
- Memiliki pengikatan WEAK atau GLOBAL.
- Visibilitasnya adalah DEFAULT atau DILINDUNGI.
- Indeks bagian tidak UNDEFINED.
- Jenisnya adalah FUNC atau OBJECT.
  Header publik library bersama ditentukan sebagai header
  yang tersedia untuk library/biner lain melalui
  atribut export_include_dirs, export_header_lib_headers,
  export_static_lib_headers,
  export_shared_lib_headers, dan
  export_generated_headers dalam definisi Android.bp
  modul yang sesuai dengan library bersama.
Tentang jenis yang dapat dijangkau
  Jenis yang dapat dijangkau adalah jenis bawaan atau yang ditentukan pengguna C/C++ yang
  dapat dijangkau secara langsung atau tidak langsung melalui simbol yang diekspor DAN diekspor
  melalui header publik. Misalnya, libfoo.so memiliki fungsi
  Foo, yang merupakan simbol yang diekspor dan ditemukan di
  tabel .dynsym. Library libfoo.so mencakup hal berikut:
| 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" ], } | 
| Tabel .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 | 
  Melihat Foo, jenis yang dapat dijangkau langsung/tidak langsung meliputi:
| Jenis | Deskripsi | 
|---|---|
| bool | Jenis nilai yang ditampilkan dari Foo. | 
| int | Jenis parameter Foopertama. | 
| bar_t * | Jenis parameter Foo kedua. Dengan bar_t *,bar_tdiekspor melaluifoo_exported.h.bar_tberisi anggotamfoo, dengan jenisfoo_t, yang diekspor melaluifoo_exported.h,
  yang menghasilkan lebih banyak jenis yang diekspor:
 Namun, foo_private_tTIDAK dapat dijangkau karena tidak
  diekspor melaluifoo_exported.h. (foo_private_t *bersifat buram, sehingga perubahan yang dilakukan padafoo_private_tdiizinkan.) | 
Penjelasan serupa dapat diberikan untuk jenis yang dapat dijangkau melalui penentu class dasar dan parameter template juga.
Memastikan kepatuhan ABI
  Kepatuhan ABI harus dipastikan untuk library yang ditandai
  vendor_available: true dan vndk.enabled: true dalam
  file Android.bp yang sesuai. Contoh:
cc_library { name: "libvndk_example", vendor_available: true, vndk: { enabled: true, } }
Untuk jenis data yang dapat dijangkau secara langsung atau tidak langsung oleh fungsi yang diekspor, perubahan berikut pada library diklasifikasikan sebagai merusak ABI:
| Jenis data | Deskripsi | 
|---|---|
| Struktur dan Kelas | 
 | 
| Gabungan | 
 | 
| Enumerasi | 
 | 
| Simbol Global | 
 | 
* Fungsi anggota publik dan pribadi tidak boleh diubah atau dihapus karena fungsi inline publik dapat merujuk ke fungsi anggota pribadi. Referensi simbol ke fungsi anggota pribadi dapat dipertahankan dalam biner pemanggil. Mengubah atau menghapus fungsi anggota pribadi dari library bersama dapat menghasilkan biner yang tidak kompatibel dengan versi sebelumnya.
** Offset ke anggota data publik atau pribadi tidak boleh diubah karena fungsi inline dapat merujuk ke anggota data ini dalam isi fungsinya. Mengubah offset anggota data dapat menghasilkan biner yang tidak kompatibel dengan versi sebelumnya.
*** Meskipun tidak mengubah tata letak memori jenis, ada perbedaan semantik yang dapat menyebabkan library tidak berfungsi seperti yang diharapkan.
Menggunakan alat kepatuhan ABI
Saat library VNDK dibuat, ABI library dibandingkan dengan referensi ABI yang sesuai untuk versi VNDK yang sedang dibuat. Referensi Dump ABI berada di:
${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/<PLATFORM_VNDK_VERSION>/<BINDER_BITNESS>/<ARCH>/source-based
  Misalnya, saat mem-build libfoo untuk x86 di level API 27,
  ABI libfoo yang disimpulkan dibandingkan dengan referensinya di:
${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/27/64/x86/source-based/libfoo.so.lsdump
Error kerusakan ABI
  Pada kerusakan ABI, log build menampilkan peringatan dengan jenis peringatan dan jalur ke laporan abi-diff. Misalnya, jika ABI libbinder memiliki
  perubahan yang tidak kompatibel, sistem build akan menampilkan error dengan pesan
  yang mirip dengan berikut:
***************************************************** 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 ----
Membangun pemeriksaan ABI library VNDK
Saat library VNDK dibuat:
- header-abi-dumpermemproses file sumber yang dikompilasi untuk membangun library VNDK (file sumber library itu sendiri serta file sumber yang diwarisi melalui dependensi transitif statis), untuk menghasilkan file- .sdumpyang sesuai dengan setiap sumber.
 - Gambar 1. Membuat file - .sdump
- header-abi-linkerkemudian memproses file- .sdump(menggunakan skrip versi yang diberikan kepadanya atau file- .soyang sesuai dengan library bersama) untuk menghasilkan file- .lsdumpyang mencatat semua informasi ABI yang sesuai dengan library bersama.
 - Gambar 2. Membuat file - .lsdump
- header-abi-diffmembandingkan file- .lsdumpdengan file- .lsdumpreferensi untuk menghasilkan laporan perbedaan yang menguraikan perbedaan dalam ABI kedua library.
 - Gambar 3. Membuat laporan perbedaan 
header-abi-dumper
  Alat header-abi-dumper mengurai file sumber C/C++ dan mengekspor ABI yang disimpulkan dari file sumber tersebut ke file perantara. Sistem
  build menjalankan header-abi-dumper pada semua file sumber yang dikompilasi sekaligus
  membangun library yang menyertakan file sumber dari dependensi
  transitif.
| Input | 
 | 
|---|---|
| Output | File yang menjelaskan ABI file sumber (misalnya, foo.sdump mewakili ABIfoo.cpp). | 
  Saat ini, file .sdump dalam format JSON, yang tidak dijamin stabil di rilis mendatang. Dengan demikian, pemformatan file .sdump
  harus dianggap sebagai detail implementasi sistem build.
  Misalnya, libfoo.so memiliki file sumber berikut
  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; }
  Anda dapat menggunakan header-abi-dumper untuk membuat file
  .sdump perantara yang merepresentasikan ABI yang ditampilkan oleh file sumber
  menggunakan:
$ header-abi-dumper foo.cpp -I exported -o foo.sdump -- -I exported -x c++
  Perintah ini memberi tahu header-abi-dumper untuk mengurai
  foo.cpp dengan flag compiler yang mengikuti --, dan
  memancarkan informasi ABI yang diekspor oleh header publik di
  direktori exported. Berikut adalah
  foo.sdump yang dibuat oleh
  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 berisi informasi ABI yang diekspor oleh file sumber
  foo.cpp dan header publik, misalnya,
- record_types. Merujuk ke struct, union, atau class yang ditentukan di header publik. Setiap jenis rekaman memiliki informasi tentang kolomnya, ukuran, penentu akses, file header tempat jenis rekaman ditentukan, dan atribut lainnya.
- pointer_types. Merujuk ke jenis pointer yang dirujuk secara langsung/tidak langsung oleh rekaman/fungsi yang diekspor di header publik, bersama dengan jenis yang ditunjuk pointer (melalui kolom- referenced_typedi- type_info). Informasi serupa dicatat dalam file- .sdumpuntuk jenis yang memenuhi syarat, jenis C/C++ bawaan, jenis array, dan jenis referensi lvalue dan rvalue. Informasi tersebut memungkinkan perbedaan rekursif.
- functions. Merepresentasikan fungsi yang diekspor oleh header publik. Mereka juga memiliki informasi tentang nama fungsi yang diubah, jenis yang ditampilkan, jenis parameter, penentu akses, dan atribut lainnya.
header-abi-linker
  Alat header-abi-linker mengambil file perantara yang dihasilkan
  oleh header-abi-dumper sebagai input, lalu menautkan file tersebut:
| Input | 
 | 
|---|---|
| Output | File yang menjelaskan ABI library bersama (misalnya, libfoo.so.lsdump mewakili ABIlibfoo). | 
  Alat ini menggabungkan grafik jenis dalam semua file perantara yang diberikan kepadanya, dengan mempertimbangkan perbedaan satu definisi (jenis yang ditentukan pengguna dalam unit terjemahan yang berbeda dengan nama yang sepenuhnya memenuhi syarat yang sama, mungkin berbeda secara semantik) di seluruh unit terjemahan. Kemudian, alat ini mengurai
  skrip versi atau tabel .dynsym library bersama
  (file .so) untuk membuat daftar simbol yang diekspor.
  Misalnya, libfoo terdiri dari foo.cpp dan
  bar.cpp. header-abi-linker dapat dipanggil untuk
  membuat dump ABI tertaut lengkap dari libfoo sebagai berikut:
header-abi-linker -I exported foo.sdump bar.sdump \ -o libfoo.so.lsdump \ -so libfoo.so \ -arch arm64 -api current
  Contoh output perintah di 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" : [] }
  Alat header-abi-linker:
- Menautkan file .sdumpyang diberikan kepadanya (foo.sdumpdanbar.sdump), memfilter informasi ABI yang tidak ada di header yang berada di direktori:exported.
- Mengurai libfoo.so, dan mengumpulkan informasi tentang simbol yang diekspor oleh library melalui tabel.dynsym-nya.
- Menambahkan _Z3FooiP3bardan_Z6FooBadiP3foo.
  libfoo.so.lsdump adalah dump ABI yang dihasilkan terakhir dari
  libfoo.so.
header-abi-diff
  Alat header-abi-diff membandingkan dua file .lsdump yang merepresentasikan ABI dari dua library dan menghasilkan laporan perbedaan yang menyatakan perbedaan antara kedua ABI tersebut.
| Input | 
 | 
|---|---|
| Output | Laporan perbedaan yang menyatakan perbedaan ABI yang ditawarkan oleh dua library bersama yang dibandingkan. | 
File perbedaan ABI dalam format teks protobuf. Format dapat berubah dalam rilis mendatang.
  Misalnya, Anda memiliki dua versi
  libfoo: libfoo_old.so dan
  libfoo_new.so. Di libfoo_new.so, di
  bar_t, Anda mengubah jenis mfoo dari
  foo_t menjadi foo_t *. Karena bar_t adalah
  jenis yang dapat dijangkau, hal ini harus ditandai sebagai perubahan yang dapat menyebabkan gangguan pada ABI oleh
  header-abi-diff.
  Untuk menjalankan header-abi-diff:
header-abi-diff -old libfoo_old.so.lsdump \
                -new libfoo_new.so.lsdump \
                -arch arm64 \
                -o libfoo.so.abidiff \
                -lib libfoo
  Contoh output perintah di 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 berisi laporan semua perubahan yang merusak ABI di libfoo. Pesan record_type_diffs
  menunjukkan bahwa suatu data telah berubah dan mencantumkan perubahan yang tidak kompatibel, yang
  mencakup:
- Ukuran rekaman berubah dari 24byte menjadi8byte.
- Jenis kolom mfooberubah darifoomenjadifoo *(semua typedef dihapus).
  Kolom type_stack menunjukkan cara header-abi-diff
  mencapai jenis yang berubah (bar). Kolom ini dapat
  ditafsirkan sebagai Foo adalah fungsi yang diekspor yang mengambil
  bar * sebagai parameter, yang mengarah ke bar, yang diekspor dan diubah.
Menerapkan ABI dan API
  Untuk menerapkan ABI dan API library bersama VNDK, referensi ABI harus
  diperiksa ke ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/.
  Untuk membuat referensi ini, jalankan perintah berikut:
${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py
Setelah membuat referensi, setiap perubahan yang dilakukan pada kode sumber yang menghasilkan perubahan ABI/API yang tidak kompatibel di library VNDK kini akan menghasilkan error build.
Untuk memperbarui referensi ABI untuk library tertentu, jalankan perintah berikut:
${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l <lib1> -l <lib2>
  Misalnya, untuk memperbarui referensi ABI libbinder, jalankan:
${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l libbinder