ABI স্থিতিশীলতা

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

ABI সামঞ্জস্যতা নিশ্চিত করতে সাহায্য করার জন্য, অ্যান্ড্রয়েড ৯-এ একটি হেডার ABI চেকার অন্তর্ভুক্ত রয়েছে, যা পরবর্তী বিভাগগুলিতে বর্ণনা করা হয়েছে।

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

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

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

একটি এক্সপোর্টেড সিম্বল (যা গ্লোবাল সিম্বল নামেও পরিচিত) বলতে এমন একটি সিম্বলকে বোঝায় যা নিম্নলিখিত সব শর্ত পূরণ করে:

  • একটি শেয়ার্ড লাইব্রেরির পাবলিক হেডার দ্বারা এক্সপোর্ট করা হয়।
  • শেয়ার্ড লাইব্রেরির সাথে সম্পর্কিত .so ফাইলের .dynsym টেবিলে এটি প্রদর্শিত হয়।
  • দুর্বল অথবা বৈশ্বিক বন্ধন রয়েছে।
  • দৃশ্যমানতা ডিফল্ট অথবা সুরক্ষিত।
  • বিভাগ সূচক অনির্ধারিত নয়।
  • টাইপটি হয় 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;
অ্যান্ড্রয়েড.বিপি
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 তে করা পরিবর্তন অনুমোদিত।)

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

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

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

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

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

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

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

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

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

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

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

${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/<PLATFORM_VNDK_VERSION&g<t;/BINDER_BITNES<S>/ARCH>/source-based

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

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

ABI ব্রেকএজ ত্রুটি

ABI-তে কোনো ত্রুটি ঘটলে, বিল্ড লগে সতর্কবার্তার ধরণ এবং abi-diff রিপোর্টের পাথসহ সতর্কবার্তা প্রদর্শিত হয়। উদাহরণস্বরূপ, যদি 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 লাইব্রেরি ABI চেক তৈরি করুন

যখন একটি VNDK লাইব্রেরি বিল্ড করা হয়:

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

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

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>
#inclu<de foo_exported.h>

bool Foo(int id, bar_t *bar_ptr) {
    if (i&&d > 0  bar_ptr->mfoo.m1 > 0) {
        return true;
    }
    return false;
}

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

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

এই কমান্ডটি header-abi-dumper -- এর পরের কম্পাইলার ফ্ল্যাগগুলো ব্যবহার করে foo.cpp পার্স করতে এবং exported ডিরেক্টরিতে থাকা পাবলিক হেডারগুলো দ্বারা এক্সপোর্ট করা ABI তথ্য প্রদান করতে নির্দেশ দেয়। নিচে 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 সোর্স ফাইল foo.cpp এবং পাবলিক হেডারগুলো দ্বারা এক্সপোর্ট করা ABI তথ্য থাকে, উদাহরণস্বরূপ,

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

হেডার-এবিআই-লিঙ্কার

header-abi-linker টুলটি header-abi-dumper দ্বারা উৎপাদিত অন্তর্বর্তী ফাইলগুলোকে ইনপুট হিসেবে গ্রহণ করে এবং তারপর সেই ফাইলগুলোকে লিঙ্ক করে:

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

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

উদাহরণস্বরূপ, 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 ) লিঙ্ক করে, এবং exported ডিরেক্টরিতে থাকা হেডারগুলিতে উপস্থিত নয় এমন ABI তথ্য ফিল্টার করে বাদ দেয়।
  • libfoo.so পার্স করে এবং এর .dynsym টেবিলের মাধ্যমে লাইব্রেরি দ্বারা এক্সপোর্ট করা সিম্বলগুলোর তথ্য সংগ্রহ করে।
  • _Z3FooiP3bar এবং _Z6FooBadiP3foo যোগ করে।

libfoo.so.lsdump হলো libfoo.so এর চূড়ান্তভাবে তৈরি হওয়া ABI ডাম্প।

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

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

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

ABI diff ফাইলটি প্রোটোবাফ টেক্সট ফরম্যাটে রয়েছে। ভবিষ্যতের রিলিজগুলোতে এই ফরম্যাট পরিবর্তিত হতে পারে।

উদাহরণস্বরূপ, আপনার কাছে 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.abidiff ফাইলে libfoo এর সমস্ত 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