Uygulama İkili Arabirimi (ABI) kararlılığı, satıcı modülleri, sistem bölümünde bulunan Satıcı Yerel Geliştirme Kiti (VNDK) paylaşılan kitaplıklarına bağlı olabileceğinden, yalnızca çerçeve güncelleştirmelerinin bir ön koşuludur. Bir Android sürümünde, yeni oluşturulmuş VNDK paylaşılan kitaplıklarının daha önce yayımlanmış VNDK paylaşılan kitaplıklarıyla ABI uyumlu olması gerekir, böylece satıcı modülleri bu kitaplıklarla yeniden derleme olmadan ve çalışma zamanı hatası olmadan çalışabilir. Android sürümleri arasında VNDK kitaplıkları değiştirilebilir ve ABI garantisi yoktur.
ABI uyumluluğunu sağlamaya yardımcı olmak için Android 9, aşağıdaki bölümlerde açıklandığı gibi bir başlık ABI denetleyicisi içerir.
VNDK ve ABI uyumluluğu hakkında
VNDK, satıcı modüllerinin bağlanabileceği ve yalnızca çerçeve güncellemelerini etkinleştiren kısıtlayıcı bir kitaplıklar kümesidir. ABI uyumluluğu , paylaşılan bir kitaplığın daha yeni bir sürümünün, kendisine dinamik olarak bağlı bir modülle beklendiği gibi çalışma yeteneğini ifade eder (yani kitaplığın eski bir sürümünün yapacağı gibi çalışır).
Dışa aktarılan semboller hakkında
Dışa aktarılan bir sembol ( genel sembol olarak da bilinir), aşağıdakilerin tümünü karşılayan bir sembole atıfta bulunur:
- Paylaşılan bir kitaplığın genel üstbilgileri tarafından dışa aktarılır.
- Paylaşılan kitaplığa karşılık gelen
.so
dosyasının.dynsym
tablosunda görünür. - ZAYIF veya KÜRESEL bağlamaya sahiptir.
- Görünürlük VARSAYILAN veya KORUMALIDIR.
- Bölüm dizini TANIMLANMAMIŞ değil.
- Tür, FUNC veya OBJECT'tir.
Paylaşılan bir kitaplığın genel başlıkları , paylaşılan kitaplığa karşılık gelen modülün Android.bp
tanımlarında export_include_dirs
, export_header_lib_headers
, export_static_lib_headers
, export_shared_lib_headers
ve export_generated_headers
öznitelikleri aracılığıyla diğer kitaplıklar/ikili dosyalar tarafından kullanılabilen başlıklar olarak tanımlanır.
Ulaşılabilir türler hakkında
Ulaşılabilir tür , dışa aktarılan bir sembol aracılığıyla doğrudan veya dolaylı olarak erişilebilen VE genel başlıklar aracılığıyla dışa aktarılan herhangi bir C/C++ yerleşik veya kullanıcı tanımlı türdür. Örneğin, libfoo.so
, .dynsym
tablosunda bulunan dışa aktarılmış bir sembol olan Foo
işlevine sahiptir. libfoo.so
kitaplığı şunları içerir:
foo_exported.h | foo.özel.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" ], } |
.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
bakıldığında, doğrudan/dolaylı erişilebilir türler şunları içerir:
Tip | Tanım |
---|---|
bool | Foo dönüş türü. |
int | İlk Foo parametresinin türü. |
bar_t * | İkinci Foo parametresinin türü. bar_t * aracılığıyla, bar_t foo_exported.h dışa aktarılır.bar_t , daha fazla türün dışa aktarılmasıyla sonuçlanan, foo_exported.h aracılığıyla dışa aktarılan, foo_t türünde bir mfoo üyesi içerir:
Ancak foo_private_t, foo_private_t aracılığıyla dışa aktarılmadığından erişilebilir foo_exported.h . ( foot_private_t * opaktır, bu nedenle foo_private_t üzerinde yapılan değişikliklere izin verilir.) |
Temel sınıf belirteçleri ve şablon parametreleri aracılığıyla ulaşılabilen türler için de benzer bir açıklama yapılabilir.
ABI uyumluluğunun sağlanması
Android.bp
dosyalarında vendor_available: true
ve vndk.enabled: true
olarak işaretlenen kitaplıklar için ABI uyumluluğu sağlanmalıdır. Örneğin:
cc_library { name: "libvndk_example", vendor_available: true, vndk: { enabled: true, } }
Dışa aktarılan bir işlev tarafından doğrudan veya dolaylı olarak erişilebilen veri türleri için, kitaplıkta yapılan aşağıdaki değişiklikler ABI'yi bozan olarak sınıflandırılır:
Veri tipi | Tanım |
---|---|
Yapılar ve Sınıflar |
|
sendikalar |
|
numaralandırmalar |
|
Küresel Semboller |
|
* Hem genel hem de özel üye işlevleri değiştirilmemeli veya kaldırılmamalıdır, çünkü genel satır içi işlevler özel üye işlevlerine atıfta bulunabilir. Özel üye işlevlerine sembol referansları, arayan ikili dosyalarında tutulabilir. Özel üye işlevlerinin paylaşılan kitaplıklardan değiştirilmesi veya kaldırılması, geriye dönük uyumsuz ikili dosyalara neden olabilir.
** Genel veya özel veri üyelerine ofsetler değiştirilmemelidir çünkü satır içi işlevler, işlev gövdelerinde bu veri üyelerine başvurabilir. Veri üyesi ofsetlerinin değiştirilmesi, geriye dönük uyumsuz ikili dosyalara neden olabilir.
*** Bunlar türün bellek düzenini değiştirmese de, kitaplıkların beklendiği gibi çalışmamasına neden olabilecek anlamsal farklılıklar vardır.
ABI uyumluluk araçlarını kullanma
Bir VNDK kitaplığı oluşturulduğunda, kitaplığın ABI'si, oluşturulan VNDK sürümü için karşılık gelen ABI referansıyla karşılaştırılır. Referans ABI dökümleri şurada bulunur:
${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/(v)ndk/<${PLATFORM_VNDK_VERSION}>/<BINDER_BITNESS>/<ARCH_ARCH-VARIANT>/source-based
Örneğin, VNDK'nın 27. API düzeyi için libfoo
oluştururken, libfoo
çıkarsanan ABI'si şu adresteki referansıyla karşılaştırılır:
${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/(v)ndk/27/64/<ARCH_ARCH-VARIANT>/source-based/libfoo.so.lsdump
ABI kırılma hatası
ABI kesintilerinde, yapı günlüğü uyarı türü ve abi-diff raporunun yolu ile uyarıları görüntüler. Örneğin, libbinder
uyumsuz bir değişiklik varsa, yapı sistemi aşağıdakine benzer bir mesajla bir hata verir:
***************************************************** 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ığı oluşturma ABI kontrolleri
Bir VNDK kitaplığı oluşturulduğunda:
-
header-abi-dumper
, her kaynağa karşılık gelen.sdump
dosyalarını üretmek için VNDK kitaplığını (kitaplığın kendi kaynak dosyalarının yanı sıra statik geçişli bağımlılıklar yoluyla devralınan kaynak dosyaları) oluşturmak için derlenen kaynak dosyalarını işler.Şekil 1. .sdump
dosyalarının oluşturulması -
header-abi-linker
daha sonra, paylaşılan kitaplığa karşılık gelen tüm ABI bilgilerini günlüğe kaydeden bir.lsdump
dosyası üretmek için.sdump
dosyalarını (kendisine sağlanan bir sürüm komut dosyasını veya paylaşılan kitaplığa karşılık gelen.so
dosyasını kullanarak) işler.Şekil 2. .lsdump
dosyasının oluşturulması -
header-abi-diff
, iki kitaplığın ABI'lerindeki farklılıkları özetleyen bir fark raporu oluşturmak için.lsdump
dosyasını bir referans.lsdump
dosyasıyla karşılaştırır.Şekil 3. Fark raporunun oluşturulması
başlık-abi-damper
header-abi-dumper
aracı, bir C/C++ kaynak dosyasını ayrıştırır ve bu kaynak dosyadan çıkarılan ABI'yi bir ara dosyaya döker. Derleme sistemi, derlenmiş tüm kaynak dosyalar üzerinde header-abi-dumper
çalıştırırken aynı zamanda geçişli bağımlılıklardan kaynak dosyaları içeren bir kitaplık oluşturur.
Şu anda .sdump
dosyaları Protobuf TextFormatted olarak biçimlendirilmiştir ve bu, gelecekteki sürümlerde kararlı olacağı garanti edilmez. Bu nedenle, .sdump
dosya biçimlendirmesi, bir yapı sistemi uygulama ayrıntısı olarak düşünülmelidir.
Örneğin, libfoo.so
aşağıdaki kaynak dosyasına 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; }
Aşağıdakileri kullanarak kaynak dosya tarafından sunulan ABI'yi temsil eden bir ara .sdump
dosyası oluşturmak için header-abi-dumper
dumper'ı kullanabilirsiniz:
$ header-abi-dumper foo.cpp -I exported -o foo.sdump -- -x c++
Bu komut, header-abi-dumper
foo.cpp
ayrıştırmasını ve exported
dizindeki genel başlıklarda gösterilen ABI bilgilerini yaymasını söyler. Bu, header-abi-dumper
tarafından oluşturulan foo.sdump
bir alıntıdır (tam bir temsil değildir):
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
, foo.cpp
kaynak dosyası tarafından sunulan ABI bilgilerini içerir, örneğin:
-
record_types
. Genel başlıklar tarafından açığa çıkarılan yapılara, birleşimlere veya sınıflara bakın. Her kayıt türü, alanları, boyutu, erişim belirteci, maruz kaldığı başlık dosyası vb. hakkında bilgilere sahiptir. -
pointer_types
. Genel başlıklar tarafından gösterilen kayıtlar/işlevler tarafından doğrudan/dolaylı olarak başvurulan işaretçi türlerine ve işaretçinin işaret ettiği türe bakın (type_info
içindekireferenced_type
alanı aracılığıyla). Nitelikli türler, yerleşik C/C++ türleri, dizi türleri ve değer ve değer referans türleri için.sdump
dosyasında benzer bilgiler günlüğe kaydedilir (türlerle ilgili bu tür günlük kaydı bilgileri, özyinelemeli farklılaşmaya izin verir). -
functions
. Genel üstbilgiler tarafından sunulan işlevleri temsil eder. Ayrıca işlevin karışık adı, dönüş türü, parametre türleri, erişim belirteci vb. hakkında da bilgileri vardır.
başlık-abi-bağlayıcı
header-abi-linker
aracı, header-abi-dumper
tarafından üretilen ara dosyaları girdi olarak alır ve ardından bu dosyaları birbirine bağlar:
girişler |
|
---|---|
Çıktı | Paylaşılan bir kitaplığın ABI'sini günlüğe kaydeden bir dosya (örn. libfoo.so.lsdump , libfoo ABI'sini temsil eder). |
Araç, kendisine verilen tüm ara dosyalardaki tür grafiklerini, çeviri birimleri arasındaki tek tanımlı (farklı çeviri birimlerinde aynı tam ada sahip kullanıcı tanımlı türler, anlamsal olarak farklı olabilir) farklılıkları dikkate alarak birleştirir. Araç daha sonra dışa aktarılan sembollerin bir listesini yapmak için paylaşılan kitaplığın ( .so
dosyası) bir sürüm komut dosyasını veya .dynsym
tablosunu ayrıştırır.
Örneğin, libfoo
, bar.cpp
dosyasını (bir C işlev bar
gösterir) eklediğinde, libfoo
tam bağlantılı ABI dökümünü oluşturmak için header-abi-linker
aşağıdaki gibi çağrılabilir:
header-abi-linker -I exported foo.sdump bar.sdump \ -o libfoo.so.lsdump \ -so libfoo.so \ -arch arm64 -api current
libfoo.so.lsdump
içindeki örnek komut çıktısı:
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" }
header-abi-linker
aracı:
- Kendisine sağlanan
.sdump
dosyalarını (foo.sdump
vebar.sdump
) bağlar, dizinde bulunan başlıklarda bulunmayan ABI bilgilerini filtreler:exported
aktarılır. -
libfoo.so
dosyasını ayrıştırır ve.dynsym
tablosu aracılığıyla kitaplık tarafından dışa aktarılan semboller hakkında bilgi toplar. -
_Z3FooiP3bar
veBar
ekler.
libfoo.so.lsdump
, libfoo.so'nun son oluşturulan ABI libfoo.so
.
başlık-abi-diff
header-abi-diff
aracı, iki kitaplığın ABI'sini temsil eden iki .lsdump
dosyasını karşılaştırır ve iki ABI arasındaki farkları belirten bir fark raporu üretir.
girişler |
|
---|---|
Çıktı | Karşılaştırılan iki paylaşılan kitaplık tarafından sunulan ABI'lerdeki farklılıkları belirten farklı bir rapor. |
ABI diff dosyası, olabildiğince ayrıntılı ve okunabilir olacak şekilde tasarlanmıştır. Biçim, gelecekteki sürümlerde değişebilir. Örneğin, libfoo_old.so
libfoo
libfoo_new.so
. libfoo_new.so
içinde, bar_t
içinde, mfoo türünü mfoo
yerine foo_t
foo_t *
olarak değiştirirsiniz. bar_t
doğrudan erişilebilir bir tür olduğundan, bu, header-abi-diff
tarafından bir ABI kırılma değişikliği olarak işaretlenmelidir.
header-abi-diff
ç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
içindeki örnek komut çıktısı:
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
, libfoo
tüm ABI kırılma değişikliklerinin bir raporunu içerir. record_type_diffs
mesajı, bir kaydın değiştiğini belirtir ve aşağıdakileri içeren uyumsuz değişiklikleri listeler:
-
24
bayttan8
bayta değişen kaydın boyutu. - mfoo'nun alan türü
mfoo
foo
foo *
'ya değişir (tüm typedef'ler çıkarılır).
type_stack
alanı, header-abi-diff
değişen türe ( bar
) nasıl ulaştığını gösterir. Bu alan, Foo
parametre olarak bar *
alan, dışa aktarılan ve değiştirilen bar
öğesine işaret eden dışa aktarılan bir işlev olduğu şeklinde yorumlanabilir.
ABI/API'yi zorlama
VNDK ve LLNDK paylaşılan kitaplıklarının ABI/API'sini uygulamak için ABI referansları ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/(v)ndk/
/ içinde kontrol edilmelidir. 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, VNDK veya LLNDK kitaplığında uyumsuz bir ABI/API değişikliğiyle sonuçlanan kaynak kodunda yapılan herhangi bir değişiklik artık bir derleme hatasıyla sonuçlanıyor.
Belirli VNDK çekirdek kitaplıkları için 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 referanslarını güncellemek için şunu çalıştırın:
${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l libbinder
Belirli LLNDK kitaplıkları için 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> --llndk
Örneğin, libm
ABI referanslarını güncellemek için şunu çalıştırın:
${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l libm --llndk