Uygulama İkili Arabirimi (ABI) kararlılığı, satıcı modüllerinde tedarikçinin yerel tedarikçi firmasına bağlı olabileceği için yalnızca çerçeve güncellemeleri Sistem bölümünde bulunan Geliştirme Kiti (VNDK) paylaşılan kitaplıkları. Android sürümünde, yeni oluşturulan VNDK paylaşılan kitaplıkları Daha önce yayınlanan VNDK paylaşılan kitaplıklarla ABI uyumlu, böylece tedarikçi modülleri bu kitaplıklarla yeniden derleme işlemi yapmadan ve çalışma zamanı hatası olmadan çalışabilir. Android sürümleri arasında VNDK kitaplıkları değiştirilebilir ve ABI yoktur garantileri.
Android 9, ABI uyumluluğunu sağlamak için aşağıdakileri içerir: aşağıdaki bölümlerde açıklandığı gibi bir başlık ABI denetleyicisi.
VNDK ve ABI uyumluluğu hakkında
VNDK, tedarikçi modüllerinin bağlanabileceği ve Bunlar yalnızca çerçeveye yönelik güncellemeleri etkinleştirir. ABI uygunluğu, beklendiği gibi çalışması için paylaşılan kitaplığın yeni sürümünün yeni bir sürüm gibi çalışan bir kod snippet'i oluşturabilirsiniz. kullanır).
Dışa aktarılan simgeler hakkında
Dışa aktarılmış simge (genel simge olarak da bilinir), şunların tümünü karşılayan bir sembol:
- Paylaşılan bir kitaplığın herkese açık başlıkları tarafından dışa aktarılır.
.so
dosyasının.dynsym
tablosunda görünür ortak bir metin seçin.- WEAK veya GLOBAL bağlamaya sahip.
- Görünürlük VARSAYILAN veya KORUYOR.
- Bölüm dizini UNDEFINED değil.
- Tür, FUNC veya OBJECT olmalıdır.
Paylaşılan bir kitaplığın herkese açık üstbilgileri,
diğer kitaplıklara/ikili programlara
export_include_dirs
, export_header_lib_headers
,
export_static_lib_headers
,
export_shared_lib_headers
ve
Android.bp
öğesinde export_generated_headers
özellikleri
paylaşılan kitaplığa karşılık gelen modülün tanımlarını içerir.
Erişilebilirlik türleri hakkında
Erişilebilir tür, herhangi bir C/C++ yerleşik veya kullanıcı tanımlı türüdür.
dışa aktarılan bir sembolle doğrudan veya dolaylı olarak erişilebilir VE dışa aktarılan
herkese açık başlıklardan yararlanın. Örneğin, libfoo.so
işlevine sahiptir
Dışa aktarılan bir simge olan Foo
.dynsym
tablosu. libfoo.so
kitaplığında şunlar yer alır:
takip etmek için:
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 tablosu | |||||||
---|---|---|---|---|---|---|---|
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
açısından bakıldığında, doğrudan/dolaylı erişilebilir türler şunlardır:
Tür | Açıklama |
---|---|
bool
|
Döndürme türü: Foo .
|
int
|
İlk Foo parametresinin türü.
|
bar_t *
|
İkinci Foo parametresinin türü. bar_t * ile birlikte,
bar_t , foo_exported.h üzerinden dışa aktarıldı.
bar_t , mfoo türünde bir üye içeriyor
foo_exported.h üzerinden dışa aktarılan foo_t ,
Bu da daha fazla türün dışa aktarılmasına neden olur:
Ancak, foo_private_t şu nedenle erişilebilir DEĞİLDİR
foo_exported.h üzerinden dışa aktarıldı. (foo_private_t * )
opak olduğu için foo_private_t üzerinde yapılan değişikliklere izin verilir.)
|
Temel sınıf üzerinden erişilebilen türler için de benzer bir açıklama sunulabilir. tanımlayıcılar ve şablon parametreleri de bulunur.
ABI uyumluluğunu sağlayın
İşaretli kitaplıklar için ABI uyumluluğu sağlanmalıdır
vendor_available: true
ve vndk.enabled: true
karşılık gelen Android.bp
dosyaları. Örnek:
cc_library { name: "libvndk_example", vendor_available: true, vndk: { enabled: true, } }
Dışa aktarılan bir işlevle doğrudan veya dolaylı olarak erişilebilen veri türleri için bir kitaplıkta yapılan şu değişiklikler ABI'yi bozan aşağıdaki değişiklikler olarak sınıflandırılır:
Veri türü | Açıklama |
---|---|
Yapılar ve Sınıflar |
|
Birlikler |
|
Numaralandırmalar |
|
Genel Simgeler |
|
* Hem herkese açık hem de gizli üye işlevleri genel satır içi işlevleri gizli üye işlevleri. Gizli üye işlevlerine sembol referansları arayan ikili programlarında tutulmalıdır. Gizli üye işlevlerini değiştirme veya kaldırma geriye dönük olarak uyumsuz ikili programlara neden olabilir.
** Herkese açık veya gizli veri üyelerine yapılacak ofsetler Çünkü satır içi işlevler kullanıcıların dokümanlarında bu veri üyelerine başvuruda fonksiyonunun gövdesi. Veri üyesi ofsetlerinin değiştirilmesi, geriye dönük olarak uyumsuz ikili programlardır.
*** Bunlar bellek düzenini değiştirmez bu tür kitaplıklar nedeniyle anlam açısından farklılık düzgün şekilde çalıştığından emin olun.
ABI uygunluk araçlarını kullanma
Bir VNDK kitaplığı oluşturulduğunda, kitaplığın ABI'sı oluşturulmakta olan VNDK sürümü için karşılık gelen ABI referansı. Referans Kaynakları ABI dökümleri şurada bulunur:
${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/<PLATFORM_VNDK_VERSION>/<BINDER_BITNESS>/<ARCH>/source-based
Örneğin, x86 için API düzeyi 27'de libfoo
derlemesinde,
libfoo
aracının türetilmiş ABI'si, şu referanstaki referansıyla karşılaştırılır:
${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/27/64/x86/source-based/libfoo.so.lsdump
ABI kesinti hatası
ABI kesintilerinde derleme günlüğü, uyarı türü ve
abi-diff raporuna giden yol. Örneğin, libbinder
adlı müşterinin ABI'si
derleme sistemi, uyumlu olmayan bir değişiklik olduğunda
aşağıdakine benzer:
***************************************************** 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 ----
VNDK kitaplığı ABI denetimleri oluşturma
Bir VNDK kitaplığı oluşturulduğunda:
header-abi-dumper
, şuna derlenen kaynak dosyaları işler: VNDK kitaplığını derler (kitaplığın kendi kaynak dosyaları ve kaynak dosyalarının yanı sıra statik geçişli bağımlılıklar üzerinden devralınır) Her bir kaynağa karşılık gelen.sdump
dosya.
.Şekil 1. .sdump
oluşturuluyor dosyalarheader-abi-linker
, daha sonra.sdump
dosyalarını (kendisine sağlanan sürüm komut dosyasını veya.so
dosyası) kullanarak bir.lsdump
oluşturun dosyası oluşturur.
.Şekil 2. .lsdump
oluşturuluyor dosyaheader-abi-diff
,.lsdump
değerini karşılaştırır bir farklılık raporu oluşturmak için referans.lsdump
dosyası içeren dosya iki kütüphanenin ABI'leri arasındaki farkları özetleyen bir kod snippet'i ekleyin.
.Şekil 3. Fark raporu oluşturma
başlık-abi-dumper
header-abi-dumper
aracı, bir C/C++ kaynak dosyasını ayrıştırır ve
kaynak dosyadan türetilen ABI'yi bir ara dosyaya alır. Derleme
sistem, tüm derlenmiş kaynak dosyalarda header-abi-dumper
öğesini çalıştırır.
aynı zamanda geçişli programlardaki kaynak dosyaları da içeren bir kitaplık
ve bildirmeyi konuştuk.
Girişler |
|
---|---|
Çıkış | Kaynak dosyanın ABI'sini açıklayan bir dosya (örneğin,
foo.sdump foo.cpp ABI'sini temsil eder).
|
Şu anda .sdump
dosyaları JSON biçimindedir
gelecekteki sürümlerde kararlı olması garanti edilmektedir. Bu nedenle, .sdump
dosya biçimlendirmesi, derleme sistemi uygulama ayrıntısı olarak kabul edilmelidir.
Örneğin, libfoo.so
aşağıdaki kaynak dosyaya sahiptir
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; }
Ara oluşturmak için header-abi-dumper
kullanabilirsiniz
Kaynak dosya tarafından sunulan ABI'yi temsil eden .sdump
dosyası
şunu kullanarak:
$ header-abi-dumper foo.cpp -I exported -o foo.sdump -- -I exported -x c++
Bu komut header-abi-dumper
uygulamasına,
--
sonrasında gelen derleyici işaretleriyle foo.cpp
ve
herkese açık başlıklardan dışa aktarılan ABI bilgilerini
exported
dizini. Bu özellik,
foo.sdump
, oluşturan:
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
, kaynak dosya tarafından dışa aktarılan ABI bilgilerini içeriyor
foo.cpp
ve herkese açık başlıklar örneğin,
record_types
Tanımlanan struct, birleşim veya sınıflara atıfta bulunur kullanabilirsiniz. Her kayıt türünün alanları hakkında bilgi vardır, boyut, erişim belirteci, tanımlandığı başlık dosyası ve diğer özellikleri hakkında daha fazla bilgi edinin.pointer_types
İşaretçi türlerine doğrudan/dolaylı olarak başvurma herkese açık başlıklardaki dışa aktarılan kayıtlar/işlevler tarafından başvurulan işaretçinin işaret ettiği yazı tipini (referenced_type
aracılığıyla) alanıtype_info
içindeki konumudur). Benzer bilgiler şurada günlüğe kaydedilir: Uygun türler için.sdump
dosyası, yerleşik C/C++ türleri, dizi ve lvalue ve rvalue referans türlerini kapsar. Bu tür bilgiler, yinelemeli fark oluşturma.functions
Herkese açık başlıklar tarafından dışa aktarılan işlevleri temsil eder. Bunlar, işlevin karıştırılmış adı, dönüş türü, erişim tanımlayıcısını ve diğer özellikleri içerir.
başlık-abi-bağlayıcı
header-abi-linker
aracı, oluşturulan ara dosyaları alır
header-abi-dumper
tarafından giriş olarak kullanılır, ardından bu dosyaları bağlar:
Girişler |
|
---|---|
Çıkış | Paylaşılan bir kitaplığın ABI'sını açıklayan dosya (örneğin,
libfoo.so.lsdump libfoo ABI'sini temsil eder).
|
Araç, kendisine verilen tüm ara dosyalardaki tür grafiklerini birleştirir,
Burada tek tanımlı (farklı boyutlardaki kullanıcı tanımlı türler)
aynı tam ada sahip çeviri birimleri (anlamsal olarak
farklı) farklılıklar olduğunu görebiliriz. Ardından, araç,
bir sürüm komut dosyası veya paylaşılan kitaplığın .dynsym
tablosu
(.so
dosyası) kullanarak dışa aktarılan simgelerin listesini oluşturun.
Örneğin, libfoo
, foo.cpp
ve
bar.cpp
. header-abi-linker
şuna çağrılabilir:
libfoo
öğesinin tam bağlı ABI dökümünü aşağıdaki gibi oluşturun:
header-abi-linker -I exported foo.sdump bar.sdump \ -o libfoo.so.lsdump \ -so libfoo.so \ -arch arm64 -api current
libfoo.so.lsdump
komutundaki örnek komut çıkışı:
{ "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
aracı:
- Sağlanan
.sdump
dosyalarını kendisine bağlar (foo.sdump
vebar.sdump
) hariç olmak üzere, dizinde bulunan başlıklar:exported
. libfoo.so
öğesini ayrıştırır ve simgeler hakkında bilgi toplar kitaplığı tarafından.dynsym
tablosundan dışa aktarılır._Z3FooiP3bar
ve_Z6FooBadiP3foo
eklenir.
libfoo.so.lsdump
, şunun oluşturulan nihai ABI dökümüdür:
libfoo.so
.
başlık-abi-diff
header-abi-diff
aracı, iki .lsdump
dosyayı karşılaştırır
her kütüphanenin ABI'sini temsil eder ve
iki ABI arasındaki farklar.
Girişler |
|
---|---|
Çıkış | İki platformun sunduğu ABI'ler arasındaki farkları belirten bir farklılık raporu ve paylaşılan kitaplıklar karşılaştırılmıştır. |
ABI fark dosyası hazır protobuf metin biçimindedir. Biçim değiştirilebilir özellikler.
Örneğin,
libfoo
: libfoo_old.so
ve
libfoo_new.so
. libfoo_new.so
bölgesinde,
bar_t
, mfoo
türünü
foo_t
- foo_t *
. bar_t
bir
bu, ABI bozucu değişikliği olarak işaretlenmelidir.
header-abi-diff
.
header-abi-diff
eklentisini çalıştırmak için:
header-abi-diff -old libfoo_old.so.lsdump \ -new libfoo_new.so.lsdump \ -arch arm64 \ -o libfoo.so.abidiff \ -lib libfoo
libfoo.so.abidiff
komutundaki örnek komut çıkışı:
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 kırılan tüm durumların raporunu içerir
libfoo
değişikliği var. record_type_diffs
mesajı
olduğunu gösterir ve uyumsuz değişiklikleri listeler.
şunlardır:
24
bayt olan kayıt boyutu8
bayt.foo
olanmfoo
alan türüfoo *
(tüm typedef'ler çıkarılır).
type_stack
alanı, header-abi-diff
özelliğinin
değiştirilen türe (bar
) ulaştınız. Bu alan,
Foo
, değeri içe aktaran ve
bar *
parametresi, bar
değerine işaret ediyor.
dışa aktarıldı ve değiştirildi.
ABI ve API'yi zorunlu kılma
VNDK paylaşılan kitaplıkların ABI ve API'sini zorunlu kılmak için ABI referansları
${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/
odasına giriş yapılacak.
Bu referansları oluşturmak için aşağıdaki komutu çalıştırın:
${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py
Referansları oluşturduktan sonra, kaynak kodunda yapılan tüm değişiklikler VNDK kitaplığındaki uyumsuz ABI/API değişiklikleri artık derleme hatasına neden oluyor.
Belirli kitaplıkların ABI referanslarını güncellemek için aşağıdaki komutu çalıştırın:
${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l <lib1> -l <lib2>
Örneğin, libbinder
ABI referansını güncellemek için şu komutu çalıştırın:
${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l libbinder