অ্যান্ড্রয়েড কার্নেল এবিআই পর্যবেক্ষণ

অ্যান্ড্রয়েড কার্নেলের ইন-কার্নেল ABI স্থিতিশীল করার জন্য, আপনি অ্যান্ড্রয়েড ১১ এবং তার পরবর্তী সংস্করণগুলিতে উপলব্ধ অ্যাপ্লিকেশন বাইনারি ইন্টারফেস (ABI) মনিটরিং টুলিং ব্যবহার করতে পারেন। এই টুলিংটি বিদ্যমান কার্নেল বাইনারি ( vmlinux + GKI মডিউল) থেকে ABI রিপ্রেজেন্টেশন সংগ্রহ ও তুলনা করে। এই ABI রিপ্রেজেন্টেশনগুলো হলো .stg ফাইল এবং সিম্বল লিস্ট। যে ইন্টারফেসের চিত্র এই রিপ্রেজেন্টেশনটি প্রদান করে, তাকে কার্নেল মডিউল ইন্টারফেস (KMI) বলা হয়। KMI-এর পরিবর্তনগুলি ট্র্যাক করতে এবং তার প্রতিকার করতে আপনি এই টুলিংটি ব্যবহার করতে পারেন।

ABI মনিটরিং টুলিংটি AOSP-তে তৈরি করা হয়েছে এবং এটি রিপ্রেজেন্টেশন তৈরি ও তুলনা করার জন্য STG (অথবা Android 13 ও তার নিচের সংস্করণগুলোতে libabigail ) ব্যবহার করে।

এই পৃষ্ঠায় টুলিং, ABI রিপ্রেজেন্টেশন সংগ্রহ ও বিশ্লেষণের প্রক্রিয়া এবং ইন-কার্নেল ABI-কে স্থিতিশীলতা প্রদানের জন্য এই ধরনের রিপ্রেজেন্টেশনের ব্যবহার বর্ণনা করা হয়েছে। এই পৃষ্ঠায় অ্যান্ড্রয়েড কার্নেলে পরিবর্তন আনার বিষয়েও তথ্য দেওয়া হয়েছে।

প্রক্রিয়া

কার্নেলের ABI বিশ্লেষণ করতে একাধিক ধাপ অনুসরণ করতে হয়, যার বেশিরভাগই স্বয়ংক্রিয় করা সম্ভব:

  1. কার্নেল এবং এর ABI উপস্থাপনা তৈরি করুন
  2. বিল্ড এবং একটি রেফারেন্সের মধ্যে ABI পার্থক্য বিশ্লেষণ করুন
  3. ABI উপস্থাপনাটি আপডেট করুন (যদি প্রয়োজন হয়)
  4. প্রতীক তালিকা নিয়ে কাজ করুন

নিম্নলিখিত নির্দেশাবলী এমন যেকোনো কার্নেলের জন্য প্রযোজ্য যা আপনি একটি সমর্থিত টুলচেইন (যেমন প্রি-বিল্ট ক্ল্যাং টুলচেইন) ব্যবহার করে বিল্ড করতে পারেন । সমস্ত অ্যান্ড্রয়েড কমন কার্নেল ব্রাঞ্চ এবং বেশ কিছু ডিভাইস-নির্দিষ্ট কার্নেলের জন্য repo manifests উপলব্ধ রয়েছে; বিশ্লেষণের জন্য কার্নেল ডিস্ট্রিবিউশন বিল্ড করার সময় সঠিক টুলচেইন ব্যবহৃত হচ্ছে কিনা, তা এগুলি যাচাই করে।

প্রতীক তালিকা

KMI-তে কার্নেলের সমস্ত সিম্বল বা এমনকি ৩০,০০০-এর বেশি এক্সপোর্ট করা সিম্বলের সবগুলো অন্তর্ভুক্ত থাকে না। এর পরিবর্তে, ভেন্ডর মডিউল দ্বারা ব্যবহারযোগ্য সিম্বলগুলো কার্নেল ট্রিতে সর্বজনীনভাবে রক্ষণাবেক্ষণ করা এক সেট সিম্বল লিস্ট ফাইলে স্পষ্টভাবে তালিকাভুক্ত করা থাকে (অ্যান্ড্রয়েড ১৫ এবং তার নিচের সংস্করণগুলোতে gki/{ARCH}/symbols/* অথবা android/abi_gki_{ARCH}_* )। সমস্ত সিম্বল লিস্ট ফাইলের সমস্ত সিম্বলের সমষ্টিই স্থিতিশীল হিসেবে রক্ষণাবেক্ষণ করা KMI সিম্বলের সেটকে সংজ্ঞায়িত করে। একটি উদাহরণ সিম্বল লিস্ট ফাইল হলো gki/aarch64/symbols/db845c , যা DragonBoard 845c-এর জন্য প্রয়োজনীয় সিম্বলগুলো ঘোষণা করে।

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

প্রতিটি অ্যান্ড্রয়েড কমন কার্নেল (ACK) KMI কার্নেল ব্রাঞ্চের নিজস্ব সিম্বল লিস্ট থাকে। বিভিন্ন KMI কার্নেল ব্রাঞ্চের মধ্যে ABI স্থিতিশীলতা প্রদানের কোনো চেষ্টা করা হয় না। উদাহরণস্বরূপ, android12-5.10 এর KMI, android13-5.10 এর KMI থেকে সম্পূর্ণ স্বাধীন।

স্থিতিশীলতার জন্য কোন ইন্টারফেসগুলো পর্যবেক্ষণ করতে হবে তা সীমিত করতে ABI টুলগুলো KMI সিম্বল লিস্ট ব্যবহার করে। ভেন্ডরদের কাছ থেকে আশা করা হয় যে তারা তাদের নিজস্ব সিম্বল লিস্ট জমা দেবে এবং আপডেট করবে, যাতে তারা যে ইন্টারফেসগুলোর উপর নির্ভর করে সেগুলো ABI সামঞ্জস্যতা বজায় রাখে কিনা তা যাচাই করা যায়। উদাহরণস্বরূপ, android16-6.12 কার্নেলের সিম্বল লিস্ট দেখতে, https://android.googlesource.com/kernel/common/+/refs/heads/android16-6.12/gki/aarch64/symbols দেখুন।

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

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

আপনি " How to work with symbol lists" থেকে নির্দেশাবলী ব্যবহার করে একটি ডিভাইসের জন্য একটি KMI সিম্বল লিস্ট তৈরি করতে পারেন। অনেক পার্টনার প্রতিটি ACK-এর জন্য একটি করে সিম্বল লিস্ট জমা দেন, কিন্তু এটি কোনো কঠোর নিয়ম নয়। রক্ষণাবেক্ষণে সুবিধার জন্য, আপনি একাধিক সিম্বল লিস্ট জমা দিতে পারেন।

কেএমআই প্রসারিত করুন

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

কেএমআই ভাঙন সম্পর্কে

একটি কার্নেলের সোর্স থাকে এবং সেই সোর্সগুলো থেকে বাইনারি তৈরি করা হয়। ABI-পর্যবেক্ষণাধীন কার্নেল ব্রাঞ্চগুলোতে বর্তমান GKI ABI-এর একটি উপস্থাপনা (একটি .stg ফাইলের আকারে) অন্তর্ভুক্ত থাকে। বাইনারিগুলো ( vmlinux , Image এবং যেকোনো GKI মডিউল) তৈরি হয়ে গেলে, বাইনারিগুলো থেকে একটি ABI উপস্থাপনা নিষ্কাশন করা যায়। কার্নেল সোর্স ফাইলে করা যেকোনো পরিবর্তন বাইনারিগুলোকে প্রভাবিত করতে পারে এবং ফলস্বরূপ নিষ্কাশিত .stg ফাইলটিকেও প্রভাবিত করতে পারে। ABI কমপ্লায়েন্স বিশ্লেষণ কমিট করা .stg ফাইলটিকে বিল্ড আর্টিফ্যাক্ট থেকে নিষ্কাশিত ফাইলের সাথে তুলনা করে এবং কোনো শব্দার্থগত পার্থক্য খুঁজে পেলে Gerrit-এ সেই পরিবর্তনের উপর একটি Lint-1 লেবেল সেট করে।

ABI ভাঙন পরিচালনা করুন

উদাহরণস্বরূপ, নিম্নলিখিত প্যাচটি একটি অত্যন্ত সুস্পষ্ট ABI লঙ্ঘন ঘটায়:

diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 42786e6364ef..e15f1d0f137b 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -657,6 +657,7 @@ struct mm_struct {
                ANDROID_KABI_RESERVE(1);
        } __randomize_layout;

+       int tickle_count;
        /*
         * The mm_cpumask needs to be at the end of mm_struct, because it
         * is dynamically sized based on nr_cpu_ids.

এই প্যাচটি প্রয়োগ করে যখন আপনি বিল্ড ABI চালান, তখন টুলিংটি একটি নন-জিরো এরর কোড সহ এক্সিট করে এবং এর মতো একটি ABI পার্থক্য রিপোর্ট করে:

function symbol 'struct block_device* I_BDEV(struct inode*)' changed
  CRC changed from 0x8d400dbd to 0xabfc92ad

function symbol 'void* PDE_DATA(const struct inode*)' changed
  CRC changed from 0xc3c38b5c to 0x7ad96c0d

function symbol 'void __ClearPageMovable(struct page*)' changed
  CRC changed from 0xf489e5e8 to 0x92bd005e

... 4492 omitted; 4495 symbols have only CRC changes

type 'struct mm_struct' changed
  byte size changed from 992 to 1000
  member 'int tickle_count' was added
  member 'unsigned long cpu_bitmap[0]' changed
    offset changed by 64

বিল্ড করার সময় ABI পার্থক্য সনাক্ত করা হয়েছে

ত্রুটির সবচেয়ে সাধারণ কারণ হলো যখন কোনো ড্রাইভার কার্নেল থেকে এমন একটি নতুন সিম্বল ব্যবহার করে যা কোনো সিম্বল লিস্টেই নেই।

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

  • বৈশিষ্ট্য পরিবর্তনের উদাহরণ aosp/1345659- এ রয়েছে।
  • প্রতীক তালিকার উদাহরণ aosp/1346742- এ রয়েছে।
  • ABI উপস্থাপনা পরিবর্তনের উদাহরণ aosp/1349377- এ রয়েছে।

যদি সিম্বলটি এক্সপোর্ট করা হয়ে থাকে (আপনার দ্বারা অথবা পূর্বে এক্সপোর্ট করা হয়ে থাকে) কিন্তু অন্য কোনো ড্রাইভার এটি ব্যবহার না করে, তাহলে আপনি নিম্নলিখিতটির মতো একটি বিল্ড এরর পেতে পারেন।

Comparing the KMI and the symbol lists:
+ build/abi/compare_to_symbol_list out/$BRANCH/common/Module.symvers out/$BRANCH/common/abi_symbollist.raw
ERROR: Differences between ksymtab and symbol list detected!
Symbols missing from ksymtab:
Symbols missing from symbol list:
 - simple_strtoull

সমাধান করতে, আপনার কার্নেল এবং ACK উভয় ক্ষেত্রেই KMI সিম্বল লিস্ট আপডেট করুন ( Update the ABI representation দেখুন)। ACK-তে সিম্বল লিস্ট এবং ABI রিপ্রেজেন্টেশন আপডেট করার একটি উদাহরণের জন্য, aosp/1367601 দেখুন।

কার্নেল ABI ত্রুটিগুলি সমাধান করুন

আপনি কোড রিফ্যাক্টরিং করে ABI পরিবর্তন না করার মাধ্যমে অথবা ABI রিপ্রেজেন্টেশন আপডেট করার মাধ্যমে কার্নেল ABI ব্রেকএজ সামলাতে পারেন। আপনার পরিস্থিতির জন্য সেরা পন্থা নির্ধারণ করতে নিম্নলিখিত চার্টটি ব্যবহার করুন।

এবিআই ভাঙন ফ্লো চার্ট

চিত্র ১. এবিআই ভাঙন সমাধান

ABI পরিবর্তন এড়াতে কোড রিফ্যাক্টর করুন

বিদ্যমান ABI পরিবর্তন করা থেকে বিরত থাকার জন্য সর্বাত্মক চেষ্টা করুন। অনেক ক্ষেত্রে, আপনি আপনার কোড রিফ্যাক্টর করে ABI-কে প্রভাবিত করে এমন পরিবর্তনগুলো বাদ দিতে পারেন।

  • স্ট্রাক্ট ফিল্ডের রিফ্যাক্টরিং পরিবর্তন। যদি কোনো পরিবর্তন একটি ডিবাগ ফিচারের ABI পরিবর্তন করে, তাহলে ফিল্ডগুলোর চারপাশে (স্ট্রাক্ট এবং সোর্স রেফারেন্সে) একটি #ifdef যোগ করুন এবং নিশ্চিত করুন যে #ifdef জন্য ব্যবহৃত CONFIG প্রোডাকশন defconfig এবং gki_defconfig জন্য নিষ্ক্রিয় করা আছে। ABI না ভেঙে কীভাবে একটি স্ট্রাক্টে ডিবাগ কনফিগ যোগ করা যায় তার উদাহরণের জন্য, এই প্যাচসেটটি দেখুন।

  • কোর কার্নেল পরিবর্তন না করে ফিচারগুলো রিফ্যাক্টরিং করুন। পার্টনার মডিউলগুলোকে সাপোর্ট করার জন্য যদি ACK-তে নতুন ফিচার যোগ করার প্রয়োজন হয়, তবে কার্নেল ABI পরিবর্তন এড়াতে পরিবর্তনের ABI অংশটি রিফ্যাক্টর করার চেষ্টা করুন। কার্নেল ABI পরিবর্তন না করে বিদ্যমান কার্নেল ABI ব্যবহার করে অতিরিক্ত সক্ষমতা যোগ করার একটি উদাহরণের জন্য aosp/1312213 দেখুন।

অ্যান্ড্রয়েড গেরিটে একটি ত্রুটিপূর্ণ ABI ঠিক করুন

আপনি যদি ইচ্ছাকৃতভাবে কার্নেল ABI নষ্ট না করে থাকেন, তাহলে ABI মনিটরিং টুলের দেওয়া নির্দেশনা ব্যবহার করে আপনাকে বিষয়টি তদন্ত করতে হবে। ডেটা স্ট্রাকচারের পরিবর্তন এবং এর সাথে সম্পর্কিত সিম্বল CRC-এর পরিবর্তন, অথবা কনফিগারেশন অপশনের এমন পরিবর্তন যা পূর্বোক্ত কারণগুলোর কোনো একটির দিকে পরিচালিত করে—এগুলোই হলো এই ধরনের ভাঙনের সবচেয়ে সাধারণ কারণ। টুলটি দ্বারা খুঁজে পাওয়া সমস্যাগুলো সমাধান করার মাধ্যমে কাজ শুরু করুন।

আপনি স্থানীয়ভাবে ABI-এর ফলাফলগুলো পুনরুৎপাদন করতে পারেন, এর জন্য "কার্নেল এবং এর ABI উপস্থাপনা তৈরি করুন" দেখুন।

লিন্ট-১ লেবেল সম্পর্কে

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

এই ABI বিশ্লেষণগুলোর প্রতিটি Lint-1 লেবেল সেট করতে পারে এবং সমস্ত সমস্যা সমাধান না হওয়া পর্যন্ত বা লেবেলটি বাতিল না হওয়া পর্যন্ত পরিবর্তন জমা দেওয়া বন্ধ করে দিতে পারে।

কার্নেল ABI আপডেট করুন

যদি ABI পরিবর্তন করা অপরিহার্য হয়, তাহলে আপনাকে অবশ্যই আপনার কোডের পরিবর্তন, ABI উপস্থাপনা এবং প্রতীক তালিকা ACK-তে প্রয়োগ করতে হবে। Lint-কে দিয়ে -1 অপসারণ করাতে এবং GKI সামঞ্জস্যতা অক্ষুণ্ণ রাখতে, এই পদক্ষেপগুলি অনুসরণ করুন:

  1. ACK-তে কোডের পরিবর্তনগুলো আপলোড করুন

  2. প্যাচসেটটির জন্য কোড-রিভিউ +২ পাওয়ার অপেক্ষা করুন।

  3. রেফারেন্স ABI উপস্থাপনা আপডেট করুন

  4. আপনার কোডের পরিবর্তন এবং ABI আপডেটের পরিবর্তনটি একত্রিত করুন।

ACK-তে ABI কোডের পরিবর্তনগুলো আপলোড করুন

ACK ABI আপডেট করা নির্ভর করে কী ধরনের পরিবর্তন করা হচ্ছে তার উপর।

  • যদি কোনো ABI পরিবর্তন এমন কোনো ফিচারের সাথে সম্পর্কিত হয় যা CTS বা VTS টেস্টকে প্রভাবিত করে, তাহলে সাধারণত পরিবর্তনটিকে সরাসরি ACK করার জন্য চেরি-পিক করা যেতে পারে। উদাহরণস্বরূপ:

    • অডিও কাজ করার জন্য aosp/1289677 প্রয়োজন।
    • ইউএসবি কাজ করার জন্য aosp/1295945 প্রয়োজন।
  • যদি কোনো ABI পরিবর্তন এমন কোনো ফিচারের জন্য হয় যা ACK-এর সাথে শেয়ার করা যায়, তাহলে সেই পরিবর্তনটি সরাসরি ACK-তে চেরি-পিক করা যেতে পারে। উদাহরণস্বরূপ, নিম্নলিখিত পরিবর্তনগুলি CTS বা VTS টেস্টের জন্য প্রয়োজন নেই, কিন্তু ACK-এর সাথে শেয়ার করার জন্য ঠিক আছে:

    • aosp/1250412 হলো একটি থার্মাল ফিচার পরিবর্তন।
    • aosp/1288857 হলো একটি EXPORT_SYMBOL_GPL পরিবর্তন।
  • যদি কোনো ABI পরিবর্তনের ফলে এমন কোনো নতুন ফিচার যুক্ত হয় যা ACK-তে অন্তর্ভুক্ত করার প্রয়োজন নেই, তাহলে আপনি পরবর্তী বিভাগে বর্ণিত পদ্ধতি অনুযায়ী একটি স্টাব ব্যবহার করে ACK-তে সিম্বলগুলো যোগ করতে পারেন।

ACK-এর জন্য স্টাব ব্যবহার করুন

স্টাব শুধুমাত্র কোর কার্নেলের সেইসব পরিবর্তনের জন্য প্রয়োজনীয় হওয়া উচিত যা ACK-এর জন্য উপকারী নয়, যেমন পারফরম্যান্স এবং পাওয়ার সংক্রান্ত পরিবর্তন। নিম্নলিখিত তালিকায় GKI-এর জন্য ACK-তে স্টাব এবং আংশিক চেরি-পিকের উদাহরণ বিস্তারিতভাবে দেওয়া হয়েছে।

  • কোর-আইসোলেট ফিচার স্টাব ( aosp/1284493 )। ACK-তে ক্যাপাবিলিটি থাকা আবশ্যক নয়, কিন্তু আপনার মডিউলগুলো এই সিম্বলগুলো ব্যবহার করার জন্য সিম্বলগুলো ACK-তে উপস্থিত থাকতে হবে।

  • ভেন্ডর মডিউলের ( aosp/1288860 ) জন্য প্লেসহোল্ডার প্রতীক।

  • প্রতি-প্রক্রিয়া mm ইভেন্ট ট্র্যাকিং বৈশিষ্ট্যের ( aosp/1288454 ) শুধুমাত্র ABI-ভিত্তিক চেরি-পিক। মূল প্যাচটি ACK-তে চেরি-পিক করা হয়েছিল এবং তারপর task_structmm_event_count জন্য ABI পার্থক্য সমাধান করতে শুধুমাত্র প্রয়োজনীয় পরিবর্তনগুলো অন্তর্ভুক্ত করার জন্য ছাঁটাই করা হয়েছিল। এই প্যাচটি mm_event_type enum-কে চূড়ান্ত সদস্যগুলো অন্তর্ভুক্ত করার জন্য আপডেট করে।

  • থার্মাল স্ট্রাকচার ABI পরিবর্তনের আংশিক বাছাই, যার জন্য শুধু নতুন ABI ফিল্ড যোগ করার চেয়েও বেশি কিছু প্রয়োজন ছিল।

    • aosp/1255544 প্যাচটি পার্টনার কার্নেল এবং ACK-এর মধ্যেকার ABI পার্থক্য সমাধান করেছে।

    • aosp/1291018 প্যাচটি পূর্ববর্তী প্যাচের GKI পরীক্ষার সময় পাওয়া কার্যকরী সমস্যাগুলো সমাধান করেছে। এই সমাধানের মধ্যে একটি একক সেন্সরে একাধিক থার্মাল জোন নিবন্ধন করার জন্য সেন্সর প্যারামিটার স্ট্রাকচারটি ইনিশিয়ালাইজ করা অন্তর্ভুক্ত ছিল।

  • CONFIG_NL80211_TESTMODE ABI পরিবর্তন ( aosp/1344321 )। এই প্যাচটি ABI-এর জন্য প্রয়োজনীয় স্ট্রাকচারাল পরিবর্তন যোগ করেছে এবং নিশ্চিত করেছে যে অতিরিক্ত ফিল্ডগুলো যেন কোনো কার্যকরী পার্থক্য তৈরি না করে, যার ফলে পার্টনাররা তাদের প্রোডাকশন কার্নেলে CONFIG_NL80211_TESTMODE অন্তর্ভুক্ত করার পরেও GKI কমপ্লায়েন্স বজায় রাখতে সক্ষম হবে।

রানটাইমে KMI প্রয়োগ করুন

GKI কার্নেলগুলো TRIM_UNUSED_KSYMS=y এবং UNUSED_KSYMS_WHITELIST=<union of all symbol lists> কনফিগারেশন অপশন ব্যবহার করে, যা এক্সপোর্ট করা সিম্বলগুলোকে (যেমন EXPORT_SYMBOL_GPL() ব্যবহার করে এক্সপোর্ট করা সিম্বল) একটি সিম্বল তালিকায় তালিকাভুক্ত সিম্বলগুলোর মধ্যে সীমাবদ্ধ রাখে। অন্য সব সিম্বল আনএক্সপোর্টেড থাকে এবং কোনো আনএক্সপোর্টেড সিম্বলের প্রয়োজন এমন মডিউল লোড করার অনুমতি দেওয়া হয় না। এই সীমাবদ্ধতা বিল্ড করার সময় প্রয়োগ করা হয় এবং অনুপস্থিত এন্ট্রিগুলোকে ফ্ল্যাগ করা হয়।

উন্নয়নের উদ্দেশ্যে, আপনি এমন একটি GKI কার্নেল বিল্ড ব্যবহার করতে পারেন যাতে সিম্বল ট্রিমিং অন্তর্ভুক্ত নেই (অর্থাৎ, সাধারণত এক্সপোর্ট করা সমস্ত সিম্বল ব্যবহার করা যাবে)। এই বিল্ডগুলি খুঁজে পেতে, ci.android.com-kernel_debug_aarch64 বিল্ডগুলি সন্ধান করুন।

মডিউল ভার্সনিং ব্যবহার করে KMI প্রয়োগ করুন

জেনেরিক কার্নেল ইমেজ (GKI) কার্নেলগুলো রানটাইমে KMI কমপ্লায়েন্স নিশ্চিত করার জন্য একটি অতিরিক্ত ব্যবস্থা হিসেবে মডিউল ভার্সনিং ( CONFIG_MODVERSIONS ) ব্যবহার করে। যদি কোনো মডিউলের প্রত্যাশিত KMI, vmlinux এর KMI-এর সাথে না মেলে, তাহলে মডিউল ভার্সনিং মডিউল লোড হওয়ার সময় সাইক্লিক রিডানডেন্সি চেক (CRC) মিসম্যাচ ফেইলারের কারণ হতে পারে। উদাহরণস্বরূপ, ` module_layout() সিম্বলের জন্য CRC মিসম্যাচের কারণে মডিউল লোড হওয়ার সময় সাধারণত নিম্নলিখিত ফেইলারটি ঘটে থাকে:

init: Loading module /lib/modules/kernel/.../XXX.ko with args ""
XXX: disagrees about version of symbol module_layout
init: Failed to insmod '/lib/modules/kernel/.../XXX.ko' with args ''

মডিউল ভার্সনিং এর ব্যবহার

মডিউল ভার্সনিং নিম্নলিখিত কারণে উপকারী:

  • মডিউল ভার্সনিং ডেটা স্ট্রাকচারের দৃশ্যমানতার পরিবর্তন শনাক্ত করে। যদি মডিউলগুলো অস্বচ্ছ ডেটা স্ট্রাকচার—অর্থাৎ, যে ডেটা স্ট্রাকচারগুলো KMI-এর অংশ নয়—পরিবর্তন করে, তবে ভবিষ্যতে সেই স্ট্রাকচারে কোনো পরিবর্তন করা হলে তা অকার্যকর হয়ে যায়।

    উদাহরণস্বরূপ, struct device এর fwnode ফিল্ডটি বিবেচনা করুন। এই ফিল্ডটি অবশ্যই মডিউলগুলোর কাছে অস্বচ্ছ হতে হবে, যাতে তারা device->fw_node এর ফিল্ডগুলোতে কোনো পরিবর্তন করতে না পারে বা এর আকার সম্পর্কে কোনো অনুমান করতে না পারে।

    তবে, যদি কোনো মডিউল <linux/fwnode.h> (সরাসরি বা পরোক্ষভাবে) অন্তর্ভুক্ত করে, তাহলে struct device এর fwnode ফিল্ডটি তার কাছে আর অস্বচ্ছ থাকে না। তখন মডিউলটি device->fwnode->dev অথবা device->fwnode->ops এ পরিবর্তন করতে পারে। এই পরিস্থিতিটি বেশ কয়েকটি কারণে সমস্যাজনক, যা নিচে উল্লেখ করা হলো:

    • এটি কোর কার্নেল কোডের অভ্যন্তরীণ ডেটা স্ট্রাকচার সম্পর্কিত অনুমানগুলোকে ভেঙে দিতে পারে।

    • ভবিষ্যতের কোনো কার্নেল আপডেটে যদি struct fwnode_handle ( fwnode এর ডেটা টাইপ) পরিবর্তিত হয়, তাহলে মডিউলটি নতুন কার্নেলের সাথে আর কাজ করবে না। অধিকন্তু, stgdiff কোনো পার্থক্য দেখাবে না, কারণ মডিউলটি অভ্যন্তরীণ ডেটা স্ট্রাকচারগুলোকে সরাসরি এমনভাবে পরিবর্তন করে KMI-কে ভেঙে ফেলছে, যা শুধুমাত্র বাইনারি উপস্থাপনা পরীক্ষা করে বোঝা সম্ভব নয়।

  • যখন কোনো বর্তমান মডিউলকে পরবর্তীকালে একটি অসামঞ্জস্যপূর্ণ নতুন কার্নেল দ্বারা লোড করা হয়, তখন সেটিকে KMI-অসামঞ্জস্যপূর্ণ বলে গণ্য করা হয়। মডিউল ভার্সনিং একটি রান-টাইম চেক যোগ করে, যাতে ভুলবশত কার্নেলের সাথে KMI-সামঞ্জস্যপূর্ণ নয় এমন কোনো মডিউল লোড হওয়া এড়ানো যায়। এই চেকটি এমন সব রান-টাইম সমস্যা এবং কার্নেল ক্র্যাশ প্রতিরোধ করে, যেগুলোর ডিবাগিং কঠিন এবং যা KMI-এর মধ্যে কোনো অনাবিষ্কৃত অসামঞ্জস্যের কারণে ঘটতে পারে।

মডিউল ভার্সনিং সক্রিয় করলে এই সমস্ত সমস্যা প্রতিরোধ করা যায়।

ডিভাইসটি বুট না করেই CRC অমিল পরীক্ষা করুন।

stgdiff কার্নেলগুলোর মধ্যে CRC অমিলের পাশাপাশি অন্যান্য ABI পার্থক্যগুলোও তুলনা করে এবং প্রতিবেদন দেয়।

এছাড়াও, CONFIG_MODVERSIONS সক্রিয় করে একটি সম্পূর্ণ কার্নেল বিল্ড করলে, সাধারণ বিল্ড প্রক্রিয়ার অংশ হিসেবে একটি Module.symvers ফাইল তৈরি হয়। এই ফাইলে কার্নেল ( vmlinux ) এবং মডিউলগুলো দ্বারা এক্সপোর্ট করা প্রতিটি সিম্বলের জন্য একটি করে লাইন থাকে। প্রতিটি লাইনে CRC ভ্যালু, সিম্বলের নাম, সিম্বল নেমস্পেস, যে vmlinux বা মডিউলটি সিম্বলটি এক্সপোর্ট করছে তার নাম এবং এক্সপোর্ট টাইপ (উদাহরণস্বরূপ, EXPORT_SYMBOL বনাম EXPORT_SYMBOL_GPL ) থাকে।

vmlinux দ্বারা এক্সপোর্ট করা সিম্বলগুলোর CRC মানে কোনো পার্থক্য আছে কিনা তা পরীক্ষা করার জন্য আপনি GKI বিল্ড এবং আপনার বিল্ডের Module.symvers ফাইলগুলো তুলনা করতে পারেন। যদি vmlinux দ্বারা এক্সপোর্ট করা কোনো সিম্বলের CRC মানে পার্থক্য থাকে এবং সেই সিম্বলটি আপনার ডিভাইসে লোড করা কোনো মডিউল দ্বারা ব্যবহৃত হয়, তাহলে মডিউলটি লোড হয় না।

যদি আপনার কাছে সমস্ত বিল্ড আর্টিফ্যাক্ট না থাকে, কিন্তু GKI কার্নেল এবং আপনার কার্নেলের vmlinux ফাইলগুলো থাকে, তাহলে আপনি উভয় কার্নেলে নিম্নলিখিত কমান্ডটি চালিয়ে এবং আউটপুট তুলনা করে একটি নির্দিষ্ট সিম্বলের CRC মানগুলো তুলনা করতে পারেন:

nm <path to vmlinux>/vmlinux | grep __crc_<symbol name>

উদাহরণস্বরূপ, নিম্নলিখিত কমান্ডটি module_layout সিম্বলের জন্য CRC মান পরীক্ষা করে:

nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout

CRC অমিলগুলি সমাধান করুন

মডিউল লোড করার সময় CRC অমিল সমাধান করতে নিম্নলিখিত ধাপগুলো অনুসরণ করুন:

  1. নিম্নলিখিত কমান্ডে দেখানো পদ্ধতি অনুযায়ী --kbuild_symtypes অপশনটি ব্যবহার করে GKI কার্নেল এবং আপনার ডিভাইস কার্নেল বিল্ড করুন:

    tools/bazel run --kbuild_symtypes //common:kernel_aarch64_dist

    এই কমান্ডটি প্রতিটি .o ফাইলের জন্য একটি .symtypes ফাইল তৈরি করে। বিস্তারিত জানতে Kleaf-এর KBUILD_SYMTYPES দেখুন।

    অ্যান্ড্রয়েড ১৩ এবং এর পূর্ববর্তী সংস্করণগুলোর জন্য, GKI কার্নেল এবং আপনার ডিভাইস কার্নেল বিল্ড করতে, কার্নেল বিল্ড করার কমান্ডের শুরুতে KBUILD_SYMTYPES=1 যুক্ত করুন, যেমনটি নিম্নলিখিত কমান্ডে দেখানো হয়েছে:

    KBUILD_SYMTYPES=1 BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh

    build_abi.sh, KBUILD_SYMTYPES=1 ফ্ল্যাগটি আগে থেকেই অন্তর্নিহিতভাবে সেট করা থাকে।

  2. নিম্নলিখিত কমান্ডটি ব্যবহার করে সেই .c ফাইলটি খুঁজুন যেখানে CRC অমিলযুক্ত সিম্বলটি এক্সপোর্ট করা হয়েছে:

    git -C common grep EXPORT_SYMBOL.*module_layout
    kernel/module/version.c:EXPORT_SYMBOL(module_layout);
  3. .c ফাইলটির একটি সংশ্লিষ্ট .symtypes ফাইল GKI এবং আপনার ডিভাইস কার্নেল বিল্ড আর্টিফ্যাক্ট-এ থাকে। নিম্নলিখিত কমান্ডগুলো ব্যবহার করে .symtypes ফাইলটি খুঁজে বের করুন:

    cd bazel-bin/common/kernel_aarch64/symtypes
    ls -1 kernel/module/version.symtypes

    অ্যান্ড্রয়েড ১৩ এবং এর নিচের সংস্করণগুলোতে, লিগ্যাসি বিল্ড স্ক্রিপ্ট ব্যবহার করার ক্ষেত্রে, লোকেশনটি সম্ভবত out/$BRANCH/common অথবা out_abi/$BRANCH/common হয়ে থাকে।

    প্রতিটি .symtypes ফাইল হলো একটি সাধারণ টেক্সট ফাইল, যাতে টাইপ এবং সিম্বলের বিবরণ থাকে:

    • প্রতিটি লাইন key description আকারে থাকে, যেখানে বিবরণটি একই ফাইলের অন্যান্য কী-কে নির্দেশ করতে পারে।

    • [s|u|e|t]#foo এর মতো কী-গুলো [struct|union|enum|typedef] foo কে নির্দেশ করে। উদাহরণস্বরূপ:

      t#bool typedef _Bool bool
      
    • যেসব কী-তে x# উপসর্গ নেই, সেগুলো কেবল প্রতীকের নাম। উদাহরণস্বরূপ:

      find_module s#module * find_module ( const char * )
      
  4. ফাইল দুটি তুলনা করুন এবং সমস্ত পার্থক্য সংশোধন করুন।

সমস্যাযুক্ত পরিবর্তনের ঠিক আগে এবং তারপর সেই পরিবর্তনের সময়ে বিল্ডের মাধ্যমে symtypes তৈরি করাই সবচেয়ে ভালো। সমস্ত ফাইল সংরক্ষণ করলে সেগুলোকে একসাথে তুলনা করা যায়।

উদাহরণস্বরূপ,

diff -r -N -U0 good bad

অন্যথায়, শুধু নির্দিষ্ট ফাইলগুলো তুলনা করুন।

ক্ষেত্র ১: ডেটা টাইপ দৃশ্যমানতার কারণে পার্থক্য

একটি নতুন #include ট্যাগ সোর্স ফাইলে একটি নতুন টাইপ ডেফিনিশন (যেমন struct foo ) নিয়ে আসতে পারে। এই ক্ষেত্রে, সংশ্লিষ্ট .symtypes ফাইলে এর বর্ণনা একটি খালি structure_type foo { } থেকে একটি পূর্ণাঙ্গ ডেফিনিশনে পরিবর্তিত হবে।

এর ফলে .symtypes ফাইলের সেই সমস্ত সিম্বলের CRC-গুলো প্রভাবিত হবে, যাদের বর্ণনা প্রত্যক্ষ বা পরোক্ষভাবে টাইপ ডেফিনিশনের উপর নির্ভরশীল।

উদাহরণস্বরূপ, আপনার কার্নেলের include/linux/device.h ফাইলে নিম্নলিখিত লাইনটি যোগ করলে CRC অমিল দেখা দেয়, যার মধ্যে একটি হলো module_layout() এর জন্য:

 #include <linux/fwnode.h>

ঐ সিম্বলটির জন্য module/version.symtypes তুলনা করলে নিম্নলিখিত পার্থক্যগুলো প্রকাশ পায়:

 $ diff -u <GKI>/kernel/module/version.symtypes <your kernel>/kernel/module/version.symtypes
  --- <GKI>/kernel/module/version.symtypes
  +++ <your kernel>/kernel/module/version.symtypes
  @@ -334,12 +334,15 @@
  ...
  -s#fwnode_handle structure_type fwnode_handle { }
  +s#fwnode_reference_args structure_type fwnode_reference_args { s#fwnode_handle * fwnode ; unsigned int nargs ; t#u64 args [ 8 ] ; }
  ...

যদি GKI কার্নেলে সম্পূর্ণ টাইপ ডেফিনিশন থাকে, কিন্তু আপনার কার্নেলে তা না থাকে (যা হওয়ার সম্ভাবনা খুবই কম), তাহলে সর্বশেষ অ্যান্ড্রয়েড কমন কার্নেলটি আপনার কার্নেলে মার্জ করুন, যাতে আপনি সর্বশেষ GKI কার্নেল বেস ব্যবহার করতে পারেন।

বেশিরভাগ ক্ষেত্রে, GKI কার্নেলের .symtypes ফাইলে সম্পূর্ণ টাইপ ডেফিনিশনটি থাকে না, কিন্তু অতিরিক্ত #include নির্দেশাবলীর কারণে আপনার কার্নেলে এটি রয়েছে।

অ্যান্ড্রয়েড ১৬ এবং তার উপরের সংস্করণের জন্য রেজোলিউশন

নিশ্চিত করুন যে প্রভাবিত সোর্স ফাইলটিতে অ্যান্ড্রয়েড KABI স্টেবিলাইজেশন হেডার অন্তর্ভুক্ত রয়েছে:

#include <linux/android_kabi.h>

প্রতিটি প্রভাবিত টাইপের জন্য, প্রভাবিত সোর্স ফাইলে গ্লোবাল স্কোপে ANDROID_KABI_DECLONLY(name); যোগ করুন।

উদাহরণস্বরূপ, যদি symtypes diff-টি এইরকম হতো:

--- good/drivers/android/vendor_hooks.symtypes
+++ bad/drivers/android/vendor_hooks.symtypes
@@ -1051 +1051,2 @@
-s#ubuf_info structure_type ubuf_info { }
+s#ubuf_info structure_type ubuf_info { member pointer_type { const_type { s#ubuf_info_ops } } ops data_member_location(0) , member t#refcount_t refcnt data_member_location(8) , member t#u8 flags data_member_location(12) } byte_size(16)
+s#ubuf_info_ops structure_type ubuf_info_ops { member pointer_type { subroutine_type ( formal_parameter pointer_type { s#sk_buff } , formal_parameter pointer_type { s#ubuf_info } , formal_parameter t#bool ) -> base_type void } complete data_member_location(0) , member pointer_type { subroutine_type ( formal_parameter pointer_type { s#sk_buff } , formal_parameter pointer_type { s#ubuf_info } ) -> base_type int byte_size(4) encoding(5) } link_skb data_member_location(8) } byte_size(16)

তাহলে সমস্যাটি হলো যে, struct ubuf_info এখন symtypes এ একটি পূর্ণাঙ্গ সংজ্ঞা রয়েছে। এর সমাধান হলো drivers/android/vendor_hooks.c তে একটি লাইন যোগ করা:

ANDROID_KABI_DECLONLY(ubuf_info);

এটি gendwarfksyms নির্দেশ দেয় যেন ফাইলটিতে নির্দিষ্ট টাইপটিকে অনির্ধারিত হিসেবে গণ্য করা হয়।

আরও একটি জটিল সম্ভাবনা হলো, নতুন #include নিজেই একটি হেডার ফাইলের মধ্যে রয়েছে। এই ক্ষেত্রে, আপনাকে বিভিন্ন সোর্স ফাইলের মধ্যে ANDROID_KABI_DECLONLY ম্যাক্রো ইনভোকেশনের ভিন্ন ভিন্ন সেট বিতরণ করতে হতে পারে, যা পরোক্ষভাবে অতিরিক্ত টাইপ ডেফিনিশন নিয়ে আসে, কারণ সেগুলোর কোনো কোনোটিতে হয়তো আগে থেকেই কিছু টাইপ ডেফিনিশন ছিল।

পাঠযোগ্যতার জন্য, এই ধরনের ম্যাক্রো আহ্বানগুলো সোর্স ফাইলের শুরুর দিকে রাখুন।

অ্যান্ড্রয়েড ১৫ এবং তার নিচের সংস্করণের জন্য রেজোলিউশন

অনেক ক্ষেত্রেই, এর সমাধান হলো genksyms থেকে নতুন #include লুকিয়ে ফেলা।

#ifndef __GENKSYMS__
#include <linux/fwnode.h>
#endif

অন্যথায়, যে #include টি পার্থক্য সৃষ্টি করছে তা শনাক্ত করতে, এই ধাপগুলো অনুসরণ করুন:

  1. যে হেডার ফাইলটিতে এই পার্থক্যযুক্ত সিম্বল বা ডেটা টাইপটি সংজ্ঞায়িত করা আছে, সেটি খুলুন। উদাহরণস্বরূপ, struct fwnode_handle জন্য include/linux/fwnode.h ফাইলটি সম্পাদনা করুন।

  2. হেডার ফাইলের শীর্ষে নিম্নলিখিত কোডটি যোগ করুন:

    #ifdef CRC_CATCH
    #error "Included from here"
    #endif
    
  3. যে মডিউলটির .c ফাইলে CRC অমিল রয়েছে, সেটির যেকোনো #include লাইনের আগে প্রথম লাইন হিসেবে নিম্নলিখিতটি যোগ করুন।

    #define CRC_CATCH 1
    
  4. আপনার মডিউলটি কম্পাইল করুন। এর ফলে যে বিল্ড-টাইম ত্রুটি দেখা দেবে, তা সেইসব হেডার ফাইলের #include চেইনটি দেখাবে যেগুলোর কারণে এই CRC অমিলটি ঘটেছে। উদাহরণস্বরূপ:

    In file included from .../drivers/clk/XXX.c:16:`
    In file included from .../include/linux/of_device.h:5:
    In file included from .../include/linux/cpu.h:17:
    In file included from .../include/linux/node.h:18:
    .../include/linux/device.h:16:2: error: "Included from here"
    #error "Included from here"
    

    #include এর এই শৃঙ্খলের একটি সংযোগ আপনার কার্নেলে করা একটি পরিবর্তনের কারণে তৈরি হয়েছে, যা GKI কার্নেলে অনুপস্থিত।

ক্ষেত্র ২: ডেটা টাইপ পরিবর্তনের কারণে পার্থক্য

যদি কোনো সিম্বল বা ডেটা টাইপের CRC অমিল তার ভিজিবিলিটির পার্থক্যের কারণে না হয়, তাহলে এর কারণ হলো ডেটা টাইপটির মধ্যেই প্রকৃত পরিবর্তন (সংযোজন, অপসারণ বা সংশোধন)।

উদাহরণস্বরূপ, আপনার কার্নেলে নিম্নলিখিত পরিবর্তনটি করলে বেশ কয়েকটি CRC অমিল দেখা দেয়, কারণ এই ধরনের পরিবর্তনের দ্বারা অনেক সিম্বল পরোক্ষভাবে প্রভাবিত হয়:

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
  --- a/include/linux/iommu.h
  +++ b/include/linux/iommu.h
  @@ -259,7 +259,7 @@ struct iommu_ops {
     void (*iotlb_sync)(struct iommu_domain *domain);
     phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova);
     phys_addr_t (*iova_to_phys_hard)(struct iommu_domain *domain,
  -        dma_addr_t iova);
  +        dma_addr_t iova, unsigned long trans_flag);
     int (*add_device)(struct device *dev);
     void (*remove_device)(struct device *dev);
     struct iommu_group *(*device_group)(struct device *dev);

একটি CRC অমিল হলো devm_of_platform_populate() এর ক্ষেত্রে।

আপনি যদি সেই সিম্বলটির জন্য .symtypes ফাইলগুলো তুলনা করেন, তাহলে তা দেখতে এইরকম হতে পারে:

 $ diff -u <GKI>/drivers/of/platform.symtypes <your kernel>/drivers/of/platform.symtypes
  --- <GKI>/drivers/of/platform.symtypes
  +++ <your kernel>/drivers/of/platform.symtypes
  @@ -399,7 +399,7 @@
  ...
  -s#iommu_ops structure_type iommu_ops { ... ; t#phy
  s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t ) ; int
    ( * add_device ) ( s#device * ) ; ...
  +s#iommu_ops structure_type iommu_ops { ... ; t#phy
  s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t , unsigned long ) ; int ( * add_device ) ( s#device * ) ; ...

পরিবর্তিত ধরনটি শনাক্ত করতে, এই ধাপগুলো অনুসরণ করুন:

  1. সোর্স কোডে (সাধারণত .h ফাইলে) প্রতীকটির সংজ্ঞা খুঁজুন।

    • আপনার কার্নেল এবং GKI কার্নেলের মধ্যে প্রতীকের পার্থক্য জানতে, নিম্নলিখিত কমান্ডটি চালিয়ে কমিটটি খুঁজুন:
    git blame
    • মুছে ফেলা সিম্বলের ক্ষেত্রে (যেখানে একটি ট্রি থেকে একটি সিম্বল মুছে ফেলা হয়েছে এবং আপনি সেটি অন্য ট্রি থেকেও মুছতে চান), আপনাকে সেই পরিবর্তনটি খুঁজে বের করতে হবে যা লাইনটি মুছে দিয়েছে। যে ট্রি থেকে লাইনটি মুছে ফেলা হয়েছে, সেখানে নিম্নলিখিত কমান্ডটি ব্যবহার করুন:
    git log -S "copy paste of deleted line/word" -- <file where it was deleted>
  2. পরিবর্তন বা মুছে ফেলা অংশটি খুঁজে বের করতে ফেরত আসা কমিটগুলোর তালিকাটি পর্যালোচনা করুন। প্রথম কমিটটিই সম্ভবত আপনি খুঁজছেন। যদি তা না হয়, কমিটটি খুঁজে না পাওয়া পর্যন্ত তালিকাটি দেখতে থাকুন।

  3. কমিটটি শনাক্ত করার পর, হয় আপনার কার্নেলে এটি রিভার্ট করুন অথবা CRC পরিবর্তনটি দমন করতে এটি আপডেট করুন এবং ACK-তে আপলোড করে মার্জ করিয়ে নিন । নিরাপত্তার জন্য প্রতিটি অবশিষ্ট ABI ব্রেক পর্যালোচনা করতে হবে এবং প্রয়োজনে একটি অনুমোদিত ব্রেক রেকর্ড করা যেতে পারে।

বিদ্যমান প্যাডিং ব্যবহার করা পছন্দ করুন

GKI-এর কিছু স্ট্রাকচারে প্যাডিং যোগ করা থাকে, যাতে বিদ্যমান ভেন্ডর মডিউলগুলো নষ্ট না করেই সেগুলোর সম্প্রসারণ করা যায়। যদি কোনো আপস্ট্রিম কমিট (উদাহরণস্বরূপ) এই ধরনের কোনো স্ট্রাকচারে একটি মেম্বার যোগ করে, তবে সেটিকে পরিবর্তন করে কিছু প্যাডিং ব্যবহার করার ব্যবস্থা করা যেতে পারে। এই পরিবর্তনটি তখন CRC গণনার আওতার বাইরে থেকে যায়।

ANDROID_KABI_RESERVE প্রমিত ও স্ব-ব্যাখ্যামূলক ম্যাক্রোটি একটি u64 পরিমাণ (অ্যালাইনড) স্থান সংরক্ষণ করে। এটি মেম্বার ডিক্লারেশনের পরিবর্তে ব্যবহৃত হয়।

উদাহরণস্বরূপ:

struct data {
        u64 handle;
        ANDROID_KABI_RESERVE(1);
        ANDROID_KABI_RESERVE(2);
};

ANDROID_KABI_USE (অথবা ANDROID_KABI_USE2 বা সংজ্ঞায়িত হতে পারে এমন অন্য কোনো ভ্যারিয়েন্ট)-এর মাধ্যমে সিম্বল CRC-কে প্রভাবিত না করেই প্যাডিং ব্যবহার করা যেতে পারে।

sekret মেম্বারটি এমনভাবে উপলব্ধ থাকে যেন এটি সরাসরি ডিক্লেয়ার করা হয়েছে, কিন্তু ম্যাক্রোটি আসলে একটি অ্যানোনিমাস ইউনিয়ন মেম্বারে প্রসারিত হয়, যার মধ্যে sekret পাশাপাশি symtype স্ট্যাবিলিটি বজায় রাখার জন্য gendwarfksyms দ্বারা ব্যবহৃত উপাদানগুলোও থাকে।

struct data {
        u64 handle;
        ANDROID_KABI_USE(1, void *sekret);
        ANDROID_KABI_RESERVE(2);
};
অ্যান্ড্রয়েড ১৬ এবং তার উপরের সংস্করণের জন্য রেজোলিউশন

CRC-গুলো gendwarfksyms দ্বারা গণনা করা হয়, যা DWARF ডিবাগিং তথ্য ব্যবহার করে, ফলে এটি C এবং Rust উভয় টাইপকেই সমর্থন করে। টাইপ পরিবর্তনের ধরনের ওপর ভিত্তি করে রেজোলিউশন ভিন্ন হয়। এখানে কিছু উদাহরণ দেওয়া হলো।

নতুন বা পরিবর্তিত গণনাকারী

কখনও কখনও নতুন এনুমেটর যোগ করা হয় এবং মাঝে মাঝে MAX বা অনুরূপ কোনো এনুমেটর মানও প্রভাবিত হয়। এই পরিবর্তনগুলি নিরাপদ যদি সেগুলি GKI-এর আওতার বাইরে না যায় অথবা যদি আমরা নিশ্চিত হতে পারি যে ভেন্ডর মডিউলগুলি তাদের মান সম্পর্কে মাথা ঘামাতে পারে না।

উদাহরণস্বরূপ:

 enum outcome {
       SUCCESS,
       FAILURE,
       RETRY,
+      TRY_HARDER,
       OUTCOME_LIMIT
 };

গ্লোবাল স্কোপে ম্যাক্রো আহ্বানের মাধ্যমে TRY_HARDER এর সংযোজন এবং OUTCOME_LIMIT এর পরিবর্তনকে CRC গণনা থেকে গোপন রাখা যেতে পারে:

ANDROID_KABI_ENUMERATOR_IGNORE(outcome, TRY_HARDER);
ANDROID_KABI_ENUMERATOR_VALUE(outcome, OUTCOME_LIMIT, 3);

পাঠযোগ্যতার জন্য, এগুলো enum সংজ্ঞার ঠিক পরেই রাখুন।

একটি নতুন কাঠামোগত অংশ যা একটি বিদ্যমান গর্ত দখল করে

অ্যালাইনমেন্টের কারণে, urgent এবং scratch মধ্যে অব্যবহৃত বাইট থাকবে।

        void *data;
        bool urgent;
+       bool retry;
        void *scratch;

retry যোগ করার ফলে বিদ্যমান কোনো মেম্বার অফসেট বা স্ট্রাকচারের আকার প্রভাবিত হয় না। তবে, এটি সিম্বল CRC, ABI রিপ্রেজেন্টেশন অথবা উভয়কেই প্রভাবিত করতে পারে।

এটি CRC গণনা থেকে এটিকে আড়াল করবে:

        void *data;
        bool urgent;
+       ANDROID_KABI_IGNORE(1, bool retry);
        void *scratch_space;

retry মেম্বারটি এমনভাবে উপলব্ধ থাকে যেন এটি সরাসরি ডিক্লেয়ার করা হয়েছে, কিন্তু ম্যাক্রোটি আসলে একটি অ্যানোনিমাস ইউনিয়ন মেম্বারে প্রসারিত হয়, যার মধ্যে retry পাশাপাশি gendwarfksyms দ্বারা সিমটাইপ স্ট্যাবিলিটি বজায় রাখার জন্য ব্যবহৃত উপাদানগুলোও থাকে।

নতুন সদস্যদের নিয়ে কাঠামোর সম্প্রসারণ

কখনও কখনও একটি স্ট্রাকচারের শেষে মেম্বার যোগ করা হয়। এটি বিদ্যমান মেম্বারদের অফসেটকে প্রভাবিত করে না, অথবা স্ট্রাকচারটির সেইসব ব্যবহারকারীদেরও প্রভাবিত করে না যারা শুধুমাত্র পয়েন্টারের মাধ্যমে এটি অ্যাক্সেস করে। স্ট্রাকচারটির আকার এর CRC-কে প্রভাবিত করে এবং গ্লোবাল স্কোপে একটি অতিরিক্ত ম্যাক্রো আহ্বানের মাধ্যমে এর পরিবর্তন দমন করা যেতে পারে, যেমনটি নিচে দেখানো হলো:

struct data {
        u64 handle;
        u64 counter;
        ANDROID_KABI_IGNORE(1, void *sekret);
};

ANDROID_KABI_BYTE_SIZE(data, 16);

পাঠযোগ্যতার জন্য, এটি struct সংজ্ঞার ঠিক পরেই রাখুন।

টাইপ বা সিম্বলের টাইপের অন্য সব পরিবর্তন

খুব কদাচিৎ এমন কিছু পরিবর্তন হতে পারে যা পূর্ববর্তী কোনো বিভাগের অন্তর্ভুক্ত নয়, যার ফলে এমন CRC পরিবর্তন ঘটে যা পূর্ববর্তী ম্যাক্রোগুলো ব্যবহার করে দমন করা যায় না।

এইসব ক্ষেত্রে, গ্লোবাল স্কোপে ANDROID_KABI_TYPE_STRING কল করার মাধ্যমে কোনো টাইপ বা সিম্বলের মূল symtypes বর্ণনা সরবরাহ করা যেতে পারে।

struct data {
        /* extensive changes */
};

ANDROID_KABI_TYPE_STRING("s#data", "original s#data symtypes definition");

পাঠযোগ্যতার জন্য, এটি টাইপ বা সিম্বল সংজ্ঞার ঠিক পরেই রাখুন।

অ্যান্ড্রয়েড ১৫ এবং তার নিচের সংস্করণের জন্য রেজোলিউশন

টাইপ এবং সিম্বল টাইপের পরিবর্তনগুলো genksyms থেকে গোপন রাখা প্রয়োজন। __GENKSYMS__ ব্যবহার করে প্রিপ্রসেসিং নিয়ন্ত্রণের মাধ্যমে এটি করা যায়।

যথেচ্ছ কোড রূপান্তর এইভাবে প্রকাশ করা যেতে পারে।

উদাহরণস্বরূপ, বিদ্যমান কাঠামোর কোনো ফাঁকা জায়গায় থাকা নতুন কোনো সদস্যকে আড়াল করতে:

struct parcel {
        void *data;
        bool urgent;
#ifndef __GENKSYMS__
        bool retry;
#endif
        void *scratch_space;
};