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 ponownej kompilacji i bez błędów w czasie wykonywania. W międzyczasie między wydaniami Androida biblioteki VNDK mogą ulec zmianie, a w przypadku ABI nie ma żadnych gwarancji.

Aby zapewnić zgodność interfejsu ABI, Android 9 zawiera sprawdzanie nagłówka ABI, jak opisano w następnych sekcjach.

Zgodność z VNDK i ABI

VNDK to ograniczony zestaw bibliotek, do których mogą się odwoływać moduły dostawców i które umożliwiają aktualizacje tylko dla frameworka. Zgodność z interfejsem ABI oznacza, że nowsza wersja biblioteki udostępnionej działa zgodnie z oczekiwaniami 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 słabe lub globalne wiązanie.
  • widoczność jest ustawiona na DOmyślna lub Chroniony.
  • Indeks sekcji nie jest UNDEFINED.
  • Typ to 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 zawiera funkcję Foo, która jest wyeksportowanym symbolem znajdującym się 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 Zwracany typ elementu Foo.
int Typ pierwszego parametru Foo.
bar_t * Typ drugiego parametru Foo. Za pomocą usługi bar_t * dane bar_t są eksportowane za pomocą usługi 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 elementu m1.
  • int * : to typ elementu m2.
  • foo_private_t * : to typ elementu mPfoo.

foo_private_t jest jednak 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 podać w przypadku typów dostępnych za pomocą wskaźników klasy podstawowej i parametrów szablonu.

Zapewnianie zgodności z zasadami ABI

Należy zapewnić zgodność z ABI bibliotek oznaczonych jako vendor_available: truevndk.enabled: true w odpowiednich plikach Android.bp. 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 klasy
  • Zmień rozmiar typu klasy lub typu struktury.
  • Klasy podstawowe
    • Dodawanie i usuwanie zajęć podstawowych.
    • Dodawanie i usuwanie wirtualnie dziedziczonych klas podstawowych.
    • Zmień kolejność podstawowych klas.
  • Funkcje członkowskie
    • Usuń funkcje członkowskie*.
    • Dodawanie i usuwanie argumentów z funkcji członkowskich.
    • 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 elementów danych.
    • Zmieniać typy elementów danych.
    • Zmień przesunięcia na niestatyczne elementy danych**.
    • Zmień wartości const, volatile lub restricted w elementach danych***.
    • Zmniejsz uprawnienia członków zespołu ds. danych***.
  • Zmień argumenty szablonu.
Związki
  • dodawać i usuwać elementy danych;
  • Zmień rozmiar typu zjednoczenia.
  • Zmieniać typy elementów danych.
Wyliczenia
  • Zmień typ bazowy.
  • Zmieniać nazwy statystyków.
  • Zmień wartości liczników.
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.
    • Zmniejsz uprawnienia użytkownika***.
  • W przypadku symboli globalnych typu OBJECT
    • Zmień odpowiedni typ C/C++.
    • Zmniejsz uprawnienia użytkownika***.

* Zarówno publiczne, jak i prywatne funkcje członka nie mogą zostać zmienione ani usunięte, ponieważ publiczne funkcje w ciele mogą się odwoływać do prywatnych funkcji członka. Odwołania do symboli funkcji prywatnych członków mogą być przechowywane w binarnych plikach wywołujących. 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ęć elementów danych może spowodować brak zgodności wstecznej binarów.

*** Chociaż nie zmieniają one rozkładu pamięci 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 aktywnością na podstawie zainteresowania

Podczas kompilowania biblioteki VNDK porównuje się 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 ABI libbinder uległ niekompatybilnej zmianie, system kompilacji zwróci błąd podobny 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 kompilowane pliki źródłowe w celu utworzenia biblioteki VNDK (własne pliki źródłowe biblioteki oraz pliki źródłowe dziedziczone przez statyczną zależność transitive) w celu wytworzenia plików .sdump odpowiadających 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 plikiem referencyjnym .lsdump, aby wygenerować raport różnic, który zawiera informacje o różnicach w ABI tych dwóch bibliotek.
    tworzenie różnic w abi,
    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++
  • Wyeksportowane katalogi include
  • 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 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ć foo.cpp z flagami kompilatora pod --, oraz emituje informacje ABI, które są eksportowane przez publiczne nagłówki 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 ABI wyeksportowane przez plik źródłowyfoo.cpp oraz 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 (przez 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. Przedstawiają funkcje eksportowane przez nagłówki publiczne. Zawierają one też informacje o zagnieżdżonej nazwie funkcji, typie zwracanym, 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 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 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 ze sobą grafy 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 przeanalizuje 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 ostatni wygenerowany zrzut interfejsu ABI dla 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 ABI diff jest w  formacie tekstowym protobuf. Format może się zmienić w kolejnych wersjach.

Na przykład masz 2 wersje strony libfoo: libfoo_old.solibfoo_new.so. W libfoo_new.sobar_t zmieniasz typ mfoofoo_t na foo_t *. Ponieważ bar_t to typ osiągalny, header-abi-diff powinien oznaczyć tę zmianę 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.libfoo Komunikat record_type_diffs wskazuje, że rekord się zmienił, i wypisuje niezgodne zmiany, takie jak:

  • 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ł 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.

Wymuś użycie ABI i interfejsu API

Aby wymusić ABI i interfejs API bibliotek współdzielonych VNDK, odniesienia ABI muszą zostać zaimportowane do ${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 niezgodną wstecznie zmianę ABI/API w bibliotece VNDK, powoduje błąd kompilacji.

Aby zaktualizować odwołania 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 libbinder ABI, uruchom:

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