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

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

ABI কম্প্যাটিবিলিটি নিশ্চিত করতে সাহায্য করতে, Android 9-এ একটি হেডার ABI চেকার অন্তর্ভুক্ত আছে, যা নিম্নলিখিত বিভাগে বর্ণনা করা হয়েছে।

VNDK ও ABI মেনে চলা সম্পর্কে

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

এক্সপোর্ট করা চিহ্ন সম্পর্কে

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

  • শেয়ার করা লাইব্রেরির পাবলিক হেডার এক্সপোর্ট করে।
  • শেয়ার করা লাইব্রেরির সাথে সম্পর্কিত .so ফাইলে .dynsym টেবিলে দেখা যায়।
  • WEAK বা GLOBAL বাইন্ডিং আছে।
  • দৃশ্যমানতা হল ডিফল্ট বা সুরক্ষিত।
  • বিভাগের ইন্ডেক্স UNDEFINED নয়।
  • টাইপ 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 মেনে চলা নিশ্চিত করা

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

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

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

ডেটার ধরন বর্ণনা
স্ট্রাকচার ও ক্লাস
  • ক্লাসের ধরন বা স্ট্রাকচারের ধরনের সাইজ পরিবর্তন করুন।
  • বেস ক্লাস
    • বেস ক্লাস যোগ করা বা সরানো।
    • ভার্চুয়ালি ইনহেরিট করা বেস ক্লাস যোগ করা বা সরানো।
    • বেস ক্লাসের ক্রম পরিবর্তন করুন।
  • মেম্বার ফাংশন
    • মেম্বার ফাংশন সরিয়ে দিন*।
    • Add or remove arguments from member functions.
    • মেম্বার ফাংশনের* আর্গুমেন্টের ধরন বা রিটার্ন করার ধরন পরিবর্তন করুন।
    • ভার্চুয়াল টেবিল লেআউট পরিবর্তন করুন।
  • ডেটা মেম্বার
    • স্ট্যাটিক ডেটা মেম্বার সরিয়ে দিন।
    • নন-স্ট্যাটিক ডেটা মেম্বার যোগ করা বা সরানো।
    • ডেটা মেম্বারের ধরন পরিবর্তন করুন।
    • অফসেট পরিবর্তন করে নন-স্ট্যাটিক ডেটা মেম্বার** করুন।
    • ডেটা মেম্বারদের 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 লেভেল ২৭-এ 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 তৈরি করা
    ছবি ১. .sdumpটি ফাইল তৈরি করা হচ্ছে
  2. header-abi-linker তারপর .sdump ফাইল (এর জন্য প্রদত্ত ভার্সন স্ক্রিপ্ট বা শেয়ার করা লাইব্রেরির সাথে সম্পর্কিত .so ফাইল ব্যবহার করে) প্রসেস করে .lsdump ফাইল তৈরি করে, যা শেয়ার করা লাইব্রেরির সাথে সম্পর্কিত সমস্ত ABI তথ্য লগ করে।
    lsdump তৈরি করা
    ছবি ২. .lsdump ফাইল
    তৈরি করা হচ্ছে
  3. header-abi-diff, .lsdump ফাইলের সাথে রেফারেন্স .lsdump ফাইলের তুলনা করে একটি ডিফারেন্স রিপোর্ট তৈরি করে যা দুটি লাইব্রেরির ABI-এর মধ্যে পার্থক্যগুলি তুলে ধরে।
    abi diff তৈরি করা
    ছবি ৩. ডিফারেন্স রিপোর্ট তৈরি করা হচ্ছে

header-abi-dumper

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

ইনপুট
  • একটি C/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;
}

আপনি 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 সোর্স ফাইল থেকে এক্সপোর্ট করা ABI তথ্য থাকে 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 ফাইল
  • এক্সপোর্ট করা ইনক্লুড ডিরেক্টরি
আউটপুট শেয়ার করা লাইব্রেরির ABI বর্ণনা করে এমন ফাইল (যেমন, libfoo.so.lsdump libfoo-এর ABI)।

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

যেমন, libfoo-এর মধ্যে foo.cpp এবং bar.cpp আছে। header-abi-linker-কে কল করে libfoo-এর সম্পূর্ণ লিঙ্ক করা ABI ডাম্প তৈরি করা যেতে পারে:

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

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

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

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

যেমন, আপনার কাছে libfoo-এর দুটি ভার্সন আছে: libfoo_old.so এবং libfoo_new.so। libfoo_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 *-এ পরিবর্তন করা হচ্ছে (সব typedef বাদ দেওয়া হয়েছে)।

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