Google is committed to advancing racial equity for Black communities. See how.
Halaman ini diterjemahkan oleh Cloud Translation API.
Switch to English

Stabilitas ABI

Stabilitas Antarmuka Biner Aplikasi (ABI) adalah prasyarat pembaruan kerangka kerja saja karena modul vendor mungkin bergantung pada pustaka bersama Vendor Native Development Kit (VNDK) yang berada di partisi sistem. Dalam rilis Android, library bersama VNDK yang baru dibuat harus kompatibel dengan ABI untuk library bersama VNDK yang dirilis sebelumnya, sehingga modul vendor dapat bekerja dengan library tersebut tanpa kompilasi ulang dan tanpa kesalahan waktu proses. Di antara rilis Android, pustaka 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 kepatuhan VNDK dan ABI

VNDK adalah kumpulan pustaka terbatas yang dapat ditautkan oleh modul vendor dan yang memungkinkan pembaruan kerangka saja. Kepatuhan ABI mengacu pada kemampuan versi yang lebih baru dari pustaka bersama untuk bekerja seperti yang diharapkan dengan modul yang ditautkan secara dinamis (yaitu, berfungsi seperti versi pustaka yang lebih lama).

Tentang simbol yang diekspor

Simbol yang diekspor (juga dikenal sebagai simbol global ) mengacu pada simbol yang memenuhi semua hal berikut:

  • Diekspor oleh header publik dari perpustakaan bersama.
  • Muncul di tabel .dynsym dari file .so sesuai dengan pustaka bersama.
  • Memiliki ikatan LEMAH atau GLOBAL.
  • Visibilitas DEFAULT atau DILINDUNGI.
  • Indeks bagian tidak DITETAPKAN.
  • Jenisnya adalah FUNC atau OBJECT.

Header publik dari pustaka bersama didefinisikan sebagai tajuk yang tersedia untuk pustaka / biner lain melalui export_include_dirs , export_header_lib_headers , export_static_lib_headers , export_shared_lib_headers , dan export_generated_headers dalam definisi modul Android.bp yang sesuai dengan pustaka bersama.

Tentang tipe yang bisa dijangkau

Jenis yang dapat dijangkau adalah jenis C / C ++ bawaan atau yang ditentukan pengguna 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 yang ditemukan dalam tabel .dynsym . Pustaka libfoo.so mencakup berikut ini:

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 : [
    "include"
  ],
}
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:

Tipe Deskripsi
bool Jenis Foo .
int Jenis parameter Foo pertama.
bar_t * Jenis parameter Foo kedua. Melalui bar_t * , bar_t diekspor melalui foo_exported.h .

bar_t berisi anggota mfoo , berjenis foo_t , yang diekspor melalui foo_exported.h , yang menghasilkan lebih banyak jenis yang diekspor:
  • int : adalah tipe m1 .
  • int * : adalah tipe m2 .
  • foo_private_t * : adalah jenis mPfoo .

Namun, foo_private_t TIDAK dapat dijangkau karena tidak diekspor melalui foo_exported.h . ( foot_private_t * tidak tembus cahaya, oleh karena itu perubahan yang dibuat pada foo_private_t diperbolehkan.)

Penjelasan serupa dapat diberikan untuk tipe yang dapat dijangkau melalui penentu kelas dasar dan parameter template juga.

Memastikan kepatuhan ABI

Kepatuhan ABI harus dipastikan untuk pustaka yang ditandai vendor_available: true dan vndk.enabled: true di file Android.bp sesuai. Sebagai contoh:

cc_library {
    name: "libvndk_example",
    vendor_available: true,
    vndk: {
        enabled: true,
    }
}

Untuk tipe data yang dapat dijangkau secara langsung atau tidak langsung oleh fungsi yang diekspor, perubahan berikut pada pustaka diklasifikasikan sebagai pemecah ABI:

Tipe data Deskripsi
Struktur dan Kelas
  • Ubah ukuran tipe kelas atau tipe struct.
  • Kelas Baes
    • Tambahkan atau hapus kelas dasar.
    • Tambahkan atau hapus kelas dasar yang diwariskan secara virtual.
    • Ubah urutan kelas dasar.
  • Fungsi anggota
    • Hapus fungsi anggota *.
    • Tambahkan atau hapus argumen dari fungsi anggota.
    • Ubah tipe argumen atau tipe kembalian dari fungsi anggota *.
    • Ubah tata letak tabel virtual.
  • Anggota data
    • Hapus anggota data statis.
    • Tambahkan atau hapus anggota data non-statis.
    • Ubah tipe anggota data.
    • Ubah offset menjadi anggota data non-statis **.
    • Ubah const , volatile , dan / atau qualifier restricted dari anggota data ***.
    • Turunkan versi penentu akses anggota data ***.
  • Ubah argumen template.
Serikat pekerja
  • Tambahkan atau hapus anggota data.
  • Ubah ukuran tipe serikat.
  • Ubah tipe anggota data.
  • Ubah urutan data anggota.
Pencacahan
  • Ubah tipe yang mendasari.
  • Ubah nama pencacah.
  • Ubah nilai pencacah.
Simbol Global
  • Hapus simbol yang diekspor oleh header publik.
  • Untuk simbol global tipe FUNC
    • Tambahkan atau hapus argumen.
    • Ubah tipe argumen.
    • Ubah jenis pengembalian.
    • Turunkan versi penentu akses ***.
  • Untuk simbol global tipe OBYEK
    • Ubah jenis C / C ++ yang sesuai.
    • Turunkan versi penentu akses ***.

* Fungsi anggota publik dan pribadi tidak boleh diubah atau dihapus karena fungsi sebaris publik dapat merujuk ke fungsi anggota pribadi. Referensi simbol ke fungsi anggota pribadi dapat disimpan dalam biner pemanggil. Mengubah atau menghapus fungsi anggota pribadi dari pustaka bersama dapat mengakibatkan biner yang tidak kompatibel dengan versi sebelumnya.

** Offset untuk anggota data publik atau pribadi tidak boleh diubah karena fungsi inline dapat merujuk ke anggota data ini di badan fungsinya. Mengubah offset anggota data dapat mengakibatkan biner yang tidak kompatibel dengan versi sebelumnya.

*** Meskipun ini tidak mengubah jenis tata letak memori, ada perbedaan semantik yang dapat menyebabkan pustaka tidak berfungsi seperti yang diharapkan.

Menggunakan alat kepatuhan ABI

Saat library VNDK dibuat, ABI library tersebut akan dibandingkan dengan referensi ABI yang sesuai untuk versi VNDK yang sedang dibuat. Referensi dump ABI berada di:

${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/(v)ndk/<${PLATFORM_VNDK_VERSION}>/<BINDER_BITNESS>/<ARCH_ARCH-VARIANT>/source-based

Misalnya, saat membuat libfoo untuk API level 27 dari VNDK, libfoo ABI libfoo dibandingkan dengan referensinya di:

${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/(v)ndk/27/64/<ARCH_ARCH-VARIANT>/source-based/libfoo.so.lsdump

Kesalahan 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 pustaka VNDK pemeriksaan ABI

Saat pustaka VNDK dibuat:

  1. header-abi-dumper memproses file sumber yang dikompilasi untuk membuat library VNDK (file sumber library itu sendiri serta file sumber yang diwarisi melalui dependensi transitif statis), untuk menghasilkan file .sdump yang sesuai dengan setiap sumber.
    sdump creation
    Gambar 1. Membuat file .sdump
  2. header-abi-linker kemudian memproses file .sdump (baik menggunakan skrip versi yang disediakan atau file .so sesuai dengan pustaka bersama) untuk menghasilkan file .lsdump yang mencatat semua informasi ABI yang sesuai dengan pustaka bersama.
    lsdump creation
    Gambar 2. Membuat file .lsdump
  3. header-abi-diff membandingkan .lsdump file dengan referensi .lsdump berkas untuk menghasilkan laporan diff yang menguraikan perbedaan dalam ABI dari dua perpustakaan.
    abi diff creation
    Gambar 3. Membuat laporan perbedaan

header-abi-dumper

Alat header-abi-dumper mengurai file sumber C / C ++ dan membuang ABI yang disimpulkan dari file sumber tersebut ke file perantara. Sistem build menjalankan header-abi-dumper pada semua file sumber yang dikompilasi sekaligus membuat library yang menyertakan file sumber dari dependensi transitif.

Saat ini file .sdump diformat sebagai Protobuf TextFormatted , yang tidak dijamin akan 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 menghasilkan file .sdump perantara yang mewakili ABI yang disajikan oleh file sumber menggunakan:

$ header-abi-dumper foo.cpp -I exported -o foo.sdump -- -x c++

Perintah ini memberi tahu header-abi-dumper untuk mengurai foo.cpp dan memancarkan informasi ABI yang ditampilkan di header publik di direktori yang exported . Ini adalah kutipan (bukan representasi lengkap) dari foo.sdump dihasilkan oleh header-abi-dumper :

record_types {
  type_info {
    name: "foo"
    size: 12
    alignment: 4
    referenced_type: "type-1"
    source_file: "foo/include/foo_exported.h"
    linker_set_key: "foo"
    self_type: "type-1"
  }
  fields {
    referenced_type: "type-2"
    field_offset: 0
    field_name: "m1"
    access: public_access
  }
  fields {
    referenced_type: "type-3"
    field_offset: 32
    field_name: "m2"
    access: public_access
  }
  fields {
    referenced_type: "type-5"
    field_offset: 64
    field_name: "mPfoo"
    access: public_access
  }
  access: public_access
  record_kind: struct_kind
  tag_info {
    unique_id: "_ZTS3foo"
  }
}
record_types {
  type_info {
    name: "bar"
    size: 12
    alignment: 4
    referenced_type: "type-6"
…
pointer_types {
  type_info {
    name: "bar *"
    size: 4
    alignment: 4
    referenced_type: "type-6"
    source_file: "foo/include/foo_exported.h"
    linker_set_key: "bar *"
    self_type: "type-8"
  }
}
builtin_types {
  type_info {
    name: "int"
    size: 4
    alignment: 4
    referenced_type: "type-2"
    source_file: ""
    linker_set_key: "int"
    self_type: "type-2"
  }
  is_unsigned: false
  is_integral: true
}
functions {
  return_type: "type-7"
  function_name: "Foo"
  source_file: "foo/include/foo_exported.h"
  parameters {
    referenced_type: "type-2"
    default_arg: false
  }
  parameters {
    referenced_type: "type-8"
    default_arg: false
  }
  linker_set_key: "_Z3FooiP3bar"
  access: public_access
}

foo.sdump berisi informasi ABI yang diekspos oleh file sumber foo.cpp , misalnya:

  • record_types . Merujuk ke struct, serikat, atau kelas yang diekspos oleh header publik. Setiap jenis record memiliki informasi tentang bidangnya, ukurannya, penentu aksesnya, file header tempat ia diekspos, dll.
  • pointer_types . Merujuk ke jenis penunjuk secara langsung / tidak langsung yang direferensikan oleh catatan / fungsi yang diekspos oleh header publik, bersama dengan jenis yang ditunjuk penunjuk (melalui bidang referenced_type di type_info ). Informasi serupa dicatat dalam file .sdump untuk tipe yang memenuhi syarat, tipe C / C ++ .sdump , tipe array, dan tipe referensi lvalue dan rvalue (informasi pencatatan tentang tipe semacam itu memungkinkan untuk recursive diffing).
  • functions . Mewakili fungsi yang diekspos oleh header publik. Mereka juga memiliki informasi tentang nama fungsi yang rusak, jenis kembalian, jenis parameter, penentu akses, dll.

header-abi-linker

Alat header-abi-linker mengambil file perantara yang dihasilkan oleh header-abi-dumper sebagai input lalu menautkan file tersebut:

Masukan
  • File perantara yang diproduksi oleh header-abi-dumper
  • Skrip versi / File peta (opsional)
  • file .so dari perpustakaan bersama
Keluaran File yang mencatat ABI dari perpustakaan bersama (misalnya libfoo.so.lsdump mewakili ABI libfoo ).

Alat ini menggabungkan jenis grafik di semua file perantara yang diberikan padanya, dengan mempertimbangkan satu definisi (jenis yang ditentukan pengguna di unit terjemahan berbeda dengan nama yang sepenuhnya memenuhi syarat yang sama, mungkin berbeda secara semantik) perbedaan di seluruh unit terjemahan. Alat tersebut kemudian mengurai skrip versi atau tabel .dynsym dari pustaka bersama (file .so ) untuk membuat daftar simbol yang diekspor.

Misalnya, ketika libfoo menambahkan file bar.cpp (yang mengekspos bar fungsi C) ke kompilasinya, header-abi-linker dapat dipanggil untuk membuat dump ABI terkait 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 keluaran perintah di libfoo.so.lsdump :

record_types {
  type_info {
    name: "foo"
    size: 24
    alignment: 8
    referenced_type: "type-1"
    source_file: "foo/include/foo_exported.h"
    linker_set_key: "foo"
    self_type: "type-1"
  }
  fields {
    referenced_type: "type-2"
    field_offset: 0
    field_name: "m1"
    access: public_access
  }
  fields {
    referenced_type: "type-3"
    field_offset: 64
    field_name: "m2"
    access: public_access
  }
  fields {
    referenced_type: "type-4"
    field_offset: 128
    field_name: "mPfoo"
    access: public_access
  }
  access: public_access
  record_kind: struct_kind
  tag_info {
    unique_id: "_ZTS3foo"
  }
}
record_types {
  type_info {
    name: "bar"
    size: 24
    alignment: 8
...
builtin_types {
  type_info {
    name: "void"
    size: 0
    alignment: 0
    referenced_type: "type-6"
    source_file: ""
    linker_set_key: "void"
    self_type: "type-6"
  }
  is_unsigned: false
  is_integral: false
}
functions {
  return_type: "type-19"
  function_name: "Foo"
  source_file: "foo/include/foo_exported.h"
  parameters {
    referenced_type: "type-2"
    default_arg: false
  }
  parameters {
    referenced_type: "type-20"
    default_arg: false
  }
  linker_set_key: "_Z3FooiP3bar"
  access: public_access
}
functions {
  return_type: "type-6"
  function_name: "FooBad"
  source_file: "foo/include/foo_exported_bad.h"
  parameters {
    referenced_type: "type-2"
    default_arg: false
  }
parameters {
    referenced_type: "type-7"
    default_arg: false
  }
  linker_set_key: "_Z6FooBadiP3foo"
  access: public_access
}
elf_functions {
  name: "_Z3FooiP3bar"
}
elf_functions {
  name: "_Z6FooBadiP3foo"
}

Alat header-abi-linker :

  • .sdump file .sdump diberikan padanya ( foo.sdump dan bar.sdump ), memfilter informasi ABI yang tidak ada di header yang berada di direktori: exported .
  • libfoo.so , dan kumpulkan informasi tentang simbol yang diekspor oleh library melalui tabel .dynsym -nya.
  • Menambahkan _Z3FooiP3bar dan Bar .

libfoo.so.lsdump adalah dump ABI akhir dari libfoo.so .

header-abi-diff

Alat header-abi-diff membandingkan dua file .lsdump mewakili ABI dari dua pustaka dan menghasilkan laporan diff yang menyatakan perbedaan antara kedua ABI.

Masukan
  • File .lsdump mewakili ABI dari pustaka bersama lama.
  • File .lsdump mewakili ABI dari pustaka bersama yang baru.
Keluaran Laporan perbedaan yang menyatakan perbedaan dalam ABI yang ditawarkan oleh dua pustaka bersama yang dibandingkan.

File ABI diff dirancang agar verbose dan dapat dibaca sebanyak mungkin. Formatnya 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 tipe yang bisa langsung dijangkau, ini harus ditandai sebagai perubahan pemutusan 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 keluaran 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 ABI yang merusak di libfoo . Pesan record_type_diffs menunjukkan bahwa record telah berubah dan mencantumkan perubahan yang tidak kompatibel, yang meliputi:

  • Ukuran record berubah dari 24 byte menjadi 8 byte.
  • Jenis mfoo berubah dari foo ke foo * (semua typedef dihapus).

Bidang type_stack menunjukkan bagaimana header-abi-diff mencapai jenis yang diubah ( bar ). Bidang ini dapat diartikan sebagai Foo adalah fungsi yang diekspor yang menggunakan bar * sebagai parameter, yang menunjuk ke bar , yang telah diekspor dan diubah.

Menerapkan ABI / API

Untuk menerapkan ABI / API library bersama VNDK dan LLNDK, referensi ABI harus diperiksa ke dalam ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/(v)ndk/ . Untuk membuat referensi ini, jalankan perintah berikut:

${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py

Setelah membuat referensi, perubahan apa pun yang dilakukan pada kode sumber yang mengakibatkan perubahan ABI / API yang tidak kompatibel di pustaka VNDK atau LLNDK sekarang menghasilkan kesalahan versi.

Untuk memperbarui referensi ABI untuk pustaka inti VNDK 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

Untuk memperbarui referensi ABI untuk pustaka LLNDK tertentu, jalankan perintah berikut:

${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l <lib1> -l <lib2> --llndk

Misalnya, untuk mengupdate referensi ABI libm , jalankan:

${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l libm --llndk