Stabilność ABI

Stabilność interfejsu binarnego aplikacji (ABI) jest warunkiem wstępnym aktualizacji wyłącznie platformy, ponieważ moduły dostawcy mogą zależeć od bibliotek współdzielonych zestawu Vendor Native Development Kit (VNDK), które znajdują się na partycji systemowej. W wersji na Androida nowo utworzone biblioteki współdzielone VNDK muszą być kompatybilne z ABI z wcześniej wydanymi bibliotekami współdzielonymi VNDK, aby moduły dostawców mogły współpracować z tymi bibliotekami bez rekompilacji i błędów w czasie wykonywania. Pomiędzy wersjami Androida biblioteki VNDK można zmieniać i nie ma gwarancji ABI.

Aby zapewnić zgodność z interfejsem ABI, system Android 9 zawiera moduł sprawdzania nagłówka ABI, zgodnie z opisem w poniższych sekcjach.

Informacje o zgodności z VNDK i ABI

VNDK to restrykcyjny zestaw bibliotek, z którymi mogą się łączyć moduły dostawców i które umożliwiają aktualizacje wyłącznie platformy. Zgodność z ABI odnosi się do zdolności nowszej wersji biblioteki współdzielonej do działania zgodnie z oczekiwaniami z modułem, który jest z nią dynamicznie połączony (tzn. działa tak, jak działałaby starsza wersja biblioteki).

Informacje o eksportowanych symbolach

Eksportowany symbol (znany również jako symbol globalny ) odnosi się do symbolu, który spełnia wszystkie poniższe kryteria:

  • Eksportowane przez publiczne nagłówki biblioteki współdzielonej.
  • Pojawia się w tabeli .dynsym pliku .so odpowiadającej bibliotece współdzielonej.
  • Ma słabe lub GLOBALNE powiązanie.
  • Widoczność jest DOMYŚLNA lub CHRONIONA.
  • Indeks sekcji nie jest NIEZDEFINIOWANY.
  • Typ to FUNC lub OBJECT.

Nagłówki publiczne biblioteki współdzielonej są zdefiniowane jako nagłówki dostępne dla innych bibliotek/plików binarnych za pośrednictwem 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 bibliotece współdzielonej.

Informacje o typach osiągalnych

Typ osiągalny to dowolny typ wbudowany lub zdefiniowany przez użytkownika w języku C/C++, który jest osiągalny bezpośrednio lub pośrednio za pośrednictwem wyeksportowanego symbolu ORAZ wyeksportowany za pośrednictwem publicznych nagłówków. Na przykład libfoo.so ma funkcję Foo , która jest wyeksportowanym symbolem znalezionym 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

Patrząc na Foo , typy osiągalne bezpośrednio/pośrednio obejmują:

Typ Opis
bool Zwracany typ Foo .
int Typ pierwszego parametru Foo .
bar_t * Typ drugiego parametru Foo. Za pomocą bar_t * , bar_t jest eksportowany poprzez foo_exported.h .

bar_t zawiera element mfoo typu foo_t , który jest eksportowany poprzez foo_exported.h , co skutkuje eksportowaniem większej liczby typów:
  • int : jest typem m1 .
  • int * : jest typem m2 .
  • foo_private_t * : jest typem mPfoo .

Jednak foo_private_t NIE jest osiągalny, ponieważ nie jest eksportowany przez foo_exported.h . ( foo_private_t * jest nieprzezroczysty, dlatego dozwolone są zmiany wprowadzone w foo_private_t .)

Podobne wyjaśnienie można podać dla typów osiągalnych poprzez specyfikatory klasy bazowej i parametry szablonu.

Zapewnienie zgodności z ABI

Należy zapewnić zgodność z ABI dla bibliotek oznaczonych vendor_available: true i vndk.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 osiągalnych bezpośrednio lub pośrednio przez eksportowaną funkcję następujące zmiany w bibliotece są klasyfikowane jako naruszające ABI:

Typ danych Opis
Struktury i klasy
  • Zmień rozmiar typu klasy lub typu struktury.
  • Klasy podstawowe
    • Dodaj lub usuń klasy podstawowe.
    • Dodaj lub usuń wirtualnie dziedziczone klasy bazowe.
    • Zmień kolejność klas bazowych.
  • Funkcje członkowskie
    • Usuń funkcje członkowskie*.
    • Dodaj lub usuń argumenty z funkcji składowych.
    • Zmień typy argumentów lub typy zwracane przez funkcje członkowskie*.
    • Zmień układ wirtualnej tabeli.
  • Członkowie danych
    • Usuń elementy członkowskie danych statycznych.
    • Dodaj lub usuń niestatyczne elementy danych.
    • Zmień typy członków danych.
    • Zmień przesunięcia na niestatyczne elementy danych**.
    • Zmień kwalifikatory const , volatile i/lub restricted elementów członkowskich danych***.
    • Zmień specyfikatory dostępu elementów danych*** na niższą wersję.
  • Zmień argumenty szablonu.
Związki
  • Dodaj lub usuń elementy członkowskie danych.
  • Zmień rozmiar typu unii.
  • Zmień typy członków danych.
Wyliczenia
  • Zmień typ bazowy.
  • Zmień nazwy modułów wyliczających.
  • Zmień wartości modułów wyliczających.
Symbole globalne
  • Usuń symbole wyeksportowane przez nagłówki publiczne.
  • Dla symboli globalnych typu FUNC
    • Dodaj lub usuń argumenty.
    • Zmień typy argumentów.
    • Zmień typ zwrotu.
    • Zmień specyfikator dostępu na niższą wersję***.
  • Dla symboli globalnych typu OBJECT
    • Zmień odpowiedni typ C/C++.
    • Zmień specyfikator dostępu na niższą wersję***.

* Nie wolno zmieniać ani usuwać zarówno publicznych, jak i prywatnych funkcji członkowskich, ponieważ publiczne funkcje wbudowane mogą odnosić się do prywatnych funkcji członkowskich. Odniesienia symboliczne do prywatnych funkcji członkowskich mogą być przechowywane w plikach binarnych wywołującego. Zmiana lub usunięcie prywatnych funkcji członkowskich z bibliotek współdzielonych może spowodować powstanie niekompatybilnych wstecz plików binarnych.

** Nie można zmieniać przesunięć w stosunku do publicznych lub prywatnych elementów danych, ponieważ funkcje wbudowane mogą odwoływać się do tych elementów danych w treści funkcji. Zmiana przesunięć elementów danych może spowodować, że pliki binarne będą niezgodne wstecz.

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

Korzystanie z narzędzi zgodności ABI

Kiedy budowana jest biblioteka VNDK, jej ABI jest porównywane z odpowiednią referencją ABI dla budowanej wersji VNDK. Referencyjne zrzuty ABI znajdują się w:

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

Na przykład, podczas budowania libfoo dla x86 na poziomie API 27, wywnioskowany ABI libfoo jest porównywany z jego referencją pod adresem:

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

Błąd uszkodzenia ABI

W przypadku awarii ABI dziennik kompilacji wyświetla ostrzeżenia z typem ostrzeżenia i ścieżką do raportu abi-diff. Na przykład, jeśli ABI libbinder zawiera niezgodną zmianę, system kompilacji zgłasza błąd i komunikat podobny do następującego:

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

Budowanie kontroli ABI biblioteki VNDK

Kiedy budowana jest biblioteka VNDK:

  1. header-abi-dumper przetwarza pliki źródłowe skompilowane w celu zbudowania biblioteki VNDK (własne pliki źródłowe biblioteki, a także pliki źródłowe dziedziczone poprzez statyczne zależności przechodnie), aby utworzyć pliki .sdump odpowiadające każdemu źródłu.
    sdump creation
    Rysunek 1. Tworzenie plików .sdump
  2. header-abi-linker następnie przetwarza pliki .sdump (używając dostarczonego mu 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.
    lsdump creation
    Rysunek 2. Tworzenie pliku .lsdump
  3. header-abi-diff porównuje plik .lsdump z referencyjnym plikiem .lsdump w celu utworzenia raportu różnicowego przedstawiającego różnice w ABI obu bibliotek.
    abi diff creation
    Rysunek 3. Tworzenie raportu różnicowego

nagłówek-abi-dumper

Narzędzie header-abi-dumper analizuje plik źródłowy C/C++ i zrzuca ABI wywnioskowane z tego pliku źródłowego do pliku pośredniego. System kompilacji uruchamia header-abi-dumper na wszystkich skompilowanych plikach źródłowych, jednocześnie budując bibliotekę zawierającą pliki źródłowe z zależności przechodnich.

Wejścia
  • Plik źródłowy AC/C++
  • Wyeksportowane katalogi obejmują
  • Flagi kompilatora
Wyjście Plik opisujący ABI pliku źródłowego (na przykład foo.sdump reprezentuje ABI foo.cpp ).

Obecnie pliki .sdump są w formacie JSON, który nie gwarantuje stabilności w przyszłych wersjach. W związku z tym formatowanie pliku .sdump należy traktować jako szczegół implementacji systemu kompilacji.

Na przykład libfoo.so ma następujący 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;
}

Możesz użyć header-abi-dumper aby wygenerować pośredni plik .sdump , który reprezentuje ABI prezentowany przez plik źródłowy, używając:

$ 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ącymi po -- i wyemitował informacje ABI eksportowane przez publiczne nagłówki w exported katalogu. 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 przez plik źródłowy foo.cpp oraz publiczne nagłówki, na przykład:

  • record_types . Odwołaj się do struktur, związków lub klas zdefiniowanych w publicznych nagłówkach. Każdy typ rekordu zawiera informacje o swoich polach, jego rozmiarze, specyfikatorze dostępu, pliku nagłówkowym, w którym jest zdefiniowany, i innych atrybutach.
  • pointer_types . Odwołaj się do typów wskaźników, do których bezpośrednio/pośrednio odwołują się wyeksportowane rekordy/funkcje w publicznych nagłówkach, wraz z typem, na który wskazuje wskaźnik (poprzez pole referenced_type w type_info ). Podobne informacje są rejestrowane w pliku .sdump dla typów kwalifikowanych, wbudowanych typów C/C++, typów tablicowych oraz typów referencyjnych lvalue i rvalue. Takie informacje umożliwiają różnicowanie rekurencyjne.
  • functions . Reprezentuj funkcje eksportowane przez nagłówki publiczne. Zawierają także informacje o zniekształconej nazwie funkcji, typie zwracanym, typach parametrów, specyfikatorze dostępu i innych atrybutach.

nagłówek-abi-linker

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

Wejścia
  • Pliki pośrednie utworzone przez header-abi-dumper
  • Wersja skryptu/pliku mapy (opcjonalnie)
  • .so plik biblioteki współdzielonej
  • Wyeksportowane katalogi obejmują
Wyjście Plik opisujący ABI biblioteki współdzielonej (na przykład libfoo.so.lsdump reprezentuje ABI libfoo ).

Narzędzie łączy wykresy typów we wszystkich otrzymanych plikach pośrednich, biorąc pod uwagę jedną definicję (typy zdefiniowane przez użytkownika w różnych jednostkach tłumaczeniowych o tej samej w pełni kwalifikowanej nazwie, mogą różnić się semantycznie) różnice pomiędzy jednostkami tłumaczeniowymi. Następnie narzędzie analizuje skrypt wersji lub tabelę .dynsym biblioteki współdzielonej (plik .so ), aby utworzyć listę wyeksportowanych symboli.

Na przykład libfoo składa się z foo.cpp i bar.cpp . można wywołać header-abi-linker aby utworzyć kompletny zrzut ABI libfoo w następujący sposób:

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

Przykładowe wyjście 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 dostarczone z nim pliki .sdump ( foo.sdump i bar.sdump ), odfiltrowując informacje ABI, których nie ma w nagłówkach znajdujących się w katalogu: exported .
  • Analizuje bibliotekę libfoo.so i zbiera informacje o symbolach wyeksportowanych przez bibliotekę za pośrednictwem tabeli .dynsym .
  • Dodaje _Z3FooiP3bar i _Z6FooBadiP3foo .

libfoo.so.lsdump to końcowy wygenerowany zrzut ABI libfoo.so .

nagłówek-abi-diff

Narzędzie header-abi-diff porównuje dwa pliki .lsdump reprezentujące ABI dwóch bibliotek i tworzy raport różnicowy stwierdzający różnice między dwoma ABI.

Wejścia
  • Plik .lsdump reprezentujący ABI starej biblioteki współdzielonej.
  • Plik .lsdump reprezentujący ABI nowej biblioteki współdzielonej.
Wyjście Raport różnicowy stwierdzający różnice w ABI oferowanych przez dwie porównywane biblioteki współdzielone.

Plik różnicowy ABI ma format tekstowy protobuf . Format może ulec zmianie w przyszłych wydaniach.

Na przykład masz dwie wersje libfoo : libfoo_old.so i libfoo_new.so . W libfoo_new.so w bar_t zmieniasz typ mfoo z foo_t na foo_t * . Ponieważ bar_t jest typem osiągalnym, powinno to zostać oznaczone jako zmiana zakłócająca ABI przez header-abi-diff .

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 wyjście 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
    }
  }
}

Plik libfoo.so.abidiff zawiera raport wszystkich istotnych zmian ABI w libfoo . Komunikat record_type_diffs wskazuje, że rekord został zmieniony i zawiera listę niezgodnych zmian, które obejmują:

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

Pole type_stack wskazuje, w jaki sposób header-abi-diff osiągnął typ, który uległ zmianie ( bar ). To pole można interpretować, ponieważ Foo jest wyeksportowaną funkcją, która przyjmuje bar * jako parametr wskazujący na bar , który został wyeksportowany i zmieniony.

Egzekwowanie ABI/API

Aby wymusić ABI/API bibliotek współdzielonych VNDK, odniesienia ABI muszą zostać sprawdzone w ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/ . Aby utworzyć te odniesienia, uruchom następujące polecenie:

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

Po utworzeniu odniesień jakakolwiek zmiana w kodzie źródłowym, która powoduje niezgodną zmianę ABI/API w bibliotece VNDK, powoduje teraz błąd kompilacji.

Aby zaktualizować odniesienia ABI dla określonych bibliotek, uruchom następującą komendę:

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

Na przykład, aby zaktualizować odniesienia ABI libbinder , uruchom:

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