ABI-Stabilität

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

Um die ABI-Kompatibilität zu gewährleisten, enthält Android 9 eine Header-ABI-Prüfung, wie in den folgenden Abschnitten beschrieben.

VNDK- und ABI-Compliance

Das VNDK ist eine restriktive Gruppe von Bibliotheken, mit denen Vendormodule verknüpft werden können und die reine 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. wie eine ältere Version der Bibliothek).

Exportierte Symbole

Ein exportiertes Symbol (auch als globales Symbol bezeichnet) ist ein Symbol, das alle folgenden Bedingungen erfüllt:

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

Die öffentlichen Headern einer gemeinsam genutzten Bibliothek werden als die 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 Android.bp-Definitionen des Moduls zur Verfügung stehen, das der gemeinsam genutzten Bibliothek entspricht.

Erreichbare Typen

Ein erreichbarer Typ ist ein integrierter oder benutzerdefinierter C/C++-Typ, der direkt oder indirekt über ein exportiertes Symbol UND über öffentliche Header exportiert wird. libfoo.so hat beispielsweise die Funktion Foo, die ein exportiertes Symbol in der Tabelle .dynsym ist. 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

In Foo sind die folgenden direkt/indirekt erreichbaren Typen enthalten:

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 das Element 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 kann auch für Typen gegeben werden, die über Basisklassenspezifizierer und Vorlagenparameter erreichbar sind.

ABI-Compliance sicherstellen

Die ABI-Konformität muss für die Bibliotheken, die in den entsprechenden Android.bp-Dateien mit vendor_available: true und vndk.enabled: true gekennzeichnet sind, gewährleistet werden. 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-inkompatibel eingestuft:

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

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

** Die Offsets für öffentliche oder private Datenmember dürfen nicht geändert werden, da Inlinefunktionen in ihrem Funktionskörper auf diese Datenmember verweisen können. Wenn Sie die Offsets von Datenmembern ändern, kann dies zu nicht abwärtskompatiblen Binärdateien führen.

*** Diese Änderungen wirken sich zwar nicht auf das Speicherlayout des Typs aus, es gibt jedoch semantische Unterschiede, die dazu führen können, dass Bibliotheken nicht wie erwartet funktionieren.

ABI-Compliance-Tools verwenden

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

${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 die 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-Fehler

Bei ABI-Änderungen werden im Build-Log Warnungen mit dem Warnungstyp und einem Pfad zum abi-diff-Bericht angezeigt. Wenn beispielsweise das ABI von libbinder eine inkompatible Änderung enthält, 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 ----

ABI-Prüfungen für VNDK-Bibliotheken 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 durch statische transitive Abhängigkeiten übernommen wurden), um .sdump-Dateien zu erstellen, die jeder Quelle entsprechen.
    Erstellung von sdump
    Abbildung 1: .sdump-Dateien erstellen
  2. header-abi-linker verarbeitet dann die .sdump-Dateien (entweder mit einem bereitgestellten Versionsskript oder mit der .so-Datei, die der gemeinsam genutzten Bibliothek entspricht), um eine .lsdump-Datei zu erstellen, in der alle ABI-Informationen für die gemeinsam genutzte Bibliothek protokolliert werden.
    lsdump-Erstellung
    Abbildung 2. .lsdump-Datei erstellen
  3. Mit header-abi-diff wird die Datei .lsdump mit einer Referenzdatei .lsdump verglichen, um einen Diff-Bericht zu erstellen, in dem die Unterschiede in den ABIs der beiden Bibliotheken aufgeführt sind.
    ABI-Differenz erstellen
    Abbildung 3. Differenzbericht erstellen

header-abi-dumper

Das Tool header-abi-dumper parst eine C/C++-Quelldatei und speichert das aus dieser Quelldatei abgeleitete 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.

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

Derzeit haben .sdump-Dateien das JSON-Format, das in zukünftigen Versionen möglicherweise nicht stabil ist. Daher sollte die Formatierung von .sdump-Dateien als Implementierungsdetail des Build-Systems betrachtet werden.

libfoo.so hat beispielsweise 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 temporäre .sdump-Datei generieren, die die ABI der Quelldatei darstellt:

$ 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 parsen und die ABI-Informationen auszugeben, die von den öffentlichen Headern im Verzeichnis exported exportiert werden. Im Folgenden finden Sie 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 und den öffentlichen Headern exportiert wurden, 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, seinem Zugriffsspezifizierer, der Headerdatei, in der er definiert ist, und anderen Attributen.
  • pointer_types: Verweist direkt oder indirekt auf Zeigertypen, auf die in den exportierten Datensätzen/Funktionen in den öffentlichen Headern verwiesen wird, zusammen mit dem 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, Array-Typen sowie Lvalue- und Rvalue-Referenztypen protokolliert. Diese Informationen ermöglichen rekursives Differenzieren.
  • functions. Stellt Funktionen dar, die von öffentlichen Headern exportiert werden. Sie enthalten auch Informationen zum mangled Name der Funktion, zum Rückgabetyp, zu den Typen der Parameter, 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 sie dann:

Eingänge
  • Von header-abi-dumper erstellte Zwischendateien
  • Versionsskript/Zuordnungsdatei (optional)
  • .so-Datei der gemeinsam genutzten Bibliothek
  • Exportierte Include-Verzeichnisse
Ausgabe Eine Datei, die die ABI einer gemeinsam genutzten Bibliothek beschreibt (z. B. libfoo.so.lsdump für die ABI von libfoo).

Das Tool führt die Typdiagramme in allen ihm übergebenen Zwischendateien zusammen und berücksichtigt dabei Unterschiede zwischen Übersetzungseinheiten, die durch die Einmaldefinition entstehen (nutzerdefinierte Typen in verschiedenen Übersetzungseinheiten mit demselben vollständig qualifizierten Namen können semantisch unterschiedlich sein). Das Tool parst dann entweder ein Versionsskript oder die .dynsym-Tabelle der gemeinsam genutzten Bibliothek (.so-Datei), um eine Liste der exportierten Symbole zu erstellen.

libfoo besteht beispielsweise aus foo.cpp und bar.cpp. header-abi-linker kann 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.
  • Analysiert libfoo.so und erfasst Informationen zu den Symbolen, die von der Bibliothek über die Tabelle .dynsym exportiert werden.
  • Fügt _Z3FooiP3bar und _Z6FooBadiP3foo hinzu.

libfoo.so.lsdump ist die endgültige generierte ABI-Dumpdatei 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 Diff-Bericht, in dem die Unterschiede zwischen den beiden ABIs angegeben werden.

Eingänge
  • Die Datei .lsdump stellt die ABI einer alten gemeinsam genutzten Bibliothek dar.
  • Die Datei .lsdump, die die ABI einer neuen gemeinsam genutzten Bibliothek darstellt.
Ausgabe Ein Diff-Bericht mit den Unterschieden in den ABIs der beiden verglichenen gemeinsam genutzten Bibliotheken.

Die ABI-Differenzdatei hat das 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 in 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-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

Beispiel für die 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 Datei libfoo.so.abidiff enthält einen Bericht zu allen ABI-inkompatiblen Änderungen in libfoo. Die Meldung record_type_diffs weist darauf hin, dass sich ein Datensatz geändert hat. Außerdem werden die inkompatiblen Änderungen aufgeführt, darunter:

  • Die Größe des Datensatzes hat sich von 24 Byte auf 8 Byte geändert.
  • Der Feldtyp von mfoo wird von foo in foo * geändert (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 akzeptiert, der auf bar verweist, der exportiert und geändert wurde.

ABI und API erzwingen

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

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

Nachdem Sie die Referenzen erstellt haben, führt jede Änderung am Quellcode, die eine inkompatible ABI-/API-Änderung in einer VNDK-Bibliothek zur Folge hat, zu einem Build-Fehler.

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 von libbinder aktualisieren möchten, führen Sie Folgendes aus:

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