ABI-Stabilität

Die Stabilität der Application Binary Interface (ABI) ist eine Voraussetzung für reine Framework-Updates, da Herstellermodule möglicherweise von den gemeinsam genutzten Bibliotheken des Vendor Native Development Kit (VNDK) abhängen, die sich in der Systempartition befinden. Innerhalb einer Android-Version müssen neu erstellte gemeinsam genutzte VNDK-Bibliotheken ABI-kompatibel zu zuvor veröffentlichten gemeinsam genutzten VNDK-Bibliotheken sein, damit Anbietermodule mit diesen Bibliotheken ohne Neukompilierung und ohne Laufzeitfehler arbeiten können. Zwischen Android-Releases können VNDK-Bibliotheken geändert werden und es gibt keine ABI-Garantien.

Um die ABI-Kompatibilität sicherzustellen, enthält Android 9 einen Header-ABI-Prüfer, wie in den folgenden Abschnitten beschrieben.

Informationen zur VNDK- und ABI-Konformität

Das VNDK ist ein restriktiver Satz von Bibliotheken, auf die Anbietermodule verlinken können und die nur Framework-Updates ermöglichen. ABI-Konformität bezieht sich auf die Fähigkeit einer neueren Version einer gemeinsam genutzten Bibliothek, wie erwartet mit einem Modul zu funktionieren, das dynamisch mit ihr verknüpft ist (d. h. so zu funktionieren, wie es eine ältere Version der Bibliothek tun würde).

Über exportierte Symbole

Ein exportiertes Symbol (auch als globales Symbol bezeichnet) bezieht sich auf ein Symbol, das alle folgenden Anforderungen erfüllt:

  • Wird von den öffentlichen Headern einer gemeinsam genutzten Bibliothek exportiert.
  • Erscheint in der .dynsym Tabelle der .so Datei, die der gemeinsam genutzten Bibliothek entspricht.
  • Hat eine schwache oder globale Bindung.
  • Die Sichtbarkeit ist STANDARD oder GESCHÜTZT.
  • Der Abschnittsindex ist nicht UNDEFINED.
  • Der Typ ist entweder FUNC oder OBJECT.

Die öffentlichen Header einer gemeinsam genutzten Bibliothek werden als Header definiert, die anderen Bibliotheken/Binärdateien über die Attribute export_include_dirs , export_header_lib_headers , export_static_lib_headers , export_shared_lib_headers und export_generated_headers in den Android.bp Definitionen des Moduls zur Verfügung stehen, das der gemeinsam genutzten Bibliothek entspricht.

Über erreichbare Typen

Ein erreichbarer Typ ist jeder in C/C++ integrierte oder benutzerdefinierte Typ, der direkt oder indirekt über ein exportiertes Symbol erreichbar UND über öffentliche Header exportiert ist. Beispielsweise verfügt libfoo.so über die Funktion Foo , bei der es sich um ein exportiertes Symbol aus der .dynsym Tabelle handelt. Die Bibliothek libfoo.so umfasst Folgendes:

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

Wenn man sich Foo ansieht, gehören zu den direkt/indirekt erreichbaren Typen:

Typ Beschreibung
bool Rückgabetyp von Foo .
int Typ des ersten Foo Parameters.
bar_t * Typ des zweiten Foo-Parameters. Über bar_t * wird bar_t über foo_exported.h exportiert.

bar_t enthält ein Mitglied mfoo vom Typ foo_t , das über foo_exported.h exportiert wird, was dazu führt, dass mehr Typen exportiert werden:
  • int : ist der Typ von m1 .
  • int * : ist der Typ von m2 .
  • foo_private_t * : ist der Typ von mPfoo .

Allerdings ist foo_private_t NICHT erreichbar, da es nicht über foo_exported.h exportiert wird. ( foo_private_t * ist undurchsichtig, daher sind Änderungen an foo_private_t zulässig.)

Eine ähnliche Erklärung kann auch für Typen gegeben werden, die über Basisklassenspezifizierer und Vorlagenparameter erreichbar sind.

Sicherstellung der ABI-Konformität

Die ABI-Konformität muss für die Bibliotheken sichergestellt werden, die in den entsprechenden Android.bp Dateien mit vendor_available: true und vndk.enabled: true gekennzeichnet sind. Zum Beispiel:

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

Für Datentypen, die direkt oder indirekt über eine exportierte Funktion erreichbar sind, werden die folgenden Änderungen an einer Bibliothek als ABI-verletzend eingestuft:

Datentyp Beschreibung
Strukturen und Klassen
  • Ändern Sie die Größe des Klassentyps oder des Strukturtyps.
  • Basisklassen
    • Basisklassen hinzufügen oder entfernen.
    • Fügen Sie virtuell geerbte Basisklassen hinzu oder entfernen Sie sie.
    • Ändern Sie die Reihenfolge der Basisklassen.
  • Mitgliedsfunktionen
    • Mitgliedsfunktionen entfernen*.
    • Fügen Sie Argumente zu Memberfunktionen hinzu oder entfernen Sie sie.
    • Ändern Sie die Argumenttypen oder die Rückgabetypen von Mitgliedsfunktionen*.
    • Ändern Sie das Layout der virtuellen Tabelle.
  • Datenmitglieder
    • Entfernen Sie statische Datenelemente.
    • Fügen Sie nicht statische Datenelemente hinzu oder entfernen Sie sie.
    • Ändern Sie die Typen der Datenelemente.
    • Ändern Sie die Offsets in nicht statische Datenelemente**.
    • Ändern Sie die const , volatile und/oder restricted Qualifizierer von Datenmitgliedern***.
    • Herabstufen der Zugriffsspezifizierer von Datenmitgliedern***.
  • Ändern Sie die Vorlagenargumente.
Gewerkschaften
  • Datenelemente hinzufügen oder entfernen.
  • Ändern Sie die Größe des Union-Typs.
  • Ändern Sie die Typen der Datenelemente.
Aufzählungen
  • Ändern Sie den zugrunde liegenden Typ.
  • Ändern Sie die Namen von Enumeratoren.
  • Ändern Sie die Werte von Enumeratoren.
Globale Symbole
  • Entfernen Sie die von öffentlichen Headern exportierten Symbole.
  • Für globale Symbole vom Typ FUNC
    • Argumente hinzufügen oder entfernen.
    • Ändern Sie die Argumenttypen.
    • Ändern Sie den Rückgabetyp.
    • Downgrade des Zugriffsspezifizierers***.
  • Für globale Symbole vom Typ OBJECT
    • Ändern Sie den entsprechenden C/C++-Typ.
    • Downgrade des Zugriffsspezifizierers***.

* Sowohl öffentliche als auch private Mitgliedsfunktionen dürfen nicht geändert oder entfernt werden, da öffentliche Inline-Funktionen auf private Mitgliedsfunktionen verweisen können. Symbolverweise auf private Memberfunktionen können in Aufrufer-Binärdateien gespeichert werden. Das Ändern oder Entfernen privater Mitgliedsfunktionen aus gemeinsam genutzten Bibliotheken kann zu abwärtsinkompatiblen Binärdateien führen.

** Die Offsets zu öffentlichen oder privaten Datenelementen dürfen nicht geändert werden, da Inline-Funktionen in ihrem Funktionskörper auf diese Datenelemente verweisen können. Das Ändern der Offsets von Datenelementen kann zu abwärtsinkompatiblen Binärdateien führen.

*** Diese ändern zwar nicht das Speicherlayout des Typs, es gibt jedoch semantische Unterschiede, die dazu führen können, dass Bibliotheken nicht wie erwartet funktionieren.

Verwendung von ABI-Compliance-Tools

Wenn eine VNDK-Bibliothek erstellt wird, wird der ABI der Bibliothek mit der entsprechenden ABI-Referenz für die Version des zu erstellenden VNDK verglichen. Referenz-ABI-Dumps befinden sich in:

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

Beim Erstellen libfoo für x86 auf API-Ebene 27 wird beispielsweise der abgeleitete ABI von libfoo mit seiner Referenz verglichen:

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

ABI-Bruchfehler

Bei ABI-Fehlern zeigt das Build-Protokoll Warnungen mit dem Warnungstyp und einem Pfad zum Abi-Diff-Bericht an. Wenn beispielsweise die ABI von libbinder eine inkompatible Änderung aufweist, gibt das Build-System einen Fehler mit einer Meldung ähnlich der folgenden aus:

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

Erstellen von ABI-Prüfungen für die VNDK-Bibliothek

Wenn eine VNDK-Bibliothek erstellt wird:

  1. header-abi-dumper verarbeitet die zum Erstellen der VNDK-Bibliothek kompilierten Quelldateien (die eigenen Quelldateien der Bibliothek sowie durch statische transitive Abhängigkeiten geerbte Quelldateien), um .sdump Dateien zu erstellen, die jeder Quelle entsprechen.
    sdump creation
    Abbildung 1. Erstellen der .sdump Dateien
  2. header-abi-linker verarbeitet dann die .sdump Dateien (entweder mithilfe eines bereitgestellten Versionsskripts oder der .so Datei, die der gemeinsam genutzten Bibliothek entspricht), um eine .lsdump Datei zu erstellen, die alle der gemeinsam genutzten Bibliothek entsprechenden ABI-Informationen protokolliert.
    lsdump creation
    Abbildung 2. Erstellen der .lsdump -Datei
  3. header-abi-diff vergleicht die .lsdump Datei mit einer Referenz .lsdump Datei, um einen Diff-Bericht zu erstellen, der die Unterschiede in den ABIs der beiden Bibliotheken beschreibt.
    abi diff creation
    Abbildung 3. Erstellen des Diff-Berichts

Header-Abi-Dumper

Das header-abi-dumper Tool analysiert eine C/C++-Quelldatei und speichert den aus dieser Quelldatei abgeleiteten ABI in einer Zwischendatei. Das Build-System führt header-abi-dumper für alle kompilierten Quelldateien aus und erstellt gleichzeitig eine Bibliothek, die die Quelldateien aus transitiven Abhängigkeiten enthält.

Eingaben
  • AC/C++-Quelldatei
  • Exportierte Include-Verzeichnisse
  • Compiler-Flags
Ausgabe Eine Datei, die den ABI der Quelldatei beschreibt ( foo.sdump stellt beispielsweise den ABI von foo.cpp dar).

Derzeit liegen .sdump Dateien im JSON-Format vor, dessen Stabilität in zukünftigen Versionen nicht garantiert werden kann. Daher sollte die Formatierung .sdump Datei als Detail der Build-System-Implementierung betrachtet werden.

Beispielsweise verfügt libfoo.so über die folgende Quelldatei 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;
}

Sie können header-abi-dumper verwenden, um eine .sdump Zwischendatei zu generieren, die den von der Quelldatei präsentierten ABI darstellt, indem Sie Folgendes verwenden:

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

Dieser Befehl weist header-abi-dumper an, foo.cpp mit den Compiler-Flags nach -- zu analysieren und die ABI-Informationen auszugeben, die von den öffentlichen Headern im exported Verzeichnis exportiert werden. Das Folgende ist foo.sdump , das von header-abi-dumper generiert wurde:

{
 "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 enthält ABI-Informationen, die von der Quelldatei foo.cpp exportiert wurden, und die öffentlichen Header, zum Beispiel:

  • record_types . Verweisen Sie auf Strukturen, Unions oder Klassen, die in den öffentlichen Headern definiert sind. Jeder Datensatztyp verfügt über Informationen zu seinen Feldern, seiner Größe, dem Zugriffsbezeichner, der Header-Datei, in der er definiert ist, und anderen Attributen.
  • pointer_types . Verweisen Sie auf Zeigertypen, die direkt/indirekt von den exportierten Datensätzen/Funktionen in den öffentlichen Headern referenziert werden, zusammen mit dem Typ, auf den der Zeiger zeigt (über das Feld referenced_type in type_info ). Ähnliche Informationen werden in der .sdump Datei für qualifizierte Typen, integrierte C/C++-Typen, Array-Typen sowie lvalue- und rvalue-Referenztypen protokolliert. Solche Informationen ermöglichen rekursives Differenzieren.
  • functions . Stellen Sie Funktionen dar, die von öffentlichen Headern exportiert werden. Sie verfügen außerdem über Informationen zum entstellten Namen der Funktion, zum Rückgabetyp, zu den Parametertypen, zum Zugriffsspezifizierer und zu anderen Attributen.

Header-Abi-Linker

Das header-abi-linker Tool verwendet die von header-abi-dumper erstellten Zwischendateien als Eingabe und verknüpft diese Dateien dann:

Eingaben
  • Von header-abi-dumper erzeugte Zwischendateien
  • Versionsskript/Map-Datei (optional)
  • .so Datei der gemeinsam genutzten Bibliothek
  • Exportierte Include-Verzeichnisse
Ausgabe Eine Datei, die den ABI einer gemeinsam genutzten Bibliothek beschreibt (beispielsweise stellt libfoo.so.lsdump den ABI von libfoo dar).

Das Tool führt die Typdiagramme in allen ihm übergebenen Zwischendateien zusammen und berücksichtigt dabei die Unterschiede zwischen den einzelnen Definitionen (benutzerdefinierte Typen in verschiedenen Übersetzungseinheiten mit demselben vollständig qualifizierten Namen können semantisch unterschiedlich sein) zwischen den Übersetzungseinheiten. Anschließend analysiert das Tool entweder ein Versionsskript oder die .dynsym Tabelle der gemeinsam genutzten Bibliothek ( .so Datei), um eine Liste der exportierten Symbole zu erstellen.

Beispielsweise besteht libfoo aus foo.cpp und bar.cpp . header-abi-linker könnte aufgerufen werden, um den vollständigen verknüpften ABI-Dump von libfoo wie folgt zu erstellen:

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

Beispielbefehlsausgabe in 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" : []
}

Das header-abi-linker Tool:

  • Verknüpft die bereitgestellten .sdump Dateien ( foo.sdump und bar.sdump ) und filtert die ABI-Informationen heraus, die nicht in den Headern im Verzeichnis vorhanden sind: exported .
  • Analysiert libfoo.so und sammelt Informationen über die von der Bibliothek über ihre .dynsym Tabelle exportierten Symbole.
  • Fügt _Z3FooiP3bar und _Z6FooBadiP3foo hinzu.

libfoo.so.lsdump ist der endgültig generierte ABI-Dump von libfoo.so .

header-abi-diff

Das header-abi-diff Tool vergleicht zwei .lsdump Dateien, die die ABI zweier Bibliotheken darstellen, und erstellt einen Diff-Bericht, der die Unterschiede zwischen den beiden ABIs angibt.

Eingaben
  • .lsdump Datei, die die ABI einer alten gemeinsam genutzten Bibliothek darstellt.
  • .lsdump Datei, die die ABI einer neuen gemeinsam genutzten Bibliothek darstellt.
Ausgabe Ein Diff-Bericht, der die Unterschiede in den ABIs angibt, die von den beiden verglichenen gemeinsam genutzten Bibliotheken angeboten werden.

Die ABI-Diff-Datei liegt im Protobuf-Textformat vor. Das Format kann sich in zukünftigen Versionen ändern.

Sie haben beispielsweise zwei Versionen von libfoo : libfoo_old.so und libfoo_new.so . In libfoo_new.so ändern Sie in bar_t den Typ von mfoo von foo_t in foo_t * . Da bar_t ein erreichbarer Typ ist, sollte dies durch header-abi-diff als ABI-Breaking Change gekennzeichnet werden.

So führen Sie header-abi-diff aus:

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

Beispielbefehlsausgabe in 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
    }
  }
}

Die libfoo.so.abidiff enthält einen Bericht aller ABI-Breaking-Änderungen in libfoo . Die Nachricht record_type_diffs gibt an, dass sich ein Datensatz geändert hat, und listet die inkompatiblen Änderungen auf, darunter:

  • Die Größe des Datensatzes ändert sich von 24 Byte auf 8 Byte.
  • Der Feldtyp von mfoo ändert sich von foo zu foo * (alle Typdefinitionen werden entfernt).

Das Feld type_stack gibt an, wie header-abi-diff den Typ erreicht hat, der sich geändert hat ( bar ). Dieses Feld kann so interpretiert werden, dass Foo eine exportierte Funktion ist, die bar * als Parameter akzeptiert, der auf bar zeigt, der exportiert und geändert wurde.

Durchsetzung von ABI/API

Um die ABI/API von gemeinsam genutzten VNDK-Bibliotheken zu erzwingen, müssen ABI-Referenzen in ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/ eingecheckt werden. Um diese Referenzen zu erstellen, führen Sie den folgenden Befehl aus:

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

Nach dem Erstellen der Referenzen führt jede am Quellcode vorgenommene Änderung, die zu einer inkompatiblen ABI/API-Änderung in einer VNDK-Bibliothek führt, nun zu einem Build-Fehler.

Um ABI-Referenzen für bestimmte Bibliotheken zu aktualisieren, führen Sie den folgenden Befehl aus:

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

Um beispielsweise libbinder ABI-Referenzen zu aktualisieren, führen Sie Folgendes aus:

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