এবিআই স্থিতিশীলতা

অ্যাপ্লিকেশন বাইনারি ইন্টারফেস (ABI) স্থায়িত্ব হল ফ্রেমওয়ার্ক-শুধু আপডেটের পূর্বশর্ত কারণ ভেন্ডর মডিউলগুলি ভেন্ডর নেটিভ ডেভেলপমেন্ট কিট (VNDK) শেয়ার্ড লাইব্রেরির উপর নির্ভর করতে পারে যা সিস্টেম পার্টিশনে থাকে। একটি অ্যান্ড্রয়েড রিলিজের মধ্যে, নতুন-নির্মিত VNDK ভাগ করা লাইব্রেরিগুলিকে পূর্বে প্রকাশিত VNDK ভাগ করা লাইব্রেরির সাথে ABI-সামঞ্জস্যপূর্ণ হতে হবে যাতে বিক্রেতা মডিউলগুলি পুনরায় সংকলন ছাড়াই এবং রানটাইম ত্রুটি ছাড়াই সেই লাইব্রেরির সাথে কাজ করতে পারে। অ্যান্ড্রয়েড রিলিজের মধ্যে, ভিএনডিকে লাইব্রেরি পরিবর্তন করা যেতে পারে এবং কোন ABI গ্যারান্টি নেই।

ABI সামঞ্জস্য নিশ্চিত করতে সাহায্য করার জন্য, Android 9-এ একটি শিরোনাম ABI চেকার রয়েছে, যা নিম্নলিখিত বিভাগে বর্ণিত হয়েছে।

VNDK এবং ABI সম্মতি সম্পর্কে

VNDK হল লাইব্রেরির একটি বিধিনিষেধমূলক সেট যেখানে বিক্রেতা মডিউলগুলি লিঙ্ক করতে পারে এবং যা শুধুমাত্র ফ্রেমওয়ার্ক আপডেটগুলি সক্ষম করে। ABI সম্মতি বলতে একটি শেয়ার্ড লাইব্রেরির একটি নতুন সংস্করণের সাথে গতিশীলভাবে যুক্ত একটি মডিউলের সাথে প্রত্যাশিতভাবে কাজ করার ক্ষমতা বোঝায় (যেমন লাইব্রেরির একটি পুরানো সংস্করণ হিসাবে কাজ করে)।

রপ্তানি প্রতীক সম্পর্কে

একটি রপ্তানিকৃত চিহ্ন (একটি বৈশ্বিক প্রতীক হিসাবেও পরিচিত) এমন একটি প্রতীককে বোঝায় যা নিম্নলিখিত সমস্তকে সন্তুষ্ট করে:

  • একটি শেয়ার্ড লাইব্রেরির পাবলিক হেডার দ্বারা রপ্তানি করা হয়েছে৷
  • শেয়ার করা লাইব্রেরির সাথে সম্পর্কিত .so ফাইলের .dynsym টেবিলে উপস্থিত হয়।
  • দুর্বল বা গ্লোবাল বাইন্ডিং আছে।
  • দৃশ্যমানতা ডিফল্ট বা সুরক্ষিত।
  • বিভাগ সূচক অনির্ধারিত নয়।
  • টাইপ হয় FUNC বা OBJECT।

শেয়ার্ড লাইব্রেরির পাবলিক হেডারগুলিকে export_include_dirs , export_header_lib_headers , export_static_lib_headers , export_shared_lib_headers , এবং export_generated_headers বৈশিষ্ট্যগুলির মাধ্যমে অন্যান্য Android.bp /বাইনারিতে উপলব্ধ হেডার হিসাবে সংজ্ঞায়িত করা হয়।

নাগালযোগ্য ধরনের সম্পর্কে

একটি পৌঁছানো যায় এমন ধরন হল যেকোন 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 একটি সদস্য mfoo রয়েছে, foo_t টাইপের, যেটি foo_exported.h মাধ্যমে রপ্তানি করা হয়, যার ফলে আরও ধরনের রপ্তানি হয়:
  • int : m1 এর ধরন।
  • int * : m2 এর ধরন।
  • foo_private_t * : mPfoo এর ধরন।

যাইহোক, foo_private_t পৌঁছানো যায় না কারণ এটি foo_exported.h মাধ্যমে রপ্তানি হয় না। ( foo_private_t * অস্বচ্ছ, তাই foo_private_t এ করা পরিবর্তন অনুমোদিত।)

বেস ক্লাস স্পেসিফায়ার এবং টেমপ্লেট পরামিতিগুলির মাধ্যমেও পৌঁছানো যায় এমন ধরণের জন্য অনুরূপ ব্যাখ্যা দেওয়া যেতে পারে।

ABI সম্মতি নিশ্চিত করা

vendor_available: true এবং vndk.enabled: true সংশ্লিষ্ট Android.bp ফাইলগুলিতে সত্য। উদাহরণ স্বরূপ:

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

রপ্তানিকৃত ফাংশন দ্বারা প্রত্যক্ষ বা পরোক্ষভাবে পৌঁছানো ডেটা প্রকারের জন্য, একটি লাইব্রেরিতে নিম্নলিখিত পরিবর্তনগুলি ABI-ব্রেকিং হিসাবে শ্রেণীবদ্ধ করা হয়েছে:

ডেটা টাইপ বর্ণনা
স্ট্রাকচার এবং ক্লাস
  • ক্লাস টাইপ বা struct টাইপের আকার পরিবর্তন করুন।
  • বেস ক্লাস
    • বেস ক্লাস যোগ করুন বা সরান।
    • কার্যত উত্তরাধিকারসূত্রে পাওয়া বেস ক্লাসগুলি যোগ করুন বা সরান৷
    • বেস ক্লাসের ক্রম পরিবর্তন করুন।
  • সদস্য ফাংশন
    • সদস্য ফাংশন সরান*.
    • সদস্য ফাংশন থেকে আর্গুমেন্ট যোগ করুন বা সরান।
    • আর্গুমেন্টের ধরন বা সদস্য ফাংশনের রিটার্ন প্রকার* পরিবর্তন করুন।
    • ভার্চুয়াল টেবিল লেআউট পরিবর্তন করুন.
  • ডেটা সদস্য
    • স্ট্যাটিক ডেটা সদস্যদের সরান।
    • নন-স্ট্যাটিক ডেটা সদস্যদের যোগ করুন বা সরান।
    • ডেটা সদস্যদের ধরন পরিবর্তন করুন।
    • অফসেটগুলিকে নন-স্ট্যাটিক ডেটা সদস্যে পরিবর্তন করুন**।
    • const , volatile , এবং/অথবা ডেটা সদস্যদের restricted যোগ্যতা পরিবর্তন করুন***।
    • ডেটা সদস্যদের অ্যাক্সেস স্পেসিফায়ার ডাউনগ্রেড করুন***।
  • টেমপ্লেট আর্গুমেন্ট পরিবর্তন করুন.
ইউনিয়ন
  • ডেটা সদস্যদের যোগ করুন বা সরান।
  • ইউনিয়নের আকার পরিবর্তন করুন।
  • ডেটা সদস্যদের ধরন পরিবর্তন করুন।
গণনা
  • অন্তর্নিহিত প্রকার পরিবর্তন করুন।
  • গণনাকারীদের নাম পরিবর্তন করুন।
  • গণনাকারীর মান পরিবর্তন করুন।
গ্লোবাল সিম্বল
  • পাবলিক হেডার দ্বারা রপ্তানি করা প্রতীকগুলি সরান।
  • FUNC টাইপের গ্লোবাল চিহ্নের জন্য
    • যুক্তি যোগ করুন বা সরান.
    • যুক্তির ধরন পরিবর্তন করুন।
    • রিটার্ন টাইপ পরিবর্তন করুন।
    • অ্যাক্সেস স্পেসিফায়ার ডাউনগ্রেড করুন ***।
  • OBJECT টাইপের বৈশ্বিক চিহ্নের জন্য
    • সংশ্লিষ্ট C/C++ প্রকার পরিবর্তন করুন।
    • অ্যাক্সেস স্পেসিফায়ার ডাউনগ্রেড করুন ***।

* উভয় পাবলিক এবং প্রাইভেট সদস্য ফাংশন পরিবর্তন বা অপসারণ করা উচিত নয় কারণ পাবলিক ইনলাইন ফাংশন ব্যক্তিগত সদস্য ফাংশন উল্লেখ করতে পারে। ব্যক্তিগত সদস্য ফাংশনের প্রতীক উল্লেখগুলি কলার বাইনারিগুলিতে রাখা যেতে পারে। ভাগ করা লাইব্রেরি থেকে ব্যক্তিগত সদস্য ফাংশন পরিবর্তন বা অপসারণের ফলে পশ্চাদগামী-অসঙ্গত বাইনারি হতে পারে।

** সর্বজনীন বা ব্যক্তিগত ডেটা সদস্যদের অফসেটগুলি অবশ্যই পরিবর্তন করা উচিত নয় কারণ ইনলাইন ফাংশনগুলি তাদের ফাংশন বডিতে এই ডেটা সদস্যদের উল্লেখ করতে পারে। ডেটা সদস্য অফসেটগুলি পরিবর্তন করার ফলে পশ্চাদপদ-বেমানান বাইনারি হতে পারে।

*** যদিও এগুলি টাইপের মেমরি লেআউট পরিবর্তন করে না, সেখানে শব্দার্থগত পার্থক্য রয়েছে যা লাইব্রেরিগুলি প্রত্যাশিত হিসাবে কাজ করতে পারে না।

ABI কমপ্লায়েন্স টুল ব্যবহার করা

যখন একটি VNDK লাইব্রেরি তৈরি করা হয়, তখন লাইব্রেরির ABI-কে VNDK-এর সংস্করণের জন্য সংশ্লিষ্ট ABI রেফারেন্সের সাথে তুলনা করা হয়। রেফারেন্স ABI ডাম্প এখানে অবস্থিত:

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

উদাহরণস্বরূপ, API স্তর 27-এ x86-এর জন্য libfoo তৈরি করার সময়, libfoo এর অনুমানকৃত ABI-কে এর রেফারেন্সের সাথে তুলনা করা হয়েছে:

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

ABI ভাঙ্গন ত্রুটি

এবিআই ব্রেকেজের ক্ষেত্রে, বিল্ড লগ সতর্কতার ধরন এবং এবি-ডিফ রিপোর্টের পথ সহ সতর্কতা প্রদর্শন করে। উদাহরণস্বরূপ, যদি libbinder এর ABI-তে একটি বেমানান পরিবর্তন থাকে, তাহলে বিল্ড সিস্টেম নিম্নলিখিতগুলির মতো একটি বার্তা সহ একটি ত্রুটি ছুড়ে দেয়:

*****************************************************
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 লাইব্রেরি নির্মিত হয়:

  1. header-abi-dumper VNDK লাইব্রেরি (লাইব্রেরির নিজস্ব সোর্স ফাইলের পাশাপাশি স্ট্যাটিক ট্রানজিটিভ নির্ভরতার মাধ্যমে উত্তরাধিকার সূত্রে প্রাপ্ত সোর্স ফাইল) তৈরি করার জন্য কম্পাইল করা .sdump ফাইলগুলিকে প্রসেস করে।
    sdump creation
    চিত্র 1. .sdump ফাইল তৈরি করা হচ্ছে
  2. header-abi-linker তারপর একটি .sdump ফাইল তৈরি করতে .lsdump ফাইলগুলিকে প্রসেস করে (হয় এটিতে দেওয়া একটি সংস্করণ স্ক্রিপ্ট ব্যবহার করে বা শেয়ার করা লাইব্রেরির সাথে সম্পর্কিত .so ফাইলটি ব্যবহার করে) যা শেয়ার করা লাইব্রেরির সাথে সম্পর্কিত ABI তথ্য লগ করে।
    lsdump creation
    চিত্র 2. .lsdump ফাইল তৈরি করা হচ্ছে
  3. header-abi-diff .lsdump ফাইলটিকে একটি রেফারেন্স .lsdump ফাইলের সাথে তুলনা করে একটি ভিন্ন প্রতিবেদন তৈরি করে যা দুটি লাইব্রেরির ABI-এর মধ্যে পার্থক্যকে রূপরেখা দেয়।
    abi diff creation
    চিত্র 3. ডিফ রিপোর্ট তৈরি করা

হেডার-আবি-ডাম্পার

header-abi-dumper টুলটি একটি C/C++ সোর্স ফাইল পার্স করে এবং সেই সোর্স ফাইল থেকে অনুমান করা ABIকে একটি মধ্যবর্তী ফাইলে ডাম্প করে। বিল্ড সিস্টেম সমস্ত কম্পাইল করা সোর্স ফাইলে header-abi-dumper চালায় এবং একটি লাইব্রেরি তৈরি করে যাতে ট্রানজিটিভ নির্ভরতা থেকে সোর্স ফাইল অন্তর্ভুক্ত থাকে।

ইনপুট
  • AC/C++ সোর্স ফাইল
  • রপ্তানি অন্তর্ভুক্ত ডিরেক্টরি
  • কম্পাইলার পতাকা
আউটপুট একটি ফাইল যা উৎস ফাইলের ABI বর্ণনা করে (উদাহরণস্বরূপ, foo.sdump foo.cpp এর ABI প্রতিনিধিত্ব করে)।

বর্তমানে .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;
}

আপনি একটি মধ্যবর্তী .sdump ফাইল তৈরি করতে header-abi-dumper ব্যবহার করতে পারেন যা ব্যবহার করে উৎস ফাইল দ্বারা উপস্থাপিত ABI প্রতিনিধিত্ব করে:

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

এই কমান্ড header-abi-dumper অনুসরণ করে কম্পাইলার ফ্ল্যাগগুলির সাথে foo.cpp পার্স করতে -- , এবং ABI তথ্য নির্গত করে যা exported ডিরেক্টরিতে পাবলিক হেডার দ্বারা এক্সপোর্ট করা হয়। নিম্নলিখিত header-abi-dumper দ্বারা উত্পন্ন foo.sdump :

{
 "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 ABI তথ্য রয়েছে যা উত্স ফাইল foo.cpp এবং পাবলিক হেডার দ্বারা রপ্তানি করা হয়, উদাহরণস্বরূপ,

  • record_types পাবলিক হেডারে সংজ্ঞায়িত স্ট্রাকট, ইউনিয়ন বা শ্রেণীগুলি পড়ুন। প্রতিটি রেকর্ডের ক্ষেত্র, এর আকার, অ্যাক্সেস স্পেসিফায়ার, এটিতে সংজ্ঞায়িত হেডার ফাইল এবং অন্যান্য বৈশিষ্ট্য সম্পর্কে তথ্য রয়েছে।
  • pointer_types । রপ্তানিকৃত রেকর্ড/ফাংশন দ্বারা সর্বজনীন শিরোনামে প্রত্যক্ষ/পরোক্ষভাবে উল্লেখ করা পয়েন্টার প্রকারগুলি উল্লেখ করুন, সাথে পয়েন্টার যে ধরনের নির্দেশ করে ( type_inforeferenced_type ক্ষেত্রের মাধ্যমে)। যোগ্য ধরনের, অন্তর্নির্মিত C/C++ প্রকার, অ্যারে প্রকার এবং lvalue এবং rvalue রেফারেন্স প্রকারের জন্য অনুরূপ তথ্য .sdump ফাইলে লগ করা হয়েছে। এই ধরনের তথ্য পুনরাবৃত্তিমূলক পার্থক্যের অনুমতি দেয়।
  • functions পাবলিক হেডার দ্বারা রপ্তানি করা ফাংশন প্রতিনিধিত্ব করে। তাদের কাছে ফাংশনের ম্যাংগলড নাম, রিটার্নের ধরন, প্যারামিটারের ধরন, অ্যাক্সেস স্পেসিফায়ার এবং অন্যান্য বৈশিষ্ট্য সম্পর্কেও তথ্য রয়েছে।

হেডার-অবি-লিঙ্কার

header-abi-linker টুলটি header-abi-dumper দ্বারা উত্পাদিত মধ্যবর্তী ফাইলগুলিকে ইনপুট হিসাবে নেয় তারপর সেই ফাইলগুলিকে লিঙ্ক করে:

ইনপুট
  • header-abi-dumper দ্বারা উত্পাদিত মধ্যবর্তী ফাইল
  • সংস্করণ স্ক্রিপ্ট/মানচিত্র ফাইল (ঐচ্ছিক)
  • .so শেয়ার করা লাইব্রেরির ফাইল
  • রপ্তানি অন্তর্ভুক্ত ডিরেক্টরি
আউটপুট একটি ফাইল যা একটি ভাগ করা লাইব্রেরির ABI বর্ণনা করে (উদাহরণস্বরূপ, libfoo.so.lsdump libfoo এর ABI প্রতিনিধিত্ব করে)।

টুলটি প্রদত্ত সমস্ত মধ্যবর্তী ফাইলের টাইপ গ্রাফগুলিকে একত্রিত করে, এক-সংজ্ঞা বিবেচনা করে (বিভিন্ন অনুবাদ ইউনিটে একই সম্পূর্ণ যোগ্য নামের ব্যবহারকারী-সংজ্ঞায়িত প্রকার, শব্দার্থগতভাবে ভিন্ন হতে পারে) অনুবাদ ইউনিট জুড়ে পার্থক্য। টুলটি তখন হয় একটি সংস্করণ স্ক্রিপ্ট বা ভাগ করা লাইব্রেরির .dynsym টেবিলকে পার্স করে ( .so ফাইল) এক্সপোর্ট করা চিহ্নগুলির একটি তালিকা তৈরি করতে।

উদাহরণস্বরূপ, libfoo foo.cpp এবং bar.cpp নিয়ে গঠিত। libfoo এর সম্পূর্ণ লিঙ্কযুক্ত ABI ডাম্প তৈরি করতে 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 টুল:

  • এটিতে প্রদত্ত .sdump ফাইলগুলিকে লিঙ্ক করে ( foo.sdump এবং bar.sdump ), ডিরেক্টরিতে থাকা হেডারগুলিতে উপস্থিত না থাকা ABI তথ্য ফিল্টার করে: exported
  • libfoo.so পার্স করে, এবং লাইব্রেরি দ্বারা রপ্তানি করা চিহ্ন সম্পর্কে তথ্য সংগ্রহ করে তার .dynsym টেবিলের মাধ্যমে।
  • _Z3FooiP3bar এবং _Z6FooBadiP3foo যোগ করে।

libfoo.so.lsdump হল libfoo.so এর চূড়ান্ত জেনারেট করা ABI ডাম্প।

হেডার-আবি-ডিফ

header-abi-diff টুল দুটি লাইব্রেরির ABI প্রতিনিধিত্বকারী দুটি .lsdump ফাইলের তুলনা করে এবং দুটি ABI-এর মধ্যে পার্থক্য উল্লেখ করে একটি ভিন্ন প্রতিবেদন তৈরি করে।

ইনপুট
  • একটি পুরানো ভাগ করা লাইব্রেরির ABI প্রতিনিধিত্বকারী .lsdump ফাইল।
  • একটি নতুন ভাগ করা লাইব্রেরির ABI প্রতিনিধিত্বকারী .lsdump ফাইল।
আউটপুট তুলনা করা দুটি শেয়ার্ড লাইব্রেরি দ্বারা প্রদত্ত ABI-এর পার্থক্য উল্লেখ করে একটি ভিন্ন প্রতিবেদন।

ABI ডিফ ফাইলটি প্রোটোবাফ টেক্সট ফরম্যাটে রয়েছে। বিন্যাস ভবিষ্যতে রিলিজ পরিবর্তন সাপেক্ষে.

উদাহরণস্বরূপ, আপনার libfoo এর দুটি সংস্করণ রয়েছে: libfoo_old.so এবং libfoo_new.solibfoo_new.so এ, bar_t এ, আপনি mfoo এর ধরন foo_t থেকে foo_t * এ পরিবর্তন করেন। যেহেতু bar_t একটি পৌঁছানো যায় এমন প্রকার, এটিকে header-abi-diff দ্বারা ABI ব্রেকিং পরিবর্তন হিসাবে পতাকাঙ্কিত করা উচিত।

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.abidifflibfoo এ ABI-এর সমস্ত পরিবর্তনের রিপোর্ট রয়েছে। record_type_diffs বার্তাটি নির্দেশ করে যে একটি রেকর্ড পরিবর্তিত হয়েছে এবং অসঙ্গত পরিবর্তনগুলি তালিকাভুক্ত করে, যার মধ্যে রয়েছে:

  • রেকর্ডের আকার 24 বাইট থেকে 8 বাইটে পরিবর্তিত হচ্ছে।
  • mfoo এর ক্ষেত্রের ধরন foo থেকে foo * তে পরিবর্তিত হচ্ছে (সমস্ত টাইপডেফ বন্ধ করে দেওয়া হয়েছে)।

type_stack ক্ষেত্র নির্দেশ করে কিভাবে header-abi-diff পরিবর্তিত প্রকারে পৌঁছেছে ( bar )। এই ক্ষেত্রটিকে ব্যাখ্যা করা যেতে পারে Foo হল একটি রপ্তানিকৃত ফাংশন যা bar * কে প্যারামিটার হিসাবে নেয়, যা bar নির্দেশ করে, যা রপ্তানি এবং পরিবর্তিত হয়েছিল।

ABI/API বলবৎ করা

VNDK ভাগ করা লাইব্রেরির ABI/API প্রয়োগ করতে, ABI রেফারেন্সগুলি অবশ্যই ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/ এ চেক করতে হবে। এই রেফারেন্স তৈরি করতে, নিম্নলিখিত কমান্ডটি চালান:

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

রেফারেন্স তৈরি করার পর, সোর্স কোডে করা যেকোন পরিবর্তনের ফলে VNDK লাইব্রেরিতে একটি বেমানান ABI/API পরিবর্তনের ফলে এখন একটি বিল্ড ত্রুটি দেখা দেয়।

নির্দিষ্ট লাইব্রেরির জন্য ABI রেফারেন্স আপডেট করতে, নিম্নলিখিত কমান্ডটি চালান:

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

উদাহরণস্বরূপ, libbinder ABI রেফারেন্স আপডেট করতে, চালান:

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