stabilność ABI;

Stabilność interfejsu ABI (Application Binary Interface) jest warunkiem wstępnym aktualizacji obejmujących tylko platformę, ponieważ moduły dostawcy mogą zależeć od bibliotek współdzielonych pakietu Vendor Native Development Kit (VNDK), które znajdują się na partycji systemowej. W ramach wersji Androida nowo utworzone biblioteki współdzielone VNDK muszą być zgodne z interfejsem ABI z wcześniej opublikowanymi bibliotekami współdzielonymi VNDK, aby moduły dostawcy mogły z nich korzystać bez ponownej kompilacji i bez błędów w czasie działania. Pomiędzy kolejnymi wersjami Androida biblioteki VNDK mogą ulec zmianie i nie ma gwarancji dotyczących ABI.

Aby zapewnić zgodność interfejsów ABI, Android 9 zawiera narzędzie do sprawdzania interfejsów ABI nagłówka, co opisujemy w kolejnych sekcjach.

Informacje o VNDK i zgodności z ABI

VNDK to ograniczony zestaw bibliotek, z którymi mogą być połączone moduły dostawcy. Umożliwia on aktualizacje tylko w zakresie platformy. Zgodność ABI oznacza, że nowsza wersja biblioteki udostępnionej działa zgodnie z oczekiwaniami w przypadku modułu, który jest z nią dynamicznie połączony (tzn. działa tak, jak starsza wersja biblioteki).

Informacje o eksportowanych symbolach

Eksportowany symbol (nazywany też symbolem globalnym) to symbol, który spełnia wszystkie te warunki:

  • Eksportowane przez publiczne pliki nagłówkowe biblioteki udostępnionej.
  • Pojawia się w tabeli .dynsym w pliku .so odpowiadającym bibliotece udostępnionej.
  • ma wiązanie WEAK lub GLOBAL;
  • Widoczność jest ustawiona na DOMYŚLNA lub CHRONIONA.
  • Indeks sekcji nie jest wartością UNDEFINED.
  • Typ to FUNC lub OBJECT.

Publiczne pliki nagłówkowe biblioteki udostępnionej to pliki nagłówkowe 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_headersexport_generated_headers w definicjach Android.bp modułu odpowiadającego bibliotece udostępnionej.

Informacje o typach, do których można dotrzeć

Typ dostępny to dowolny wbudowany lub zdefiniowany przez użytkownika typ C/C++, który jest dostępny bezpośrednio lub pośrednio przez wyeksportowany symbol ORAZ wyeksportowany przez publiczne pliki nagłówkowe. Na przykład libfoo.so ma funkcję Foo, która jest wyeksportowanym symbolem znajdującym się w tabeli .dynsym. Biblioteka libfoo.so zawiera następujące elementy:

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 bezpośrednie i pośrednie typy, do których można dotrzeć, to:

Typ Opis
bool Typ zwracany przez Foo.
int Typ pierwszego parametru Foo.
bar_t * Typ drugiego parametru Foo. Za pomocą bar_t * eksportowane są bar_t przez foo_exported.h.

bar_t zawiera element mfoo typu foo_t, który jest eksportowany przez foo_exported.h. W rezultacie eksportowanych jest więcej typów:
  • int : to typ elementu m1.
  • int * : to typ elementu m2.
  • foo_private_t * : to typ elementu mPfoo.

Jednak do foo_private_t NIE można dotrzeć, ponieważ nie jest on eksportowany przez foo_exported.h. (foo_private_t * jest nieprzezroczysty, więc zmiany w foo_private_t są dozwolone).

Podobne wyjaśnienie można podać w przypadku typów osiągalnych za pomocą specyfikatorów klasy bazowej i parametrów szablonu.

Zapewnianie zgodności 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, do których można uzyskać dostęp bezpośrednio lub pośrednio za pomocą wyeksportowanej funkcji, te zmiany w bibliotece są klasyfikowane jako powodujące niezgodność interfejsu ABI:

Typ danych Opis
Struktury i klasy
  • Zmień rozmiar typu klasy lub typu struktury.
  • Klasy bazowe
    • Dodawanie i usuwanie klas bazowych.
    • Dodawanie i usuwanie wirtualnie dziedziczonych klas bazowych.
    • Zmień kolejność klas bazowych.
  • Funkcje składowe
    • Usuń funkcje członkowskie*.
    • Dodawanie i usuwanie argumentów z funkcji składowych.
    • zmieniać typy argumentów lub typy zwracane funkcji składowych*;
    • Zmień układ wirtualnego stołu.
  • Elementy danych
    • Usuń statyczne elementy danych.
    • Dodawanie i usuwanie niestatycznych elementów danych.
    • Zmień typy elementów danych.
    • Zmień przesunięcia na niestatyczne elementy danych**.
    • Zmień kwalifikatory const, volatile lub restricted elementów danych***.
    • Obniż poziom dostępu do elementów danych***.
  • Zmień argumenty szablonu.
Związki zawodowe
  • Dodawanie i usuwanie członków zespołu ds. danych.
  • Zmień rozmiar typu unii.
  • Zmień typy elementów danych.
Wyliczenia
  • Zmień typ bazowy.
  • zmieniać nazwy elementów wyliczeniowych;
  • Zmień wartości wyliczeń.
Symbole globalne
  • Usuń symbole wyeksportowane przez publiczne pliki nagłówkowe.
  • W przypadku symboli globalnych typu FUNC
    • Dodaj lub usuń argumenty.
    • Zmień typy argumentów.
    • Zmień typ zwrotu.
    • Obniż poziom specyfikatora dostępu***.
  • W przypadku symboli globalnych typu OBJECT
    • Zmień odpowiedni typ C/C++.
    • Obniż poziom specyfikatora dostępu***.

* Zarówno publiczne, jak i prywatne funkcje składowe nie mogą być zmieniane ani usuwane, ponieważ publiczne funkcje wbudowane mogą odwoływać się do prywatnych funkcji składowych. Odwołania do symboli prywatnych funkcji członkowskich mogą być przechowywane w binariach wywołujących. Zmiana lub usunięcie prywatnych funkcji składowych z bibliotek udostępnionych może spowodować brak zgodności wstecznej plików binarnych.

** Przesunięcia do publicznych lub prywatnych elementów danych nie mogą być zmieniane, ponieważ funkcje wstawiane mogą odwoływać się do tych elementów danych w treści funkcji. Zmiana przesunięć elementów danych może spowodować brak zgodności wstecznej plików binarnych.

*** Chociaż nie zmieniają one układu pamięci typu, istnieją różnice semantyczne, które mogą powodować, że biblioteki nie będą działać zgodnie z oczekiwaniami.

Korzystanie z narzędzi do sprawdzania zgodności ABI

Podczas kompilowania biblioteki VNDK jej interfejs ABI jest porównywany z odpowiednim interfejsem ABI referencyjnym dla kompilowanej wersji VNDK. Pliki zrzutów ABI znajdują się w tym folderze:

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

Na przykład w przypadku kompilacji libfoo dla x86 na poziomie API 27 wnioskowany interfejs ABI libfoo jest porównywany z interfejsem referencyjnym w tym miejscu:

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

Błąd przerwania interfejsu ABI

W przypadku niezgodności interfejsu ABI w dzienniku kompilacji wyświetlają się ostrzeżenia z informacją o typie ostrzeżenia i ścieżką do raportu abi-diff. Jeśli na przykład interfejs ABI biblioteki libbinder zawiera niezgodną zmianę, 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 tworzenia biblioteki VNDK:

  1. header-abi-dumper przetwarza pliki źródłowe skompilowane w celu utworzenia biblioteki VNDK (własne pliki źródłowe biblioteki, a także pliki źródłowe odziedziczone przez statyczne zależności przechodnie), aby utworzyć pliki .sdump odpowiadające każdemu źródłu.
    tworzenie sdump,
    Rysunek 1. Tworzenie plików .sdump
  2. header-abi-linker przetwarza pliki .sdump (używając skryptu wersji lub pliku .so odpowiadającego bibliotece współdzielonej), aby utworzyć plik .lsdump, który rejestruje wszystkie informacje ABI odpowiadające bibliotece współdzielonej.
    tworzenie pliku lsdump,
    Rysunek 2. Tworzenie pliku .lsdump
  3. header-abi-diff porównuje plik .lsdump z plikiem referencyjnym .lsdump, aby utworzyć raport różnicowy zawierający różnice w interfejsach ABI obu bibliotek.
    tworzenie różnic w interfejsie ABI,
    Rysunek 3. Tworzenie raportu różnicowego

header-abi-dumper

Narzędzie header-abi-dumper analizuje plik źródłowy C/C++ i zrzuca interfejs ABI wywnioskowany z tego pliku do pliku pośredniego. System kompilacji uruchamia 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ści przechodnich.

Wejścia
  • plik źródłowy C/C++;
  • Wyeksportowane katalogi dołączane
  • Flagi kompilatora
Urządzenie wyjściowe Plik opisujący interfejs ABI pliku źródłowego (np. foo.sdump reprezentuje interfejs ABI foo.cpp).

Obecnie pliki .sdump są w formacie JSON, który nie musi być stabilny w przyszłych wersjach. Dlatego formatowanie pliku .sdump należy traktować jako 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ą header-abi-dumper możesz wygenerować pośredni plik .sdump, który reprezentuje interfejs ABI przedstawiony w pliku źródłowym:

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

To polecenie nakazuje narzędziu header-abi-dumper przeanalizować plik foo.cpp za pomocą flag kompilatora podanych po -- i wygenerować informacje o interfejsie ABI eksportowane przez nagłówki publiczne w katalogu exported. Poniżej znajduje się 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 ABI wyeksportowane z pliku źródłowegofoo.cpp i nagłówki publiczne, np.

  • record_types. Odwołuj się do struktur, unii lub klas zdefiniowanych w publicznych plikach nagłówkowych. Każdy typ rekordu zawiera informacje o polach, rozmiarze, specyfikatorze dostępu, pliku nagłówkowym, w którym jest zdefiniowany, i innych atrybutach.
  • pointer_types. Odwołuj się bezpośrednio lub pośrednio do typów wskaźników, do których odwołują się wyeksportowane rekordy lub funkcje w publicznych nagłówkach, wraz z typem, do którego wskaźnik wskazuje (za pomocą pola referenced_typetype_info). Podobne informacje są rejestrowane w pliku .sdump w przypadku kwalifikowanych typów, wbudowanych typów C/C++, typów tablic, typów odwołań do wartości lvalue i rvalue. Takie informacje umożliwiają rekurencyjne porównywanie różnic.
  • functions Reprezentuj funkcje wyeksportowane przez publiczne pliki nagłówkowe. Zawierają one również informacje o zniekształconej nazwie funkcji, typie zwracanej wartości, typach parametrów, specyfikatorze dostępu i innych atrybutach.

header-abi-linker

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

Wejścia
  • Pliki pośrednie wygenerowane przez header-abi-dumper
  • Skrypt wersji lub plik mapy (opcjonalnie)
  • .so plik z biblioteki udostępnionej,
  • Wyeksportowane katalogi dołączane
Urządzenie wyjściowe Plik opisujący ABI biblioteki współdzielonej (np. libfoo.so.lsdump reprezentuje libfoo ABI).

Narzędzie łączy wykresy typów we wszystkich przekazanych mu plikach pośrednich, uwzględniając różnice w definicjach (zdefiniowane przez użytkownika typy w różnych jednostkach tłumaczenia o tej samej w pełni kwalifikowanej nazwie mogą się różnić semantycznie) w różnych jednostkach tłumaczenia. Narzędzie analizuje następnie skrypt wersji lub .dynsymtabelę biblioteki udostępnionej.dynsym (plik .so), aby utworzyć listę wyeksportowanych symboli.

Na przykład pole libfoo składa się z pól foo.cppbar.cpp. header-abi-linker można wywołać, aby utworzyć kompletny zlinkowany zrzut ABI header-abi-linker w ten sposób:libfoo

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 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 podane pliki .sdump (foo.sdumpbar.sdump), odfiltrowując informacje ABI, których nie ma w nagłówkach znajdujących się w katalogu exported.
  • Analizuje libfoo.so i zbiera informacje o symbolach eksportowanych przez bibliotekę za pomocą tabeli .dynsym.
  • Dodaje _Z3FooiP3bar i _Z6FooBadiP3foo.

libfoo.so.lsdump to ostateczny wygenerowany zrzut interfejsu ABI z libfoo.so.

header-abi-diff

Narzędzie header-abi-diff porównuje 2 .lsdump pliki reprezentujące interfejs ABI 2 bibliotek i generuje raport z różnicami między tymi interfejsami.

Wejścia
  • .lsdump plik reprezentujący ABI starej biblioteki współdzielonej.
  • Plik .lsdump reprezentujący interfejs ABI nowej biblioteki udostępnionej.
Urządzenie wyjściowe Raport różnicowy zawierający różnice w interfejsach ABI oferowanych przez porównywane 2 biblioteki współdzielone.

Plik różnic ABI jest w formacie tekstowym protokołu protobuf. Format może ulec zmianie w kolejnych wersjach.

Na przykład masz 2 wersje strony libfoo: libfoo_old.solibfoo_new.so. W sekcji libfoo_new.sobar_t zmieniasz typ mfoofoo_t na foo_t *. Ponieważ bar_t jest typem osiągalnym, header-abi-diff powinien oznaczyć tę zmianę jako zmianę powodującą niezgodność 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 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 zawiera raport ze wszystkimi zmianami w libfoo, które powodują niezgodność z ABI. record_type_diffs wiadomość wskazuje, że rekord został zmieniony, i zawiera listę niezgodnych zmian, do których należą:

  • Rozmiar rekordu zmienia się z 24 bajtów na 8 bajtów.
  • Typ pola mfoo zmienia się z foo na foo * (wszystkie definicje typów są usuwane).

Pole type_stack wskazuje, jak header-abi-diff osiągnął typ, który uległ zmianie (bar). To pole można interpretować jako Foo to wyeksportowana funkcja, która przyjmuje bar * jako parametr, który wskazuje bar, który został wyeksportowany i zmieniony.

Wymuszanie ABI i API

Aby wymusić ABI i API bibliotek współdzielonych VNDK, odwołania do ABI muszą być zarejestrowane 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 w kodzie źródłowym, która powoduje niezgodną zmianę ABI/API w bibliotece VNDK, będzie teraz powodować błąd kompilacji.

Aby zaktualizować odniesienia do interfejsu ABI w przypadku konkretnych 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 libbinder ABI, uruchom:

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