ABI-Stabilität

Die Stabilität der Application Binary Interface (ABI) ist eine Voraussetzung für Updates, die sich nur auf das Framework beziehen, da Anbietermodule von den freigegebenen VNDK-Bibliotheken (Vendor Native Development Kit) abhängen können, die sich in der Systempartition befinden. Innerhalb eines Android-Release müssen neu erstellte VNDK-Freigabebibliotheken ABI-kompatibel mit zuvor veröffentlichten VNDK-Freigabebibliotheken sein, damit Anbietermodule ohne Neukompilierung und ohne Laufzeitfehler mit diesen Bibliotheken funktionieren können. Zwischen Android-Releases können VNDK-Bibliotheken geändert werden und es gibt keine ABI-Garantien.

Zur Gewährleistung der ABI-Kompatibilität enthält Android 9 einen Header-ABI-Checker, wie in den folgenden Abschnitten beschrieben.

VNDK- und ABI-Compliance

Das VNDK ist eine eingeschränkte Gruppe von Bibliotheken, auf die Anbietermodule verknüpft werden können und die nur Framework-Updates ermöglichen. Die ABI-Compliance bezieht sich darauf, ob eine neuere Version einer freigegebenen Bibliothek wie erwartet mit einem dynamisch verknüpften Modul funktioniert (d.h. wie eine ältere Version der Bibliothek).

Exportierte Symbole

Ein exportiertes Symbol (auch globales Symbol genannt) ist ein Symbol, das alle folgenden Kriterien erfüllt:

  • Wird von den öffentlichen Headern einer freigegebenen Bibliothek exportiert.
  • Wird in der Tabelle .dynsym der Datei .so angezeigt, die der freigegebenen Bibliothek entspricht.
  • Hat eine WEAK- oder GLOBAL-Bindung.
  • Die Sichtbarkeit ist STANDARD oder GESCHÜTZT.
  • Der Abschnittsindex ist nicht UNDEFINED.
  • „Typ“ ist entweder „FUNC“ oder „OBJECT“.

Die öffentlichen Header einer freigegebenen Bibliothek sind die Header, 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 freigegebenen Bibliothek zur Verfügung stehen.

Arten von Nutzern, die Sie erreichen können

Ein erreichbarer Typ ist jeder C/C++-interne oder benutzerdefinierte Typ, der direkt oder indirekt über ein exportiertes Symbol und über öffentliche Header erreichbar ist. Beispiel: libfoo.so hat die Funktion Foo, ein exportiertes Symbol in der Tabelle .dynsym. Die libfoo.so-Bibliothek enthält 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

Zu den direkt/indirekt erreichbaren Typen gehören:Foo

Eingeben 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. Dadurch werden mehr Typen exportiert:
  • int : ist der Typ von m1.
  • int * : ist der Typ von m2.
  • foo_private_t * : ist der Typ von mPfoo.

foo_private_t ist jedoch 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 gilt auch für Typen, die über Basisklassenspezifizierer und Vorlagenparameter erreichbar sind.

ABI-Compliance sicherstellen

Die ABI-Compliance muss für die Bibliotheken gewährleistet sein, die in den entsprechenden Android.bp-Dateien als vendor_available: true und vndk.enabled: true gekennzeichnet sind. Beispiel:

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

Bei Datentypen, die direkt oder indirekt über eine exportierte Funktion erreichbar sind, werden die folgenden Änderungen an einer Bibliothek als ABI-Bruch klassifiziert:

Datentyp Beschreibung
Strukturen und Klassen
  • Ändern Sie die Größe des Klassentyps oder des Strukturtyps.
  • Basisklassen
    • Basisklassen hinzufügen oder entfernen
    • Virtuell vererbte Basisklassen hinzufügen oder entfernen
    • Reihenfolge der Basisklassen ändern
  • Mitgliedsfunktionen
    • Entfernen Sie die Mitgliedsfunktionen*.
    • Argumenten zu Mitgliedsfunktionen hinzufügen oder sie daraus entfernen.
    • Argumenttypen oder Rückgabetypen von Mitgliedsfunktionen ändern*
    • Ändern Sie das Layout der virtuellen Tabelle.
  • Datenelemente
    • Entfernen Sie statische Datenmitglieder.
    • Nicht statische Datenmitglieder hinzufügen oder entfernen.
    • Ändern Sie die Datenelementtypen.
    • Ändern Sie die Offset-Werte in nicht statische Datenglieder**.
    • Ändern Sie die const-, volatile- und/oder restricted-Qualifikatoren der Datenelemente.***
    • Reduzieren Sie die Zugriffsspezifier für Datenmitglieder.***
  • Ändern Sie die Vorlagenargumente.
Gewerkschaften
  • Fügen Sie Datenelemente hinzu oder entfernen Sie sie.
  • Ändern Sie die Größe des Union-Typs.
  • Ändern Sie die Datenelementtypen.
Aufzählungen
  • Ändern Sie den zugrunde liegenden Typ.
  • Ändern Sie die Namen der Zähler.
  • Ändern Sie die Werte der Zähler.
Globale Symbole
  • Entfernen Sie die Symbole, die über öffentliche Header exportiert wurden.
  • Für globale Symbole vom Typ FUNC
    • Fügen Sie Argumente hinzu oder entfernen Sie sie.
    • Ändern Sie die Argumenttypen.
    • Ändern Sie den Rückgabetyp.
    • Reduzieren Sie die Zugriffsspezifikation.***
  • Für globale Symbole vom Typ OBJECT
    • Ändern Sie den entsprechenden C/C++-Typ.
    • Reduzieren Sie die Zugriffsspezifikation.***

* Sowohl öffentliche als auch private Mitgliedsfunktionen dürfen nicht geändert oder entfernt werden, da öffentliche Inline-Funktionen auf private Mitgliedsfunktionen verweisen können. Symbolreferenzen auf private Mitgliedsfunktionen können in Binärdateien des Aufrufers beibehalten werden. Das Ändern oder Entfernen privater Mitgliedsfunktionen aus freigegebenen Bibliotheken kann zu nicht abwärtskompatiblen Binärdateien führen.

** Die Offsetwerte für öffentliche oder private Datenglieder dürfen nicht geändert werden, da Inlinefunktionen in ihrem Funktionskörper auf diese Datenglieder verweisen können. Änderungen an den Datenglied-Offsets können zu nicht abwärtskompatiblen Binärdateien führen.

*** Das Speicherlayout des Typs ändert sich dadurch zwar nicht, es gibt jedoch semantische Unterschiede, die dazu führen können, dass Bibliotheken nicht wie erwartet funktionieren.

ABI-Compliance-Tools verwenden

Beim Erstellen einer VNDK-Bibliothek wird das ABI der Bibliothek mit der entsprechenden ABI-Referenz für die Version des erstellten VNDK verglichen. Referenz ABI-Dumps finden Sie hier:

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

Wenn Sie beispielsweise libfoo für x86 auf API-Ebene 27 erstellen, wird das abgeleitete ABI von libfoo mit der Referenz unter folgendem Pfad verglichen:

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

ABI-Bruchfehler

Bei ABI-Unterbrechungen werden im Build-Log Warnungen mit dem Warntyp und einem Pfad zum abi-diff-Bericht angezeigt. Wenn beispielsweise das ABI von libbinder eine inkompatible Änderung aufweist, gibt das Buildsystem einen Fehler mit einer Meldung aus, die in etwa so aussieht:

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

ABI-Prüfungen für VNDK-Bibliothek erstellen

Wenn eine VNDK-Bibliothek erstellt wird, geschieht Folgendes:

  1. header-abi-dumper verarbeitet die Quelldateien, die zum Erstellen der VNDK-Bibliothek kompiliert wurden (die eigenen Quelldateien der Bibliothek sowie Quelldateien, die über statische übertragbare Abhängigkeiten übernommen wurden), um .sdump-Dateien zu generieren, die den einzelnen Quellen entsprechen.
    sdump-Erstellung
    Abbildung 1 .sdump-Dateien erstellen
  2. header-abi-linker verarbeitet dann die .sdump-Dateien (entweder mit einem bereitgestellten Versionsscript oder der .so-Datei, die der freigegebenen Bibliothek entspricht), um eine .lsdump-Datei zu erstellen, in der alle ABI-Informationen für die freigegebene Bibliothek protokolliert werden.
    lsdump-Erstellung
    Abbildung 2. .lsdump-Datei erstellen
  3. header-abi-diff vergleicht die .lsdump-Datei mit einer Referenz.lsdump-Datei, um einen Differenzbericht zu erstellen, der die Unterschiede in den ABIs der beiden Bibliotheken aufzeigt.
    abi diff creation
    Abbildung 3 Differenzbericht erstellen

header-abi-dumper

Das Tool header-abi-dumper analysiert eine C/C++-Quelldatei und speichert das daraus abgeleitete ABI in einer Zwischendatei. Das Build-System führt header-abi-dumper auf allen kompilierten Quelldateien aus und erstellt gleichzeitig eine Bibliothek, die die Quelldateien aus transitiven Abhängigkeiten enthält.

Eingänge
  • Eine C/C++-Quelldatei
  • Exportierte Include-Verzeichnisse
  • Compiler-Flags
Ausgabe Eine Datei, die das ABI der Quelldatei beschreibt (z. B. foo.sdump für das ABI von foo.cpp).

Derzeit sind .sdump-Dateien im JSON-Format, das in zukünftigen Releases möglicherweise nicht mehr unterstützt wird. Daher sollte die .sdump-Dateiformatierung als Implementierungsdetail des Build-Systems betrachtet werden.

Angenommen, libfoo.so enthält 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;
}

Mit header-abi-dumper können Sie eine Zwischendatei vom Typ .sdump generieren, die das von der Quelldatei dargestellte ABI darstellt:

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

Mit diesem Befehl wird header-abi-dumper angewiesen, foo.cpp mit den Compiler-Flags nach -- zu parsen und die ABI-Informationen auszugeben, die von den öffentlichen Headern im Verzeichnis exported exportiert werden. Im Folgenden finden Sie ein Beispiel für einen foo.sdump, der 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 aus der Quelldatei foo.cpp exportiert wurden, und die öffentlichen Header, z. B.

  • record_types. Sie beziehen sich auf in den öffentlichen Headern definierte Strukturen, Unionen oder Klassen. Jeder Datensatztyp enthält Informationen zu seinen Feldern, seiner Größe, dem Zugriffsspezifier, der Headerdatei, in der er definiert ist, und anderen Attributen.
  • pointer_types: Hier finden Sie Informationen zu den Zeigertypen, auf die die exportierten Einträge/Funktionen in den öffentlichen Headern direkt oder indirekt verweisen, sowie zum Typ, auf den der Zeiger verweist (über das Feld referenced_type in type_info). Ähnliche Informationen werden in der Datei .sdump für qualifizierte Typen, vordefinierte C/C++-Typen, Arraytypen sowie L‑ und R‑Wert-Referenztypen protokolliert. Diese Informationen ermöglichen rekursives Diffing.
  • functions. Stellt Funktionen dar, die über öffentliche Header exportiert wurden. Außerdem enthalten sie Informationen zum mangled-Namen der Funktion, zum Rückgabetyp, zu den Parametertypen, zum Zugriffsspezifizierer und zu anderen Attributen.

header-abi-linker

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

Eingänge
  • Zwischendateien, die von header-abi-dumper erstellt wurden
  • Versionsskript/Kartendatei (optional)
  • .so-Datei der freigegebenen Bibliothek
  • Exportierte Include-Verzeichnisse
Ausgabe Eine Datei, die das ABI einer freigegebenen Bibliothek beschreibt (z. B. libfoo.so.lsdump für das ABI von libfoo).

Das Tool führt die Typgrafen in allen angegebenen Zwischendateien zusammen und berücksichtigt dabei Unterschiede zwischen Übersetzungseinheiten, die sich auf eine Definition beziehen (benutzerdefinierte Typen in verschiedenen Übersetzungseinheiten mit demselben vollqualifizierten Namen, die semantisch unterschiedlich sein können). Das Tool analysiert dann entweder ein Versionsscript oder die .dynsym-Tabelle der freigegebenen Bibliothek (.so-Datei), um eine Liste der exportierten Symbole zu erstellen.

libfoo besteht beispielsweise aus foo.cpp und bar.cpp. header-abi-linker kann wie unten beschrieben aufgerufen werden, um den vollständigen verknüpften ABI-Dump von libfoo zu erstellen:

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

Beispiel für eine Befehlsausgabe 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 exported vorhanden sind.
  • Hier wird libfoo.so analysiert und Informationen zu den Symbolen erfasst, die über die .dynsym-Tabelle aus der Bibliothek exportiert wurden.
  • 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 das ABI von zwei Bibliotheken darstellen, und erstellt einen Differenzbericht mit den Unterschieden zwischen den beiden ABIs.

Eingänge
  • .lsdump-Datei, die das ABI einer alten freigegebenen Bibliothek darstellt.
  • .lsdump-Datei, die das ABI einer neuen freigegebenen Bibliothek darstellt.
Ausgabe Einen Diff-Bericht mit den Unterschieden in den ABIs, die von den beiden verglichenen geteilten Bibliotheken angeboten werden.

Die ABI-Diff-Datei ist im Protobuf-Textformat. Das Format kann sich in zukünftigen Releases ändern.

Angenommen, Sie haben zwei Versionen von libfoo: libfoo_old.so und libfoo_new.so. In libfoo_new.so ändern Sie unter bar_t den Typ von mfoo von foo_t in foo_t *. Da bar_t ein erreichbarer Typ ist, sollte dies von header-abi-diff als ABI-Bruchänderung 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

Beispiel für eine Befehlsausgabe 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 zu allen ABI-Unterbrechungsänderungen in libfoo. Die record_type_diffs-Nachricht weist darauf hin, dass sich ein Eintrag geändert hat, und listet die inkompatiblen Änderungen auf. Dazu gehören:

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

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

ABI und API erzwingen

Um die ABI und API der freigegebenen VNDK-Bibliotheken durchzusetzen, müssen ABI-Referenzen in ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/ eingecheckt werden. Führen Sie den folgenden Befehl aus, um diese Verweise zu erstellen:

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

Nach dem Erstellen der Verweise führt jede Änderung am Quellcode, die zu einer inkompatiblen ABI-/API-Änderung in einer VNDK-Bibliothek führt, zu einem Buildfehler.

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

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

Wenn Sie beispielsweise die ABI-Referenzen für libbinder aktualisieren möchten, führen Sie Folgendes aus:

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