एबीआई की स्थिरता

ऐप्लिकेशन बाइनरी इंटरफ़ेस (एबीआई) की स्थिरता, सिर्फ़ फ़्रेमवर्क के अपडेट के लिए एक ज़रूरी शर्त है. इसकी वजह यह है कि वेंडर मॉड्यूल, सिस्टम पार्टिशन में मौजूद वेंडर नेटिव डेवलपमेंट किट (वीएनडीके) की शेयर की गई लाइब्रेरी पर निर्भर हो सकते हैं. किसी Android रिलीज़ में, नई बनाई गई VNDK शेयर की गई लाइब्रेरी, पहले रिलीज़ की गई VNDK शेयर की गई लाइब्रेरी के साथ एबीआई के हिसाब से काम करनी चाहिए, ताकि वेंडर मॉड्यूल, उन लाइब्रेरी के साथ फिर से कंपाइल किए बिना और रनटाइम गड़बड़ियों के बिना काम कर सकें. Android रिलीज़ के बीच, VNDK लाइब्रेरी बदली जा सकती हैं और एबीआई के काम करने की कोई गारंटी नहीं है.

एबीआई के साथ काम करने की सुविधा देने के लिए, Android 9 में हेडर एबीआई चेकर शामिल किया गया है. इस बारे में यहां बताया गया है.

VNDK और एबीआई के अनुपालन के बारे में जानकारी

VNDK, लाइब्रेरी का एक ऐसा सेट है जिस पर पाबंदी लगी होती है. वेंडर मॉड्यूल, इस सेट से लिंक किए जा सकते हैं और सिर्फ़ फ़्रेमवर्क के अपडेट चालू किए जा सकते हैं. एबीआई के मुताबिक होना का मतलब है कि शेयर की गई लाइब्रेरी के नए वर्शन में, उससे डाइनैमिक तौर पर लिंक किए गए मॉड्यूल के साथ उम्मीद के मुताबिक काम करने की सुविधा हो. इसका मतलब है कि लाइब्रेरी का नया वर्शन, लाइब्रेरी के पुराने वर्शन की तरह काम करे.

एक्सपोर्ट किए गए सिंबल के बारे में जानकारी

एक्सपोर्ट किया गया सिंबल (इसे ग्लोबल सिंबल भी कहा जाता है) का मतलब ऐसे सिंबल से है जो इन सभी शर्तों को पूरा करता है:

  • शेयर की गई लाइब्रेरी के सार्वजनिक हेडर से एक्सपोर्ट किया जाता है.
  • शेयर की गई लाइब्रेरी से जुड़ी .so फ़ाइल की .dynsym टेबल में दिखता है.
  • WEAK या ग्लोबल बाइंडिंग है.
  • वीडियो किसे दिखेगा, यह डिफ़ॉल्ट या सुरक्षित है.
  • सेक्शन का इंडेक्स, UNDEFINED नहीं है.
  • टाइप, FUNC या OBJECT में से कोई एक होता है.

किसी शेयर की गई लाइब्रेरी के सार्वजनिक हेडर, अन्य लाइब्रेरी/बाइनरी के लिए उपलब्ध हेडर के तौर पर तय किए जाते हैं. ऐसा, शेयर की गई लाइब्रेरी से जुड़े मॉड्यूल की Android.bp परिभाषाओं में export_include_dirs, export_header_lib_headers, export_static_lib_headers, export_shared_lib_headers, और export_generated_headers एट्रिब्यूट के ज़रिए किया जाता है.

पहुंच के लिए उपलब्ध टाइप के बारे में जानकारी

ऐसा टाइप जिसे ऐक्सेस किया जा सकता है, C/C++ में पहले से मौजूद या उपयोगकर्ता का तय किया गया ऐसा टाइप होता है जिसे सीधे तौर पर या किसी दूसरे तरीके से, एक्सपोर्ट किए गए सिंबल और सार्वजनिक हेडर के ज़रिए ऐक्सेस किया जा सकता है. उदाहरण के लिए, libfoo.so में Foo फ़ंक्शन है, जो एक्सपोर्ट किया गया एक सिंबल है, जो .dynsym टेबल में मिलता है. libfoo.so लाइब्रेरी में ये चीज़ें शामिल हैं:

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 टेबल
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

Foo में देखा जा सकता है कि डायरेक्ट या इनडायरेक्ट ऐक्सेस किए जा सकने वाले डेटा टाइप में ये शामिल हैं:

टाइप ब्यौरा
bool Foo का रिटर्न टाइप.
int पहले Foo पैरामीटर का टाइप.
bar_t * दूसरे Foo पैरामीटर का टाइप. bar_t * के मुताबिक, bar_t को foo_exported.h के ज़रिए एक्सपोर्ट किया जाता है.

bar_t में foo_t टाइप का एक सदस्य mfoo है, जिसे foo_exported.h के ज़रिए एक्सपोर्ट किया जाता है. इससे, ज़्यादा टाइप एक्सपोर्ट किए जाते हैं:
  • int :, m1 का टाइप है.
  • int * :, m2 का टाइप है.
  • foo_private_t * : , mPfoo का टाइप है.

हालांकि, foo_private_t को ऐक्सेस नहीं किया जा सकता, क्योंकि इसे foo_exported.h के ज़रिए एक्सपोर्ट नहीं किया गया है. (foo_private_t * पारदर्शी नहीं है, इसलिए foo_private_t में किए गए बदलावों की अनुमति है.)

ऐसा ही एक उदाहरण, बेस क्लास स्पेसिफ़िकेशन और टेंप्लेट पैरामीटर की मदद से ऐक्सेस किए जा सकने वाले टाइप के लिए भी दिया जा सकता है.

एबीआई से जुड़ी नीति का पालन करना

इससे जुड़ी Android.bp फ़ाइलों में vendor_available: true और vndk.enabled: true के तौर पर मार्क की गई लाइब्रेरी के लिए, एबीआई का पालन करना ज़रूरी है. उदाहरण के लिए:

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

एक्सपोर्ट किए गए फ़ंक्शन से सीधे या किसी अन्य तरीके से ऐक्सेस किए जा सकने वाले डेटा टाइप के लिए, लाइब्रेरी में किए गए इन बदलावों को एबीआई (एबिट्रेशन इंटरफ़ेस) को तोड़ने वाले बदलावों के तौर पर बांटा जाता है:

डेटा टाइप ब्यौरा
स्ट्रक्चर और क्लास
  • क्लास टाइप या स्ट्रक्चर टाइप का साइज़ बदलें.
  • बेस क्लास
    • बेस क्लास जोड़ें या हटाएं.
    • वर्चुअल तरीके से इनहेरिट की गई बेस क्लास जोड़ें या हटाएं.
    • बेस क्लास का क्रम बदलें.
  • मेंबर फ़ंक्शन
    • सदस्य फ़ंक्शन हटाएं*.
    • मेम्बर फ़ंक्शन में आर्ग्युमेंट जोड़ें या हटाएं.
    • पैरामीटर के टाइप या सदस्य फ़ंक्शन के रिटर्न टाइप बदलें*.
    • वर्चुअल टेबल लेआउट बदलें.
  • डेटा के सदस्य
    • स्टैटिक डेटा सदस्यों को हटाएं.
    • नॉन-स्टैटिक डेटा में सदस्य जोड़ना या हटाना.
    • डेटा के सदस्यों के टाइप बदलें.
    • ऑफ़सेट को नॉन-स्टैटिक डेटा मेंबर** में बदलें.
    • डेटा में मौजूद सदस्यों के const, volatile, और/या restricted क्वालिफ़ायर बदलें***.
    • डेटा में शामिल सदस्यों के ऐक्सेस स्पेसिफ़ायर को डाउनग्रेड करें***.
  • टेंप्लेट के आर्ग्युमेंट बदलें.
यूनियन
  • डेटा में सदस्यों को जोड़ना या हटाना.
  • यूनियन टाइप का साइज़ बदलें.
  • डेटा के सदस्यों के टाइप बदलें.
एनोटेशन
  • डेटा टाइप बदलें.
  • एनोमेटर के नाम बदलना.
  • एनोमेरेटर की वैल्यू बदलें.
ग्लोबल सिंबल
  • सार्वजनिक हेडर से एक्सपोर्ट किए गए सिंबल हटाएं.
  • FUNC टाइप के ग्लोबल सिंबल के लिए
    • आर्ग्युमेंट जोड़ें या हटाएं.
    • आर्ग्युमेंट के टाइप बदलें.
    • सामान लौटाने का तरीका बदलें.
    • ऐक्सेस स्पेसिफ़ायर को डाउनग्रेड करें***.
  • OBJECT टाइप के ग्लोबल सिंबल के लिए
    • उससे जुड़े C/C++ टाइप को बदलें.
    • ऐक्सेस स्पेसिफ़ायर को डाउनग्रेड करें***.

* सार्वजनिक और निजी सदस्य फ़ंक्शन, दोनों को बदलना या हटाना नहीं चाहिए, क्योंकि सार्वजनिक इनलाइन फ़ंक्शन निजी सदस्य फ़ंक्शन के बारे में बता सकते हैं. निजी सदस्य फ़ंक्शन के सिंबल रेफ़रंस को कॉलर बाइनरी में रखा जा सकता है. शेयर की गई लाइब्रेरी से, प्राइवेट मेंबर फ़ंक्शन को बदलने या हटाने की वजह से, पुराने सिस्टम के साथ काम नहीं करने वाली बाइनरी बन सकती हैं.

** सार्वजनिक या निजी डेटा के सदस्यों के ऑफ़सेट में बदलाव नहीं किया जाना चाहिए, क्योंकि इनलाइन फ़ंक्शन अपने फ़ंक्शन बॉडी में इन डेटा के सदस्यों का रेफ़रंस दे सकते हैं. डेटा मेंबर के ऑफ़सेट बदलने से, पुराने सिस्टम के साथ काम न करने वाली बाइनरी बन सकती हैं.

*** हालांकि, इनसे इस तरह के मेमोरी लेआउट में बदलाव नहीं होता, लेकिन सिमेंटिक अंतर हो सकता है. इसकी वजह से हो सकता है कि लाइब्रेरी उम्मीद के मुताबिक काम न करें.

एबीआई के नियमों का पालन करने वाले टूल इस्तेमाल करें

जब कोई VNDK लाइब्रेरी बनाई जाती है, तो लाइब्रेरी के एबीआई की तुलना, VNDK के उस वर्शन के एबीआई रेफ़रंस से की जाती है जिसे बनाया जा रहा है. रेफ़रंस एबीआई डंप यहां मौजूद हैं:

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

उदाहरण के लिए, एपीआई लेवल 27 पर x86 के लिए libfoo बनाने पर, libfoo के अनुमानित एबीआई की तुलना, यहां दी गई उसके रेफ़रंस से की जाती है:

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

एबीआई के काम न करने की गड़बड़ी

एबीआई के गड़बड़ होने पर, बिल्ड लॉग में चेतावनियां दिखती हैं. इनमें चेतावनी के टाइप के साथ-साथ, abi-diff रिपोर्ट का पाथ भी दिखता है. उदाहरण के लिए, अगर libbinder के एबीआई में ऐसा बदलाव किया गया है जो काम नहीं करता, तो बिल्ड सिस्टम गड़बड़ी का मैसेज दिखाता है. यह मैसेज कुछ ऐसा होता है:

*****************************************************
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 लाइब्रेरी के एबीआई की जांच करना

VNDK लाइब्रेरी बनाने पर:

  1. header-abi-dumper, वीएनडीके लाइब्रेरी (लाइब्रेरी की अपनी सोर्स फ़ाइलें और स्टैटिक ट्रांज़िटिव डिपेंडेंसी से इनहेरिट की गई सोर्स फ़ाइलें) बनाने के लिए, इकट्ठा की गई सोर्स फ़ाइलों को प्रोसेस करता है. इससे हर सोर्स से जुड़ी .sdump फ़ाइलें बनाई जाती हैं.
    sdump बनाना
    पहला डायग्राम. .sdump फ़ाइलें बनाई जा रही हैं
  2. इसके बाद, header-abi-linker .sdump फ़ाइलों को प्रोसेस करता है. इसके लिए, उसे दी गई वर्शन स्क्रिप्ट या शेयर की गई लाइब्रेरी से जुड़ी .so फ़ाइल का इस्तेमाल किया जाता है. इससे .lsdump फ़ाइल बनती है, जिसमें शेयर की गई लाइब्रेरी से जुड़ी एबीआई की सारी जानकारी लॉग होती है.
    lsdump बनाना
    दूसरी इमेज. .lsdump फ़ाइल बनाना
  3. header-abi-diff, .lsdump फ़ाइल की तुलना, रेफ़रंस .lsdump फ़ाइल से करता है. इससे, दोनों लाइब्रेरी के एबीआई में अंतर की जानकारी देने वाली डिफ़रेंस रिपोर्ट बनती है.
    अबी डिफ़ेंस बनाना
    तीसरी इमेज. अंतर की रिपोर्ट बनाना

हेडर-ऐबी-डंपर

header-abi-dumper टूल, C/C++ सोर्स फ़ाइल को पार्स करता है और उस सोर्स फ़ाइल से अनुमानित एबीआई को किसी इंटरमीडिएट फ़ाइल में डाल देता है. बिल्ड सिस्टम, सभी कंपाइल की गई सोर्स फ़ाइलों पर header-abi-dumper चलाता है. साथ ही, एक लाइब्रेरी भी बनाता है, जिसमें ट्रांज़िटिव डिपेंडेंसी की सोर्स फ़ाइलें शामिल होती हैं.

इनपुट
  • C/C++ सोर्स फ़ाइल
  • एक्सपोर्ट की गई शामिल डायरेक्ट्री
  • कंपाइलर फ़्लैग
आउटपुट यह एक ऐसी फ़ाइल है जिसमें सोर्स फ़ाइल के एबीआई के बारे में बताया गया है. उदाहरण के लिए, foo.sdump , foo.cpp के एबीआई को दिखाता है.

फ़िलहाल, .sdump फ़ाइलें JSON फ़ॉर्मैट में हैं. हालांकि, आने वाले समय में रिलीज़ होने वाले वर्शन में, इन फ़ाइलों के काम करने की गारंटी नहीं है. इसलिए, .sdump फ़ाइल फ़ॉर्मैटिंग को बिल्ड सिस्टम लागू करने की जानकारी माना जाना चाहिए.

उदाहरण के लिए, libfoo.so में यह सोर्स फ़ाइल 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;
}

header-abi-dumper का इस्तेमाल करके, इंटरमीडिएट .sdump फ़ाइल जनरेट की जा सकती है. यह फ़ाइल, सोर्स फ़ाइल से मिले एबीआई की जानकारी देती है. इसके लिए, इनका इस्तेमाल किया जा सकता है:

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

यह निर्देश header-abi-dumper को -- के बाद मौजूद कंपाइलर फ़्लैग के साथ foo.cpp को पार्स करने के लिए कहता है. साथ ही, exported डायरेक्ट्री में मौजूद सार्वजनिक हेडर से एक्सपोर्ट की गई एबीआई जानकारी को उत्सर्जित करता है. यहां दिया गया foo.sdump, 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 में, सोर्स फ़ाइल foo.cpp से एक्सपोर्ट की गई एबीआई जानकारी और सार्वजनिक हेडर शामिल होते हैं. उदाहरण के लिए,

  • record_types. सार्वजनिक हेडर में बताए गए स्ट्रक्चर, यूनियन या क्लास देखें. हर रिकॉर्ड टाइप में फ़ील्ड, साइज़, ऐक्सेस की खास जानकारी, फ़ाइल के बारे में जानकारी देने वाली हेडर फ़ाइल, और अन्य एट्रिब्यूट की जानकारी होती है.
  • pointer_types. पब्लिक हेडर में, एक्सपोर्ट किए गए रिकॉर्ड/फ़ंक्शन के ज़रिए सीधे/अप्रत्यक्ष रूप से रेफ़र किए गए पॉइंटर टाइप के साथ-साथ, उस टाइप के बारे में जानकारी दें जिस पर पॉइंटर (type_info में referenced_type फ़ील्ड के ज़रिए) पॉइंट करता है. इसी तरह की जानकारी, क्वालीफ़ाइड टाइप, पहले से मौजूद C/C++ टाइप, ऐरे टाइप, और lvalue और rvalue रेफ़रंस टाइप के लिए .sdump फ़ाइल में लॉग की जाती है. इस जानकारी की मदद से, बार-बार अंतर का पता लगाया जा सकता है.
  • functions. सार्वजनिक हेडर से एक्सपोर्ट किए गए फ़ंक्शन दिखाएं. इनमें फ़ंक्शन के बदले गए नाम, रिटर्न टाइप, पैरामीटर के टाइप, ऐक्सेस की खास जानकारी, और अन्य एट्रिब्यूट की जानकारी भी होती है.

header-abi-linker

header-abi-linker टूल, header-abi-dumper से बनाई गई इंटरमीडिएट फ़ाइलों को इनपुट के तौर पर लेकर उन फ़ाइलों को लिंक करता है:

इनपुट
  • header-abi-dumper से जनरेट की गई इंटरमीडियरी फ़ाइलें
  • वर्शन स्क्रिप्ट/मैप फ़ाइल (ज़रूरी नहीं)
  • शेयर की गई लाइब्रेरी की .so फ़ाइल
  • एक्सपोर्ट की गई, डायरेक्ट्री शामिल हैं
आउटपुट ऐसी फ़ाइल जो किसी शेयर की गई लाइब्रेरी के एबीआई के बारे में बताती है. उदाहरण के लिए, libfoo.so.lsdump , libfoo के एबीआई को दिखाता है.

यह टूल, ट्रांसलेशन यूनिट के बीच के अंतर को ध्यान में रखते हुए, ट्रांसलेशन यूनिट में मौजूद सभी इंटरमीडियरी फ़ाइलों में टाइप ग्राफ़ को मर्ज करता है. यह अंतर, एक ही परिभाषा (अलग-अलग ट्रांसलेशन यूनिट में उपयोगकर्ता के तय किए गए टाइप, एक ही पूरी तरह से सही नाम के साथ, अलग-अलग अर्थ के हो सकते हैं) से जुड़ा हो सकता है. इसके बाद, टूल, एक्सपोर्ट किए गए सिंबल की सूची बनाने के लिए, वर्शन स्क्रिप्ट या शेयर की गई लाइब्रेरी (.so फ़ाइल) की .dynsym टेबल को पार्स करता है.

उदाहरण के लिए, libfoo में foo.cpp और bar.cpp शामिल हैं. libfoo का पूरा लिंक किया गया एबीआई डंप बनाने के लिए, header-abi-linker को इस तरह शुरू किया जा सकता है:

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

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

header-abi-linker टूल:

  • यह डायरेक्ट्री में मौजूद हेडर में मौजूद ABI जानकारी को फ़िल्टर करके, .sdump फ़ाइलों (foo.sdump और bar.sdump) को लिंक करता है.exported
  • libfoo.so को पार्स करता है और लाइब्रेरी की .dynsym टेबल के ज़रिए, एक्सपोर्ट किए गए सिंबल के बारे में जानकारी इकट्ठा करता है.
  • इसमें _Z3FooiP3bar और _Z6FooBadiP3foo जोड़े जाते हैं.

libfoo.so.lsdump, libfoo.so का जनरेट किया गया आखिरी एबीआई डंप है.

header-abi-diff

header-abi-diff टूल, दो लाइब्रेरी के एबीआई को दिखाने वाली दो .lsdump फ़ाइलों की तुलना करता है. साथ ही, दोनों एबीआई के बीच के अंतर की जानकारी देने वाली एक डिफ़रेंस रिपोर्ट बनाता है.

इनपुट
  • .lsdump फ़ाइल, शेयर की गई किसी पुरानी लाइब्रेरी के एबीआई के बारे में बताती है.
  • .lsdump फ़ाइल, शेयर की गई नई लाइब्रेरी के एबीआई (एबिट्रेशन इंटरफ़ेस) को दिखाती है.
आउटपुट तुलना की गई दो शेयर की गई लाइब्रेरी के एबीआई में अंतर बताने वाली डिफ़रेंस रिपोर्ट.

एबीआई की डिफ़रेंस फ़ाइल, प्रोटोबस टेक्स्ट फ़ॉर्मैट में हो. आने वाले समय में, इस फ़ॉर्मैट में बदलाव हो सकता है.

उदाहरण के लिए, आपके पास libfoo के दो वर्शन हैं: libfoo_old.so और libfoo_new.so. libfoo_new.so में, bar_t में, mfoo के टाइप को foo_t से बदलकर foo_t * किया जाता है. bar_t एक ऐसा टाइप है जिसे ऐक्सेस किया जा सकता है. इसलिए, इसे header-abi-diff के ज़रिए, एबीआई में बदलाव करने वाले बदलाव के तौर पर फ़्लैग किया जाना चाहिए.

header-abi-diff चलाने के लिए:

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

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

libfoo.so.abidiff में, libfoo में एबीआई के सभी बदलावों की रिपोर्ट होती है. record_type_diffs मैसेज से पता चलता है कि किसी रिकॉर्ड में बदलाव हुआ है. साथ ही, इसमें ऐसे बदलावों की सूची भी होती है जो काम नहीं करते. इनमें ये शामिल हैं:

  • रिकॉर्ड का साइज़, 24 बाइट से 8 बाइट में बदल रहा है.
  • mfoo फ़ील्ड का टाइप, foo से बदलकर foo * हो गया है (सभी typedef हटा दिए गए हैं).

type_stack फ़ील्ड से पता चलता है कि header-abi-diff कैसे बदले गए टाइप (bar) तक पहुंचा. इस फ़ील्ड को इस तरह समझा जा सकता है कि Foo एक एक्सपोर्ट किया गया फ़ंक्शन है, जो पैरामीटर के तौर पर bar * लेता है. यह bar पर ले जाता है, जिसे एक्सपोर्ट किया गया था और बदला गया था.

एबीआई और एपीआई लागू करना

VNDK की शेयर की गई लाइब्रेरी के एबीआई और एपीआई को लागू करने के लिए, एबीआई रेफ़रंस को ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/ में चेक इन करना ज़रूरी है. ये रेफ़रंस बनाने के लिए, यह कमांड चलाएं:

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

रेफ़रंस बनाने के बाद, सोर्स कोड में किया गया कोई भी बदलाव, VNDK लाइब्रेरी में ABI/API में बदलाव के साथ काम नहीं करता. इस वजह से, अब बिल्ड करने में गड़बड़ी होती है.

किसी खास लाइब्रेरी के लिए एबीआई रेफ़रंस अपडेट करने के लिए, यह कमांड चलाएं:

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

उदाहरण के लिए, libbinder एबीआई के रेफ़रंस अपडेट करने के लिए, इसे चलाएं:

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