ABI-Stabilität

Die ABI-Stabilität (Application Binary Interface) ist eine Voraussetzung für reine Framework-Updates, da die Anbietermodule von den gemeinsam genutzten Bibliotheken des Vendor Native Development Kit (VNDK) in der Systempartition abhängen können. 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 gemeinsam genutzten Bibliothek entspricht.
  • Die Bindung hat SCHWACH oder GLOBALE.
  • Die Sichtbarkeit ist STANDARD oder GESCHÜTZT.
  • Abschnittsindex ist nicht UNEFFEKT.
  • Der Typ ist entweder FUNC oder OBJECT.

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

Erreichbare Typen

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. libfoo.so hat beispielsweise 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:

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 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 von Datenelementen.***
    • 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 Typen der Datenmitglieder.
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. Das Ändern von Offsets für Datenmitglieder kann zu nicht abwärtskompatiblen Binärdateien führen.

*** Dies ändert zwar nicht das Speicherlayout des Typs, 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

Beim Erstellen von libfoo für x86 auf API-Ebene 27 wird beispielsweise das abgeleitete ABI von libfoo mit der Referenz unter folgendem Link 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 Build-System einen Fehler mit einer Meldung wie 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 ----

VNDK-Bibliothek-ABI-Prüfungen erstellen

Wenn eine VNDK-Bibliothek erstellt wird:

  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 transitive Abhängigkeiten übernommen werden), um .sdump-Dateien zu erstellen, die der jeweiligen Quelle 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: Bericht „Unterschiede“ erstellen

Header-Abi-Dump

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 „Einschließen“-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 die foo.sdump, die 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. Verweisen Sie auf Strukturen, Unions oder Klassen, die in den öffentlichen Headern definiert sind. 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. Verweisen Sie auf Zeigertypen, auf die die exportierten Datensätze/Funktionen in den öffentlichen Headern direkt/indirekt verweisen, sowie den 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, integrierte C/C++-Typen, Arraytypen sowie Lvalue- und rvalue-Referenztypen protokolliert. Solche Informationen ermöglichen rekursive Differenzen.
  • functions. Stellt Funktionen dar, die über öffentliche Header exportiert wurden. Sie enthalten auch Informationen zum verwalteten Namen der Funktion, zum Rückgabetyp, zu den Parametertypen, zum Zugriffsbezeichner 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
  • Von header-abi-dumper erstellte Zwischendateien
  • Versionsskript/Kartendatei (optional)
  • .so-Datei der gemeinsam genutzten Bibliothek
  • Exportierte „Einschließen“-Verzeichnisse
Ausgabe Eine Datei, die die ABI einer gemeinsam genutzten Bibliothek beschreibt (z. B. steht 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 die 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 Ein Differenzbericht, der die Unterschiede in den ABIs angibt, die von den beiden gemeinsam genutzten Bibliotheken im Vergleich 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, in bar_t, ändern Sie 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-Ä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 in 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

Zum Erzwingen der ABI und API von gemeinsam genutzten VNDK-Bibliotheken 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