Stabilność ABI

Stabilność interfejsu binarnego aplikacji (ABI) jest warunkiem wstępnym aktualizacji tylko frameworku, ponieważ moduły dostawcy mogą zależeć od udostępnionych bibliotek pakietu programistycznego dostawcy (VNDK), które znajdują się na partycji systemowej. W ramach wersji Androida nowo utworzone biblioteki udostępnione VNDK muszą być zgodne z ABI bibliotek udostępnionych VNDK, które zostały opublikowane wcześniej, aby moduły dostawców mogły współpracować z tymi bibliotekami bez konieczności ponownego kompilowania i bez błędów w czasie wykonywania. Między wersjami Androida można zmieniać biblioteki VNDK bez gwarancji ABI.

Aby zapewnić zgodność z interfejsem ABI, Android 9 zawiera narzędzie do sprawdzania interfejsu ABI nagłówka. Więcej informacji znajdziesz w kolejnych sekcjach.

Zgodność z VNDK i ABI

VNDK to ograniczony zbiór bibliotek, do których moduły dostawców mogą zamieszczać linki, a które umożliwiają aktualizacje tylko na poziomie platformy. Zgodność z interfejsem ABI to zdolność nowszej wersji biblioteki udostępnionej do prawidłowego działania z modułem, który jest z nią dynamicznie powiązany (czyli działa tak samo jak starsza wersja biblioteki).

Wyeksportowane symbole

Symbol wyeksportowany (zwany też symbolem globalnym) to symbol, który spełnia wszystkie te warunki:

  • Eksportowane za pomocą publicznych nagłówków w zasobach wspólnych.
  • Pojawia się w tabeli .dynsym pliku .so odpowiadającego zasobom wspólnym.
  • Ma wiązanie słabe lub GLOBALNE.
  • widoczność jest ustawiona na DOMYŚLNIE lub CHRONIONY.
  • Indeks sekcji nie jest UNDEFINED.
  • Typ może być FUNC lub OBJECT.

Publiczne nagłówki wspólnej biblioteki są definiowane jako nagłówki dostępne dla innych bibliotek lub plików binarnych za pomocą atrybutów export_include_dirs, export_header_lib_headers, export_static_lib_headers, export_shared_lib_headers i export_generated_headers w definicjach Android.bp modułu odpowiadającego wspólnej bibliotece.

Typy dostępnych miejsc docelowych

Dostępny typ to dowolny typ wbudowany lub zdefiniowany przez użytkownika w C/C++, który jest dostępny bezpośrednio lub pośrednio za pomocą wyeksportowanego symbolu ORAZ wyeksportowanego za pomocą nagłówków publicznych. Na przykład libfoo.so ma funkcję Foo, która jest eksportowanym symbolem znalezionym w tabeli .dynsym. Biblioteka libfoo.so zawiera:

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"
  ],
}
tabela .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

W przypadku Foo typy bezpośrednie/pośrednie to:

Typ Opis
bool Typ zwrotu: Foo.
int Typ pierwszego parametru Foo.
bar_t * Typ drugiego parametru Foo. Za pomocą funkcji bar_t * dane bar_t są eksportowane za pomocą funkcji foo_exported.h.

bar_t zawiera element mfoo typu foo_t, który jest eksportowany przez foo_exported.h, co powoduje eksport większej liczby typów:
  • int : to typ m1.
  • int * : to typ m2.
  • foo_private_t * : to typ mPfoo.

Jednak foo_private_t jest niedostępna, ponieważ nie została wyeksportowana przez foo_exported.h. (foo_private_t * jest nieprzezroczysty, dlatego zmiany wprowadzone w foo_private_t są dozwolone).

Podobne wyjaśnienie można też wyjaśnić w przypadku typów osiągalnych za pomocą specyfikatorów klas podstawowych i parametrów szablonu.

Zadbaj o zgodność z ABI

Zgodność z ABI musi być zapewniona w przypadku bibliotek oznaczonych jako vendor_available: truevndk.enabled: true w odpowiednich plikach Android.bp. Na przykład:

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

W przypadku typów danych dostępnych bezpośrednio lub pośrednio przez wyeksportowaną funkcję te zmiany w bibliotece są klasyfikowane jako naruszające ABI:

Typ danych Opis
Struktury i zajęcia
  • Zmień rozmiar typu klasy lub typu struktury.
  • Klasy podstawowe
    • Dodawanie i usuwanie zajęć podstawowych.
    • Dodawanie i usuwanie dziedziczonych klas bazowych.
    • Zmień kolejność klas podstawowych.
  • Funkcje członkowskie
    • Usuń funkcje członkowskie*.
    • Dodaj lub usuń argumenty z funkcji składowych.
    • Zmieniać typy argumentów ani typy zwracane przez funkcje członkowskie*.
    • Zmień układ tabeli wirtualnej.
  • Dane członków
    • Usuń elementy danych statycznych.
    • Dodawanie i usuwanie niestatycznych użytkowników danych.
    • Zmieniać typy elementów danych.
    • Zmień przesunięcia na niestatyczne elementy danych**.
    • Zmień w elementach danych*** kwalifikatory const, volatile lub restricted.
    • Zmień na starszą wersję specyfikatorów dostępu użytkowników danych***.
  • Zmień argumenty szablonu.
Związki
  • Dodawanie i usuwanie elementów danych.
  • Zmień rozmiar typu zjednoczenia.
  • Zmieniać typy elementów danych.
Wyliczenia
  • Zmień typ bazowy.
  • Zmieniać nazwy statystyków.
  • Zmień wartości elementów wyliczających.
Global Symbols
  • Usuń symbole wyeksportowane przez nagłówki publiczne.
  • W przypadku symboli globalnych typu FUNC
    • Dodawanie i usuwanie argumentów.
    • Zmień typy argumentów.
    • Zmień typ zwrotu.
    • Zmień wersję specyfikatora dostępu na starszą wersję***.
  • W przypadku symboli globalnych typu OBJECT
    • Zmień odpowiedni typ C/C++.
    • Zmień wersję specyfikatora dostępu na starszą wersję***.

* Nie można zmieniać ani usuwać ani publicznych, jak i prywatnych funkcji składowych, ponieważ publiczne funkcje wbudowane mogą odnosić się do prywatnych funkcji członków. Odwołania do symboli funkcji prywatnych członków mogą być przechowywane w plikach binarnych wywołującego. Zmiana lub usunięcie prywatnych funkcji członkowskich z bibliotek udostępnionych może spowodować brak zgodności wstecznej plików binarnych.

** Odsunięcia do publicznych lub prywatnych elementów danych nie można zmieniać, ponieważ funkcje wbudowane mogą się do nich odwoływać w swoim kodzie. Zmiana przesunięcia elementów danych może spowodować brak zgodności wstecznej plików binarnych.

*** Chociaż te zmiany nie wpływają na układ pamięci danego typu, istnieją różnice semantyczne, które mogą spowodować, że biblioteki nie będą działać zgodnie z oczekiwaniami.

Korzystanie z narzędzi do zapewnienia zgodności z przepisami ABI

Podczas kompilowania biblioteki VNDK porównujemy ABI biblioteki z odpowiednim odwołaniem ABI dla wersji VNDK, która jest kompilowana. Informacje Dumpy ABI znajdują się w tych miejscach:

${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/<PLATFORM_VNDK_VERSION>/<BINDER_BITNESS>/<ARCH>/source-based

Na przykład podczas kompilowania libfoo na platformie x86 na poziomie API 27 wywnioskowany ABI libfoo jest porównywany z odniesieniem w tych miejscach:

${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/27/64/x86/source-based/libfoo.so.lsdump

Błąd naruszenia interfejsu ABI

W przypadku naruszenia ABI w logu kompilacji wyświetlane są ostrzeżenia z typem ostrzeżenia i ścieżką do raportu abi-diff. Jeśli na przykład w interfejsie ABI libbinder występuje niekompatybilna zmiana, system kompilacji zgłosi błąd z komunikatem podobnym do tego:

*****************************************************
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 ----

Tworzenie kontroli ABI biblioteki VNDK

Podczas kompilowania biblioteki VNDK:

  1. header-abi-dumper przetwarza pliki źródłowe skompilowane w celu utworzenia biblioteki VNDK (własne pliki źródłowe biblioteki oraz pliki źródłowe dziedziczone przez statyczną zależność transitive), aby wygenerować pliki .sdump odpowiadające poszczególnym źródłom.
    tworzenie pliku sdump.
    Rysunek 1. Tworzenie plików .sdump
  2. Następnie header-abi-linker przetwarza pliki .sdump (korzystając z dostarczonego skryptu wersji lub pliku .so odpowiadającego współdzielonej bibliotece), aby wygenerować plik .lsdump, który zawiera wszystkie informacje ABI odpowiadające współdzielonej bibliotece.
    tworzenie lsdump.
    Rysunek 2. Tworzenie pliku .lsdump
  3. header-abi-diff porównuje plik .lsdump z pobranym pliku .lsdump, aby wygenerować raport różnic, który zawiera informacje o różnicach w ABI tych dwóch bibliotek.
    tworzenie abi diff
    Rysunek 3. Tworzenie raportu różnic

header-abi-dumper

Narzędzie header-abi-dumper analizuje plik źródłowy C/C++ i zapisują wywnioskowany z niego ABI do pliku pośredniego. System kompilacji wykonuje header-abi-dumper na wszystkich skompilowanych plikach źródłowych, a także tworzy bibliotekę, która zawiera pliki źródłowe z zależnościami biernymi.

Wejścia
  • Plik źródłowy C/C++
  • Wyeksportowano katalogi uwzględniania
  • Flagi kompilatora
Urządzenie wyjściowe Plik, który opisuje ABI pliku źródłowego (np. foo.sdump reprezentuje ABI pliku foo.cpp).

Obecnie pliki .sdump są w formacie JSON, który nie jest gwarantowany jako stabilny w przyszłych wersjach. Dlatego formatowanie pliku .sdump należy uznać za szczegół implementacji systemu kompilacji.

Na przykład libfoo.so ma ten plik źródłowy: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;
}

Za pomocą narzędzia header-abi-dumper możesz wygenerować pośredni plik .sdump, który reprezentuje interfejs ABI przedstawiony przez plik źródłowy. Aby to zrobić, użyj:

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

To polecenie informuje header-abi-dumper, aby przeanalizował plik foo.cpp z flagami kompilatora następujący po -- i wysłał informacje ABI eksportowane przez nagłówki publiczne w katalogu exported. Poniżej przedstawiamy foo.sdump wygenerowany przez 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 zawiera informacje o interfejsie ABI wyeksportowane przez plik źródłowy foo.cpp i nagłówki publiczne, na przykład

  • record_types. Zapoznaj się ze strukturami, uniami i klasami zdefiniowanymi w publicznych nagłówkach. Każdy typ rekordu zawiera informacje o polach, rozmiarze, specyfikatorze dostępu, pliku nagłówka, w którym jest zdefiniowany, oraz inne atrybuty.
  • pointer_types. Odwołuje się do typów wskaźników, do których bezpośrednio lub pośrednio odwołują się wyeksportowane rekordy/funkcje w nagłówkach publicznych, oraz do typu, do którego odwołuje się wskaźnik (poprzez pole referenced_type w pliku type_info). Podobne informacje są rejestrowane w pliku .sdump w przypadku typów kwalifikowanych, wbudowanych typów C/C++, typów tablic oraz typów referencji lvalue i rvalue. Te informacje umożliwiają rekurencyjne porównywanie.
  • functions. Reprezentuj funkcje wyeksportowane za pomocą nagłówków publicznych. Zawierają one też informacje o zagnieżdżonym nazwie funkcji, typie zwracanym, typach parametrów, specyfikatorze dostępu i innych atrybutach.

nagłówek-abi-linker,

Narzędzie header-abi-linker pobiera jako dane wejściowe pliki pośrednie utworzone przez header-abi-dumper, a następnie łączy te pliki:

Wejścia
  • Pliki pośrednie utworzone przez header-abi-dumper
  • Skrypt wersji/plik mapy (opcjonalnie)
  • .so pliku z biblioteki współdzielonej.
  • Wyeksportowane katalogi include
Urządzenie wyjściowe Plik opisujący ABI biblioteki współdzielonej (na przykład libfoo.so.lsdump reprezentuje ABI biblioteki libfoo).

Narzędzie scala wykresy typów we wszystkich podanych mu plikach pośrednich, biorąc pod uwagę różnice w definicji (typy zdefiniowane przez użytkownika w różnych jednostkach tłumaczenia o tej samej pełnej nazwie mogą się różnić pod względem semantycznym) w jednostkach tłumaczenia. Następnie narzędzie analizuje skrypt wersji lub tabelę .dynsym w zasobach wspólnych (plik .so), aby utworzyć listę wyeksportowanych symboli.

Na przykład pole libfoo składa się z polów foo.cppbar.cpp. Aby utworzyć pełny powiązany zrzut ABI dla libfoo, można wywołać header-abi-linker w ten sposób:

header-abi-linker -I exported foo.sdump bar.sdump \
                  -o libfoo.so.lsdump \
                  -so libfoo.so \
                  -arch arm64 -api current

Przykładowe dane wyjściowe polecenia w formacie 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" : []
}

Narzędzie header-abi-linker:

  • Łączy przekazane mu pliki .sdump (foo.sdump i bar.sdump), odfiltrowując informacje ABI, których nie ma w nagłówkach znajdujących się w katalogu exported.
  • Przetwarza libfoo.so i zbiera informacje o symbolach wyeksportowanych przez bibliotekę za pomocą tabeli .dynsym.
  • Dodaje _Z3FooiP3bar i _Z6FooBadiP3foo.

libfoo.so.lsdump to końcowy zrzut interfejsu ABI aplikacji libfoo.so.

header-abi-diff

Narzędzie header-abi-diff porównuje 2 pliki .lsdump reprezentujące ABI 2 bibliotek i generuje raport różnic, w którym podano różnice między tymi 2 ABI.

Wejścia
  • Plik .lsdump odpowiadający ABI starej biblioteki współdzielonej.
  • Plik .lsdump odpowiadający ABI nowej biblioteki udostępnionej.
Urządzenie wyjściowe Raport różnic podający różnice w ABI oferowanych przez 2 porównywane biblioteki wspólne.

Plik diff ABI jest w formacie tekstowym protobuf. Format może się zmienić w kolejnych wersjach.

Załóżmy, że masz 2 wersje tagu libfoo: libfoo_old.so i libfoo_new.so. W libfoo_new.so w zadaniu bar_t zmieniasz typ wartości mfoo z foo_t na foo_t *. Ponieważ bar_t to typ osiągalny, header-abi-diff powinien oznaczyć to jako zmianę ABI.

Aby uruchomić header-abi-diff:

header-abi-diff -old libfoo_old.so.lsdump \
                -new libfoo_new.so.lsdump \
                -arch arm64 \
                -o libfoo.so.abidiff \
                -lib libfoo

Przykładowe dane wyjściowe polecenia w formacie 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
    }
  }
}

Plik libfoo.so.abidiff zawiera raport o wszystkich zmianach w plikach ABI, które powodują przerwanie zgodności z wersją ABI. Komunikat record_type_diffs wskazuje, że rekord się zmienił, i wypisuje niezgodne zmiany, które obejmują:

  • Rozmiar rekordu zmienił się z 24 na 8 bajtów.
  • Typ pola mfoo zmienił się z foo na foo * (wszystkie typy definicji zostały usunięte).

Pole type_stack wskazuje, jak header-abi-diff dotarło do typu, który się zmienił (bar). To pole może być interpretowane jako Foo, czyli wyeksportowana funkcja, która przyjmuje jako parametr bar *, który wskazuje na bar, który został wyeksportowany i zmieniony.

Wymuszaj ABI i API

Aby egzekwować interfejsy ABI i API w bibliotekach udostępnionych VNDK, odwołania ABI muszą być sprawdzane w ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/. Aby utworzyć te odwołania, uruchom to polecenie:

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

Po utworzeniu odwołań każda zmiana wprowadzona w źródle, która powoduje niezgodność ABI/API w bibliotece VNDK, powoduje błąd kompilacji.

Aby zaktualizować odwołania do ABI dla określonych bibliotek, uruchom to polecenie:

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

Aby na przykład zaktualizować odwołania do interfejsu ABI libbinder, uruchom polecenie:

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