OTA আকার কমিয়ে দিন

এই পৃষ্ঠায় AOSP-তে যোগ করা পরিবর্তনগুলো বর্ণনা করা হয়েছে, যা বিল্ডগুলোর মধ্যে অপ্রয়োজনীয় ফাইল পরিবর্তন কমাতে সাহায্য করে। যেসব ডিভাইস ইমপ্লিমেন্টার তাদের নিজস্ব বিল্ড সিস্টেম রক্ষণাবেক্ষণ করেন, তারা তাদের ওভার-দ্য-এয়ার (OTA) আপডেটের আকার কমানোর জন্য এই তথ্যটিকে একটি নির্দেশিকা হিসেবে ব্যবহার করতে পারেন।

অ্যান্ড্রয়েড OTA আপডেটে মাঝে মাঝে এমন কিছু পরিবর্তিত ফাইল থাকে যা কোডের পরিবর্তনের সাথে মেলে না। এগুলো আসলে বিল্ড সিস্টেম আর্টিফ্যাক্ট। একই কোড যখন বিভিন্ন সময়ে, বিভিন্ন ডিরেক্টরি থেকে বা বিভিন্ন মেশিনে বিল্ড করা হয়, তখন প্রচুর পরিমাণে পরিবর্তিত ফাইল তৈরি হলে এমনটা হতে পারে। এই ধরনের অতিরিক্ত ফাইলগুলো একটি OTA প্যাচের আকার বাড়িয়ে দেয় এবং কোন কোড পরিবর্তিত হয়েছে তা নির্ধারণ করা কঠিন করে তোলে।

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

একটি বিল্ড সিস্টেম বিভিন্ন উপায়ে অপ্রয়োজনীয়ভাবে বড় প্যাচ তৈরি করতে পারে। এর প্রতিকারের জন্য, অ্যান্ড্রয়েড ৮.০ এবং তার পরবর্তী সংস্করণগুলোতে প্রতিটি ফাইল ডিফের প্যাচ সাইজ কমানোর জন্য নতুন ফিচার যুক্ত করা হয়েছে। যে উন্নতিগুলো OTA-আপডেট প্যাকেজের আকার কমিয়েছে, সেগুলো হলো:

  • নন-এ/বি ডিভাইস আপডেটে সম্পূর্ণ ইমেজের জন্য ZSTD- এর ব্যবহার, যা একটি সাধারণ-উদ্দেশ্যের, লসলেস-কম্প্রেশন অ্যালগরিদম। কম্প্রেশন লেভেল বাড়িয়ে উচ্চতর কম্প্রেশন রেশিওর জন্য ZSTD কাস্টমাইজ করা যায়। কম্প্রেশন লেভেল OTA জেনারেশনের সময় সেট করা হয় এবং --vabc_compression_param=zstd,$COMPRESSION_LEVEL ফ্ল্যাগটি পাস করে এটি সেট করা যায়।
  • OTA চলাকালীন ব্যবহৃত কম্প্রেশন উইন্ডোর আকার বৃদ্ধি করা। একটি ডিভাইসের .mk ফাইলে বিল্ড প্যারামিটার কাস্টমাইজ করে সর্বোচ্চ কম্প্রেশন উইন্ডোর আকার নির্ধারণ করা যায়। এই ভেরিয়েবলটি PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144 হিসাবে সেট করা হয়।
  • পাফিন রিকম্প্রেশন-এর ব্যবহার, যা ডিফ্লেট স্ট্রিমের জন্য একটি ডিটারমিনিস্টিক প্যাচিং টুল এবং এটি A/B OTA আপডেট তৈরির জন্য কম্প্রেশন ও ডিফারেন্স ফাংশনগুলো পরিচালনা করে।
  • ডেল্টা-জেনারেটর টুলের ব্যবহারে পরিবর্তন, যেমন প্যাচ কম্প্রেস করার জন্য bsdiff লাইব্রেরি কীভাবে ব্যবহৃত হয়। অ্যান্ড্রয়েড ৯ এবং তার পরবর্তী সংস্করণগুলোতে, bsdiff টুলটি এমন কম্প্রেশন অ্যালগরিদম নির্বাচন করে যা একটি প্যাচের জন্য সেরা কম্প্রেশন ফলাফল দেবে।
  • update_engine এর উন্নতির ফলে A/B ডিভাইস আপডেটের জন্য প্যাচ প্রয়োগ করার সময় ব্যবহৃত মেমরির পরিমাণ কমে গেছে।

নিম্নলিখিত বিভাগগুলিতে OTA-আপডেট সাইজকে প্রভাবিত করে এমন বিভিন্ন সমস্যা, সেগুলির সমাধান এবং AOSP-তে বাস্তবায়নের উদাহরণ নিয়ে আলোচনা করা হয়েছে।

ফাইলের ক্রম

সমস্যা : কোনো ডিরেক্টরির ফাইলগুলোর তালিকা চাইলে ফাইলসিস্টেমগুলো ফাইলের ক্রম নিশ্চিত করে না, যদিও একই চেকআউটের জন্য ক্রমটি সাধারণত একই থাকে। ls এর মতো টুলগুলো ডিফল্টভাবে ফলাফল সাজিয়ে নেয়, কিন্তু find এবং make এর মতো কমান্ডে ব্যবহৃত ওয়াইল্ডকার্ড ফাংশন ফলাফলগুলো সাজায় না। এই টুলগুলো ব্যবহার করার আগে, আপনাকে অবশ্যই আউটপুটগুলো সাজিয়ে নিতে হবে।

সমাধান : যখন আপনি ওয়াইল্ডকার্ড ফাংশনের সাথে find এবং make মতো টুল ব্যবহার করেন, তখন এই কমান্ডগুলোর আউটপুট ব্যবহারের আগে সর্ট করে নিন। Android.mk ফাইলে $(wildcard) বা $(shell find) ব্যবহার করার সময়, সেগুলোও সর্ট করে নিন। জাভার মতো কিছু টুল ইনপুট সর্ট করে নেয়, তাই ফাইলগুলো সর্ট করার আগে যাচাই করে নিন যে আপনি যে টুলটি ব্যবহার করছেন সেটি ইতোমধ্যেই তা করে ফেলেছে কি না।

উদাহরণস্বরূপ: কোর বিল্ড সিস্টেমে বিল্টইন all-*-files-under ম্যাক্রো ব্যবহার করে অনেক সমস্যার সমাধান করা হয়েছে, যার মধ্যে all-cpp-files-under অন্তর্ভুক্ত (কারণ বেশ কিছু ডেফিনিশন অন্যান্য মেকফাইলে ছড়িয়ে ছিটিয়ে ছিল)। বিস্তারিত জানতে নিম্নলিখিতটি দেখুন:

ডিরেক্টরি তৈরি করুন

সমস্যা: যে ডিরেক্টরিতে বিল্ড করা হয়, তা পরিবর্তন করলে বাইনারিগুলো ভিন্ন হয়ে যেতে পারে। অ্যান্ড্রয়েড বিল্ডের বেশিরভাগ পাথই রিলেটিভ পাথ, তাই C/C++-এর __FILE__ কোনো সমস্যা নয়। তবে, ডিবাগ সিম্বলগুলো ডিফল্টভাবে সম্পূর্ণ পাথনেম এনকোড করে, এবং .note.gnu.build-id প্রি-স্ট্রিপড বাইনারি হ্যাশ করে তৈরি করা হয়, তাই ডিবাগ সিম্বল পরিবর্তিত হলে এটিও পরিবর্তিত হবে।

সমাধান: AOSP এখন ডিবাগ পাথগুলোকে রিলেটিভ করে। বিস্তারিত জানতে, এই CL দেখুন: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02

টাইমস্ট্যাম্প

সমস্যা: বিল্ড আউটপুটে টাইমস্ট্যাম্প থাকার কারণে ফাইলে অপ্রয়োজনীয় পরিবর্তন ঘটে। এটি নিম্নলিখিত স্থানগুলিতে ঘটার সম্ভাবনা রয়েছে:

  • C বা C++ কোডে __DATE__/__TIME__/__TIMESTAMP__ ম্যাক্রো।
  • জিপ-ভিত্তিক আর্কাইভে টাইমস্ট্যাম্প অন্তর্ভুক্ত থাকে।

সমাধান/উদাহরণ: বিল্ড আউটপুট থেকে টাইমস্ট্যাম্প অপসারণ করতে, C/C++-এ __DATE__/__TIME__/__TIMESTAMP__ এবং আর্কাইভে এমবেডেড টাইমস্ট্যাম্পের ক্ষেত্রে নিচে দেওয়া নির্দেশাবলী ব্যবহার করুন।

C/C++ এ __DATE__/__TIME__/__TIMESTAMP__

এই ম্যাক্রোগুলো বিভিন্ন বিল্ডের জন্য সবসময় ভিন্ন ভিন্ন আউটপুট তৈরি করে, তাই এগুলো ব্যবহার করবেন না। এই ম্যাক্রোগুলো বাদ দেওয়ার জন্য এখানে কয়েকটি উপায় দেওয়া হলো:

আর্কাইভে (জিপ, জার) এমবেড করা টাইমস্ট্যাম্প

অ্যান্ড্রয়েড ৭.০, zip কমান্ডের সকল ব্যবহারে -X যোগ করার মাধ্যমে জিপ আর্কাইভে এমবেড করা টাইমস্ট্যাম্পের সমস্যাটি সমাধান করেছে। এর ফলে জিপ ফাইল থেকে বিল্ডারের UID/GID এবং এক্সটেন্ডেড ইউনিক্স টাইমস্ট্যাম্প মুছে যেত।

ziptime নামক একটি নতুন টুল (যা /platform/build/+/android17-release/tools/ziptime/ অবস্থিত) জিপ হেডারের সাধারণ টাইমস্ট্যাম্পগুলো রিসেট করে। বিস্তারিত জানতে README ফাইলটি দেখুন।

signapk টুলটি APK ফাইলগুলির জন্য টাইমস্ট্যাম্প সেট করে, যা সার্ভার টাইমজোনের উপর নির্ভর করে পরিবর্তিত হতে পারে। বিস্তারিত জানতে, এই CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028 দেখুন।

signapk টুলটি APK ফাইলগুলির জন্য টাইমস্ট্যাম্প সেট করে, যা সার্ভার টাইমজোনের উপর নির্ভর করে পরিবর্তিত হতে পারে। বিস্তারিত জানতে, এই CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028 দেখুন।

সংস্করণ স্ট্রিং

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

সমাধান: APK ভার্সন স্ট্রিং থেকে বিল্ড নম্বরটি মুছে ফেলুন।

উদাহরণ:

ডিভাইসে সত্যতা গণনা সক্ষম করুন

যদি আপনার ডিভাইসে dm-verity সক্রিয় করা থাকে, তাহলে OTA টুলগুলি স্বয়ংক্রিয়ভাবে আপনার ভেরিটি কনফিগারেশন গ্রহণ করে এবং ডিভাইসেই ভেরিটি গণনা সক্ষম করে। এর ফলে, আপনার OTA প্যাকেজে সরাসরি বাইট হিসেবে সংরক্ষণ না করে, অ্যান্ড্রয়েড ডিভাইসেই ভেরিটি ব্লকগুলি গণনা করা যায়। একটি ২ জিবি পার্টিশনের জন্য ভেরিটি ব্লকগুলি প্রায় ১৬ এমবি জায়গা নিতে পারে।

তবে, ডিভাইসে ভেরিটি গণনা করতে অনেক সময় লাগতে পারে। বিশেষ করে, ফরওয়ার্ড এরর-কারেকশন কোডটি অনেক সময় নিতে পারে। পিক্সেল ডিভাইসগুলিতে, এতে সাধারণত ১০ মিনিট পর্যন্ত সময় লাগে। লো-এন্ড ডিভাইসগুলিতে এটি আরও বেশি সময় নিতে পারে। আপনি যদি ডিভাইসে ভেরিটি গণনা নিষ্ক্রিয় করতে চান, কিন্তু dm-verity সক্রিয় রাখতে চান, তাহলে একটি OTA আপডেট তৈরি করার সময় ota_from_target_files টুলে --disable_fec_computation ফ্ল্যাগটি পাস করে তা করতে পারেন। এই ফ্ল্যাগটি OTA আপডেটের সময় ডিভাইসে ভেরিটি গণনা নিষ্ক্রিয় করে। এটি OTA ইনস্টলেশনের সময় কমায়, কিন্তু OTA প্যাকেজের আকার বাড়িয়ে দেয়। যদি আপনার ডিভাইসে dm-verity সক্রিয় না থাকে, তাহলে এই ফ্ল্যাগটি পাস করার কোনো প্রভাব পড়বে না।

সামঞ্জস্যপূর্ণ বিল্ড টুলস

সমস্যা: ইনস্টল করা ফাইল তৈরি করে এমন টুলগুলোকে অবশ্যই সামঞ্জস্যপূর্ণ হতে হবে (একটি নির্দিষ্ট ইনপুট থেকে সর্বদা একই আউটপুট পাওয়া উচিত)।

সমাধান/উদাহরণ: নিম্নলিখিত বিল্ড টুলগুলিতে পরিবর্তন প্রয়োজন ছিল:

  • নোটিস ফাইল ক্রিয়েটর । পুনরুৎপাদনযোগ্য নোটিস কালেকশন তৈরি করার জন্য নোটিস ফাইল ক্রিয়েটরটি পরিবর্তন করা হয়েছে। এই CL দেখুন: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64
  • জাভা অ্যান্ড্রয়েড কম্পাইলার কিট (জ্যাক) । জেনারেটেড কনস্ট্রাক্টরের ক্রমবিন্যাসে মাঝে মাঝে হওয়া পরিবর্তনগুলো সামাল দেওয়ার জন্য জ্যাক টুলচেইনটির একটি আপডেটের প্রয়োজন ছিল। টুলচেইনটিতে কনস্ট্রাক্টরের জন্য ডিটারমিনিস্টিক অ্যাক্সেসর যুক্ত করা হয়েছে: https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b
  • ART AOT কম্পাইলার (dex2oat) । ART কম্পাইলার বাইনারিটি একটি আপডেট পেয়েছে, যাতে একটি ডিটারমিনিস্টিক ইমেজ তৈরি করার অপশন যোগ করা হয়েছে: https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9
  • libpac.so ফাইল (V8) । প্রতিটি বিল্ডের জন্য V8 স্ন্যাপশট পরিবর্তিত হওয়ায়, প্রতিটি বিল্ড একটি ভিন্ন /system/lib/libpac.so ফাইল তৈরি করে। এর সমাধান হলো স্ন্যাপশটটি মুছে ফেলা: https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29
  • অ্যাপ্লিকেশন প্রি-ডেক্সঅপট (.odex) ফাইলগুলোতে ৬৪-বিট সিস্টেমে অনির্দিষ্ট প্যাডিং ছিল। এটি সংশোধন করা হয়েছে: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029

বিল্ড ডিফারেন্স টুল ব্যবহার করুন

যেসব ক্ষেত্রে বিল্ড-সম্পর্কিত ফাইলের পরিবর্তনগুলো বাদ দেওয়া সম্ভব হয় না, সেসব ক্ষেত্রে দুটি ফাইল প্যাকেজ তুলনা করার জন্য AOSP-তে target_files_diff.py নামে একটি বিল্ড ডিফারেন্স টুল অন্তর্ভুক্ত রয়েছে। এই টুলটি দুটি বিল্ডের মধ্যে একটি রিকার্সিভ ডিফারেন্স সম্পাদন করে, যেখানে সাধারণ বিল্ড-সম্পর্কিত ফাইলের পরিবর্তনগুলো বাদ দেওয়া হয়, যেমন—

  • বিল্ড আউটপুটে প্রত্যাশিত পরিবর্তন (উদাহরণস্বরূপ, বিল্ড নম্বর পরিবর্তনের কারণে)।
  • বর্তমান বিল্ড সিস্টেমে জ্ঞাত সমস্যার কারণে পরিবর্তন আনা হয়েছে।

বিল্ড ডিফারেন্স টুলটি ব্যবহার করতে, নিম্নলিখিত কমান্ডটি চালান:

target_files_diff.py dir1 dir2

dir1 এবং dir2 হলো মূল ডিরেক্টরি, যেগুলোতে প্রতিটি বিল্ডের জন্য এক্সট্র্যাক্ট করা টার্গেট ফাইলগুলো থাকে।

ব্লক বরাদ্দ সামঞ্জস্যপূর্ণ রাখুন

একটি নির্দিষ্ট ফাইলের ক্ষেত্রে, দুটি বিল্ডের মধ্যে এর বিষয়বস্তু একই থাকলেও, ডেটা ধারণকারী প্রকৃত ব্লকগুলো পরিবর্তিত হয়ে থাকতে পারে। ফলে, একটি OTA আপডেটের জন্য ব্লকগুলো স্থানান্তরিত করতে আপডেটারকে অপ্রয়োজনীয় I/O সম্পাদন করতে হয়।

একটি ভার্চুয়াল A/B OTA আপডেটে, অপ্রয়োজনীয় I/O কপি-অন-রাইট স্ন্যাপশট সংরক্ষণের জন্য প্রয়োজনীয় স্টোরেজ স্পেস ব্যাপকভাবে বাড়িয়ে দিতে পারে। একটি নন-A/B OTA আপডেটে, OTA আপডেটের জন্য ব্লকগুলো স্থানান্তরিত করার ফলে আপডেটের সময় বেড়ে যায়, কারণ ব্লক স্থানান্তরের কারণে I/O বেশি হয়।

এই সমস্যাটির সমাধান করতে, অ্যান্ড্রয়েড ৭.০-তে গুগল বিভিন্ন বিল্ড জুড়ে ব্লক অ্যালোকেশন সামঞ্জস্যপূর্ণ রাখার জন্য make_ext4fs টুলটিকে সম্প্রসারিত করেছে। make_ext4fs টুলটি একটি ঐচ্ছিক -d base_fs ফ্ল্যাগ গ্রহণ করে, যা একটি ext4 ইমেজ তৈরি করার সময় ফাইলগুলোকে একই ব্লকে বরাদ্দ করার চেষ্টা করে। আপনি পূর্ববর্তী কোনো বিল্ডের টার্গেট ফাইলগুলোর জিপ ফাইল থেকে ব্লক ম্যাপিং ফাইলগুলো (যেমন base_fs ম্যাপ ফাইল) এক্সট্র্যাক্ট করতে পারেন। প্রতিটি ext4 পার্টিশনের জন্য IMAGES ডিরেক্টরিতে একটি .map ফাইল থাকে (উদাহরণস্বরূপ, IMAGES/system.map system পার্টিশনকে নির্দেশ করে)। এরপর এই base_fs ফাইলগুলোকে চেক-ইন করা যায় এবং PRODUCT_<partition>_BASE_FS_PATH এর মাধ্যমে নির্দিষ্ট করে দেওয়া যায়, যেমনটি এই উদাহরণে দেখানো হয়েছে:

  PRODUCT_SYSTEM_BASE_FS_PATH := path/to/base_fs_files/base_system.map
  PRODUCT_SYSTEM_EXT_BASE_FS_PATH := path/to/base_fs_files/base_system_ext.map
  PRODUCT_VENDOR_BASE_FS_PATH := path/to/base_fs_files/base_vendor.map
  PRODUCT_PRODUCT_BASE_FS_PATH := path/to/base_fs_files/base_product.map
  PRODUCT_ODM_BASE_FS_PATH := path/to/base_fs_files/base_odm.map

যদিও এটি সামগ্রিক OTA প্যাকেজের আকার কমাতে সাহায্য করে না, তবে এটি I/O-এর পরিমাণ কমিয়ে OTA আপডেটের পারফরম্যান্স উন্নত করে। ভার্চুয়াল A/B আপডেটের ক্ষেত্রে, এটি OTA প্রয়োগ করার জন্য প্রয়োজনীয় স্টোরেজ স্পেসের পরিমাণ ব্যাপকভাবে হ্রাস করে।

অ্যাপ আপডেট করা এড়িয়ে চলুন

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