পুনরুদ্ধার সিস্টেমে ডিভাইস-নির্দিষ্ট কোড ঢোকানোর জন্য বেশ কয়েকটি হুক রয়েছে যাতে OTA আপডেটগুলি অ্যান্ড্রয়েড সিস্টেম (যেমন, বেসব্যান্ড বা রেডিও প্রসেসর) ব্যতীত ডিভাইসের অংশগুলিও আপডেট করতে পারে।
নিম্নলিখিত বিভাগ এবং উদাহরণগুলি yoyodyne বিক্রেতা দ্বারা উত্পাদিত tardis ডিভাইস কাস্টমাইজ করে।
পার্টিশন মানচিত্র
অ্যান্ড্রয়েড 2.3 হিসাবে, প্ল্যাটফর্মটি eMMc ফ্ল্যাশ ডিভাইস এবং ext4 ফাইল সিস্টেম সমর্থন করে যা সেই ডিভাইসগুলিতে চলে। এটি মেমরি টেকনোলজি ডিভাইস (MTD) ফ্ল্যাশ ডিভাইস এবং পুরানো রিলিজ থেকে yaffs2 ফাইলসিস্টেম সমর্থন করে।
পার্টিশন ম্যাপ ফাইলটি TARGET_RECOVERY_FSTAB দ্বারা নির্দিষ্ট করা হয়েছে; এই ফাইলটি পুনরুদ্ধার বাইনারি এবং প্যাকেজ-বিল্ডিং সরঞ্জাম উভয় দ্বারা ব্যবহৃত হয়। আপনি BoardConfig.mk-এ TARGET_RECOVERY_FSTAB-এ মানচিত্র ফাইলের নাম উল্লেখ করতে পারেন।
একটি নমুনা পার্টিশন মানচিত্র ফাইল এই মত দেখতে হতে পারে:
device/yoyodyne/tardis/recovery.fstab
# mount point fstype device [device2] [options (3.0+ only)] /sdcard vfat /dev/block/mmcblk0p1 /dev/block/mmcblk0 /cache yaffs2 cache /misc mtd misc /boot mtd boot /recovery emmc /dev/block/platform/s3c-sdhci.0/by-name/recovery /system ext4 /dev/block/platform/s3c-sdhci.0/by-name/system length=-4096 /data ext4 /dev/block/platform/s3c-sdhci.0/by-name/userdata
/sdcard
ব্যতীত, যা ঐচ্ছিক, এই উদাহরণের সমস্ত মাউন্ট পয়েন্ট অবশ্যই সংজ্ঞায়িত করা আবশ্যক (ডিভাইস অতিরিক্ত পার্টিশনও যোগ করতে পারে)। পাঁচটি সমর্থিত ফাইল সিস্টেম প্রকার রয়েছে:
- yaffs2
- একটি MTD ফ্ল্যাশ ডিভাইসের উপরে একটি yaffs2 ফাইল সিস্টেম। "device" অবশ্যই MTD পার্টিশনের নাম হতে হবে এবং অবশ্যই
/proc/mtd
এ উপস্থিত হতে হবে। - mtd
- একটি কাঁচা MTD পার্টিশন, বুটযোগ্য পার্টিশন যেমন বুট এবং পুনরুদ্ধারের জন্য ব্যবহৃত হয়। MTD আসলে মাউন্ট করা হয় না, কিন্তু মাউন্ট পয়েন্টটি পার্টিশন সনাক্ত করার জন্য একটি কী হিসাবে ব্যবহৃত হয়। "device" অবশ্যই
/proc/mtd
এ MTD পার্টিশনের নাম হতে হবে। - ext4
- একটি eMMc ফ্ল্যাশ ডিভাইসের উপরে একটি ext4 ফাইল সিস্টেম। "ডিভাইস" অবশ্যই ব্লক ডিভাইসের পাথ হতে হবে।
- emmc
- একটি কাঁচা eMMc ব্লক ডিভাইস, বুটযোগ্য পার্টিশন যেমন বুট এবং পুনরুদ্ধারের জন্য ব্যবহৃত হয়। mtd প্রকারের অনুরূপ, eMMc কখনোই মাউন্ট করা হয় না, কিন্তু মাউন্ট পয়েন্ট স্ট্রিংটি টেবিলে ডিভাইসটি সনাক্ত করতে ব্যবহৃত হয়।
- vfat
- একটি ব্লক ডিভাইসের উপরে একটি FAT ফাইল সিস্টেম, সাধারণত বহিরাগত স্টোরেজ যেমন একটি SD কার্ডের জন্য। ডিভাইসটি ব্লক ডিভাইস; device2 হল একটি দ্বিতীয় ব্লক ডিভাইস যা সিস্টেম মাউন্ট করার চেষ্টা করে যদি প্রাথমিক ডিভাইস মাউন্ট করা ব্যর্থ হয় (SD কার্ডের সাথে সামঞ্জস্যের জন্য যা পার্টিশন টেবিলের সাথে ফরম্যাট হতে পারে বা নাও হতে পারে)।
সমস্ত পার্টিশন অবশ্যই রুট ডিরেক্টরিতে মাউন্ট করতে হবে (অর্থাৎ মাউন্ট পয়েন্টের মান অবশ্যই স্ল্যাশ দিয়ে শুরু হবে এবং অন্য কোন স্ল্যাশ থাকবে না)। এই নিষেধাজ্ঞা শুধুমাত্র পুনরুদ্ধারের মধ্যে মাউন্ট করা ফাইল সিস্টেমের ক্ষেত্রে প্রযোজ্য; প্রধান সিস্টেম যে কোন জায়গায় তাদের মাউন্ট বিনামূল্যে. ডিরেক্টরিগুলি
/boot
,/recovery
, এবং/misc
raw টাইপের (mtd বা emmc) হওয়া উচিত, যখন ডিরেক্টরিগুলি/system
,/data
,/cache
, এবং/sdcard
(যদি পাওয়া যায়) ফাইল-সিস্টেম প্রকার (yaffs2, ext4, বা vfat) হওয়া উচিত।
অ্যান্ড্রয়েড 3.0 থেকে শুরু করে, recovery.fstab ফাইলটি একটি অতিরিক্ত ঐচ্ছিক ক্ষেত্র, বিকল্পগুলি লাভ করে। বর্তমানে শুধুমাত্র সংজ্ঞায়িত বিকল্প হল length , যা আপনাকে পার্টিশনের দৈর্ঘ্য স্পষ্টভাবে উল্লেখ করতে দেয়। এই দৈর্ঘ্যটি পার্টিশনটি পুনরায় ফরম্যাট করার সময় ব্যবহার করা হয় (যেমন, ডেটা ওয়াইপ/ফ্যাক্টরি রিসেট অপারেশনের সময় ব্যবহারকারী ডেটা পার্টিশনের জন্য, অথবা সম্পূর্ণ OTA প্যাকেজ ইনস্টল করার সময় সিস্টেম পার্টিশনের জন্য)। যদি দৈর্ঘ্যের মান ঋণাত্মক হয়, তাহলে প্রকৃত পার্টিশনের আকারে দৈর্ঘ্যের মান যোগ করে বিন্যাসের আকার নেওয়া হয়। উদাহরণস্বরূপ, "length=-16384" সেট করার অর্থ হল পার্টিশনটির শেষ 16k ওভাররাইট করা হবে না যখন সেই পার্টিশনটি পুনরায় ফর্ম্যাট করা হয়। এটি ব্যবহারকারী ডেটা পার্টিশনের এনক্রিপশনের মতো বৈশিষ্ট্যগুলিকে সমর্থন করে (যেখানে এনক্রিপশন মেটাডেটা পার্টিশনের শেষে সংরক্ষণ করা হয় যা ওভাররাইট করা উচিত নয়)।
দ্রষ্টব্য: ডিভাইস2 এবং বিকল্প ক্ষেত্রগুলি ঐচ্ছিক, পার্সিংয়ের ক্ষেত্রে অস্পষ্টতা তৈরি করে। যদি লাইনের চতুর্থ ক্ষেত্রের এন্ট্রিটি '/' অক্ষর দিয়ে শুরু হয়, তাহলে এটি একটি device2 এন্ট্রি হিসেবে বিবেচিত হবে; যদি এন্ট্রিটি '/' অক্ষর দিয়ে শুরু না হয় তবে এটি একটি বিকল্প ক্ষেত্র হিসাবে বিবেচিত হয়।
বুট অ্যানিমেশন
ডিভাইস নির্মাতাদের একটি Android ডিভাইস বুট করার সময় দেখানো অ্যানিমেশন কাস্টমাইজ করার ক্ষমতা আছে। এটি করার জন্য, বুটানিমেশন ফরম্যাটে স্পেসিফিকেশন অনুযায়ী সংগঠিত এবং অবস্থিত একটি .zip ফাইল তৈরি করুন।
অ্যান্ড্রয়েড থিংস ডিভাইসগুলির জন্য, নির্বাচিত পণ্যে ছবিগুলি অন্তর্ভুক্ত করার জন্য আপনি Android থিংস কনসোলে জিপ করা ফাইলটি আপলোড করতে পারেন৷
দ্রষ্টব্য: এই ছবিগুলি অবশ্যই অ্যান্ড্রয়েড ব্র্যান্ড নির্দেশিকা পূরণ করবে৷ ব্র্যান্ড নির্দেশিকাগুলির জন্য, অংশীদার বিপণন হাবের Android বিভাগটি পড়ুন৷
পুনরুদ্ধার UI
বিভিন্ন উপলব্ধ হার্ডওয়্যার (শারীরিক বোতাম, LED, স্ক্রিন ইত্যাদি) সহ ডিভাইসগুলিকে সমর্থন করতে, আপনি স্থিতি প্রদর্শন করতে এবং প্রতিটি ডিভাইসের জন্য ম্যানুয়ালি-চালিত লুকানো বৈশিষ্ট্যগুলি অ্যাক্সেস করতে পুনরুদ্ধার ইন্টারফেস কাস্টমাইজ করতে পারেন।
আপনার লক্ষ্য হল ডিভাইস-নির্দিষ্ট কার্যকারিতা প্রদানের জন্য কয়েকটি C++ বস্তুর সাথে একটি ছোট স্ট্যাটিক লাইব্রেরি তৈরি করা। bootable/recovery/default_device.cpp
ফাইলটি ডিফল্টরূপে ব্যবহৃত হয়, এবং আপনার ডিভাইসের জন্য এই ফাইলটির একটি সংস্করণ লেখার সময় অনুলিপি করার জন্য একটি ভাল সূচনা বিন্দু তৈরি করে৷
দ্রষ্টব্য: আপনি এখানে নো কমান্ড বলে একটি বার্তা দেখতে পারেন। টেক্সট টগল করতে, আপনি ভলিউম আপ বোতামটি চাপার সময় পাওয়ার বোতামটি ধরে রাখুন। যদি আপনার ডিভাইসে দুটি বোতাম না থাকে, তাহলে টেক্সট টগল করতে যেকোনো বোতাম দীর্ঘক্ষণ টিপুন।
device/yoyodyne/tardis/recovery/recovery_ui.cpp
#include <linux/input.h> #include "common.h" #include "device.h" #include "screen_ui.h"
হেডার এবং আইটেম ফাংশন
লুকানো পুনরুদ্ধার মেনুতে প্রদর্শিত শিরোনাম এবং আইটেমগুলি ফেরানোর জন্য ডিভাইস ক্লাসের ফাংশন প্রয়োজন। হেডারগুলি বর্ণনা করে কিভাবে মেনু পরিচালনা করতে হয় (যেমন হাইলাইট করা আইটেম পরিবর্তন/নির্বাচনের নিয়ন্ত্রণ)।
static const char* HEADERS[] = { "Volume up/down to move highlight;", "power button to select.", "", NULL }; static const char* ITEMS[] = {"reboot system now", "apply update from ADB", "wipe data/factory reset", "wipe cache partition", NULL };
দ্রষ্টব্য: লম্বা লাইনগুলি কাটা হয় (মোড়ানো হয় না), তাই আপনার ডিভাইসের স্ক্রিনের প্রস্থের কথা মাথায় রাখুন।
চেককি কাস্টমাইজ করুন
এরপরে, আপনার ডিভাইসের RecoveryUI বাস্তবায়ন সংজ্ঞায়িত করুন। এই উদাহরণটি ধরে নেয় tardis ডিভাইসের একটি স্ক্রীন রয়েছে, তাই আপনি অন্তর্নির্মিত ScreenRecoveryUI ইমপ্লিমেন্টেশন থেকে উত্তরাধিকারী হতে পারেন ( স্ক্রিন ছাড়া ডিভাইসগুলির জন্য নির্দেশাবলী দেখুন।) ScreenRecoveryUI থেকে কাস্টমাইজ করার একমাত্র ফাংশন হল CheckKey()
, যা প্রাথমিক অ্যাসিঙ্ক্রোনাস কী পরিচালনা করে:
class TardisUI : public ScreenRecoveryUI { public: virtual KeyAction CheckKey(int key) { if (key == KEY_HOME) { return TOGGLE; } return ENQUEUE; } };
KEY ধ্রুবক
KEY_* ধ্রুবকগুলি linux/input.h
এ সংজ্ঞায়িত করা হয়েছে। বাকী পুনরুদ্ধারের ক্ষেত্রে যা ঘটছে না কেন CheckKey()
বলা হয়: যখন মেনুটি টগল করা হয়, কখন এটি চালু থাকে, প্যাকেজ ইনস্টলেশনের সময়, ব্যবহারকারীর ডেটা মুছার সময়, ইত্যাদি। এটি চারটি ধ্রুবকের মধ্যে একটি ফিরিয়ে দিতে পারে:
- টগল করুন । মেনু প্রদর্শন টগল করুন এবং/অথবা টেক্সট লগ অন বা অফ করুন
- রিবুট করুন । অবিলম্বে ডিভাইস রিবুট
- উপেক্ষা করুন । এই কীপ্রেস উপেক্ষা করুন
- সারিবদ্ধ । সিঙ্ক্রোনাসভাবে ব্যবহার করার জন্য এই কীপ্রেসটি সারিবদ্ধ করুন (অর্থাৎ, ডিসপ্লে সক্রিয় থাকলে পুনরুদ্ধার মেনু সিস্টেম দ্বারা)
প্রত্যেকবার একই কী-এর জন্য একটি কী-আপ ইভেন্ট অনুসরণ করে একটি কী-ডাউন ইভেন্ট হলে CheckKey()
বলা হয়। (ঘটনার ক্রম এ-ডাউন বি-ডাউন বি-আপ এ-আপের ফলাফল শুধুমাত্র CheckKey(B)
কল করা হচ্ছে।) CheckKey()
IsKeyPressed()
কল করতে পারে, অন্য কী চেপে রাখা হচ্ছে কিনা তা খুঁজে বের করতে। (কী ইভেন্টগুলির উপরোক্ত ক্রমানুসারে, যদি CheckKey(B)
কে IsKeyPressed(A)
বলা হয় তবে এটি সত্য হয়ে উঠত।)
CheckKey()
তার ক্লাসে অবস্থা বজায় রাখতে পারে; এটি কীগুলির ক্রম সনাক্ত করতে কার্যকর হতে পারে। এই উদাহরণটি কিছুটা জটিল সেটআপ দেখায়: পাওয়ার চেপে ধরে এবং ভলিউম-আপ টিপে ডিসপ্লেটি টগল করা হয় এবং পরপর পাঁচবার পাওয়ার বোতাম টিপে ডিভাইসটি অবিলম্বে রিবুট করা যেতে পারে (অন্য কোনও হস্তক্ষেপকারী কী ছাড়া):
class TardisUI : public ScreenRecoveryUI { private: int consecutive_power_keys; public: TardisUI() : consecutive_power_keys(0) {} virtual KeyAction CheckKey(int key) { if (IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) { return TOGGLE; } if (key == KEY_POWER) { ++consecutive_power_keys; if (consecutive_power_keys >= 5) { return REBOOT; } } else { consecutive_power_keys = 0; } return ENQUEUE; } };
ScreenRecoveryUI
ScreenRecoveryUI এর সাথে আপনার নিজের ছবি (ত্রুটি আইকন, ইনস্টলেশন অ্যানিমেশন, অগ্রগতি বার) ব্যবহার করার সময়, আপনি অ্যানিমেশনের প্রতি সেকেন্ডে (FPS) ফ্রেমে গতি নিয়ন্ত্রণ করতে পরিবর্তনশীল animation_fps
সেট করতে পারেন।
দ্রষ্টব্য: বর্তমান interlace-frames.py
স্ক্রিপ্ট আপনাকে চিত্রটিতেই animation_fps
তথ্য সংরক্ষণ করতে সক্ষম করে। অ্যান্ড্রয়েডের পূর্ববর্তী সংস্করণগুলিতে animation_fps
সেট করা প্রয়োজন ছিল।
পরিবর্তনশীল animation_fps
সেট করতে, আপনার সাবক্লাসে ScreenRecoveryUI::Init()
ফাংশনটিকে ওভাররাইড করুন। মান সেট করুন, তারপর শুরু করার জন্য parent Init()
ফাংশনটি কল করুন। ডিফল্ট মান (20 FPS) ডিফল্ট পুনরুদ্ধার চিত্রের সাথে মিলে যায়; এই ছবিগুলি ব্যবহার করার সময় আপনাকে একটি Init()
ফাংশন প্রদান করতে হবে না। চিত্রগুলির বিশদ বিবরণের জন্য, রিকভারি UI চিত্রগুলি দেখুন।
ডিভাইস ক্লাস
আপনার একটি রিকভারিইউআই বাস্তবায়নের পরে, আপনার ডিভাইসের শ্রেণী নির্ধারণ করুন (বিল্ট-ইন ডিভাইস ক্লাস থেকে সাবক্লাস)। এটি আপনার UI ক্লাসের একটি একক দৃষ্টান্ত তৈরি করবে এবং GetUI()
ফাংশন থেকে ফেরত দেবে:
class TardisDevice : public Device { private: TardisUI* ui; public: TardisDevice() : ui(new TardisUI) { } RecoveryUI* GetUI() { return ui; }
স্টার্ট রিকভারি
StartRecovery()
পদ্ধতিটিকে পুনরুদ্ধারের শুরুতে বলা হয়, UI শুরু হওয়ার পরে এবং আর্গুমেন্টগুলি পার্স করার পরে, কিন্তু কোনো পদক্ষেপ নেওয়ার আগে। ডিফল্ট বাস্তবায়ন কিছুই করে না, তাই আপনার কিছু করার না থাকলে আপনার সাবক্লাসে এটি প্রদান করার প্রয়োজন নেই:
void StartRecovery() { // ... do something tardis-specific here, if needed .... }
পুনরুদ্ধারের মেনু সরবরাহ এবং পরিচালনা করুন
হেডার লাইনের তালিকা এবং আইটেমগুলির তালিকা পেতে সিস্টেমটি দুটি পদ্ধতি কল করে। এই বাস্তবায়নে, এটি ফাইলের শীর্ষে সংজ্ঞায়িত স্ট্যাটিক অ্যারে ফেরত দেয়:
const char* const* GetMenuHeaders() { return HEADERS; } const char* const* GetMenuItems() { return ITEMS; }
হ্যান্ডেল মেনুকি
এরপরে, একটি HandleMenuKey()
ফাংশন প্রদান করুন, যা একটি কীপ্রেস এবং বর্তমান মেনু দৃশ্যমানতা নেয় এবং সিদ্ধান্ত নেয় কোন পদক্ষেপ নিতে হবে:
int HandleMenuKey(int key, int visible) { if (visible) { switch (key) { case KEY_VOLUMEDOWN: return kHighlightDown; case KEY_VOLUMEUP: return kHighlightUp; case KEY_POWER: return kInvokeItem; } } return kNoAction; }
পদ্ধতিটি একটি কী কোড নেয় (যা পূর্বে UI অবজেক্টের CheckKey()
পদ্ধতি দ্বারা প্রক্রিয়া করা হয়েছে এবং সারিবদ্ধ করা হয়েছে), এবং মেনু/টেক্সট লগ দৃশ্যমানতার বর্তমান অবস্থা। ফেরত মান একটি পূর্ণসংখ্যা. যদি মানটি 0 বা তার বেশি হয় তবে এটি একটি মেনু আইটেমের অবস্থান হিসাবে নেওয়া হয়, যা অবিলম্বে আহ্বান করা হয় (নীচের InvokeMenuItem()
পদ্ধতিটি দেখুন)। অন্যথায় এটি নিম্নলিখিত পূর্বনির্ধারিত ধ্রুবকগুলির মধ্যে একটি হতে পারে:
- kHighlightUp . মেনু হাইলাইটটিকে আগের আইটেমে নিয়ে যান
- kHighlightDown . মেনু হাইলাইটটিকে পরবর্তী আইটেমে নিয়ে যান
- kInvokeItem . বর্তমানে হাইলাইট করা আইটেমটি আহ্বান করুন
- kNoAction । এই কী প্রেস দিয়ে কিছুই করবেন না
দৃশ্যমান আর্গুমেন্ট দ্বারা উহ্য হিসাবে, মেনুটি দৃশ্যমান না হলেও HandleMenuKey()
বলা হয়। CheckKey()
বিপরীতে, রিকভারি ডেটা মুছে ফেলা বা একটি প্যাকেজ ইনস্টল করার মতো কিছু করার সময় এটিকে বলা হয় না - এটি শুধুমাত্র তখনই বলা হয় যখন পুনরুদ্ধার নিষ্ক্রিয় থাকে এবং ইনপুটের জন্য অপেক্ষা করা হয়।
ট্র্যাকবল মেকানিজম
যদি আপনার ডিভাইসে ট্র্যাকবল-এর মতো ইনপুট প্রক্রিয়া থাকে (ইভি_REL এবং কোড REL_Y টাইপ সহ ইনপুট ইভেন্ট তৈরি করে), ট্র্যাকবল-এর মতো ইনপুট ডিভাইস Y অক্ষে গতির প্রতিবেদন করলে পুনরুদ্ধার KEY_UP এবং KEY_DOWN কী চাপে। আপনাকে যা করতে হবে তা হল মেনু ক্রিয়াগুলিতে KEY_UP এবং KEY_DOWN ইভেন্টগুলিকে ম্যাপ করা৷ এই ম্যাপিং CheckKey()
এর জন্য ঘটবে না , তাই আপনি ডিসপ্লে রিবুট বা টগল করার জন্য ট্রিগার হিসাবে ট্র্যাকবল গতি ব্যবহার করতে পারবেন না।
পরিবর্তনকারী কী
সংশোধক হিসাবে চেপে রাখা কীগুলি পরীক্ষা করতে, আপনার নিজস্ব UI অবজেক্টের IsKeyPressed()
পদ্ধতিতে কল করুন। উদাহরণস্বরূপ, কিছু ডিভাইসে পুনরুদ্ধারে Alt-W চাপলে মেনুটি দৃশ্যমান ছিল কিনা তা ডাটা মুছা শুরু হবে। আপনি এই মত বাস্তবায়ন করতে পারে:
int HandleMenuKey(int key, int visible) { if (ui->IsKeyPressed(KEY_LEFTALT) && key == KEY_W) { return 2; // position of the "wipe data" item in the menu } ... }
দ্রষ্টব্য: দৃশ্যমানটি মিথ্যা হলে, ব্যবহারকারী হাইলাইটটি দেখতে না পাওয়ার কারণে মেনুতে (হাইলাইট সরান, হাইলাইট করা আইটেম আহ্বান করুন) বিশেষ মানগুলি ফেরত দেওয়ার কোনও মানে হয় না৷ যাইহোক, যদি আপনি চান মান ফেরত দিতে পারেন.
মেনু আইটেম আহ্বান করুন
এরপরে, একটি InvokeMenuItem()
পদ্ধতি প্রদান করুন যা GetMenuItems()
দ্বারা অ্যাকশনে ফিরে আসা আইটেমের অ্যারেতে পূর্ণসংখ্যার অবস্থান ম্যাপ করে। টার্ডিস উদাহরণে আইটেমগুলির অ্যারের জন্য, ব্যবহার করুন:
BuiltinAction InvokeMenuItem(int menu_position) { switch (menu_position) { case 0: return REBOOT; case 1: return APPLY_ADB_SIDELOAD; case 2: return WIPE_DATA; case 3: return WIPE_CACHE; default: return NO_ACTION; } }
এই পদ্ধতিটি BuiltinAction enum-এর যেকোন সদস্যকে সিস্টেমকে সেই ব্যবস্থা নিতে বলতে ফেরত দিতে পারে (বা NO_ACTION সদস্য যদি আপনি চান যে সিস্টেমটি কিছুই না করুক)। এটি সিস্টেমে যা আছে তার বাইরে অতিরিক্ত পুনরুদ্ধার কার্যকারিতা প্রদান করার জায়গা: আপনার মেনুতে এটির জন্য একটি আইটেম যুক্ত করুন, যখন সেই মেনু আইটেমটি আহ্বান করা হয় তখন এটি এখানে কার্যকর করুন এবং NO_ACTION ফেরত দিন যাতে সিস্টেম আর কিছু না করে৷
BuiltinAction নিম্নলিখিত মান ধারণ করে:
- NO_ACTION কিছুই করবেন না।
- রিবুট করুন । পুনরুদ্ধার থেকে প্রস্থান করুন এবং ডিভাইসটি স্বাভাবিকভাবে রিবুট করুন।
- APPLY_EXT, APPLY_CACHE, APPLY_ADB_SIDELOAD । বিভিন্ন জায়গা থেকে একটি আপডেট প্যাকেজ ইনস্টল করুন। বিস্তারিত জানার জন্য, সাইডলোডিং দেখুন।
- WIPE_CACHE । শুধুমাত্র ক্যাশে পার্টিশন রিফর্ম্যাট করুন। কোন নিশ্চিতকরণের প্রয়োজন নেই কারণ এটি তুলনামূলকভাবে ক্ষতিকারক।
- WIPE_DATA ব্যবহারকারীর ডেটা এবং ক্যাশে পার্টিশনগুলিকে পুনরায় ফর্ম্যাট করুন, যা ফ্যাক্টরি ডেটা রিসেট হিসাবেও পরিচিত। ব্যবহারকারীকে এগিয়ে যাওয়ার আগে এই ক্রিয়াটি নিশ্চিত করতে বলা হয়৷
শেষ পদ্ধতি, WipeData()
, ঐচ্ছিক এবং যখনই একটি ডেটা মুছা অপারেশন শুরু করা হয় (হয় মেনুর মাধ্যমে পুনরুদ্ধার থেকে বা ব্যবহারকারী যখন মূল সিস্টেম থেকে ফ্যাক্টরি ডেটা রিসেট করা বেছে নেয়) তখন এটিকে বলা হয়। ব্যবহারকারীর ডেটা এবং ক্যাশে পার্টিশনগুলি মুছে ফেলার আগে এই পদ্ধতিটি বলা হয়। যদি আপনার ডিভাইসটি এই দুটি পার্টিশন ব্যতীত অন্য কোথাও ব্যবহারকারীর ডেটা সঞ্চয় করে, তাহলে আপনার এটি এখানে মুছে ফেলা উচিত। সাফল্য নির্দেশ করতে আপনার 0 এবং ব্যর্থতার জন্য আরেকটি মান ফেরত দেওয়া উচিত, যদিও বর্তমানে রিটার্ন মান উপেক্ষা করা হয়েছে। আপনি সাফল্য বা ব্যর্থতা ফিরিয়ে আনুন কিনা ব্যবহারকারী ডেটা এবং ক্যাশে পার্টিশনগুলি মুছে ফেলা হয়।
int WipeData() { // ... do something tardis-specific here, if needed .... return 0; }
ডিভাইস তৈরি করুন
অবশেষে, make_device()
ফাংশনের জন্য recovery_ui.cpp ফাইলের শেষে কিছু বয়লারপ্লেট অন্তর্ভুক্ত করুন যা আপনার ডিভাইস ক্লাসের একটি উদাহরণ তৈরি করে এবং ফেরত দেয়:
class TardisDevice : public Device { // ... all the above methods ... }; Device* make_device() { return new TardisDevice(); }
তৈরি করুন এবং ডিভাইস পুনরুদ্ধার লিঙ্ক
recovery_ui.cpp ফাইলটি সম্পূর্ণ করার পরে, এটি তৈরি করুন এবং এটিকে আপনার ডিভাইসে পুনরুদ্ধারের সাথে লিঙ্ক করুন৷ Android.mk-এ, একটি স্ট্যাটিক লাইব্রেরি তৈরি করুন যাতে শুধুমাত্র এই C++ ফাইলটি থাকে:
device/yoyodyne/tardis/recovery/Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := eng LOCAL_C_INCLUDES += bootable/recovery LOCAL_SRC_FILES := recovery_ui.cpp # should match TARGET_RECOVERY_UI_LIB set in BoardConfig.mk LOCAL_MODULE := librecovery_ui_tardis include $(BUILD_STATIC_LIBRARY)
তারপর, এই ডিভাইসের জন্য বোর্ড কনফিগারেশনে, TARGET_RECOVERY_UI_LIB এর মান হিসাবে আপনার স্ট্যাটিক লাইব্রেরি নির্দিষ্ট করুন৷
device/yoyodyne/tardis/BoardConfig.mk [...] # device-specific extensions to the recovery UI TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis
পুনরুদ্ধার UI ইমেজ
রিকভারি ইউজার ইন্টারফেস ইমেজ নিয়ে গঠিত। আদর্শভাবে, ব্যবহারকারীরা কখনই UI এর সাথে ইন্টারঅ্যাক্ট করেন না: একটি সাধারণ আপডেটের সময়, ফোন পুনরুদ্ধারে বুট হয়, ইনস্টলেশনের অগ্রগতি বারটি পূরণ করে এবং ব্যবহারকারীর কাছ থেকে ইনপুট ছাড়াই নতুন সিস্টেমে আবার বুট হয়। একটি সিস্টেম আপডেট সমস্যার ক্ষেত্রে, শুধুমাত্র ব্যবহারকারীর পদক্ষেপ নেওয়া যেতে পারে তা হল কাস্টমার কেয়ারে কল করা।
একটি ইমেজ-শুধু ইন্টারফেস স্থানীয়করণের প্রয়োজনীয়তা দূর করে। যাইহোক, অ্যান্ড্রয়েড 5.0 হিসাবে আপডেটটি চিত্রের সাথে পাঠ্যের একটি স্ট্রিং (যেমন "সিস্টেম আপডেট ইনস্টল করা হচ্ছে...") প্রদর্শন করতে পারে। বিশদ বিবরণের জন্য, স্থানীয়কৃত পুনরুদ্ধার পাঠ্য দেখুন।
Android 5.0 এবং পরবর্তী
Android 5.0 এবং পরবর্তী পুনরুদ্ধার UI দুটি প্রধান চিত্র ব্যবহার করে: ত্রুটি চিত্র এবং ইনস্টল করা অ্যানিমেশন।
![]() চিত্র 1. icon_error.png | ![]() চিত্র 2. icon_installing.png |
ইন্সটল করা অ্যানিমেশনটিকে একটি একক PNG ইমেজ হিসেবে উপস্থাপিত করা হয় অ্যানিমেশনের বিভিন্ন ফ্রেমের সাথে সারি দ্বারা ইন্টারলেস করা হয় (যার কারণে চিত্র 2 স্কুইশ করা হয়)। উদাহরণস্বরূপ, একটি 200x200 সাত-ফ্রেম অ্যানিমেশনের জন্য, একটি একক 200x1400 চিত্র তৈরি করুন যেখানে প্রথম ফ্রেমটি সারি 0, 7, 14, 21, ...; দ্বিতীয় ফ্রেমটি হল সারি 1, 8, 15, 22, ...; ইত্যাদি। সম্মিলিত চিত্রটিতে একটি পাঠ্য অংশ রয়েছে যা অ্যানিমেশন ফ্রেমের সংখ্যা এবং প্রতি সেকেন্ডে ফ্রেমের সংখ্যা (FPS) নির্দেশ করে। টুল bootable/recovery/interlace-frames.py
ইনপুট ফ্রেমের একটি সেট নেয় এবং সেগুলিকে পুনরুদ্ধারের দ্বারা ব্যবহৃত প্রয়োজনীয় যৌগিক ছবিতে একত্রিত করে।
ডিফল্ট ছবিগুলি বিভিন্ন ঘনত্বে পাওয়া যায় এবং bootable/recovery/res-$DENSITY/images
অবস্থিত (যেমন, bootable/recovery/res-hdpi/images
)। ইনস্টলেশনের সময় একটি স্ট্যাটিক ইমেজ ব্যবহার করতে, আপনাকে শুধুমাত্র icon_installing.png ইমেজ প্রদান করতে হবে এবং অ্যানিমেশনে ফ্রেমের সংখ্যা 0 এ সেট করতে হবে (ত্রুটির আইকন অ্যানিমেটেড নয়; এটি সবসময় একটি স্ট্যাটিক ইমেজ)।
Android 4.x এবং তার আগের
Android 4.x এবং আগের পুনরুদ্ধার UI ত্রুটি চিত্র (উপরে দেখানো হয়েছে) এবং ইনস্টল করা অ্যানিমেশন এবং বেশ কিছু ওভারলে চিত্র ব্যবহার করে:
![]() চিত্র 3. icon_installing.png | ![]() চিত্র 4. icon-installing_overlay01.png |
![]() চিত্র 5. icon_installing_overlay07.png |
ইন্সটলেশনের সময়, অন-স্ক্রীন ডিসপ্লেটি icon_installing.png ইমেজ অঙ্কন করে, তারপর সঠিক অফসেটে এর উপরে ওভারলে ফ্রেমগুলির একটি আঁকিয়ে তৈরি করা হয়। এখানে, বেস ইমেজের উপরে যেখানে ওভারলে স্থাপন করা হয়েছে তা হাইলাইট করার জন্য একটি লাল বাক্স সুপারইম্পোজ করা হয়েছে:
![]() চিত্র 6. অ্যানিমেশন ফ্রেম 1 ইনস্টল করা হচ্ছে (icon_installing.png + icon_installing_overlay01.png) | ![]() চিত্র 7. অ্যানিমেশন ফ্রেম 7 ইনস্টল করা হচ্ছে (icon_installing.png + icon_installing_overlay07.png) |
পরবর্তী ফ্রেমগুলি ইতিমধ্যে সেখানে যা আছে তার উপরে শুধুমাত্র পরবর্তী ওভারলে চিত্র অঙ্কন করে প্রদর্শিত হয়; বেস ইমেজ পুনরায় আঁকা হয় না.
অ্যানিমেশনে ফ্রেমের সংখ্যা, কাঙ্খিত গতি এবং বেসের সাথে সম্পর্কিত ওভারলে-এর x- এবং y-অফসেটগুলি ScreenRecoveryUI ক্লাসের সদস্য ভেরিয়েবল দ্বারা সেট করা হয়। ডিফল্ট চিত্রগুলির পরিবর্তে কাস্টম চিত্রগুলি ব্যবহার করার সময়, আপনার কাস্টম চিত্রগুলির জন্য এই মানগুলি পরিবর্তন করতে আপনার সাবক্লাসে Init()
পদ্ধতিটি ওভাররাইড করুন (বিশদ বিবরণের জন্য, ScreenRecoveryUI দেখুন)। স্ক্রিপ্ট bootable/recovery/make-overlay.py
প্রয়োজনীয় অফসেটগুলির গণনা সহ পুনরুদ্ধারের জন্য প্রয়োজনীয় "বেস ইমেজ + ওভারলে ইমেজ" ফর্মে ইমেজ ফ্রেমের একটি সেট রূপান্তর করতে সহায়তা করতে পারে।
ডিফল্ট চিত্রগুলি bootable/recovery/res/images
অবস্থিত। ইনস্টলেশনের সময় একটি স্ট্যাটিক ইমেজ ব্যবহার করতে, আপনাকে শুধুমাত্র icon_installing.png ইমেজ প্রদান করতে হবে এবং অ্যানিমেশনে ফ্রেমের সংখ্যা 0 এ সেট করতে হবে (ত্রুটির আইকন অ্যানিমেটেড নয়; এটি সবসময় একটি স্ট্যাটিক ইমেজ)।
স্থানীয়কৃত পুনরুদ্ধারের পাঠ্য
Android 5.x চিত্রের সাথে পাঠ্যের একটি স্ট্রিং (যেমন, "সিস্টেম আপডেট ইনস্টল করা হচ্ছে...") প্রদর্শন করে। যখন মূল সিস্টেমটি পুনরুদ্ধারে বুট হয় তখন এটি ব্যবহারকারীর বর্তমান লোকেলটিকে পুনরুদ্ধারের জন্য কমান্ড-লাইন বিকল্প হিসাবে পাস করে। প্রতিটি বার্তা প্রদর্শনের জন্য, পুনরুদ্ধারে প্রতিটি লোকেলে সেই বার্তাটির জন্য পূর্ব-রেন্ডার করা পাঠ্য স্ট্রিং সহ একটি দ্বিতীয় যৌগিক চিত্র অন্তর্ভুক্ত করে।
পুনরুদ্ধার পাঠ্য স্ট্রিংগুলির নমুনা চিত্র:

চিত্র 8. পুনরুদ্ধার বার্তাগুলির জন্য স্থানীয় পাঠ্য
পুনরুদ্ধার পাঠ্য নিম্নলিখিত বার্তাগুলি প্রদর্শন করতে পারে:
- সিস্টেম আপডেট ইনস্টল করা হচ্ছে...
- ত্রুটি!
- মুছে ফেলা হচ্ছে... (একটি ডেটা মুছা/ফ্যাক্টরি রিসেট করার সময়)
- কোন কমান্ড নেই (যখন একজন ব্যবহারকারী ম্যানুয়ালি পুনরুদ্ধারের জন্য বুট করে)
bootable/recovery/tools/recovery_l10n/
এ অ্যান্ড্রয়েড অ্যাপ একটি বার্তার স্থানীয়করণ রেন্ডার করে এবং কম্পোজিট ইমেজ তৈরি করে। এই অ্যাপটি ব্যবহার করার বিষয়ে বিস্তারিত জানার জন্য, bootable/recovery/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java
এ মন্তব্য দেখুন।
যখন একজন ব্যবহারকারী ম্যানুয়ালি পুনরুদ্ধারের জন্য বুট করে, তখন লোকেল উপলব্ধ নাও হতে পারে এবং কোনও পাঠ্য প্রদর্শিত হয় না। পুনরুদ্ধার প্রক্রিয়ার জন্য পাঠ্য বার্তাগুলিকে গুরুত্বপূর্ণ করে তুলবেন না।
দ্রষ্টব্য: লুকানো ইন্টারফেস যা লগ বার্তাগুলি প্রদর্শন করে এবং ব্যবহারকারীকে মেনু থেকে ক্রিয়া নির্বাচন করার অনুমতি দেয় শুধুমাত্র ইংরেজিতে উপলব্ধ।
অগ্রগতি বার
অগ্রগতি বার প্রধান চিত্র (বা অ্যানিমেশন) নীচে প্রদর্শিত হতে পারে. অগ্রগতি বার দুটি ইনপুট চিত্র একত্রিত করে তৈরি করা হয়, যা একই আকারের হতে হবে:

চিত্র 9. progress_empty.png

চিত্র 10. progress_fill.png
অগ্রগতি বার তৈরি করতে পূর্ণ চিত্রের বাম প্রান্তটি খালি চিত্রের ডান প্রান্তের পাশে প্রদর্শিত হয়। অগ্রগতি নির্দেশ করতে দুটি চিত্রের মধ্যে সীমানার অবস্থান পরিবর্তন করা হয়েছে। উদাহরণস্বরূপ, উপরের জোড়া ইনপুট চিত্রগুলির সাথে, প্রদর্শন করুন:

চিত্র 11. 1% এ প্রগ্রেস বার>

চিত্র 12. 10% এ প্রগ্রেস বার

চিত্র 13. 50% এ প্রগ্রেস বার
আপনি (এই উদাহরণে) device/yoyodyne/tardis/recovery/res/images
এ স্থাপন করে এই ছবিগুলির ডিভাইস-নির্দিষ্ট সংস্করণ প্রদান করতে পারেন। ফাইলের নামগুলি অবশ্যই উপরে তালিকাভুক্তগুলির সাথে মেলে; যখন একটি ফাইল সেই ডিরেক্টরিতে পাওয়া যায়, তখন বিল্ড সিস্টেম এটিকে সংশ্লিষ্ট ডিফল্ট চিত্রের অগ্রাধিকারে ব্যবহার করে। 8-বিট রঙের গভীরতা সহ RGB বা RGBA ফর্ম্যাটে শুধুমাত্র PNG সমর্থিত।
দ্রষ্টব্য: Android 5.x-এ, যদি লোকেলটি পুনরুদ্ধারের জন্য পরিচিত হয় এবং এটি একটি ডান-থেকে-বাম (RTL) ভাষা (আরবি, হিব্রু, ইত্যাদি), তাহলে অগ্রগতি বারটি ডান থেকে বামে পূর্ণ হয়।
স্ক্রিন ছাড়া ডিভাইস
সব অ্যান্ড্রয়েড ডিভাইসে স্ক্রিন নেই। যদি আপনার ডিভাইসটি একটি হেডলেস অ্যাপ্লায়েন্স হয় বা একটি অডিও-অনলি ইন্টারফেস থাকে, তাহলে আপনাকে পুনরুদ্ধার UI এর আরও ব্যাপক কাস্টমাইজেশন করতে হতে পারে। ScreenRecoveryUI এর একটি সাবক্লাস তৈরি করার পরিবর্তে, সরাসরি এর মূল ক্লাস RecoveryUI সাবক্লাস করুন।
RecoveryUI-এর একটি নিম্ন-স্তরের UI ক্রিয়াকলাপ পরিচালনা করার পদ্ধতি রয়েছে যেমন "ডিসপ্লে টগল করুন," "প্রগ্রেস বার আপডেট করুন," "মেনু দেখান," "মেনু নির্বাচন পরিবর্তন করুন" ইত্যাদি। আপনার ডিভাইসের জন্য একটি উপযুক্ত ইন্টারফেস প্রদান করতে আপনি এগুলি ওভাররাইড করতে পারেন। হতে পারে আপনার ডিভাইসে LED আছে যেখানে আপনি অবস্থা নির্দেশ করতে বিভিন্ন রং বা ফ্ল্যাশিং প্যাটার্ন ব্যবহার করতে পারেন, অথবা আপনি অডিও চালাতে পারেন। (সম্ভবত আপনি কোনও মেনু বা "টেক্সট ডিসপ্লে" মোড সমর্থন করতে চান না; আপনি CheckKey()
এবং HandleMenuKey()
বাস্তবায়নের মাধ্যমে সেগুলি অ্যাক্সেস করা প্রতিরোধ করতে পারেন যা কখনই প্রদর্শনকে টগল করে না বা একটি মেনু আইটেম নির্বাচন করে না। এই ক্ষেত্রে, আপনাকে প্রদান করতে হবে এমন অনেক RecoveryUI পদ্ধতি খালি স্টাব হতে পারে।)
RecoveryUI-এর ঘোষণার জন্য bootable/recovery/ui.h
দেখুন আপনার কোন পদ্ধতিগুলিকে সমর্থন করতে হবে। RecoveryUI হল বিমূর্ত—কিছু পদ্ধতি খাঁটি ভার্চুয়াল এবং অবশ্যই সাবক্লাস দ্বারা সরবরাহ করা উচিত—কিন্তু এতে কী ইনপুটগুলির প্রক্রিয়াকরণ করার জন্য কোড থাকে৷ যদি আপনার ডিভাইসে কী না থাকে বা আপনি সেগুলিকে ভিন্নভাবে প্রক্রিয়া করতে চান তবে আপনি সেটিও ওভাররাইড করতে পারেন।
আপডেটার
আপনি আপনার নিজস্ব এক্সটেনশন ফাংশন প্রদান করে আপডেট প্যাকেজ ইনস্টল করার জন্য ডিভাইস-নির্দিষ্ট কোড ব্যবহার করতে পারেন যা আপনার আপডেটার স্ক্রিপ্ট থেকে কল করা যেতে পারে। টার্ডিস ডিভাইসের জন্য এখানে একটি নমুনা ফাংশন রয়েছে:
device/yoyodyne/tardis/recovery/recovery_updater.c
#include <stdlib.h> #include <string.h> #include "edify/expr.h"
প্রতিটি এক্সটেনশন ফাংশন একই স্বাক্ষর আছে. আর্গুমেন্ট হল সেই নাম যার দ্বারা ফাংশনটিকে ডাকা হয়েছিল, একটি State*
কুকি, ইনকামিং আর্গুমেন্টের সংখ্যা, এবং আর্গুমেন্টের প্রতিনিধিত্বকারী Expr*
পয়েন্টারগুলির একটি অ্যারে। রিটার্ন মান হল একটি নতুন বরাদ্দ করা Value*
।
Value* ReprogramTardisFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); }
আপনার ফাংশন কল করার সময় আপনার আর্গুমেন্টের মূল্যায়ন করা হয়নি—আপনার ফাংশনের লজিক নির্ধারণ করে তাদের মধ্যে কোনটি মূল্যায়ন করা হবে এবং কতবার। সুতরাং, আপনি আপনার নিজস্ব নিয়ন্ত্রণ কাঠামো বাস্তবায়ন করতে এক্সটেনশন ফাংশন ব্যবহার করতে পারেন। একটি Expr*
যুক্তি মূল্যায়ন করার জন্য Call Evaluate()
, একটি Value*
। যদি Evaluate()
NULL রিটার্ন করে, তাহলে আপনার কাছে থাকা কোনো রিসোর্স মুক্ত করা উচিত এবং অবিলম্বে NULL ফেরত দেওয়া উচিত (এটি এডিফাই স্ট্যাককে বাতিল করে দেয়)। অন্যথায়, আপনি ফেরত দেওয়া মানটির মালিকানা গ্রহণ করবেন এবং অবশেষে এটিতে FreeValue()
কল করার জন্য দায়ী।
ধরুন ফাংশনের দুটি আর্গুমেন্ট দরকার: একটি স্ট্রিং-মূল্যবান কী এবং একটি ব্লব-মূল্যবান চিত্র । আপনি এই মত আর্গুমেন্ট পড়তে পারেন:
Value* key = EvaluateValue(state, argv[0]); if (key == NULL) { return NULL; } if (key->type != VAL_STRING) { ErrorAbort(state, "first arg to %s() must be string", name); FreeValue(key); return NULL; } Value* image = EvaluateValue(state, argv[1]); if (image == NULL) { FreeValue(key); // must always free Value objects return NULL; } if (image->type != VAL_BLOB) { ErrorAbort(state, "second arg to %s() must be blob", name); FreeValue(key); FreeValue(image) return NULL; }
NULL চেক করা এবং পূর্বে মূল্যায়ন করা আর্গুমেন্ট মুক্ত করা একাধিক আর্গুমেন্টের জন্য ক্লান্তিকর হতে পারে। ReadValueArgs()
ফাংশন এটি সহজ করতে পারে। উপরের কোডের পরিবর্তে, আপনি এটি লিখতে পারতেন:
Value* key; Value* image; if (ReadValueArgs(state, argv, 2, &key, &image) != 0) { return NULL; // ReadValueArgs() will have set the error message } if (key->type != VAL_STRING || image->type != VAL_BLOB) { ErrorAbort(state, "arguments to %s() have wrong type", name); FreeValue(key); FreeValue(image) return NULL; }
ReadValueArgs()
টাইপ-চেকিং করে না, তাই আপনাকে এটি এখানে করতে হবে; এটি ব্যর্থ হলে কিছুটা কম নির্দিষ্ট ত্রুটি বার্তা তৈরির খরচে একটি যদি বিবৃতি দিয়ে এটি করা আরও সুবিধাজনক। কিন্তু ReadValueArgs()
প্রতিটি আর্গুমেন্টের মূল্যায়ন পরিচালনা করে এবং পূর্বে মূল্যায়ন করা সমস্ত আর্গুমেন্ট মুক্ত করে (পাশাপাশি একটি দরকারী ত্রুটি বার্তা সেট করে) যদি কোনো মূল্যায়ন ব্যর্থ হয়। আপনি একটি পরিবর্তনশীল সংখ্যক আর্গুমেন্ট মূল্যায়নের জন্য একটি ReadValueVarArgs()
সুবিধার ফাংশন ব্যবহার করতে পারেন (এটি Value*
এর একটি অ্যারে প্রদান করে)।
আর্গুমেন্ট মূল্যায়ন করার পরে, ফাংশনের কাজটি করুন:
// key->data is a NUL-terminated string // image->data and image->size define a block of binary data // // ... some device-specific magic here to // reprogram the tardis using those two values ...
রিটার্ন মান অবশ্যই একটি Value*
বস্তু হতে হবে; এই বস্তুর মালিকানা কলারের কাছে চলে যাবে। কলকারী এই Value*
দ্বারা নির্দেশিত যেকোন ডেটার মালিকানা নেয় - বিশেষ করে ডেটামেম্বার।
এই উদাহরণে, আপনি সাফল্য নির্দেশ করতে একটি সত্য বা মিথ্যা মান ফেরত দিতে চান। কনভেনশনটি মনে রাখবেন যে খালি স্ট্রিং মিথ্যা এবং অন্য সমস্ত স্ট্রিং সত্য । আপনাকে অবশ্যই একটি মান অবজেক্ট malloc করতে হবে যার সাথে একটি malloc'd কপি ধ্রুবক স্ট্রিং ফেরত দিতে হবে, যেহেতু কলকারী উভয়ই free()
করবে। আপনার আর্গুমেন্ট মূল্যায়ন করে আপনি যে অবজেক্ট পেয়েছেন তাতে FreeValue()
কল করতে ভুলবেন না!
FreeValue(key); FreeValue(image); Value* result = malloc(sizeof(Value)); result->type = VAL_STRING; result->data = strdup(successful ? "t" : ""); result->size = strlen(result->data); return result; }
সুবিধার ফাংশন StringValue()
একটি নতুন মান বস্তুর মধ্যে একটি স্ট্রিং মোড়ানো হয়। উপরের কোডটি আরও সংক্ষিপ্তভাবে লিখতে ব্যবহার করুন:
FreeValue(key); FreeValue(image); return StringValue(strdup(successful ? "t" : "")); }
এডিফাই ইন্টারপ্রেটারে ফাংশনগুলিকে হুক করার জন্য, Register_ foo
ফাংশনটি প্রদান করুন যেখানে foo এই কোডটি ধারণকারী স্ট্যাটিক লাইব্রেরির নাম। প্রতিটি এক্সটেনশন ফাংশন নিবন্ধন করতে RegisterFunction()
কল করুন। নিয়ম অনুযায়ী, নাম ডিভাইস-নির্দিষ্ট ফাংশন device . whatever
ভবিষ্যত বিল্ট-ইন ফাংশনের সাথে দ্বন্দ্ব এড়াতে device . whatever
।
void Register_librecovery_updater_tardis() { RegisterFunction("tardis.reprogram", ReprogramTardisFn); }
আপনি এখন আপনার কোড দিয়ে একটি স্ট্যাটিক লাইব্রেরি তৈরি করতে makefile কনফিগার করতে পারেন। (এটি আগের বিভাগে পুনরুদ্ধার UI কাস্টমাইজ করতে ব্যবহৃত একই মেকফাইল; আপনার ডিভাইসের উভয় স্ট্যাটিক লাইব্রেরি এখানে সংজ্ঞায়িত থাকতে পারে।)
device/yoyodyne/tardis/recovery/Android.mk
include $(CLEAR_VARS) LOCAL_SRC_FILES := recovery_updater.c LOCAL_C_INCLUDES += bootable/recovery
স্ট্যাটিক লাইব্রেরির নাম অবশ্যই এর মধ্যে থাকা Register_ libname
ফাংশনের নামের সাথে মিলতে হবে।
LOCAL_MODULE := librecovery_updater_tardis include $(BUILD_STATIC_LIBRARY)
অবশেষে, আপনার লাইব্রেরিতে টানতে পুনরুদ্ধারের বিল্ড কনফিগার করুন। TARGET_RECOVERY_UPDATER_LIBS-এ আপনার লাইব্রেরি যোগ করুন (যাতে একাধিক লাইব্রেরি থাকতে পারে; সেগুলি সব নিবন্ধিত হয়)। যদি আপনার কোড অন্যান্য স্ট্যাটিক লাইব্রেরিগুলির উপর নির্ভর করে যেগুলি নিজেরাই এক্সটেনশনগুলি সম্পাদনা করে না (অর্থাৎ, তাদের একটি Register_ libname
ফাংশন নেই), আপনি TARGET_RECOVERY_UPDATER_EXTRA_LIBS-এ তাদের তালিকাভুক্ত করতে পারেন যাতে তাদের (অবিদ্যমান) নিবন্ধন ফাংশনকে কল না করে আপডেটারের সাথে লিঙ্ক করতে পারেন৷ উদাহরণস্বরূপ, যদি আপনার ডিভাইস-নির্দিষ্ট কোড ডেটা ডিকম্প্রেস করতে zlib ব্যবহার করতে চায়, আপনি এখানে libz অন্তর্ভুক্ত করবেন।
device/yoyodyne/tardis/BoardConfig.mk
[...] # add device-specific extensions to the updater binary TARGET_RECOVERY_UPDATER_LIBS += librecovery_updater_tardis TARGET_RECOVERY_UPDATER_EXTRA_LIBS +=
আপনার OTA প্যাকেজের আপডেটার স্ক্রিপ্টগুলি এখন আপনার ফাংশনটিকে অন্য যে কোনও হিসাবে কল করতে পারে। আপনার tardis ডিভাইস পুনরায় প্রোগ্রাম করতে, আপডেট স্ক্রিপ্টে থাকতে পারে: tardis.reprogram("the-key", package_extract_file("tardis-image.dat"))
এটি বিল্ট-ইন ফাংশন package_extract_file()
এর একক-আর্গুমেন্ট সংস্করণ ব্যবহার করে, যা নতুন এক্সটেনশন ফাংশনে দ্বিতীয় আর্গুমেন্ট তৈরি করতে ব্লব হিসাবে আপডেট প্যাকেজ থেকে বের করা ফাইলের বিষয়বস্তু ফেরত দেয়।
OTA প্যাকেজ প্রজন্ম
চূড়ান্ত উপাদান হল আপনার ডিভাইস-নির্দিষ্ট ডেটা সম্পর্কে জানার জন্য ওটিএ প্যাকেজ তৈরির সরঞ্জামগুলি এবং আপনার এক্সটেনশন ফাংশনগুলিতে কলগুলি অন্তর্ভুক্ত করে আপডেটার স্ক্রিপ্টগুলি নির্গত করে৷
প্রথমে, ডেটার একটি ডিভাইস-নির্দিষ্ট ব্লব সম্পর্কে জানতে বিল্ড সিস্টেমটি পান। আপনার ডেটা ফাইলটি device/yoyodyne/tardis/tardis.dat
এ রয়েছে বলে ধরে নিয়ে, আপনার ডিভাইসের AndroidBoard.mk-এ নিম্নলিখিত ঘোষণা করুন:
device/yoyodyne/tardis/AndroidBoard.mk
[...] $(call add-radio-file,tardis.dat)
আপনি এর পরিবর্তে এটিকে একটি Android.mk-এও রাখতে পারেন, কিন্তু তারপরে এটি অবশ্যই একটি ডিভাইস চেক দ্বারা রক্ষা করা উচিত, যেহেতু গাছের সমস্ত Android.mk ফাইলগুলি লোড করা হয়েছে তা যাই হোক না কেন ডিভাইস তৈরি করা হচ্ছে৷ (যদি আপনার গাছে একাধিক ডিভাইস থাকে, আপনি tardis ডিভাইস তৈরি করার সময় শুধুমাত্র tardis.dat ফাইল যোগ করতে চান।)
device/yoyodyne/tardis/Android.mk
[...] # an alternative to specifying it in AndroidBoard.mk ifeq (($TARGET_DEVICE),tardis) $(call add-radio-file,tardis.dat) endif
ঐতিহাসিক কারণে এগুলোকে রেডিও ফাইল বলা হয়; ডিভাইস রেডিওর সাথে তাদের কিছু করার নেই (যদি উপস্থিত থাকে)। এগুলি কেবলমাত্র ডেটার অস্বচ্ছ ব্লব যা বিল্ড সিস্টেম টার্গেট-ফাইল .zip-এ OTA জেনারেশন টুলস দ্বারা কপি করে। আপনি যখন একটি বিল্ড করেন, tardis.dat টার্গেট-files.zip-এ RADIO/tardis.dat
হিসাবে সংরক্ষণ করা হয়। আপনি যতগুলি চান ততগুলি ফাইল যুক্ত করতে আপনি add-radio-file
একাধিকবার কল করতে পারেন।
পাইথন মডিউল
রিলিজ টুল বাড়ানোর জন্য, একটি পাইথন মডিউল লিখুন (অবশ্যই releasetools.py নাম দিতে হবে) যদি উপস্থিত থাকলে টুলগুলি কল করতে পারে। উদাহরণ:
device/yoyodyne/tardis/releasetools.py
import common def FullOTA_InstallEnd(info): # copy the data into the package. tardis_dat = info.input_zip.read("RADIO/tardis.dat") common.ZipWriteStr(info.output_zip, "tardis.dat", tardis_dat) # emit the script code to install this data on the device info.script.AppendExtra( """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
একটি পৃথক ফাংশন একটি ক্রমবর্ধমান OTA প্যাকেজ তৈরির ক্ষেত্রে পরিচালনা করে। এই উদাহরণের জন্য, ধরুন আপনাকে tardis পুনরায় প্রোগ্রাম করতে হবে তখনই যখন tardis.dat ফাইল দুটি বিল্ডের মধ্যে পরিবর্তিত হয়।
def IncrementalOTA_InstallEnd(info): # copy the data into the package. source_tardis_dat = info.source_zip.read("RADIO/tardis.dat") target_tardis_dat = info.target_zip.read("RADIO/tardis.dat") if source_tardis_dat == target_tardis_dat: # tardis.dat is unchanged from previous build; no # need to reprogram it return # include the new tardis.dat in the OTA package common.ZipWriteStr(info.output_zip, "tardis.dat", target_tardis_dat) # emit the script code to install this data on the device info.script.AppendExtra( """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
মডিউল ফাংশন
আপনি মডিউলে নিম্নলিখিত ফাংশনগুলি প্রদান করতে পারেন (শুধুমাত্র আপনার প্রয়োজনগুলি প্রয়োগ করুন)।
-
FullOTA_Assertions()
- একটি সম্পূর্ণ OTA তৈরির শুরুর কাছাকাছি কল করা হয়েছে৷ ডিভাইসের বর্তমান অবস্থা সম্পর্কে দাবী প্রকাশ করার জন্য এটি একটি ভাল জায়গা। ডিভাইসে পরিবর্তন করে এমন স্ক্রিপ্ট কমান্ডগুলি নির্গত করবেন না।
-
FullOTA_InstallBegin()
- ডিভাইসের অবস্থা সম্পর্কে সমস্ত দাবী পেরিয়ে যাওয়ার পরে কিন্তু কোনও পরিবর্তন করার আগে কল করা হয়েছে। আপনি ডিভাইস-নির্দিষ্ট আপডেটগুলির জন্য কমান্ড নির্গত করতে পারেন যা ডিভাইসে অন্য কিছু পরিবর্তন করার আগে অবশ্যই চালাতে হবে।
-
FullOTA_InstallEnd()
- বুট এবং সিস্টেম পার্টিশন আপডেট করার জন্য স্ক্রিপ্ট কমান্ড নির্গত হওয়ার পরে, স্ক্রিপ্ট প্রজন্মের শেষে বলা হয়। আপনি ডিভাইস-নির্দিষ্ট আপডেটের জন্য অতিরিক্ত কমান্ড নির্গত করতে পারেন।
-
IncrementalOTA_Assertions()
-
FullOTA_Assertions()
এর মতো কিন্তু একটি বর্ধিত আপডেট প্যাকেজ তৈরি করার সময় বলা হয়। -
IncrementalOTA_VerifyBegin()
- ডিভাইসের স্থিতি সম্পর্কে সমস্ত দাবী পেরিয়ে যাওয়ার পরে কিন্তু কোনও পরিবর্তন করার আগে কল করা হয়েছে। আপনি ডিভাইস-নির্দিষ্ট আপডেটগুলির জন্য কমান্ড নির্গত করতে পারেন যা ডিভাইসে অন্য কিছু পরিবর্তন করার আগে অবশ্যই চালাতে হবে।
-
IncrementalOTA_VerifyEnd()
- যাচাইকরণ পর্বের শেষে কল করা হয়, যখন স্ক্রিপ্ট ফাইলগুলি নিশ্চিত করা শেষ করে তখন এটি প্রত্যাশিত শুরুর বিষয়বস্তুগুলি স্পর্শ করবে৷ এই মুহুর্তে ডিভাইসে কিছুই পরিবর্তন করা হয়নি। আপনি অতিরিক্ত ডিভাইস-নির্দিষ্ট যাচাইকরণের জন্য কোড নির্গত করতে পারেন।
-
IncrementalOTA_InstallBegin()
- প্যাচ করার জন্য ফাইলগুলিকে রাজ্যের আগে প্রত্যাশিত হিসাবে যাচাই করা হয়েছে কিন্তু কোনো পরিবর্তন করার আগে কল করা হয়েছে। আপনি ডিভাইস-নির্দিষ্ট আপডেটগুলির জন্য কমান্ড নির্গত করতে পারেন যা ডিভাইসে অন্য কিছু পরিবর্তন করার আগে অবশ্যই চালাতে হবে।
-
IncrementalOTA_InstallEnd()
- এটির সম্পূর্ণ OTA প্যাকেজ কাউন্টারপার্টের মতো, এটিকে স্ক্রিপ্ট জেনারেশনের শেষে বলা হয়, বুট আপডেট করার জন্য স্ক্রিপ্ট কমান্ড এবং সিস্টেম পার্টিশন নির্গত হওয়ার পরে। আপনি ডিভাইস-নির্দিষ্ট আপডেটের জন্য অতিরিক্ত কমান্ড নির্গত করতে পারেন।
দ্রষ্টব্য: ডিভাইসটি পাওয়ার হারালে, OTA ইনস্টলেশন শুরু থেকে পুনরায় চালু হতে পারে। এই কমান্ডগুলি ইতিমধ্যেই সম্পূর্ণ বা আংশিকভাবে চালানো হয়েছে এমন ডিভাইসগুলির সাথে মানিয়ে নিতে প্রস্তুত থাকুন৷
তথ্য বস্তুর ফাংশন পাস
একটি একক তথ্য বস্তুতে ফাংশনগুলি পাস করুন যাতে বিভিন্ন দরকারী আইটেম থাকে:
- info.input_zip (শুধুমাত্র সম্পূর্ণ OTA) ইনপুট টার্গেট-ফাইল .zip-এর জন্য
zipfile.ZipFile
অবজেক্ট। - info.source_zip (শুধুমাত্র ইনক্রিমেন্টাল ওটিএ) সোর্স টার্গেট-ফাইল .zip-এর জন্য
zipfile.ZipFile
অবজেক্ট (ইনক্রিমেন্টাল প্যাকেজ ইনস্টল করার সময় ডিভাইসে ইতিমধ্যেই বিল্ড)। - info.target_zip (শুধুমাত্র ইনক্রিমেন্টাল ওটিএ) টার্গেট টার্গেট-ফাইল .zip-এর জন্য
zipfile.ZipFile
অবজেক্ট (ডিভাইসটিতে ইনক্রিমেন্টাল প্যাকেজটি বিল্ড করে)। - info.output_zip প্যাকেজ তৈরি করা হচ্ছে; লেখার জন্য একটি
zipfile.ZipFile
অবজেক্ট খোলা হয়েছে। প্যাকেজে একটি ফাইল যোগ করতে common.ZipWriteStr(info.output_zip, ফাইলের নাম , ডেটা ) ব্যবহার করুন। - info.script স্ক্রিপ্ট অবজেক্ট যেখানে আপনি কমান্ড যোগ করতে পারেন। স্ক্রিপ্টে টেক্সট আউটপুট করতে
info.script.AppendExtra( script_text )
কল করুন। নিশ্চিত করুন যে আউটপুট পাঠ্য একটি সেমিকোলন দিয়ে শেষ হয় যাতে এটি পরে নির্গত কমান্ডগুলিতে না চলে।
তথ্য বস্তুর বিশদ বিবরণের জন্য, ZIP সংরক্ষণাগারের জন্য পাইথন সফ্টওয়্যার ফাউন্ডেশন ডকুমেন্টেশন পড়ুন।
মডিউল অবস্থান নির্দিষ্ট করুন
আপনার BoardConfig.mk ফাইলে আপনার ডিভাইসের releasetools.py স্ক্রিপ্টের অবস্থান নির্দিষ্ট করুন:
device/yoyodyne/tardis/BoardConfig.mk
[...] TARGET_RELEASETOOLS_EXTENSIONS := device/yoyodyne/tardis
TARGET_RELEASETOOLS_EXTENSIONS সেট করা না থাকলে, এটি $(TARGET_DEVICE_DIR)/../common
ডিরেক্টরি (এই উদাহরণে device/yoyodyne/common
) এ ডিফল্ট হয়। releasetools.py স্ক্রিপ্টের অবস্থান স্পষ্টভাবে সংজ্ঞায়িত করা ভাল। tardis ডিভাইস তৈরি করার সময়, releasetools.py স্ক্রিপ্ট টার্গেট-ফাইল .zip ফাইলে অন্তর্ভুক্ত করা হয় ( META/releasetools.py
)।
আপনি যখন রিলিজ টুলগুলি চালান (হয় img_from_target_files
বা ota_from_target_files
), টার্গেট-ফাইল .zip-এ releasetools.py স্ক্রিপ্ট, যদি উপস্থিত থাকে, তাহলে Android সোর্স ট্রি থেকে একটির চেয়ে পছন্দ করা হয়। এছাড়াও আপনি -s
(বা --device_specific
) বিকল্পের সাথে ডিভাইস-নির্দিষ্ট এক্সটেনশনের পথটি স্পষ্টভাবে নির্দিষ্ট করতে পারেন, যা সর্বোচ্চ অগ্রাধিকার নেয়। এটি আপনাকে ত্রুটিগুলি সংশোধন করতে এবং রিলিজ টুল এক্সটেনশনগুলিতে পরিবর্তন করতে এবং সেই পরিবর্তনগুলিকে পুরানো টার্গেট-ফাইলগুলিতে প্রয়োগ করতে সক্ষম করে৷
এখন, আপনি যখন ota_from_target_files
চালান, এটি স্বয়ংক্রিয়ভাবে target_files .zip ফাইল থেকে ডিভাইস-নির্দিষ্ট মডিউলটি তুলে নেয় এবং OTA প্যাকেজ তৈরি করার সময় এটি ব্যবহার করে:
./build/make/tools/releasetools/ota_from_target_files \
-i PREVIOUS-tardis-target_files.zip \
dist_output/tardis-target_files.zip \
incremental_ota_update.zip
বিকল্পভাবে, আপনি যখন ota_from_target_files
চালান তখন আপনি ডিভাইস-নির্দিষ্ট এক্সটেনশন নির্দিষ্ট করতে পারেন।
./build/make/tools/releasetools/ota_from_target_files \
-s device/yoyodyne/tardis \
-i PREVIOUS-tardis-target_files.zip \
dist_output/tardis-target_files.zip \
incremental_ota_update.zip
দ্রষ্টব্য: বিকল্পগুলির একটি সম্পূর্ণ তালিকার জন্য, build/make/tools/releasetools/ota_from_target_files
এ ota_from_target_files
মন্তব্যগুলি দেখুন।
সাইডলোডিং মেকানিজম
পুনরুদ্ধারের একটি সাইডলোডিং মেকানিজম রয়েছে যা মূল সিস্টেমের মাধ্যমে ওভার-দ্য-এয়ার ডাউনলোড না করে ম্যানুয়ালি একটি আপডেট প্যাকেজ ইনস্টল করার জন্য। সাইডলোডিং ডিভাইসে ডিবাগিং বা পরিবর্তন করার জন্য দরকারী যেখানে প্রধান সিস্টেম বুট করা যায় না।
ঐতিহাসিকভাবে, ডিভাইসের এসডি কার্ড থেকে প্যাকেজ লোড করার মাধ্যমে সাইডলোডিং করা হয়েছে; একটি নন-বুটিং ডিভাইসের ক্ষেত্রে, প্যাকেজটি অন্য কোনো কম্পিউটার ব্যবহার করে SD কার্ডে রাখা যেতে পারে এবং তারপর ডিভাইসে SD কার্ড ঢোকানো যেতে পারে। অপসারণযোগ্য বাহ্যিক সঞ্চয়স্থান ছাড়াই অ্যান্ড্রয়েড ডিভাইসগুলিকে মিটমাট করতে, পুনরুদ্ধার সাইডলোডিংয়ের জন্য দুটি অতিরিক্ত প্রক্রিয়া সমর্থন করে: ক্যাশে পার্টিশন থেকে প্যাকেজগুলি লোড করা এবং অ্যাডবি ব্যবহার করে USB-এর মাধ্যমে লোড করা৷
প্রতিটি সাইডলোড মেকানিজম চালু করতে, আপনার ডিভাইসের Device::InvokeMenuItem()
পদ্ধতি বিল্টিন অ্যাকশনের নিম্নলিখিত মানগুলি ফিরিয়ে দিতে পারে:
- APPLY_EXT । বাহ্যিক সঞ্চয়স্থান (
/sdcard
ডিরেক্টরি) থেকে একটি আপডেট প্যাকেজ সাইডলোড করুন। আপনার recovery.fstab অবশ্যই/sdcard
মাউন্ট পয়েন্ট সংজ্ঞায়িত করবে। এটি এমন ডিভাইসগুলিতে ব্যবহারযোগ্য নয় যেগুলি/data
(বা কিছু অনুরূপ প্রক্রিয়া) এর সিমলিঙ্ক সহ একটি SD কার্ড অনুকরণ করে৷/data
সাধারণত পুনরুদ্ধারের জন্য উপলব্ধ নয় কারণ এটি এনক্রিপ্ট করা হতে পারে। পুনরুদ্ধার UI/sdcard
এ .zip ফাইলগুলির একটি মেনু প্রদর্শন করে এবং ব্যবহারকারীকে একটি নির্বাচন করার অনুমতি দেয়। - APPLY_CACHE
/sdcard
থেকে প্যাকেজ লোড করার অনুরূপ/cache
ডিরেক্টরি (যা সর্বদা পুনরুদ্ধারের জন্য উপলব্ধ ) এর পরিবর্তে ব্যবহৃত হয়। নিয়মিত সিস্টেম থেকে,/cache
কেবল সুবিধাবঞ্চিত ব্যবহারকারীদের দ্বারা লিখিত হয় এবং যদি ডিভাইসটি বুটেবল না হয় তবে/cache
ডিরেক্টরিটি মোটেও লেখা যায় না (যা সীমিত ইউটিলিটির এই প্রক্রিয়াটিকে তৈরি করে)। - প্রয়োগ_এডবি_সাইডেলড । ব্যবহারকারীকে একটি ইউএসবি কেবল এবং এডিবি বিকাশ সরঞ্জামের মাধ্যমে ডিভাইসে একটি প্যাকেজ প্রেরণের অনুমতি দেয়। যখন এই প্রক্রিয়াটি আহ্বান করা হয়, তখন কোনও সংযুক্ত হোস্ট কম্পিউটারের সাথে এডিবিকে এটির সাথে আলাপের জন্য এডিবিডি ডেমনের নিজস্ব মিনি সংস্করণটি পুনরুদ্ধার শুরু করে। এই মিনি সংস্করণটি কেবলমাত্র একটি একক কমান্ড সমর্থন করে:
adb sideload filename
। নামযুক্ত ফাইলটি হোস্ট মেশিন থেকে ডিভাইসে প্রেরণ করা হয়, যা পরে এটি যাচাই করে এবং ইনস্টল করে ঠিক যেমন এটি স্থানীয় স্টোরেজে ছিল।
কয়েকটি সতর্কতা:
- শুধুমাত্র ইউএসবি পরিবহন সমর্থিত।
- যদি আপনার পুনরুদ্ধারটি সাধারণত এডিবিডি চালায় (সাধারণত ইউজারডেবাগ এবং ইঞ্জি বিল্ডগুলির জন্য সত্য), ডিভাইসটি এডিবি সাইডেললোড মোডে থাকাকালীন এটি বন্ধ হয়ে যাবে এবং এডিবি সিডেললোড একটি প্যাকেজ গ্রহণ শেষ করার সময় পুনরায় চালু করা হবে। এডিবি সাইডেলোড মোডে থাকাকালীন, কোনও এডিবি
sideload
কাজ (logcat
,reboot
,push
,pull
,shell
ইত্যাদি ব্যতীত অন্য কোনও কমান্ড দেয় না। - আপনি ডিভাইসে এডিবি সাইডেললোড মোড থেকে প্রস্থান করতে পারবেন না। বাতিল করার জন্য, আপনি প্যাকেজ হিসাবে
/dev/null
(বা অন্য যে কোনও কিছু যা বৈধ প্যাকেজ নয়) প্রেরণ করতে পারেন এবং তারপরে ডিভাইসটি এটি যাচাই করতে ব্যর্থ হবে এবং ইনস্টলেশন পদ্ধতিটি বন্ধ করতে পারে। রিকভারিউআইআই বাস্তবায়নেরCheckKey()
পদ্ধতিটি কীপ্রেসগুলির জন্য কল করা অব্যাহত থাকবে, যাতে আপনি একটি মূল ক্রম সরবরাহ করতে পারেন যা ডিভাইসটিকে পুনরায় বুট করে এবং এডিবি সিডেললোড মোডে কাজ করে।
পুনরুদ্ধার সিস্টেমে ডিভাইস-নির্দিষ্ট কোড সন্নিবেশ করার জন্য বেশ কয়েকটি হুক অন্তর্ভুক্ত রয়েছে যাতে ওটিএ আপডেটগুলি অ্যান্ড্রয়েড সিস্টেম (যেমন, বেসব্যান্ড বা রেডিও প্রসেসর) ব্যতীত অন্য ডিভাইসের অংশগুলি আপডেট করতে পারে।
নিম্নলিখিত বিভাগগুলি এবং উদাহরণগুলি YOYODYNE বিক্রেতার দ্বারা উত্পাদিত টারডিস ডিভাইসটি কাস্টমাইজ করে।
পার্টিশন মানচিত্র
অ্যান্ড্রয়েড ২.৩ হিসাবে, প্ল্যাটফর্মটি EMMC ফ্ল্যাশ ডিভাইস এবং ext4 ফাইল সিস্টেম সমর্থন করে যা এই ডিভাইসগুলিতে চলে। এটি পুরানো রিলিজগুলি থেকে মেমরি প্রযুক্তি ডিভাইস (এমটিডি) ফ্ল্যাশ ডিভাইস এবং ইয়াএফএস 2 ফাইল সিস্টেম সমর্থন করে।
পার্টিশন মানচিত্রের ফাইলটি টার্গেট_আরকোভারি_ফস্ট্যাব দ্বারা নির্দিষ্ট করা হয়েছে; এই ফাইলটি পুনরুদ্ধার বাইনারি এবং প্যাকেজ-বিল্ডিং সরঞ্জাম উভয় দ্বারা ব্যবহৃত হয়। আপনি বোর্ডকনফিগ.এমকে টার্গেট_আরসিওভারি_ফস্ট্যাব এ মানচিত্রের ফাইলের নাম নির্দিষ্ট করতে পারেন।
একটি নমুনা পার্টিশন মানচিত্রের ফাইলটি এর মতো দেখতে পারে:
device/yoyodyne/tardis/recovery.fstab
# mount point fstype device [device2] [options (3.0+ only)] /sdcard vfat /dev/block/mmcblk0p1 /dev/block/mmcblk0 /cache yaffs2 cache /misc mtd misc /boot mtd boot /recovery emmc /dev/block/platform/s3c-sdhci.0/by-name/recovery /system ext4 /dev/block/platform/s3c-sdhci.0/by-name/system length=-4096 /data ext4 /dev/block/platform/s3c-sdhci.0/by-name/userdata
/sdcard
ব্যতীত, যা al চ্ছিক, এই উদাহরণের সমস্ত মাউন্ট পয়েন্টগুলি অবশ্যই সংজ্ঞায়িত করতে হবে (ডিভাইসগুলি অতিরিক্ত পার্টিশনও যুক্ত করতে পারে)। পাঁচটি সমর্থিত ফাইল সিস্টেমের ধরণ রয়েছে:
- yaffs2
- একটি এমটিডি ফ্ল্যাশ ডিভাইসের উপরে একটি ইয়াএফএস 2 ফাইল সিস্টেম। "ডিভাইস" অবশ্যই এমটিডি পার্টিশনের নাম হতে হবে এবং অবশ্যই
/proc/mtd
এ উপস্থিত হতে হবে। - mtd
- একটি কাঁচা এমটিডি পার্টিশন, বুট এবং পুনরুদ্ধারের মতো বুটেবল পার্টিশনের জন্য ব্যবহৃত। এমটিডি আসলে মাউন্ট করা হয় না, তবে মাউন্ট পয়েন্টটি পার্টিশনটি সনাক্ত করতে কী হিসাবে ব্যবহৃত হয়। "ডিভাইস" অবশ্যই
/proc/mtd
-তে এমটিডি পার্টিশনের নাম হতে হবে। - ext4
- একটি EXT4 ফাইল সিস্টেমের উপরে একটি EMMC ফ্ল্যাশ ডিভাইসের উপরে। "ডিভাইস" অবশ্যই ব্লক ডিভাইসের পথ হতে হবে।
- emmc
- বুট এবং পুনরুদ্ধারের মতো বুটেবল পার্টিশনের জন্য ব্যবহৃত একটি কাঁচা ইএমএমসি ব্লক ডিভাইস। এমটিডি ধরণের অনুরূপ, ইএমএমসি আসলে কখনও মাউন্ট করা হয় না, তবে মাউন্ট পয়েন্ট স্ট্রিংটি টেবিলের মধ্যে ডিভাইসটি সনাক্ত করতে ব্যবহৃত হয়।
- vfat
- সাধারণত একটি এসডি কার্ডের মতো বাহ্যিক স্টোরেজের জন্য একটি ব্লক ডিভাইসের উপরে একটি ফ্যাট ফাইল সিস্টেম। ডিভাইসটি ব্লক ডিভাইস; ডিভাইস 2 একটি দ্বিতীয় ব্লক ডিভাইস যা সিস্টেমটি মাউন্ট করার চেষ্টা করে যদি প্রাথমিক ডিভাইসটি ব্যর্থ হয় (এসডি কার্ডগুলির সাথে সামঞ্জস্যের জন্য যা পার্টিশন টেবিলের সাথে ফর্ম্যাট করা বা নাও হতে পারে)।
সমস্ত পার্টিশন অবশ্যই রুট ডিরেক্টরিতে মাউন্ট করা উচিত (অর্থাত্ মাউন্ট পয়েন্টের মানটি একটি স্ল্যাশ দিয়ে শুরু করতে হবে এবং অন্য কোনও স্ল্যাশ নেই)। এই সীমাবদ্ধতা কেবল পুনরুদ্ধারে ফাইল সিস্টেমগুলি মাউন্ট করার ক্ষেত্রে প্রযোজ্য; মূল সিস্টেমটি তাদের যে কোনও জায়গায় মাউন্ট করতে বিনামূল্যে। ডিরেক্টরি
/boot
,/recovery
, এবং/misc
কাঁচা প্রকারের (এমটিডি বা ইএমএমসি) হওয়া উচিত, যখন ডিরেক্টরি/system
,/data
,/cache
, এবং/sdcard
(যদি উপলভ্য থাকে) ফাইল সিস্টেমের ধরণগুলি (ইএএফএফএস 2, এক্সট 4, বা ভিএফএটি) হওয়া উচিত।
অ্যান্ড্রয়েড 3.0 এ শুরু করে, পুনরুদ্ধার.ফস্টাব ফাইলটি একটি অতিরিক্ত al চ্ছিক ক্ষেত্র, বিকল্পগুলি অর্জন করে। বর্তমানে একমাত্র সংজ্ঞায়িত বিকল্পটি দৈর্ঘ্য , যা আপনাকে পার্টিশনের দৈর্ঘ্য স্পষ্টভাবে নির্দিষ্ট করতে দেয়। এই দৈর্ঘ্যটি পার্টিশনটি পুনরায় ফর্ম্যাট করার সময় ব্যবহৃত হয় (যেমন, ডেটা ওয়াইপ/ফ্যাক্টরি রিসেট অপারেশন চলাকালীন ইউজারডাটা পার্টিশনের জন্য, বা একটি পূর্ণ ওটিএ প্যাকেজ স্থাপনের সময় সিস্টেম বিভাজনের জন্য)। যদি দৈর্ঘ্যের মানটি নেতিবাচক হয়, তবে সত্য পার্টিশনের আকারে দৈর্ঘ্যের মান যুক্ত করে ফর্ম্যাট থেকে আকারটি নেওয়া হয়। উদাহরণস্বরূপ, "দৈর্ঘ্য = -16384" সেট করা মানে সেই পার্টিশনের শেষ 16 কে ওভাররাইট করা হবে না যখন সেই পার্টিশনটি পুনরায় ফর্ম্যাট করা হয়। এটি ইউজারডাটা পার্টিশনের এনক্রিপশন (যেখানে এনক্রিপশন মেটাডেটা পার্টিশনের শেষে সংরক্ষণ করা হয় যা ওভাররাইট করা উচিত নয়) এর মতো বৈশিষ্ট্যগুলিকে সমর্থন করে।
দ্রষ্টব্য: ডিভাইস 2 এবং বিকল্প ক্ষেত্রগুলি al চ্ছিক, পার্সিংয়ে অস্পষ্টতা তৈরি করে। যদি লাইনের চতুর্থ ক্ষেত্রে প্রবেশটি একটি '/' চরিত্রের সাথে শুরু হয় তবে এটি একটি ডিভাইস 2 এন্ট্রি হিসাবে বিবেচিত হয়; যদি এন্ট্রি কোনও '/' চরিত্রের সাথে শুরু না হয় তবে এটি একটি বিকল্প ক্ষেত্র হিসাবে বিবেচিত হয়।
বুট অ্যানিমেশন
ডিভাইস নির্মাতাদের অ্যান্ড্রয়েড ডিভাইস বুট করার সময় প্রদর্শিত অ্যানিমেশনটি কাস্টমাইজ করার ক্ষমতা রাখে। এটি করার জন্য, একটি .zip ফাইলটি সংগঠিত এবং বুটানিমেশন ফর্ম্যাটে স্পেসিফিকেশন অনুসারে অবস্থিত।
অ্যান্ড্রয়েড থিংস ডিভাইসের জন্য, আপনি নির্বাচিত পণ্যটিতে চিত্রগুলি অন্তর্ভুক্ত করতে অ্যান্ড্রয়েড থিংস কনসোলে জিপড ফাইলটি আপলোড করতে পারেন।
দ্রষ্টব্য: এই চিত্রগুলি অবশ্যই অ্যান্ড্রয়েড ব্র্যান্ডের নির্দেশিকাগুলি পূরণ করবে। ব্র্যান্ডের নির্দেশিকাগুলির জন্য, অংশীদার বিপণন হাবের অ্যান্ড্রয়েড বিভাগটি দেখুন।
পুনরুদ্ধার ইউআই
বিভিন্ন উপলভ্য হার্ডওয়্যার (শারীরিক বোতাম, এলইডি, স্ক্রিন ইত্যাদি) সহ ডিভাইসগুলিকে সমর্থন করার জন্য, আপনি প্রতিটি ডিভাইসের জন্য ম্যানুয়ালি চালিত লুকানো বৈশিষ্ট্যগুলি অ্যাক্সেস করতে এবং পুনরুদ্ধার ইন্টারফেসটি কাস্টমাইজ করতে পারেন।
আপনার লক্ষ্য হ'ল ডিভাইস-নির্দিষ্ট কার্যকারিতা সরবরাহ করতে কয়েকটি সি ++ অবজেক্ট সহ একটি ছোট স্ট্যাটিক লাইব্রেরি তৈরি করা। ফাইল bootable/recovery/default_device.cpp
ডিফল্টরূপে ব্যবহৃত হয় এবং আপনার ডিভাইসের জন্য এই ফাইলের একটি সংস্করণ লেখার সময় অনুলিপি করার জন্য একটি ভাল সূচনা পয়েন্ট তৈরি করে।
দ্রষ্টব্য: আপনি এখানে কোনও বার্তা না বলে কোনও বার্তা দেখতে পাবেন। পাঠ্য টগল করতে, আপনি ভলিউম আপ বোতামটি আঘাত করার সময় পাওয়ার বোতামটি ধরে রাখুন। যদি আপনার ডিভাইসে উভয় বোতাম না থাকে তবে পাঠ্য টগল করতে কোনও বোতাম টিপুন।
device/yoyodyne/tardis/recovery/recovery_ui.cpp
#include <linux/input.h> #include "common.h" #include "device.h" #include "screen_ui.h"
শিরোনাম এবং আইটেম ফাংশন
ডিভাইস শ্রেণীর লুকানো পুনরুদ্ধার মেনুতে প্রদর্শিত শিরোনাম এবং আইটেমগুলির জন্য ফাংশন প্রয়োজন। শিরোনামগুলি কীভাবে মেনুটি পরিচালনা করতে হয় তা বর্ণনা করে (যেমন হাইলাইটযুক্ত আইটেমটি পরিবর্তন/নির্বাচন করতে নিয়ন্ত্রণ করে)।
static const char* HEADERS[] = { "Volume up/down to move highlight;", "power button to select.", "", NULL }; static const char* ITEMS[] = {"reboot system now", "apply update from ADB", "wipe data/factory reset", "wipe cache partition", NULL };
দ্রষ্টব্য: দীর্ঘ লাইনগুলি কাটা হয় (মোড়ানো নয়), তাই আপনার ডিভাইসের স্ক্রিনটির প্রস্থটি মাথায় রাখুন।
চেককে কাস্টমাইজ করুন
এরপরে, আপনার ডিভাইসের পুনরুদ্ধার বাস্তবায়ন সংজ্ঞায়িত করুন। এই উদাহরণটি ধরে নিয়েছে যে টারডিস ডিভাইসের একটি স্ক্রিন রয়েছে, তাই আপনি অন্তর্নির্মিত স্ক্রিনরেকওভারইউইম্প্লেমেন্টেশন থেকে উত্তরাধিকারী হতে পারেন ( কোনও স্ক্রিন ছাড়াই ডিভাইসের জন্য নির্দেশাবলী দেখুন)) স্ক্রিনরেকোভারইউই থেকে কাস্টমাইজ করার একমাত্র ফাংশন হ'ল CheckKey()
, যা প্রাথমিক অ্যাসিঙ্ক্রোনাস কী হ্যান্ডলিং করে:
class TardisUI : public ScreenRecoveryUI { public: virtual KeyAction CheckKey(int key) { if (key == KEY_HOME) { return TOGGLE; } return ENQUEUE; } };
মূল ধ্রুবক
কী_* ধ্রুবকগুলি linux/input.h
-তে সংজ্ঞায়িত করা হয়েছে। CheckKey()
কে বলা হয় বাকি পুনরুদ্ধারে কী চলছে তা বিবেচনা করা হয় না: যখন মেনুটি টগল করা হয়, যখন এটি চালু থাকে, প্যাকেজ ইনস্টলেশন চলাকালীন, ইউজারডাটা ওয়াইপিংয়ের সময় ইত্যাদি এটি চারটি ধ্রুবকগুলির মধ্যে একটি ফিরিয়ে দিতে পারে:
- টগল মেনু এবং/অথবা টেক্সট লগ চালু বা বন্ধের প্রদর্শন টগল করুন
- রিবুট সঙ্গে সঙ্গে ডিভাইসটি পুনরায় বুট করুন
- উপেক্ষা । এই কীপ্রেস উপেক্ষা করুন
- এনকিউ এই কীপ্রেসকে সিঙ্ক্রোনালিভাবে গ্রাস করতে হবে (যেমন, পুনরুদ্ধার মেনু সিস্টেম দ্বারা প্রদর্শনটি সক্ষম করা থাকলে)
CheckKey()
কে প্রতিবার বলা হয় একটি কী-ডাউন ইভেন্টটি একই কীটির জন্য একটি কী-আপ ইভেন্ট অনুসরণ করে। (ইভেন্টগুলির ক্রম এ-ডাউন বি-ডাউন বি-আপ এ-আপ ফলাফলগুলি কেবল CheckKey()
CheckKey(B)
ডাকা হচ্ছে IsKeyPressed()
(মূল ইভেন্টগুলির উপরোক্ত ক্রমগুলিতে, যদি CheckKey(B)
IsKeyPressed(A)
বলা হয় তবে এটি সত্য ফিরে আসত))
CheckKey()
তার শ্রেণিতে রাজ্য বজায় রাখতে পারে; এটি কীগুলির ক্রমগুলি সনাক্ত করতে দরকারী হতে পারে। এই উদাহরণটি আরও কিছুটা জটিল সেটআপ দেখায়: প্রদর্শনটি শক্তি ধরে রেখে এবং ভলিউম-আপ টিপে টগল করা হয় এবং ডিভাইসটি পরপর পাঁচবার পাওয়ার বোতামটি টিপে অবিলম্বে পুনরায় বুট করা যায় (অন্য কোনও হস্তক্ষেপকারী কী ছাড়াই):
class TardisUI : public ScreenRecoveryUI { private: int consecutive_power_keys; public: TardisUI() : consecutive_power_keys(0) {} virtual KeyAction CheckKey(int key) { if (IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) { return TOGGLE; } if (key == KEY_POWER) { ++consecutive_power_keys; if (consecutive_power_keys >= 5) { return REBOOT; } } else { consecutive_power_keys = 0; } return ENQUEUE; } };
স্ক্রিনরেকোভারইউই
স্ক্রিনরেকোভারইউইয়ের সাথে আপনার নিজস্ব চিত্রগুলি (ত্রুটি আইকন, ইনস্টলেশন অ্যানিমেশন, প্রগতিশীল বারগুলি) ব্যবহার করার সময়, আপনি অ্যানিমেশনগুলির ফ্রেমের ফ্রেমের গতি নিয়ন্ত্রণ করতে ভেরিয়েবল animation_fps
সেট করতে পারেন।
দ্রষ্টব্য: বর্তমান interlace-frames.py
স্ক্রিপ্ট আপনাকে চিত্রটিতে নিজেই animation_fps
তথ্য সংরক্ষণ করতে সক্ষম করে। অ্যান্ড্রয়েডের পূর্ববর্তী সংস্করণগুলিতে নিজেকে animation_fps
সেট করা প্রয়োজন ছিল।
ভেরিয়েবল animation_fps
সেট করতে, আপনার সাবক্লাসে ScreenRecoveryUI::Init()
ফাংশনটি ওভাররাইড করুন। মানটি সেট করুন, তারপরে প্রারম্ভিককরণ সম্পূর্ণ করতে parent Init()
ফাংশনটিকে কল করুন। ডিফল্ট মান (20 এফপিএস) ডিফল্ট পুনরুদ্ধার চিত্রগুলির সাথে সম্পর্কিত; এই চিত্রগুলি ব্যবহার করার সময় আপনাকে কোনও Init()
ফাংশন সরবরাহ করার দরকার নেই। চিত্রগুলির বিশদগুলির জন্য, পুনরুদ্ধার ইউআই চিত্রগুলি দেখুন।
ডিভাইস ক্লাস
আপনার একটি পুনরুদ্ধার বাস্তবায়নের পরে, আপনার ডিভাইস ক্লাসটি সংজ্ঞায়িত করুন (অন্তর্নির্মিত ডিভাইস শ্রেণি থেকে সাবক্লাসড)। এটি আপনার ইউআই শ্রেণীর একটি একক উদাহরণ তৈরি করা উচিত এবং GetUI()
ফাংশন থেকে ফিরে আসা উচিত:
class TardisDevice : public Device { private: TardisUI* ui; public: TardisDevice() : ui(new TardisUI) { } RecoveryUI* GetUI() { return ui; }
স্টারট্রেকোভারি
ইউআইআই আরম্ভ করার পরে এবং যুক্তিগুলি পার্স করার পরে, তবে কোনও পদক্ষেপ নেওয়ার আগে, তবে কোনও পদক্ষেপ নেওয়ার আগে StartRecovery()
পদ্ধতিটি পুনরুদ্ধারের শুরুতে ডাকা হয়। ডিফল্ট বাস্তবায়ন কিছুই করে না, সুতরাং আপনার যদি কিছু করার না থাকে তবে আপনার সাবক্লাসে এটি সরবরাহ করার দরকার নেই:
void StartRecovery() { // ... do something tardis-specific here, if needed .... }
পুনরুদ্ধার মেনু সরবরাহ এবং পরিচালনা করুন
শিরোনাম লাইনের তালিকা এবং আইটেমগুলির তালিকা পেতে সিস্টেম দুটি পদ্ধতি কল করে। এই বাস্তবায়নে, এটি ফাইলের শীর্ষে সংজ্ঞায়িত স্ট্যাটিক অ্যারেগুলি প্রদান করে:
const char* const* GetMenuHeaders() { return HEADERS; } const char* const* GetMenuItems() { return ITEMS; }
হ্যান্ডলমেনুকি
এরপরে, একটি HandleMenuKey()
ফাংশন সরবরাহ করুন, যা একটি কীপ্রেস এবং বর্তমান মেনু দৃশ্যমানতা নেয় এবং কোন পদক্ষেপ নিতে হবে তা সিদ্ধান্ত নেয়:
int HandleMenuKey(int key, int visible) { if (visible) { switch (key) { case KEY_VOLUMEDOWN: return kHighlightDown; case KEY_VOLUMEUP: return kHighlightUp; case KEY_POWER: return kInvokeItem; } } return kNoAction; }
পদ্ধতিটি একটি কী কোড নেয় (যা পূর্বে ইউআই অবজেক্টের CheckKey()
পদ্ধতি দ্বারা প্রক্রিয়া করা হয়েছে এবং এনকিউড করা হয়েছে) এবং মেনু/পাঠ্য লগের দৃশ্যমানতার বর্তমান অবস্থা। ফেরত মান একটি পূর্ণসংখ্যা. যদি মানটি 0 বা উচ্চতর হয় তবে এটি কোনও মেনু আইটেমের অবস্থান হিসাবে নেওয়া হয়, যা অবিলম্বে আহ্বান করা হয় (নীচে InvokeMenuItem()
পদ্ধতিটি দেখুন)। অন্যথায় এটি নিম্নলিখিত পূর্বনির্ধারিত ধ্রুবকগুলির মধ্যে একটি হতে পারে:
- খলাইটলাইট । পূর্ববর্তী আইটেমটিতে মেনু হাইলাইটটি সরান
- খলাইটডাউন । মেনু হাইলাইটটি পরবর্তী আইটেমটিতে সরান
- কিনভোকিটেম । বর্তমানে হাইলাইট করা আইটেমটি অনুরোধ করুন
- নওকশন এই কীপ্রেস দিয়ে কিছুই করবেন না
দৃশ্যমান যুক্তি দ্বারা নিহিত হিসাবে, মেনুটি দৃশ্যমান না হলেও HandleMenuKey()
বলা হয়। CheckKey()
বিপরীতে, এটি বলা হয় না যখন পুনরুদ্ধার ডেটা মুছতে বা প্যাকেজ ইনস্টল করার মতো কিছু করছে - এটি কেবল তখনই বলা হয় যখন পুনরুদ্ধার অলস থাকে এবং ইনপুটটির জন্য অপেক্ষা করে।
ট্র্যাকবল প্রক্রিয়া
যদি আপনার ডিভাইসে ট্র্যাকবলের মতো ইনপুট প্রক্রিয়া থাকে (টাইপ ইভি_রেল এবং কোড rel_y সহ ইনপুট ইভেন্টগুলি উত্পন্ন করে), পুনরুদ্ধার KEY_UP এবং KEY_DOWN কীপ্রেসগুলি সংশ্লেষ করে যখনই ট্র্যাকবলের মতো ইনপুট ডিভাইসটি ওয়াই অক্ষের গতি রিপোর্ট করে। আপনাকে যা করতে হবে তা হ'ল মেনু ক্রিয়াকলাপগুলিতে KEY_UP এবং কী_ডাউন ইভেন্টগুলি। এই ম্যাপিংটি CheckKey()
এর জন্য ঘটে না , তাই আপনি প্রদর্শনটি পুনরায় বুট বা টগল করার জন্য ট্রিগার হিসাবে ট্র্যাকবল গতিগুলি ব্যবহার করতে পারবেন না।
পরিবর্তনকারী কী
মডিফায়ার হিসাবে ধরে রাখা কীগুলি পরীক্ষা করার জন্য, আপনার নিজের ইউআই অবজেক্টের IsKeyPressed()
পদ্ধতিটি কল করুন। উদাহরণস্বরূপ, পুনরুদ্ধারে ALT-W টিপে কিছু ডিভাইসে মেনুটি দৃশ্যমান ছিল কি না তা মুছতে একটি ডেটা শুরু করবে। আপনি এই মত বাস্তবায়ন করতে পারে:
int HandleMenuKey(int key, int visible) { if (ui->IsKeyPressed(KEY_LEFTALT) && key == KEY_W) { return 2; // position of the "wipe data" item in the menu } ... }
দ্রষ্টব্য: যদি দৃশ্যমানটি মিথ্যা হয় তবে মেনুটি (হাইলাইট হাইলাইট করুন, হাইলাইট করা আইটেমটি অনুরোধ করুন) এমন বিশেষ মানগুলি ফেরত দেওয়ার অর্থ হয় না যেহেতু ব্যবহারকারী হাইলাইটটি দেখতে পাচ্ছেন না। তবে আপনি ইচ্ছা হলে মানগুলি ফিরিয়ে দিতে পারেন।
Invokemenuetem
এরপরে, একটি InvokeMenuItem()
পদ্ধতি সরবরাহ করুন যা GetMenuItems()
দ্বারা ফিরে আসা আইটেমগুলির অ্যারেতে পূর্ণসংখ্যার অবস্থানগুলিকে মানচিত্র করে। টারডিস উদাহরণে আইটেমগুলির অ্যারের জন্য, ব্যবহার:
BuiltinAction InvokeMenuItem(int menu_position) { switch (menu_position) { case 0: return REBOOT; case 1: return APPLY_ADB_SIDELOAD; case 2: return WIPE_DATA; case 3: return WIPE_CACHE; default: return NO_ACTION; } }
এই পদ্ধতিটি সিস্টেমটিকে সেই পদক্ষেপ নিতে (বা আপনি যদি সিস্টেমটি কিছু না করতে চান তবে NO_ACTION সদস্য) সিস্টেমটিকে বলার জন্য বিল্টাইনাকশন এনাম এর যে কোনও সদস্যকে ফিরিয়ে দিতে পারে। এটি সিস্টেমে যা আছে তার বাইরে অতিরিক্ত পুনরুদ্ধারের কার্যকারিতা সরবরাহ করার জায়গা: আপনার মেনুতে এটির জন্য কোনও আইটেম যুক্ত করুন, মেনু আইটেমটি যখন অনুরোধ করা হয় তখন এটি এখানে সম্পাদন করুন এবং কোনও _অ্যাকশন ফেরত দিন যাতে সিস্টেমটি অন্য কিছু করে না।
বিল্টাইনাকশনটিতে নিম্নলিখিত মানগুলি রয়েছে:
- না_অ্যাকশন কিছুই করবেন না।
- রিবুট পুনরুদ্ধার থেকে প্রস্থান করুন এবং সাধারণত ডিভাইসটি পুনরায় বুট করুন।
- প্রয়োগ_এক্সট, প্রয়োগ_ক্যাচে, প্রয়োগ_এডবি_সাইডেলড । বিভিন্ন জায়গা থেকে একটি আপডেট প্যাকেজ ইনস্টল করুন। বিশদের জন্য, সাইডেলোডিং দেখুন।
- ওয়াইপ_ক্যাচ । কেবল ক্যাশে পার্টিশন পুনরায় ফর্ম্যাট করুন। এটি তুলনামূলকভাবে নিরীহ হওয়ায় কোনও নিশ্চিতকরণের প্রয়োজন নেই।
- ওয়াইপ_ডাটা ইউজারডাটা এবং ক্যাশে পার্টিশনগুলি পুনরায় ফর্ম্যাট করুন, এটি কারখানার ডেটা রিসেট হিসাবেও পরিচিত। ব্যবহারকারীকে এগিয়ে যাওয়ার আগে এই ক্রিয়াটি নিশ্চিত করতে বলা হয়।
WipeData()
শেষ পদ্ধতিটি al চ্ছিক এবং যখনই কোনও ডেটা ওয়াইপ অপারেশন শুরু করা হয় (মেনু দিয়ে পুনরুদ্ধার থেকে বা যখন ব্যবহারকারী মূল সিস্টেম থেকে কোনও কারখানার ডেটা পুনরায় সেট করতে বেছে নিয়েছেন) তখন বলা হয়। ব্যবহারকারীর ডেটা এবং ক্যাশে পার্টিশনগুলি মুছে দেওয়ার আগে এই পদ্ধতিটি ডাকা হয়। যদি আপনার ডিভাইসটি এই দুটি পার্টিশন ব্যতীত অন্য কোথাও ব্যবহারকারীর ডেটা সঞ্চয় করে তবে আপনার এটি এখানে মুছে ফেলা উচিত। সাফল্য এবং ব্যর্থতার জন্য আরও একটি মান নির্দেশ করতে আপনার 0 ফিরে আসা উচিত, যদিও বর্তমানে রিটার্নের মান উপেক্ষা করা হয়। আপনি সাফল্য বা ব্যর্থতা ফিরে আসুক না কেন ব্যবহারকারীর ডেটা এবং ক্যাশে পার্টিশনগুলি মুছে ফেলা হয়।
int WipeData() { // ... do something tardis-specific here, if needed .... return 0; }
ডিভাইস তৈরি করুন
শেষ অবধি, make_device()
ফাংশনের জন্য পুনরুদ্ধার_উই.সিপিএপ ফাইলের শেষে কিছু বয়লারপ্লেট অন্তর্ভুক্ত করুন যা আপনার ডিভাইস শ্রেণীর একটি উদাহরণ তৈরি করে এবং প্রদান করে:
class TardisDevice : public Device { // ... all the above methods ... }; Device* make_device() { return new TardisDevice(); }
ডিভাইস পুনরুদ্ধারের জন্য তৈরি করুন এবং লিঙ্ক করুন
পুনরুদ্ধার_উই.সিপিপি ফাইলটি শেষ করার পরে, এটি তৈরি করুন এবং এটি আপনার ডিভাইসে পুনরুদ্ধারের সাথে সংযুক্ত করুন। অ্যান্ড্রয়েড.এমকে -তে, একটি স্ট্যাটিক লাইব্রেরি তৈরি করুন যাতে কেবলমাত্র এই সি ++ ফাইল রয়েছে:
device/yoyodyne/tardis/recovery/Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := eng LOCAL_C_INCLUDES += bootable/recovery LOCAL_SRC_FILES := recovery_ui.cpp # should match TARGET_RECOVERY_UI_LIB set in BoardConfig.mk LOCAL_MODULE := librecovery_ui_tardis include $(BUILD_STATIC_LIBRARY)
তারপরে, এই ডিভাইসের জন্য বোর্ড কনফিগারেশনে, আপনার স্ট্যাটিক লাইব্রেরিটিকে টার্গেট_রেকোভারি_ইউআই_লিবের মান হিসাবে নির্দিষ্ট করুন।
device/yoyodyne/tardis/BoardConfig.mk [...] # device-specific extensions to the recovery UI TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis
পুনরুদ্ধার ইউআই চিত্র
পুনরুদ্ধার ব্যবহারকারী ইন্টারফেসে চিত্র রয়েছে। আদর্শভাবে, ব্যবহারকারীরা কখনই ইউআইয়ের সাথে যোগাযোগ করেন না: একটি সাধারণ আপডেটের সময়, ফোনটি পুনরুদ্ধারে বুট করে, ইনস্টলেশন অগ্রগতি বারটি পূরণ করে এবং ব্যবহারকারীর কাছ থেকে ইনপুট ছাড়াই নতুন সিস্টেমে ফিরে আসে। কোনও সিস্টেম আপডেট সমস্যার ক্ষেত্রে, একমাত্র ব্যবহারকারী ক্রিয়া যা নেওয়া যেতে পারে তা হ'ল গ্রাহক যত্নকে কল করা।
একটি চিত্র-কেবল ইন্টারফেস স্থানীয়করণের প্রয়োজনীয়তাটিকে আবদ্ধ করে। তবে অ্যান্ড্রয়েড 5.0 হিসাবে আপডেটটি চিত্রের সাথে পাঠ্যের একটি স্ট্রিং (যেমন "ইনস্টলিং সিস্টেম আপডেট ...") প্রদর্শন করতে পারে। বিশদের জন্য, স্থানীয়ভাবে পুনরুদ্ধার পাঠ্য দেখুন।
Android 5.0 এবং পরবর্তী
অ্যান্ড্রয়েড 5.0 এবং পরে পুনরুদ্ধার ইউআই দুটি প্রধান চিত্র ব্যবহার করে: ত্রুটি চিত্র এবং ইনস্টলিং অ্যানিমেশন।
![]() চিত্র 1। আইকন_আরআরআর.পিএনজি | ![]() চিত্র 2। আইকন_ইনস্টলিং.পিএনজি |
ইনস্টলিং অ্যানিমেশনটি একক পিএনজি চিত্র হিসাবে উপস্থাপিত হয় যা সারি দ্বারা সংযুক্ত অ্যানিমেশনের বিভিন্ন ফ্রেমের সাথে (এজন্য চিত্র 2 স্কুইশড প্রদর্শিত হয়)। উদাহরণস্বরূপ, 200x200 সাত-ফ্রেম অ্যানিমেশনের জন্য, একটি একক 200x1400 চিত্র তৈরি করুন যেখানে প্রথম ফ্রেমটি সারি 0, 7, 14, 21, ...; দ্বিতীয় ফ্রেমটি সারি 1, 8, 15, 22, ...; ইত্যাদি সংযুক্ত চিত্রটিতে একটি পাঠ্য অংশ অন্তর্ভুক্ত রয়েছে যা অ্যানিমেশন ফ্রেমের সংখ্যা এবং প্রতি সেকেন্ডে ফ্রেমের সংখ্যা (এফপিএস) নির্দেশ করে। সরঞ্জামটি bootable/recovery/interlace-frames.py
ইনপুট ফ্রেমের একটি সেট নেয় এবং পুনরুদ্ধারের মাধ্যমে ব্যবহৃত প্রয়োজনীয় যৌগিক চিত্রের সাথে তাদের একত্রিত করে।
ডিফল্ট চিত্রগুলি বিভিন্ন ঘনত্বগুলিতে উপলব্ধ এবং bootable/recovery/res-$DENSITY/images
অবস্থিত (যেমন, bootable/recovery/res-hdpi/images
)। ইনস্টলেশন চলাকালীন একটি স্ট্যাটিক চিত্র ব্যবহার করতে আপনার কেবল আইকন_ইনস্টলিং.পিএনজি চিত্র সরবরাহ করতে হবে এবং অ্যানিমেশনটিতে ফ্রেমের সংখ্যা 0 এ সেট করতে হবে (ত্রুটি আইকনটি অ্যানিমেটেড নয়; এটি সর্বদা একটি স্থির চিত্র)।
অ্যান্ড্রয়েড 4.x এবং তার আগে
অ্যান্ড্রয়েড 4.x এবং পূর্ববর্তী পুনরুদ্ধার ইউআই ত্রুটি চিত্র (উপরে দেখানো) এবং ইনস্টলিং অ্যানিমেশন প্লাস বেশ কয়েকটি ওভারলে চিত্র ব্যবহার করে:
![]() চিত্র 3। আইকন_ইনস্টলিং.পিএনজি | ![]() চিত্র 4। আইকন-ইনস্টলিং_ওভারলে 01.png |
![]() চিত্র 5। আইকন_ইনস্টলিং_ওভারলে 07.png |
ইনস্টলেশন চলাকালীন, অন-স্ক্রিন ডিসপ্লেটি আইকন_ইনস্টলিং.পিএনজি চিত্রটি আঁকিয়ে নির্মিত হয়, তারপরে যথাযথ অফসেটে এটির উপরে ওভারলে ফ্রেমগুলির একটি অঙ্কন করে। এখানে, একটি লাল বাক্সটি হাইলাইট করার জন্য সুপারমোজ করা হয়েছে যেখানে বেস চিত্রের উপরে ওভারলে রাখা হয়েছে:
![]() চিত্র 6। অ্যানিমেশন ফ্রেম 1 ইনস্টল করা (আইকন_ইনস্টলিং.পিএনজি + আইকন_ইনস্টলিং_ওভারলে 01.png) | ![]() চিত্র। |
পরবর্তী ফ্রেমগুলি ইতিমধ্যে যা আছে তার উপরে কেবল পরবর্তী ওভারলে চিত্র অঙ্কন করে প্রদর্শিত হয়; বেস চিত্রটি পুনরায় সাজানো হয় না।
বেসের সাথে সম্পর্কিত ওভারলেটির অ্যানিমেশন, কাঙ্ক্ষিত গতি এবং এক্স- এবং ওয়াই-অফসেটগুলিতে ফ্রেমের সংখ্যা স্ক্রিনরেকওভারইউই শ্রেণীর সদস্য ভেরিয়েবল দ্বারা সেট করা আছে। ডিফল্ট চিত্রগুলির পরিবর্তে কাস্টম চিত্রগুলি ব্যবহার করার সময়, আপনার কাস্টম চিত্রগুলির জন্য এই মানগুলি পরিবর্তন করতে আপনার সাবক্লাসে Init()
পদ্ধতিটি ওভাররাইড করুন (বিশদগুলির জন্য, স্ক্রিনরেকওভারইউআই দেখুন)। স্ক্রিপ্ট bootable/recovery/make-overlay.py
চিত্র ফ্রেমের একটি সেটকে "বেস ইমেজ + ওভারলে ইমেজ" ফর্মটিতে প্রয়োজনীয় অফসেটগুলির কম্পিউটিং সহ পুনরুদ্ধারের প্রয়োজনীয় ফর্মটিতে রূপান্তর করতে সহায়তা করতে পারে।
ডিফল্ট চিত্রগুলি bootable/recovery/res/images
অবস্থিত। ইনস্টলেশন চলাকালীন একটি স্ট্যাটিক চিত্র ব্যবহার করতে আপনার কেবল আইকন_ইনস্টলিং.পিএনজি চিত্র সরবরাহ করতে হবে এবং অ্যানিমেশনটিতে ফ্রেমের সংখ্যা 0 এ সেট করতে হবে (ত্রুটি আইকনটি অ্যানিমেটেড নয়; এটি সর্বদা একটি স্থির চিত্র)।
স্থানীয়ভাবে পুনরুদ্ধার পাঠ্য
অ্যান্ড্রয়েড 5.x চিত্রের সাথে পাঠ্যের একটি স্ট্রিং (যেমন, "সিস্টেম আপডেট ইনস্টল ...") প্রদর্শন করে। যখন মূল সিস্টেমটি পুনরুদ্ধারে বুট করে তখন এটি পুনরুদ্ধারের কমান্ড-লাইন বিকল্প হিসাবে ব্যবহারকারীর বর্তমান লোকেলকে পাস করে। প্রতিটি বার্তা প্রদর্শনের জন্য, পুনরুদ্ধারের মধ্যে প্রতিটি লোকালে সেই বার্তার জন্য প্রাক-রেন্ডার করা পাঠ্য স্ট্রিং সহ একটি দ্বিতীয় যৌগিক চিত্র অন্তর্ভুক্ত রয়েছে।
পুনরুদ্ধার পাঠ্য স্ট্রিংগুলির নমুনা চিত্র:

চিত্র 8। পুনরুদ্ধার বার্তাগুলির জন্য স্থানীয় পাঠ্য
পুনরুদ্ধার পাঠ্য নিম্নলিখিত বার্তাগুলি প্রদর্শন করতে পারে:
- সিস্টেম আপডেট ইনস্টল করা ...
- ত্রুটি!
- মুছে ফেলা হচ্ছে ... (যখন কোনও ডেটা করার সময় মুছুন/কারখানার পুনরায় সেট করুন)
- কোনও কমান্ড নেই (যখন কোনও ব্যবহারকারী ম্যানুয়ালি পুনরুদ্ধারে বুট করে)
bootable/recovery/tools/recovery_l10n/
এ অ্যান্ড্রয়েড অ্যাপ্লিকেশনটি কোনও বার্তার স্থানীয়করণকে রেন্ডার করে এবং যৌগিক চিত্র তৈরি করে। এই অ্যাপ্লিকেশনটি ব্যবহার করার বিশদগুলির জন্য, bootable/recovery/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java
মন্তব্যগুলি দেখুন।
যখন কোনও ব্যবহারকারী ম্যানুয়ালি পুনরুদ্ধারে বুট করে, লোকেলটি উপলভ্য নাও হতে পারে এবং কোনও পাঠ্য প্রদর্শিত হয় না। পুনরুদ্ধার প্রক্রিয়াটির জন্য পাঠ্য বার্তাগুলি সমালোচনা করবেন না।
দ্রষ্টব্য: লুকানো ইন্টারফেস যা লগ বার্তাগুলি প্রদর্শন করে এবং ব্যবহারকারীকে মেনু থেকে ক্রিয়া নির্বাচন করতে দেয় কেবল ইংরেজিতে উপলব্ধ।
অগ্রগতি বার
অগ্রগতি বারগুলি মূল চিত্রের (বা অ্যানিমেশন) এর নীচে উপস্থিত হতে পারে। অগ্রগতি বারটি দুটি ইনপুট চিত্রের সংমিশ্রণ করে তৈরি করা হয়, যা অবশ্যই একই আকারের হতে হবে:

চিত্র 9। প্রগ্রেস_প্র্টি.পিএনজি

চিত্র 10। অগ্রগতি_ফিল.পিএনজি
ফিল ইমেজের বাম প্রান্তটি অগ্রগতি বারটি তৈরি করতে খালি চিত্রের ডান প্রান্তের পাশে প্রদর্শিত হয়। দুটি চিত্রের মধ্যে সীমানার অবস্থান অগ্রগতি নির্দেশ করতে পরিবর্তন করা হয়। উদাহরণস্বরূপ, উপরের জোড়া ইনপুট চিত্রগুলির সাথে, প্রদর্শন:

চিত্র 11। অগ্রগতি বার 1%>

চিত্র 12। 10% এ অগ্রগতি বার

চিত্র 13। 50% এ অগ্রগতি বার
আপনি এই চিত্রগুলির ডিভাইস-নির্দিষ্ট সংস্করণগুলি (এই উদাহরণে) device/yoyodyne/tardis/recovery/res/images
রেখে সরবরাহ করতে পারেন। ফাইলের নামগুলি অবশ্যই উপরে তালিকাভুক্তগুলির সাথে মেলে; যখন সেই ডিরেক্টরিতে কোনও ফাইল পাওয়া যায়, তখন বিল্ড সিস্টেমটি এটি সংশ্লিষ্ট ডিফল্ট চিত্রের পছন্দ হিসাবে ব্যবহার করে। 8-বিট রঙের গভীরতা সহ কেবল আরজিবি বা আরজিবিএ ফর্ম্যাটে কেবল পিএনজিগুলি সমর্থিত।
দ্রষ্টব্য: অ্যান্ড্রয়েড 5.x এ, যদি লোকেলটি পুনরুদ্ধারের জন্য পরিচিত হয় এবং ডান থেকে বাম (আরটিএল) ভাষা (আরবি, হিব্রু, ইত্যাদি) হয় তবে অগ্রগতি বারটি ডান থেকে বামে ভরাট হয়।
স্ক্রিন ছাড়াই ডিভাইস
সমস্ত অ্যান্ড্রয়েড ডিভাইসের স্ক্রিন নেই। যদি আপনার ডিভাইসটি হেডলেস অ্যাপ্লায়েন্স হয় বা কেবলমাত্র অডিও-কেবল ইন্টারফেস থাকে তবে আপনাকে পুনরুদ্ধার ইউআইয়ের আরও বিস্তৃত কাস্টমাইজেশন করতে হতে পারে। স্ক্রিনরেকোভারইউইয়ের একটি সাবক্লাস তৈরি করার পরিবর্তে, সরাসরি এর পিতামাতার শ্রেণি পুনরুদ্ধারটি সাবক্লাস করুন।
রিকভারিউআইয়ের কাছে নিম্ন-স্তরের ইউআই অপারেশনগুলি পরিচালনা করার জন্য পদ্ধতি রয়েছে যেমন "টগল ডিসপ্লে," "প্রগ্রেস বার আপডেট করুন," "মেনুটি দেখান," "মেনু নির্বাচন পরিবর্তন করুন," ইত্যাদি আপনি আপনার ডিভাইসের জন্য উপযুক্ত ইন্টারফেস সরবরাহ করতে এগুলি ওভাররাইড করতে পারেন। হতে পারে আপনার ডিভাইসে এলইডি রয়েছে যেখানে আপনি রাষ্ট্রকে নির্দেশ করতে ফ্ল্যাশিংয়ের বিভিন্ন রঙ বা নিদর্শন ব্যবহার করতে পারেন, বা আপনি অডিও খেলতে পারেন। (সম্ভবত আপনি কোনও মেনু বা "টেক্সট ডিসপ্লে" মোডকে মোটেও সমর্থন করতে চান না; আপনি CheckKey()
এবং HandleMenuKey()
বাস্তবায়নগুলি যা তাদের কাছে অ্যাক্সেস করতে বাধা দিতে পারেন যা কোনও মেনু আইটেমটিতে প্রদর্শন করতে বা নির্বাচন করে না।
আপনাকে কোন পদ্ধতিগুলি সমর্থন করতে হবে তা দেখতে রিকভারিউআইআইয়ের ঘোষণার জন্য bootable/recovery/ui.h
দেখুন। রিকভারিউই বিমূর্ত - কিছু পদ্ধতি খাঁটি ভার্চুয়াল এবং অবশ্যই সাবক্লাস দ্বারা সরবরাহ করা উচিত - তবে এটিতে কী ইনপুটগুলির প্রক্রিয়াকরণ করার জন্য কোড রয়েছে। আপনার ডিভাইসে যদি কী না থাকে বা আপনি সেগুলি আলাদাভাবে প্রক্রিয়া করতে চান তবে আপনি এটিকে ওভাররাইড করতে পারেন।
আপডেটার
আপনি আপনার নিজস্ব এক্সটেনশন ফাংশনগুলি সরবরাহ করে আপডেট প্যাকেজটি ইনস্টল করার ক্ষেত্রে ডিভাইস-নির্দিষ্ট কোডটি ব্যবহার করতে পারেন যা আপনার আপডেটের স্ক্রিপ্টের মধ্যে থেকে কল করা যেতে পারে। টার্ডিস ডিভাইসের জন্য এখানে একটি নমুনা ফাংশন:
device/yoyodyne/tardis/recovery/recovery_updater.c
#include <stdlib.h> #include <string.h> #include "edify/expr.h"
প্রতিটি এক্সটেনশন ফাংশন একই স্বাক্ষর আছে। যুক্তিগুলি সেই নাম যার দ্বারা ফাংশনটি বলা হত, একটি State*
কুকি, আগত যুক্তিগুলির সংখ্যা এবং Expr*
পয়েন্টারগুলির একটি অ্যারে যুক্তিগুলির প্রতিনিধিত্ব করে। রিটার্ন মানটি একটি নতুন-বরাদ্দকৃত Value*
।
Value* ReprogramTardisFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); }
আপনার ফাংশনটি বলা হওয়ার সময় আপনার যুক্তিগুলি মূল্যায়ন করা হয়নি - আপনার ফাংশনের যুক্তি নির্ধারণ করে যে তাদের মধ্যে কোনটি মূল্যায়ন করা হয় এবং কতবার। সুতরাং, আপনি নিজের নিয়ন্ত্রণ কাঠামো প্রয়োগ করতে এক্সটেনশন ফাংশনগুলি ব্যবহার করতে পারেন। একটি Expr*
আর্গুমেন্ট মূল্যায়ন করতে Call Evaluate()
, একটি Value*
ফিরিয়ে। যদি Evaluate()
বাতিল হয় তবে আপনার যে কোনও সংস্থান রয়েছে তা আপনার মুক্ত করা উচিত এবং অবিলম্বে নালটি ফিরিয়ে দেওয়া উচিত (এটি এডিফাই স্ট্যাকটি বাতিল করে দেয়)। অন্যথায়, আপনি প্রত্যাবর্তিত মানের মালিকানা গ্রহণ করেন এবং শেষ পর্যন্ত এটিতে FreeValue()
কল করার জন্য দায়বদ্ধ।
ধরুন ফাংশনটির দুটি যুক্তি দরকার: একটি স্ট্রিং-মূল্যবান কী এবং একটি ব্লব-মূল্যবান চিত্র । আপনি এই জাতীয় যুক্তি পড়তে পারেন:
Value* key = EvaluateValue(state, argv[0]); if (key == NULL) { return NULL; } if (key->type != VAL_STRING) { ErrorAbort(state, "first arg to %s() must be string", name); FreeValue(key); return NULL; } Value* image = EvaluateValue(state, argv[1]); if (image == NULL) { FreeValue(key); // must always free Value objects return NULL; } if (image->type != VAL_BLOB) { ErrorAbort(state, "second arg to %s() must be blob", name); FreeValue(key); FreeValue(image) return NULL; }
নুলের জন্য পরীক্ষা করা এবং পূর্বে মূল্যায়ন করা যুক্তিগুলি একাধিক যুক্তির জন্য ক্লান্তিকর হতে পারে। ReadValueArgs()
ফাংশন এটি আরও সহজ করে তুলতে পারে। উপরের কোডের পরিবর্তে, আপনি এটি লিখতে পারতেন:
Value* key; Value* image; if (ReadValueArgs(state, argv, 2, &key, &image) != 0) { return NULL; // ReadValueArgs() will have set the error message } if (key->type != VAL_STRING || image->type != VAL_BLOB) { ErrorAbort(state, "arguments to %s() have wrong type", name); FreeValue(key); FreeValue(image) return NULL; }
ReadValueArgs()
টাইপ-চেকিং করে না, তাই আপনাকে অবশ্যই এটি এখানে করতে হবে; এটি ব্যর্থ হলে কিছুটা কম নির্দিষ্ট ত্রুটি বার্তা উত্পাদন ব্যয় করে বিবৃতি যদি একটি দিয়ে এটি করা আরও সুবিধাজনক। তবে ReadValueArgs()
প্রতিটি যুক্তি মূল্যায়ন করে এবং সমস্ত পূর্ব-মূল্যায়িত যুক্তিগুলি মুক্ত করে (পাশাপাশি একটি দরকারী ত্রুটি বার্তা সেট করা) হ্যান্ডেল করে যদি কোনও মূল্যায়ন ব্যর্থ হয়। আপনি একটি ReadValueVarArgs()
সুবিধার্থে ফাংশন ব্যবহার করতে পারেন একটি পরিবর্তনশীল সংখ্যার আর্গুমেন্ট (এটি Value*
প্রদান করে) মূল্যায়ন করার জন্য।
যুক্তিগুলি মূল্যায়ন করার পরে, ফাংশনের কাজটি করুন:
// key->data is a NUL-terminated string // image->data and image->size define a block of binary data // // ... some device-specific magic here to // reprogram the tardis using those two values ...
রিটার্ন মান অবশ্যই একটি Value*
অবজেক্ট হতে হবে; এই বস্তুর মালিকানা কলারের কাছে চলে যাবে। কলার এই Value*
- নির্দিষ্টভাবে ডেটামেম্বার।
এই উদাহরণস্বরূপ, আপনি সাফল্য নির্দেশ করতে একটি সত্য বা মিথ্যা মান ফিরিয়ে দিতে চান। কনভেনশনটি মনে রাখবেন যে খালি স্ট্রিংটি মিথ্যা এবং অন্যান্য সমস্ত স্ট্রিং সত্য । আপনাকে অবশ্যই কনস্ট্যান্ট স্ট্রিংয়ের ম্যালোক'ড অনুলিপি সহ একটি মান অবজেক্টটি অবশ্যই ম্যালোক করতে হবে, যেহেতু কলার উভয়ই free()
করবে। আপনার যুক্তিগুলি মূল্যায়ন করে আপনি যে অবজেক্টগুলি পেয়েছেন সেগুলিতে FreeValue()
কল করতে ভুলবেন না!
FreeValue(key); FreeValue(image); Value* result = malloc(sizeof(Value)); result->type = VAL_STRING; result->data = strdup(successful ? "t" : ""); result->size = strlen(result->data); return result; }
সুবিধার্থে ফাংশন StringValue()
একটি স্ট্রিংকে একটি নতুন মান অবজেক্টে আবৃত করে। উপরের কোডটি আরও সংক্ষিপ্তভাবে লিখতে ব্যবহার করুন:
FreeValue(key); FreeValue(image); return StringValue(strdup(successful ? "t" : "")); }
এডিফাই দোভাষীর মধ্যে ফাংশনগুলি হুক করতে, ফাংশন Register_ foo
সরবরাহ করুন যেখানে ফু এই কোডটিযুক্ত স্ট্যাটিক লাইব্রেরির নাম। প্রতিটি এক্সটেনশন ফাংশন নিবন্ধন করতে RegisterFunction()
কল করুন। কনভেনশন দ্বারা, নাম ডিভাইস-নির্দিষ্ট ফাংশন device . whatever
ভবিষ্যতের অন্তর্নির্মিত ফাংশনগুলির সাথে দ্বন্দ্ব এড়াতে device . whatever
যুক্ত করা হয়েছে।
void Register_librecovery_updater_tardis() { RegisterFunction("tardis.reprogram", ReprogramTardisFn); }
আপনি এখন আপনার কোড সহ একটি স্ট্যাটিক লাইব্রেরি তৈরি করতে মেকফাইলটি কনফিগার করতে পারেন। (এটি পূর্ববর্তী বিভাগে পুনরুদ্ধার ইউআই কাস্টমাইজ করতে ব্যবহৃত একই মেকফিল; আপনার ডিভাইসে উভয় স্ট্যাটিক লাইব্রেরি এখানে সংজ্ঞায়িত হতে পারে))
device/yoyodyne/tardis/recovery/Android.mk
include $(CLEAR_VARS) LOCAL_SRC_FILES := recovery_updater.c LOCAL_C_INCLUDES += bootable/recovery
স্ট্যাটিক লাইব্রেরির নামটি অবশ্যই এর মধ্যে থাকা Register_ libname
ফাংশনের নামের সাথে মেলে।
LOCAL_MODULE := librecovery_updater_tardis include $(BUILD_STATIC_LIBRARY)
অবশেষে, আপনার লাইব্রেরিতে টানতে পুনরুদ্ধারের বিল্ডটি কনফিগার করুন। আপনার লাইব্রেরিটি টার্গেট_আরকোভারি_আপডেটার_লিবগুলিতে যুক্ত করুন (এতে একাধিক লাইব্রেরি থাকতে পারে; তারা সকলেই নিবন্ধিত হয়)। যদি আপনার কোডটি অন্যান্য স্ট্যাটিক লাইব্রেরির উপর নির্ভর করে যা তারা নিজেরাই এক্সটেনশানগুলি এডিফাই করে না (যেমন, তাদের কোনও Register_ libname
ফাংশন নেই), আপনি তাদের (অস্তিত্বহীন) নিবন্ধকরণ ফাংশনটি কল না করে আপডেটের সাথে লিঙ্ক করার জন্য টার্গেট_আরসিওভারি_আপডেটার_এক্সট্রা_লিবগুলি তালিকাভুক্ত করতে পারেন। উদাহরণস্বরূপ, যদি আপনার ডিভাইস-নির্দিষ্ট কোডটি ডেটা ডিকম্প্রেস করতে zlib ব্যবহার করতে চায় তবে আপনি এখানে লিবিজ অন্তর্ভুক্ত করবেন।
device/yoyodyne/tardis/BoardConfig.mk
[...] # add device-specific extensions to the updater binary TARGET_RECOVERY_UPDATER_LIBS += librecovery_updater_tardis TARGET_RECOVERY_UPDATER_EXTRA_LIBS +=
আপনার ওটিএ প্যাকেজে আপডেটার স্ক্রিপ্টগুলি এখন আপনার ফাংশনটিকে অন্য যে কোনও হিসাবে কল করতে পারে। আপনার টারডিস ডিভাইসটি পুনরায় প্রোগ্রাম করতে, আপডেট স্ক্রিপ্টটিতে থাকতে পারে: tardis.reprogram("the-key", package_extract_file("tardis-image.dat"))
। এটি অন্তর্নির্মিত ফাংশন package_extract_file()
এর একক-যুক্তি সংস্করণ ব্যবহার করে, যা নতুন এক্সটেনশন ফাংশনটির দ্বিতীয় যুক্তি তৈরি করতে একটি ব্লব হিসাবে আপডেট প্যাকেজ থেকে নিষ্কাশিত একটি ফাইলের বিষয়বস্তু প্রদান করে।
ওটিএ প্যাকেজ জেনারেশন
চূড়ান্ত উপাদানটি আপনার ডিভাইস-নির্দিষ্ট ডেটা সম্পর্কে জানতে ওটিএ প্যাকেজ প্রজন্মের সরঞ্জামগুলি পাচ্ছে এবং আপনার এক্সটেনশন ফাংশনগুলিতে কলগুলি অন্তর্ভুক্ত করে আপডেটার স্ক্রিপ্টগুলি নির্গত করে।
প্রথমে, ডেটাগুলির একটি ডিভাইস-নির্দিষ্ট ব্লব সম্পর্কে জানার জন্য বিল্ড সিস্টেমটি পান। আপনার ডেটা ফাইলটি device/yoyodyne/tardis/tardis.dat
রয়েছে ধরে নিচ্ছি, আপনার ডিভাইসের অ্যান্ড্রয়েডবোর্ডে নিম্নলিখিতগুলি ঘোষণা করুন: এমকে:
device/yoyodyne/tardis/AndroidBoard.mk
[...] $(call add-radio-file,tardis.dat)
পরিবর্তে আপনি এটি একটি অ্যান্ড্রয়েড.এমকেতেও রাখতে পারেন, তবে তারপরে এটি কোনও ডিভাইস চেক দ্বারা রক্ষণ করা আবশ্যক, যেহেতু গাছের সমস্ত অ্যান্ড্রয়েড.এমকে ফাইলগুলি কোনও ডিভাইস নির্মিত হচ্ছে তা বিবেচনা করা হয় না। (যদি আপনার গাছে একাধিক ডিভাইস অন্তর্ভুক্ত থাকে তবে আপনি কেবল তারডিস ডিভাইসটি তৈরি করার সময় যুক্ত হওয়া টার্ডিস.ড্যাট ফাইলটি যুক্ত করতে চান))
device/yoyodyne/tardis/Android.mk
[...] # an alternative to specifying it in AndroidBoard.mk ifeq (($TARGET_DEVICE),tardis) $(call add-radio-file,tardis.dat) endif
এগুলিকে historical তিহাসিক কারণে রেডিও ফাইল বলা হয়; ডিভাইস রেডিওর সাথে তাদের কোনও সম্পর্ক নেই (উপস্থিত থাকলে)। এগুলি কেবলমাত্র ডেটাগুলির অস্বচ্ছ ব্লবগুলি বিল্ড সিস্টেমটি টার্গেট-ফাইলগুলিতে অনুলিপি করে OT ওটিএ প্রজন্মের সরঞ্জামগুলি দ্বারা ব্যবহৃত জিপ। আপনি যখন কোনও বিল্ড করেন, টারডিস.ড্যাটটি টার্গেট RADIO/tardis.dat
ফাইলগুলিতে সংরক্ষণ করা হয় z আপনি যতটা ফাইল যুক্ত করতে পারেন তত একাধিকবার add-radio-file
কল করতে পারেন।
পাইথন মডিউল
রিলিজ সরঞ্জামগুলি প্রসারিত করতে, একটি পাইথন মডিউল লিখুন (অবশ্যই রিলিজেটুলস.পি নামকরণ করা উচিত) সরঞ্জামগুলি উপস্থিত থাকলে কল করতে পারে। উদাহরণ:
device/yoyodyne/tardis/releasetools.py
import common def FullOTA_InstallEnd(info): # copy the data into the package. tardis_dat = info.input_zip.read("RADIO/tardis.dat") common.ZipWriteStr(info.output_zip, "tardis.dat", tardis_dat) # emit the script code to install this data on the device info.script.AppendExtra( """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
একটি পৃথক ফাংশন একটি ইনক্রিমেন্টাল ওটিএ প্যাকেজ উত্পন্ন করার ক্ষেত্রে পরিচালনা করে। এই উদাহরণের জন্য, ধরুন আপনাকে কেবল তখনই টার্ডিস পুনরায় প্রোগ্রাম করা দরকার যখন টার্ডিস.ড্যাট ফাইল দুটি বিল্ডের মধ্যে পরিবর্তিত হয়েছে।
def IncrementalOTA_InstallEnd(info): # copy the data into the package. source_tardis_dat = info.source_zip.read("RADIO/tardis.dat") target_tardis_dat = info.target_zip.read("RADIO/tardis.dat") if source_tardis_dat == target_tardis_dat: # tardis.dat is unchanged from previous build; no # need to reprogram it return # include the new tardis.dat in the OTA package common.ZipWriteStr(info.output_zip, "tardis.dat", target_tardis_dat) # emit the script code to install this data on the device info.script.AppendExtra( """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
মডিউল ফাংশন
আপনি মডিউলটিতে নিম্নলিখিত ফাংশনগুলি সরবরাহ করতে পারেন (কেবলমাত্র আপনার প্রয়োজনগুলি প্রয়োগ করুন)।
-
FullOTA_Assertions()
- একটি পূর্ণ ওটিএ উত্পাদনের শুরুতে কাছে ডাকা হয়। ডিভাইসের বর্তমান অবস্থা সম্পর্কে দৃ ser ়তা নির্গত করার জন্য এটি একটি ভাল জায়গা। স্ক্রিপ্ট কমান্ডগুলি নির্গত করবেন না যা ডিভাইসে পরিবর্তন করে।
-
FullOTA_InstallBegin()
- ডিভাইসের অবস্থা সম্পর্কে সমস্ত দাবী পেরিয়ে গেছে তবে কোনও পরিবর্তন হওয়ার আগে ডাকা হয়েছে। আপনি ডিভাইস-নির্দিষ্ট আপডেটের জন্য কমান্ডগুলি নির্গত করতে পারেন যা ডিভাইসে অন্য কিছু পরিবর্তন করার আগে অবশ্যই চলতে হবে।
-
FullOTA_InstallEnd()
- স্ক্রিপ্ট প্রজন্মের শেষে কল করা হয়েছে, বুট এবং সিস্টেম পার্টিশনগুলি আপডেট করার জন্য স্ক্রিপ্ট কমান্ডগুলি নির্গত হওয়ার পরে। আপনি ডিভাইস-নির্দিষ্ট আপডেটের জন্য অতিরিক্ত কমান্ডগুলিও নির্গত করতে পারেন।
-
IncrementalOTA_Assertions()
-
FullOTA_Assertions()
এর মতো তবে একটি ইনক্রিমেন্টাল আপডেট প্যাকেজ তৈরি করার সময় কল করা হয়। -
IncrementalOTA_VerifyBegin()
- ডিভাইসের অবস্থা সম্পর্কে সমস্ত দাবী পেরিয়ে গেছে তবে কোনও পরিবর্তন হওয়ার আগে। আপনি ডিভাইস-নির্দিষ্ট আপডেটের জন্য কমান্ডগুলি নির্গত করতে পারেন যা ডিভাইসে অন্য কিছু পরিবর্তন করার আগে অবশ্যই চলতে হবে।
-
IncrementalOTA_VerifyEnd()
- যাচাইকরণ পর্বের শেষে কল করা হয়েছে, যখন স্ক্রিপ্টটি ফাইলগুলি নিশ্চিত করে শেষ করে এটি স্পর্শ করতে চলেছে তা প্রত্যাশিত শুরুর সামগ্রী রয়েছে। এই মুহুর্তে ডিভাইসে কিছুই পরিবর্তন করা হয়নি। আপনি অতিরিক্ত ডিভাইস-নির্দিষ্ট যাচাইয়ের জন্য কোডও নির্গত করতে পারেন।
-
IncrementalOTA_InstallBegin()
- প্যাচ করার জন্য ফাইলগুলির পরে কল করা হয়েছে রাষ্ট্রের আগে প্রত্যাশিত হিসাবে তবে কোনও পরিবর্তন হওয়ার আগে যাচাই করা হয়েছে। আপনি ডিভাইস-নির্দিষ্ট আপডেটের জন্য কমান্ডগুলি নির্গত করতে পারেন যা ডিভাইসে অন্য কিছু পরিবর্তন করার আগে অবশ্যই চলতে হবে।
-
IncrementalOTA_InstallEnd()
- এর সম্পূর্ণ ওটিএ প্যাকেজের সমকক্ষের অনুরূপ, স্ক্রিপ্ট প্রজন্মের শেষে এটি বলা হয়, বুট এবং সিস্টেম পার্টিশনগুলি আপডেট করার জন্য স্ক্রিপ্ট কমান্ডগুলি নির্গত হওয়ার পরে। আপনি ডিভাইস-নির্দিষ্ট আপডেটের জন্য অতিরিক্ত কমান্ডগুলিও নির্গত করতে পারেন।
দ্রষ্টব্য: যদি ডিভাইসটি শক্তি হারাতে থাকে তবে ওটিএ ইনস্টলেশন শুরু থেকেই পুনরায় চালু হতে পারে। এই কমান্ডগুলি ইতিমধ্যে সম্পূর্ণ বা আংশিকভাবে চালিত হয়েছে এমন ডিভাইসগুলির সাথে মোকাবিলা করার জন্য প্রস্তুত থাকুন।
তথ্য অবজেক্টগুলিতে ফাংশন পাস করুন
একটি একক তথ্য অবজেক্টে ফাংশনগুলি পাস করুন যাতে বিভিন্ন দরকারী আইটেম থাকে:
- তথ্য.ইনপুট_জিপ । (কেবলমাত্র সম্পূর্ণ ওটিএ) ইনপুট টার্গেট-ফাইলগুলির জন্য
zipfile.ZipFile
অবজেক্ট .zip। - তথ্য.সোর্স_জিপ । (কেবলমাত্র ইনক্রিমেন্টাল ওটিএ) উত্স টার্গেট-ফাইলগুলির জন্য
zipfile.ZipFile
অবজেক্ট। জিপ (ইনক্রিমেন্টাল প্যাকেজটি ইনস্টল করা হচ্ছে যখন ডিভাইসে ইতিমধ্যে বিল্ড)। - info.target_zip । (কেবলমাত্র ইনক্রিমেন্টাল ওটিএ) টার্গেট টার্গেট-ফাইলগুলির জন্য
zipfile.ZipFile
অবজেক্ট। জিপ (বিল্ডটি ইনক্রিমেন্টাল প্যাকেজটি ডিভাইসে রাখে)। - তথ্য.আউটপুট_জিপ । প্যাকেজ তৈরি হচ্ছে; একটি
zipfile.ZipFile
অবজেক্ট লেখার জন্য খোলা। প্যাকেজে একটি ফাইল যুক্ত করতে কমন.জিপিউরিটেস্ট্রেট (তথ্য.আউটপুট_জিপ, ফাইলের নাম , ডেটা ) ব্যবহার করুন। - info.script । স্ক্রিপ্ট অবজেক্ট যার সাথে আপনি কমান্ডগুলি সংযোজন করতে পারেন। স্ক্রিপ্টে পাঠ্য আউটপুট করতে
info.script.AppendExtra( script_text )
কল করুন। নিশ্চিত করুন যে আউটপুট পাঠ্যটি একটি সেমিকোলনের সাথে শেষ হয় যাতে এটি পরে নির্গত কমান্ডগুলিতে চলে না।
তথ্য অবজেক্টের বিশদগুলির জন্য, জিপ সংরক্ষণাগারগুলির জন্য পাইথন সফটওয়্যার ফাউন্ডেশন ডকুমেন্টেশন দেখুন।
মডিউল অবস্থান নির্দিষ্ট করুন
আপনার বোর্ডকনফিগ.এমকে ফাইলটিতে আপনার ডিভাইসের রিলিজটুল.পি স্ক্রিপ্টটির অবস্থান উল্লেখ করুন:
device/yoyodyne/tardis/BoardConfig.mk
[...] TARGET_RELEASETOOLS_EXTENSIONS := device/yoyodyne/tardis
যদি টার্গেট_রিলিজেটলস_ এক্সটেনশনগুলি সেট না করা থাকে তবে এটি $(TARGET_DEVICE_DIR)/../common
ডিরেক্টরি ( device/yoyodyne/common
) এ ডিফল্ট হয়। রিলিজটুলস.পি স্ক্রিপ্টের অবস্থান স্পষ্টভাবে সংজ্ঞায়িত করা ভাল। টারডিস ডিভাইসটি তৈরি করার সময়, রিলিজটুলস.পি স্ক্রিপ্টটি লক্ষ্য-ফাইলগুলিতে অন্তর্ভুক্ত করা হয়েছে Z জিপ ফাইল ( META/releasetools.py
)।
আপনি যখন রিলিজ সরঞ্জামগুলি চালান (হয় img_from_target_files
বা ota_from_target_files
), টার্গেট-ফাইলগুলিতে রিলিজটুল.পি স্ক্রিপ্ট। জিপ, যদি উপস্থিত থাকে তবে অ্যান্ড্রয়েড উত্স গাছ থেকে একটির চেয়ে বেশি পছন্দ করা হয়। আপনি স্পষ্টভাবে ডিভাইস -নির্দিষ্ট এক্সটেনশনের পথটি -s
(বা --device_specific
) বিকল্পের সাথে নির্দিষ্ট করতে পারেন, যা শীর্ষস্থানীয় অগ্রাধিকার গ্রহণ করে। এটি আপনাকে ত্রুটিগুলি সংশোধন করতে এবং রিলিজটুলস এক্সটেনশনে পরিবর্তন করতে এবং পুরানো টার্গেট-ফাইলগুলিতে এই পরিবর্তনগুলি প্রয়োগ করতে সক্ষম করে।
Now, when you run ota_from_target_files
, it automatically picks up the device-specific module from the target_files .zip file and uses it when generating OTA packages:
./build/make/tools/releasetools/ota_from_target_files \
-i PREVIOUS-tardis-target_files.zip \
dist_output/tardis-target_files.zip \
incremental_ota_update.zip
Alternatively, you can specify device-specific extensions when you run ota_from_target_files
.
./build/make/tools/releasetools/ota_from_target_files \
-s device/yoyodyne/tardis \
-i PREVIOUS-tardis-target_files.zip \
dist_output/tardis-target_files.zip \
incremental_ota_update.zip
Note: For a complete list of options, refer to the ota_from_target_files
comments in build/make/tools/releasetools/ota_from_target_files
.
Sideloading mechanism
Recovery has a sideloading mechanism for manually installing an update package without downloading it over-the-air by the main system. Sideloading is useful for debugging or making changes on devices where the main system can't be booted.
Historically, sideloading has been done through loading packages off the device's SD card; in the case of a non-booting device, the package can be put onto the SD card using some other computer and then the SD card inserted into the device. To accommodate Android devices without removable external storage, recovery supports two additional mechanisms for sideloading: loading packages from the cache partition, and loading them over USB using adb.
To invoke each sideload mechanism, your device's Device::InvokeMenuItem()
method can return the following values of BuiltinAction:
- APPLY_EXT . Sideload an update package from external storage (
/sdcard
directory). Your recovery.fstab must define the/sdcard
mount point. This is not usable on devices that emulate an SD card with a symlink to/data
(or some similar mechanism)./data
is typically not available to recovery because it may be encrypted. The recovery UI displays a menu of .zip files in/sdcard
and allows the user to select one. - APPLY_CACHE . Similar to loading a package from
/sdcard
except that the/cache
directory (which is always available to recovery) is used instead. From the regular system,/cache
is only writable by privileged users, and if the device isn't bootable then the/cache
directory can't be written to at all (which makes this mechanism of limited utility). - APPLY_ADB_SIDELOAD . Allows user to send a package to the device via a USB cable and the adb development tool. When this mechanism is invoked, recovery starts up its own mini version of the adbd daemon to let adb on a connected host computer talk to it. This mini version supports only a single command:
adb sideload filename
. The named file is sent from the host machine to the device, which then verifies and installs it just as if it had been on local storage.
কয়েকটি সতর্কতা:
- Only USB transport is supported.
- If your recovery runs adbd normally (usually true for userdebug and eng builds), that will be shut down while the device is in adb sideload mode and will be restarted when adb sideload has finished receiving a package. While in adb sideload mode, no adb commands other than
sideload
work (logcat
,reboot
,push
,pull
,shell
, etc. all fail). - You cannot exit adb sideload mode on the device. To abort, you can send
/dev/null
(or anything else that's not a valid package) as the package, and then the device will fail to verify it and stop the installation procedure. The RecoveryUI implementation'sCheckKey()
method will continue to be called for keypresses, so you can provide a key sequence that reboots the device and works in adb sideload mode.
The recovery system includes several hooks for inserting device-specific code so that OTA updates can also update parts of the device other than the Android system (eg, the baseband or radio processor).
The following sections and examples customize the tardis device produced by the yoyodyne vendor.
পার্টিশন মানচিত্র
As of Android 2.3, the platform supports eMMc flash devices and the ext4 filesystem that runs on those devices. It also supports Memory Technology Device (MTD) flash devices and the yaffs2 filesystem from older releases.
The partition map file is specified by TARGET_RECOVERY_FSTAB; this file is used by both the recovery binary and the package-building tools. You can specify the name of the map file in TARGET_RECOVERY_FSTAB in BoardConfig.mk.
A sample partition map file might look like this:
device/yoyodyne/tardis/recovery.fstab
# mount point fstype device [device2] [options (3.0+ only)] /sdcard vfat /dev/block/mmcblk0p1 /dev/block/mmcblk0 /cache yaffs2 cache /misc mtd misc /boot mtd boot /recovery emmc /dev/block/platform/s3c-sdhci.0/by-name/recovery /system ext4 /dev/block/platform/s3c-sdhci.0/by-name/system length=-4096 /data ext4 /dev/block/platform/s3c-sdhci.0/by-name/userdata
With the exception of /sdcard
, which is optional, all mount points in this example must be defined (devices may also add extra partitions). There are five supported filesystem types:
- yaffs2
- A yaffs2 filesystem atop an MTD flash device. "device" must be the name of the MTD partition and must appear in
/proc/mtd
. - mtd
- A raw MTD partition, used for bootable partitions such as boot and recovery. MTD is not actually mounted, but the mount point is used as a key to locate the partition. "device" must be the name of the MTD partition in
/proc/mtd
. - ext4
- An ext4 filesystem atop an eMMc flash device. "device" must be the path of the block device.
- emmc
- A raw eMMc block device, used for bootable partitions such as boot and recovery. Similar to the mtd type, eMMc is never actually mounted, but the mount point string is used to locate the device in the table.
- vfat
- A FAT filesystem atop a block device, typically for external storage such as an SD card. The device is the block device; device2 is a second block device the system attempts to mount if mounting the primary device fails (for compatibility with SD cards which may or may not be formatted with a partition table).
All partitions must be mounted in the root directory (ie the mount point value must begin with a slash and have no other slashes). This restriction applies only to mounting filesystems in recovery; the main system is free to mount them anywhere. The directories
/boot
,/recovery
, and/misc
should be raw types (mtd or emmc), while the directories/system
,/data
,/cache
, and/sdcard
(if available) should be filesystem types (yaffs2, ext4, or vfat).
Starting in Android 3.0, the recovery.fstab file gains an additional optional field, options . Currently the only defined option is length , which lets you explicitly specify the length of the partition. This length is used when reformatting the partition (eg, for the userdata partition during a data wipe/factory reset operation, or for the system partition during installation of a full OTA package). If the length value is negative, then the size to format is taken by adding the length value to the true partition size. For instance, setting "length=-16384" means the last 16k of that partition will not be overwritten when that partition is reformatted. This supports features such as encryption of the userdata partition (where encryption metadata is stored at the end of the partition that should not be overwritten).
Note: The device2 and options fields are optional, creating ambiguity in parsing. If the entry in the fourth field on the line begins with a '/' character, it is considered a device2 entry; if the entry does not begin with a '/' character, it is considered an options field.
বুট অ্যানিমেশন
Device manufacturers have the ability to customize the animation shown when an Android device is booting. To do this, construct a .zip file organized and located according to the specifications in bootanimation format .
For Android Things devices, you may upload the zipped file in the Android Things console to have the images included in the selected product.
Note: These images must meet Android brand guidelines. For brand guidelines, refer to the Android section of the Partner Marketing Hub .
Recovery UI
To support devices with different available hardware (physical buttons, LEDs, screens, etc.), you can customize the recovery interface to display status and access the manually-operated hidden features for each device.
Your goal is to build a small static library with a couple of C++ objects to provide the device-specific functionality. The file bootable/recovery/default_device.cpp
is used by default, and makes a good starting point to copy when writing a version of this file for your device.
Note: You might see a message saying No Command here. To toggle text, hold the power button while you hit the volume up button. If your devices doesn't have both buttons, long press any button to toggle text.
device/yoyodyne/tardis/recovery/recovery_ui.cpp
#include <linux/input.h> #include "common.h" #include "device.h" #include "screen_ui.h"
Header and item functions
The Device class requires functions for returning headers and items that appear in the hidden recovery menu. Headers describe how to operate the menu (ie controls to change/select the highlighted item).
static const char* HEADERS[] = { "Volume up/down to move highlight;", "power button to select.", "", NULL }; static const char* ITEMS[] = {"reboot system now", "apply update from ADB", "wipe data/factory reset", "wipe cache partition", NULL };
Note: Long lines are truncated (not wrapped), so keep the width of your device screen in mind.
Customize CheckKey
Next, define your device's RecoveryUI implementation. This example assumes the tardis device has a screen, so you can inherit from the built-in ScreenRecoveryUIimplementation (see instructions for devices without a screen .) The only function to customize from ScreenRecoveryUI is CheckKey()
, which does the initial asynchronous key handling:
class TardisUI : public ScreenRecoveryUI { public: virtual KeyAction CheckKey(int key) { if (key == KEY_HOME) { return TOGGLE; } return ENQUEUE; } };
KEY constants
The KEY_* constants are defined in linux/input.h
. CheckKey()
is called no matter what is going on in the rest of recovery: when the menu is toggled off, when it is on, during package installation, during userdata wiping, etc. It can return one of four constants:
- TOGGLE . Toggle the display of the menu and/or text log on or off
- REBOOT . Immediately reboot the device
- IGNORE . Ignore this keypress
- ENQUEUE . Enqueue this keypress to be consumed synchronously (ie, by the recovery menu system if the display is enabled)
CheckKey()
is called each time a key-down event is followed by a key-up event for the same key. (The sequence of events A-down B-down B-up A-up results only in CheckKey(B)
being called.) CheckKey()
can call IsKeyPressed()
, to find out if other keys are being held down. (In the above sequence of key events, if CheckKey(B)
called IsKeyPressed(A)
it would have returned true.)
CheckKey()
can maintain state in its class; this can be useful to detect sequences of keys. This example shows a slightly more complex setup: the display is toggled by holding down power and pressing volume-up, and the device can be rebooted immediately by pressing the power button five times in a row (with no other intervening keys):
class TardisUI : public ScreenRecoveryUI { private: int consecutive_power_keys; public: TardisUI() : consecutive_power_keys(0) {} virtual KeyAction CheckKey(int key) { if (IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) { return TOGGLE; } if (key == KEY_POWER) { ++consecutive_power_keys; if (consecutive_power_keys >= 5) { return REBOOT; } } else { consecutive_power_keys = 0; } return ENQUEUE; } };
ScreenRecoveryUI
When using your own images (error icon, installation animation, progress bars) with ScreenRecoveryUI, you can set the variable animation_fps
to control the speed in frames per second (FPS) of animations.
Note: The current interlace-frames.py
script enables you to store the animation_fps
information in the image itself. In earlier versions of Android it was necessary to set animation_fps
yourself.
To set the variable animation_fps
, override the ScreenRecoveryUI::Init()
function in your subclass. Set the value, then call the parent Init()
function to complete initialization. The default value (20 FPS) corresponds to the default recovery images; when using these images you don't need to provide an Init()
function. For details on images, see Recovery UI Images .
ডিভাইস ক্লাস
After you have a RecoveryUI implementation, define your device class (subclassed from the built-in Device class). It should create a single instance of your UI class and return that from the GetUI()
function:
class TardisDevice : public Device { private: TardisUI* ui; public: TardisDevice() : ui(new TardisUI) { } RecoveryUI* GetUI() { return ui; }
StartRecovery
The StartRecovery()
method is called at the start of recovery, after the UI has been initialized and after the arguments have been parsed, but before any action has been taken. The default implementation does nothing, so you do not need to provide this in your subclass if you have nothing to do:
void StartRecovery() { // ... do something tardis-specific here, if needed .... }
Supply and manage recovery menu
The system calls two methods to get the list of header lines and the list of items. In this implementation, it returns the static arrays defined at the top of the file:
const char* const* GetMenuHeaders() { return HEADERS; } const char* const* GetMenuItems() { return ITEMS; }
HandleMenuKey
Next, provide a HandleMenuKey()
function, which takes a keypress and the current menu visibility, and decides what action to take:
int HandleMenuKey(int key, int visible) { if (visible) { switch (key) { case KEY_VOLUMEDOWN: return kHighlightDown; case KEY_VOLUMEUP: return kHighlightUp; case KEY_POWER: return kInvokeItem; } } return kNoAction; }
The method takes a key code (which has previously been processed and enqueued by the CheckKey()
method of the UI object), and the current state of the menu/text log visibility. ফেরত মান একটি পূর্ণসংখ্যা. If the value is 0 or higher, that is taken as the position of a menu item, which is invoked immediately (see the InvokeMenuItem()
method below). Otherwise it can be one of the following predefined constants:
- kHighlightUp . Move the menu highlight to the previous item
- kHighlightDown . Move the menu highlight to the next item
- kInvokeItem . Invoke the currently highlighted item
- kNoAction . Do nothing with this keypress
As implied by the visible argument, HandleMenuKey()
is called even if the menu is not visible. Unlike CheckKey()
, it is not called while recovery is doing something such as wiping data or installing a package—it's called only when recovery is idle and waiting for input.
Trackball mechanisms
If your device has a trackball-like input mechanism (generates input events with type EV_REL and code REL_Y), recovery synthesizes KEY_UP and KEY_DOWN keypresses whenever the trackball-like input device reports motion in the Y axis. All you need to do is map KEY_UP and KEY_DOWN events onto menu actions. This mapping does not happen for CheckKey()
, so you can't use trackball motions as triggers for rebooting or toggling the display.
পরিবর্তনকারী কী
To check for keys being held down as modifiers, call the IsKeyPressed()
method of your own UI object. For example, on some devices pressing Alt-W in recovery would start a data wipe whether the menu was visible or not. YOu could implement like this:
int HandleMenuKey(int key, int visible) { if (ui->IsKeyPressed(KEY_LEFTALT) && key == KEY_W) { return 2; // position of the "wipe data" item in the menu } ... }
Note: If visible is false, it doesn't make sense to return the special values that manipulate the menu (move highlight, invoke highlighted item) since the user can't see the highlight. However, you can return the values if desired.
InvokeMenuItem
Next, provide an InvokeMenuItem()
method that maps integer positions in the array of items returned by GetMenuItems()
to actions. For the array of items in the tardis example, use:
BuiltinAction InvokeMenuItem(int menu_position) { switch (menu_position) { case 0: return REBOOT; case 1: return APPLY_ADB_SIDELOAD; case 2: return WIPE_DATA; case 3: return WIPE_CACHE; default: return NO_ACTION; } }
This method can return any member of the BuiltinAction enum to tell the system to take that action (or the NO_ACTION member if you want the system to do nothing). This is the place to provide additional recovery functionality beyond what's in the system: Add an item for it in your menu, execute it here when that menu item is invoked, and return NO_ACTION so the system does nothing else.
BuiltinAction contains the following values:
- NO_ACTION . কিছুই করবেন না।
- REBOOT . Exit recovery and reboot the device normally.
- APPLY_EXT, APPLY_CACHE, APPLY_ADB_SIDELOAD . Install an update package from various places. For details, see Sideloading .
- WIPE_CACHE . Reformat the cache partition only. No confirmation required as this is relatively harmless.
- WIPE_DATA . Reformat the userdata and cache partitions, also known as a factory data reset. The user is asked to confirm this action before proceeding.
The last method, WipeData()
, is optional and is called whenever a data wipe operation is initiated (either from recovery via the menu or when the user has chosen to do a factory data reset from the main system). This method is called before the user data and cache partitions are wiped. If your device stores user data anywhere other than those two partitions, you should erase it here. You should return 0 to indicate success and another value for failure, though currently the return value is ignored. The user data and cache partitions are wiped whether you return success or failure.
int WipeData() { // ... do something tardis-specific here, if needed .... return 0; }
Make device
Finally, include some boilerplate at the end of the recovery_ui.cpp file for the make_device()
function that creates and returns an instance of your Device class:
class TardisDevice : public Device { // ... all the above methods ... }; Device* make_device() { return new TardisDevice(); }
Build and link to device recovery
After completing the recovery_ui.cpp file, built it and link it to recovery on your device. In Android.mk, create a static library that contains only this C++ file:
device/yoyodyne/tardis/recovery/Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := eng LOCAL_C_INCLUDES += bootable/recovery LOCAL_SRC_FILES := recovery_ui.cpp # should match TARGET_RECOVERY_UI_LIB set in BoardConfig.mk LOCAL_MODULE := librecovery_ui_tardis include $(BUILD_STATIC_LIBRARY)
Then, in the board configuration for this device, specify your static library as the value of TARGET_RECOVERY_UI_LIB.
device/yoyodyne/tardis/BoardConfig.mk [...] # device-specific extensions to the recovery UI TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis
Recovery UI images
The recovery user interface consists of images. Ideally, users never interact with the UI: During a normal update, the phone boots into recovery, fills the installation progress bar, and boots back into the new system without input from the user. In the event of a system update problem, the only user action that can be taken is to call customer care.
An image-only interface obviates the need for localization. However, as of Android 5.0 the update can display a string of text (eg "Installing system update...") along with the image. For details, see Localized recovery text .
Android 5.0 এবং পরবর্তী
The Android 5.0 and later recovery UI uses two main images: the error image and the installing animation.
![]() Figure 1. icon_error.png | ![]() Figure 2. icon_installing.png |
The installing animation is represented as a single PNG image with different frames of the animation interlaced by row (which is why Figure 2 appears squished). For example, for a 200x200 seven-frame animation, create a single 200x1400 image where first frame is rows 0, 7, 14, 21, ...; the second frame is rows 1, 8, 15, 22, ...; etc. The combined image includes a text chunk that indicates the number of animation frames and the number of frames per second (FPS). The tool bootable/recovery/interlace-frames.py
takes a set of input frames and combines them into the necessary composite image used by recovery.
Default images are available in different densities and are located in bootable/recovery/res-$DENSITY/images
(eg, bootable/recovery/res-hdpi/images
). To use a static image during installation, you need only provide the icon_installing.png image and set the number of frames in the animation to 0 (the error icon is not animated; it is always a static image).
Android 4.x and earlier
The Android 4.x and earlier recovery UI uses the error image (shown above) and the installing animation plus several overlay images:
![]() Figure 3. icon_installing.png | ![]() Figure 4. icon-installing_overlay01.png |
![]() Figure 5. icon_installing_overlay07.png |
During installation, the on-screen display is constructed by drawing the icon_installing.png image, then drawing one of the overlay frames on top of it at the proper offset. Here, a red box is superimposed to highlight where the overlay is placed on top of the base image:
![]() Figure 6. Installing animation frame 1 (icon_installing.png + icon_installing_overlay01.png) | ![]() Figure 7. Installing animation frame 7 (icon_installing.png + icon_installing_overlay07.png) |
Subsequent frames are displayed by drawing only the next overlay image atop what's already there; the base image is not redrawn.
The number of frames in the animation, desired speed, and x- and y-offsets of the overlay relative to the base are set by member variables of the ScreenRecoveryUI class. When using custom images instead of default images, override the Init()
method in your subclass to change these values for your custom images (for details, see ScreenRecoveryUI ). The script bootable/recovery/make-overlay.py
can assist in converting a set of image frames to the "base image + overlay images" form needed by recovery, including computing of the necessary offsets.
Default images are located in bootable/recovery/res/images
. To use a static image during installation, you need only provide the icon_installing.png image and set the number of frames in the animation to 0 (the error icon is not animated; it is always a static image).
Localized recovery text
Android 5.x displays a string of text (eg, "Installing system update...") along with the image. When the main system boots into recovery it passes the user's current locale as a command-line option to recovery. For each message to display, recovery includes a second composite image with pre-rendered text strings for that message in each locale.
Sample image of recovery text strings:

Figure 8. Localized text for recovery messages
Recovery text can display the following messages:
- Installing system update...
- ত্রুটি!
- Erasing... (when doing a data wipe/factory reset)
- No command (when a user boots into recovery manually)
The Android app in bootable/recovery/tools/recovery_l10n/
renders localizations of a message and creates the composite image. For details on using this app, refer to the comments in bootable/recovery/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java
.
When a user boots into recovery manually, the locale might not be available and no text is displayed. Do not make the text messages critical to the recovery process.
Note: The hidden interface that displays log messages and allows the user to select actions from the menu is available only in English.
অগ্রগতি বার
Progress bars can appear below the main image (or animation). The progress bar is made by combining two input images, which must be of the same size:

Figure 9. progress_empty.png

Figure 10. progress_fill.png
The left end of the fill image is displayed next to the right end of the empty image to make the progress bar. The position of the boundary between the two images is changed to indicate the progress. For example, with the above pairs of input images, display:

Figure 11. Progress bar at 1%>

Figure 12. Progress bar at 10%

Figure 13. Progress bar at 50%
You can provide device-specific versions of these images by placing them into (in this example) device/yoyodyne/tardis/recovery/res/images
. Filenames must match the ones listed above; when a file is found in that directory, the build system uses it in preference to the corresponding default image. Only PNGs in RGB or RGBA format with 8-bit color depth are supported.
Note: In Android 5.x, if the locale is known to recovery and is a right-to-left (RTL) language (Arabic, Hebrew, etc.), the progress bar fills from right to left.
Devices without screens
Not all Android devices have screens. If your device is a headless appliance or has an audio-only interface, you may need to do more extensive customization of recovery UI. Instead of creating a subclass of ScreenRecoveryUI, subclass its parent class RecoveryUI directly.
RecoveryUI has methods for handling a lower-level UI operations such as "toggle the display," "update the progress bar," "show the menu," "change the menu selection," etc. You can override these to provide an appropriate interface for your device. Maybe your device has LEDs where you can use different colors or patterns of flashing to indicate state, or maybe you can play audio. (Perhaps you don't want to support a menu or the "text display" mode at all; you can prevent accessing them with CheckKey()
and HandleMenuKey()
implementations that never toggle the display on or select a menu item. In this case, many of the RecoveryUI methods you need to provide can just be empty stubs.)
See bootable/recovery/ui.h
for the declaration of RecoveryUI to see what methods you must support. RecoveryUI is abstract—some methods are pure virtual and must be provided by subclasses—but it does contain the code to do processing of key inputs. You can override that too, if your device doesn't have keys or you want to process them differently.
আপডেটার
You can use device-specific code in the installation of the update package by providing your own extension functions that can be called from within your updater script. Here's a sample function for the tardis device:
device/yoyodyne/tardis/recovery/recovery_updater.c
#include <stdlib.h> #include <string.h> #include "edify/expr.h"
Every extension function has the same signature. The arguments are the name by which the function was called, a State*
cookie, the number of incoming arguments, and an array of Expr*
pointers representing the arguments. The return value is a newly-allocated Value*
.
Value* ReprogramTardisFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); }
Your arguments have not been evaluated at the time your function is called—your function's logic determines which of them get evaluated and how many times. Thus, you can use extension functions to implement your own control structures. Call Evaluate()
to evaluate an Expr*
argument, returning a Value*
. If Evaluate()
returns NULL, you should free any resources you're holding and immediately return NULL (this propagates aborts up the edify stack). Otherwise, you take ownership of the Value returned and are responsible for eventually calling FreeValue()
on it.
Suppose the function needs two arguments: a string-valued key and a blob-valued image . You could read arguments like this:
Value* key = EvaluateValue(state, argv[0]); if (key == NULL) { return NULL; } if (key->type != VAL_STRING) { ErrorAbort(state, "first arg to %s() must be string", name); FreeValue(key); return NULL; } Value* image = EvaluateValue(state, argv[1]); if (image == NULL) { FreeValue(key); // must always free Value objects return NULL; } if (image->type != VAL_BLOB) { ErrorAbort(state, "second arg to %s() must be blob", name); FreeValue(key); FreeValue(image) return NULL; }
Checking for NULL and freeing previously evaluated arguments can get tedious for multiple arguments. The ReadValueArgs()
function can make this easier. Instead of the code above, you could have written this:
Value* key; Value* image; if (ReadValueArgs(state, argv, 2, &key, &image) != 0) { return NULL; // ReadValueArgs() will have set the error message } if (key->type != VAL_STRING || image->type != VAL_BLOB) { ErrorAbort(state, "arguments to %s() have wrong type", name); FreeValue(key); FreeValue(image) return NULL; }
ReadValueArgs()
doesn't do type-checking, so you must do that here; it's more convenient to do it with one if statement at the cost of producing a somewhat less specific error message when it fails. But ReadValueArgs()
does handle evaluating each argument and freeing all the previously-evaluated arguments (as well as setting a useful error message) if any of the evaluations fail. You can use a ReadValueVarArgs()
convenience function for evaluating a variable number of arguments (it returns an array of Value*
).
After evaluating the arguments, do the work of the function:
// key->data is a NUL-terminated string // image->data and image->size define a block of binary data // // ... some device-specific magic here to // reprogram the tardis using those two values ...
The return value must be a Value*
object; ownership of this object will pass to the caller. The caller takes ownership of any data pointed to by this Value*
—specifically the datamember.
In this instance, you want to return a true or false value to indicate success. Remember the convention that the empty string is false and all other strings are true . You must malloc a Value object with a malloc'd copy of the constant string to return, since the caller will free()
both. Don't forget to call FreeValue()
on the objects you got by evaluating your arguments!
FreeValue(key); FreeValue(image); Value* result = malloc(sizeof(Value)); result->type = VAL_STRING; result->data = strdup(successful ? "t" : ""); result->size = strlen(result->data); return result; }
The convenience function StringValue()
wraps a string into a new Value object. Use to write the above code more succinctly:
FreeValue(key); FreeValue(image); return StringValue(strdup(successful ? "t" : "")); }
To hook functions into the edify interpreter, provide the function Register_ foo
where foo is the name of the static library containing this code. Call RegisterFunction()
to register each extension function. By convention, name device-specific functions device . whatever
to avoid conflicts with future built-in functions added.
void Register_librecovery_updater_tardis() { RegisterFunction("tardis.reprogram", ReprogramTardisFn); }
You can now configure the makefile to build a static library with your code. (This is the same makefile used to customize the recovery UI in the previous section; your device may have both static libraries defined here.)
device/yoyodyne/tardis/recovery/Android.mk
include $(CLEAR_VARS) LOCAL_SRC_FILES := recovery_updater.c LOCAL_C_INCLUDES += bootable/recovery
The name of the static library must match the name of the Register_ libname
function contained within it.
LOCAL_MODULE := librecovery_updater_tardis include $(BUILD_STATIC_LIBRARY)
Finally, configure the build of recovery to pull in your library. Add your library to TARGET_RECOVERY_UPDATER_LIBS (which may contain multiple libraries; they all get registered). If your code depends on other static libraries that are not themselves edify extensions (ie, they don't have a Register_ libname
function), you can list those in TARGET_RECOVERY_UPDATER_EXTRA_LIBS to link them to updater without calling their (non-existent) registration function. For example, if your device-specific code wanted to use zlib to decompress data, you would include libz here.
device/yoyodyne/tardis/BoardConfig.mk
[...] # add device-specific extensions to the updater binary TARGET_RECOVERY_UPDATER_LIBS += librecovery_updater_tardis TARGET_RECOVERY_UPDATER_EXTRA_LIBS +=
The updater scripts in your OTA package can now call your function as any other. To reprogram your tardis device, the update script might contain: tardis.reprogram("the-key", package_extract_file("tardis-image.dat"))
. This uses the single-argument version of the built-in function package_extract_file()
, which returns the contents of a file extracted from the update package as a blob to produce the second argument to the new extension function.
OTA package generation
The final component is getting the OTA package generation tools to know about your device-specific data and emit updater scripts that include calls to your extension functions.
First, get the build system to know about a device-specific blob of data. Assuming your data file is in device/yoyodyne/tardis/tardis.dat
, declare the following in your device's AndroidBoard.mk:
device/yoyodyne/tardis/AndroidBoard.mk
[...] $(call add-radio-file,tardis.dat)
You could also put it in an Android.mk instead, but then it must to be guarded by a device check, since all the Android.mk files in the tree are loaded no matter what device is being built. (If your tree includes multiple devices, you only want the tardis.dat file added when building the tardis device.)
device/yoyodyne/tardis/Android.mk
[...] # an alternative to specifying it in AndroidBoard.mk ifeq (($TARGET_DEVICE),tardis) $(call add-radio-file,tardis.dat) endif
These are called radio files for historical reasons; they may have nothing to do with the device radio (if present). They are simply opaque blobs of data the build system copies into the target-files .zip used by the OTA generation tools. When you do a build, tardis.dat is stored in the target-files.zip as RADIO/tardis.dat
. You can call add-radio-file
multiple times to add as many files as you want.
পাইথন মডিউল
To extend the release tools, write a Python module (must be named releasetools.py) the tools can call into if present. উদাহরণ:
device/yoyodyne/tardis/releasetools.py
import common def FullOTA_InstallEnd(info): # copy the data into the package. tardis_dat = info.input_zip.read("RADIO/tardis.dat") common.ZipWriteStr(info.output_zip, "tardis.dat", tardis_dat) # emit the script code to install this data on the device info.script.AppendExtra( """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
A separate function handles the case of generating an incremental OTA package. For this example, suppose you need to reprogram the tardis only when the tardis.dat file has changed between two builds.
def IncrementalOTA_InstallEnd(info): # copy the data into the package. source_tardis_dat = info.source_zip.read("RADIO/tardis.dat") target_tardis_dat = info.target_zip.read("RADIO/tardis.dat") if source_tardis_dat == target_tardis_dat: # tardis.dat is unchanged from previous build; no # need to reprogram it return # include the new tardis.dat in the OTA package common.ZipWriteStr(info.output_zip, "tardis.dat", target_tardis_dat) # emit the script code to install this data on the device info.script.AppendExtra( """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
মডিউল ফাংশন
You can provide the following functions in the module (implement only the ones you need).
-
FullOTA_Assertions()
- Called near the start of generating a full OTA. This is a good place to emit assertions about the current state of the device. Do not emit script commands that make changes to the device.
-
FullOTA_InstallBegin()
- Called after all the assertions about the device state have passed but before any changes have been made. You can emit commands for device-specific updates that must run before anything else on the device has been changed.
-
FullOTA_InstallEnd()
- Called at the end of the script generation, after the script commands to update the boot and system partitions have been emitted. You can also emit additional commands for device-specific updates.
-
IncrementalOTA_Assertions()
- Similar to
FullOTA_Assertions()
but called when generating an incremental update package. -
IncrementalOTA_VerifyBegin()
- Called after all assertions about the device state have passed but before any changes have been made. You can emit commands for device-specific updates that must run before anything else on the device has been changed.
-
IncrementalOTA_VerifyEnd()
- Called at the end of the verification phase, when the script has finished confirming the files it is going to touch have the expected starting contents. At this point nothing on the device has been changed. You can also emit code for additional device-specific verifications.
-
IncrementalOTA_InstallBegin()
- Called after files to be patched have been verified as having the expected before state but before any changes have been made. You can emit commands for device-specific updates that must run before anything else on the device has been changed.
-
IncrementalOTA_InstallEnd()
- Similar to its full OTA package counterpart, this is called at the end of the script generation, after the script commands to update the boot and system partitions have been emitted. You can also emit additional commands for device-specific updates.
Note: If the device loses power, OTA installation may restart from the beginning. Be prepared to cope with devices on which these commands have already been run, fully or partially.
Pass functions to info objects
Pass functions to a single info object that contains various useful items:
- info.input_zip . (Full OTAs only) The
zipfile.ZipFile
object for the input target-files .zip. - info.source_zip . (Incremental OTAs only) The
zipfile.ZipFile
object for the source target-files .zip (the build already on the device when the incremental package is being installed). - info.target_zip . (Incremental OTAs only) The
zipfile.ZipFile
object for the target target-files .zip (the build the incremental package puts on the device). - info.output_zip . Package being created; a
zipfile.ZipFile
object opened for writing. Use common.ZipWriteStr(info.output_zip, filename , data ) to add a file to the package. - info.script . Script object to which you can append commands. Call
info.script.AppendExtra( script_text )
to output text into the script. Make sure output text ends with a semicolon so it does not run into commands emitted afterwards.
For details on the info object, refer to the Python Software Foundation documentation for ZIP archives .
Specify module location
Specify the location of your device's releasetools.py script in your BoardConfig.mk file:
device/yoyodyne/tardis/BoardConfig.mk
[...] TARGET_RELEASETOOLS_EXTENSIONS := device/yoyodyne/tardis
If TARGET_RELEASETOOLS_EXTENSIONS is not set, it defaults to the $(TARGET_DEVICE_DIR)/../common
directory ( device/yoyodyne/common
in this example). It's best to explicitly define the location of the releasetools.py script. When building the tardis device, the releasetools.py script is included in the target-files .zip file ( META/releasetools.py
).
When you run the release tools (either img_from_target_files
or ota_from_target_files
), the releasetools.py script in the target-files .zip, if present, is preferred over the one from the Android source tree. You can also explicitly specify the path to the device-specific extensions with the -s
(or --device_specific
) option, which takes the top priority. This enables you to correct errors and make changes in the releasetools extensions and apply those changes to old target-files.
Now, when you run ota_from_target_files
, it automatically picks up the device-specific module from the target_files .zip file and uses it when generating OTA packages:
./build/make/tools/releasetools/ota_from_target_files \
-i PREVIOUS-tardis-target_files.zip \
dist_output/tardis-target_files.zip \
incremental_ota_update.zip
Alternatively, you can specify device-specific extensions when you run ota_from_target_files
.
./build/make/tools/releasetools/ota_from_target_files \
-s device/yoyodyne/tardis \
-i PREVIOUS-tardis-target_files.zip \
dist_output/tardis-target_files.zip \
incremental_ota_update.zip
Note: For a complete list of options, refer to the ota_from_target_files
comments in build/make/tools/releasetools/ota_from_target_files
.
Sideloading mechanism
Recovery has a sideloading mechanism for manually installing an update package without downloading it over-the-air by the main system. Sideloading is useful for debugging or making changes on devices where the main system can't be booted.
Historically, sideloading has been done through loading packages off the device's SD card; in the case of a non-booting device, the package can be put onto the SD card using some other computer and then the SD card inserted into the device. To accommodate Android devices without removable external storage, recovery supports two additional mechanisms for sideloading: loading packages from the cache partition, and loading them over USB using adb.
To invoke each sideload mechanism, your device's Device::InvokeMenuItem()
method can return the following values of BuiltinAction:
- APPLY_EXT . Sideload an update package from external storage (
/sdcard
directory). Your recovery.fstab must define the/sdcard
mount point. This is not usable on devices that emulate an SD card with a symlink to/data
(or some similar mechanism)./data
is typically not available to recovery because it may be encrypted. The recovery UI displays a menu of .zip files in/sdcard
and allows the user to select one. - APPLY_CACHE . Similar to loading a package from
/sdcard
except that the/cache
directory (which is always available to recovery) is used instead. From the regular system,/cache
is only writable by privileged users, and if the device isn't bootable then the/cache
directory can't be written to at all (which makes this mechanism of limited utility). - APPLY_ADB_SIDELOAD . Allows user to send a package to the device via a USB cable and the adb development tool. When this mechanism is invoked, recovery starts up its own mini version of the adbd daemon to let adb on a connected host computer talk to it. This mini version supports only a single command:
adb sideload filename
. The named file is sent from the host machine to the device, which then verifies and installs it just as if it had been on local storage.
কয়েকটি সতর্কতা:
- Only USB transport is supported.
- If your recovery runs adbd normally (usually true for userdebug and eng builds), that will be shut down while the device is in adb sideload mode and will be restarted when adb sideload has finished receiving a package. While in adb sideload mode, no adb commands other than
sideload
work (logcat
,reboot
,push
,pull
,shell
, etc. all fail). - You cannot exit adb sideload mode on the device. To abort, you can send
/dev/null
(or anything else that's not a valid package) as the package, and then the device will fail to verify it and stop the installation procedure. The RecoveryUI implementation'sCheckKey()
method will continue to be called for keypresses, so you can provide a key sequence that reboots the device and works in adb sideload mode.
The recovery system includes several hooks for inserting device-specific code so that OTA updates can also update parts of the device other than the Android system (eg, the baseband or radio processor).
The following sections and examples customize the tardis device produced by the yoyodyne vendor.
পার্টিশন মানচিত্র
As of Android 2.3, the platform supports eMMc flash devices and the ext4 filesystem that runs on those devices. It also supports Memory Technology Device (MTD) flash devices and the yaffs2 filesystem from older releases.
The partition map file is specified by TARGET_RECOVERY_FSTAB; this file is used by both the recovery binary and the package-building tools. You can specify the name of the map file in TARGET_RECOVERY_FSTAB in BoardConfig.mk.
A sample partition map file might look like this:
device/yoyodyne/tardis/recovery.fstab
# mount point fstype device [device2] [options (3.0+ only)] /sdcard vfat /dev/block/mmcblk0p1 /dev/block/mmcblk0 /cache yaffs2 cache /misc mtd misc /boot mtd boot /recovery emmc /dev/block/platform/s3c-sdhci.0/by-name/recovery /system ext4 /dev/block/platform/s3c-sdhci.0/by-name/system length=-4096 /data ext4 /dev/block/platform/s3c-sdhci.0/by-name/userdata
With the exception of /sdcard
, which is optional, all mount points in this example must be defined (devices may also add extra partitions). There are five supported filesystem types:
- yaffs2
- A yaffs2 filesystem atop an MTD flash device. "device" must be the name of the MTD partition and must appear in
/proc/mtd
. - mtd
- A raw MTD partition, used for bootable partitions such as boot and recovery. MTD is not actually mounted, but the mount point is used as a key to locate the partition. "device" must be the name of the MTD partition in
/proc/mtd
. - ext4
- An ext4 filesystem atop an eMMc flash device. "device" must be the path of the block device.
- emmc
- A raw eMMc block device, used for bootable partitions such as boot and recovery. Similar to the mtd type, eMMc is never actually mounted, but the mount point string is used to locate the device in the table.
- vfat
- A FAT filesystem atop a block device, typically for external storage such as an SD card. The device is the block device; device2 is a second block device the system attempts to mount if mounting the primary device fails (for compatibility with SD cards which may or may not be formatted with a partition table).
All partitions must be mounted in the root directory (ie the mount point value must begin with a slash and have no other slashes). This restriction applies only to mounting filesystems in recovery; the main system is free to mount them anywhere. The directories
/boot
,/recovery
, and/misc
should be raw types (mtd or emmc), while the directories/system
,/data
,/cache
, and/sdcard
(if available) should be filesystem types (yaffs2, ext4, or vfat).
Starting in Android 3.0, the recovery.fstab file gains an additional optional field, options . Currently the only defined option is length , which lets you explicitly specify the length of the partition. This length is used when reformatting the partition (eg, for the userdata partition during a data wipe/factory reset operation, or for the system partition during installation of a full OTA package). If the length value is negative, then the size to format is taken by adding the length value to the true partition size. For instance, setting "length=-16384" means the last 16k of that partition will not be overwritten when that partition is reformatted. This supports features such as encryption of the userdata partition (where encryption metadata is stored at the end of the partition that should not be overwritten).
Note: The device2 and options fields are optional, creating ambiguity in parsing. If the entry in the fourth field on the line begins with a '/' character, it is considered a device2 entry; if the entry does not begin with a '/' character, it is considered an options field.
বুট অ্যানিমেশন
Device manufacturers have the ability to customize the animation shown when an Android device is booting. To do this, construct a .zip file organized and located according to the specifications in bootanimation format .
For Android Things devices, you may upload the zipped file in the Android Things console to have the images included in the selected product.
Note: These images must meet Android brand guidelines. For brand guidelines, refer to the Android section of the Partner Marketing Hub .
Recovery UI
To support devices with different available hardware (physical buttons, LEDs, screens, etc.), you can customize the recovery interface to display status and access the manually-operated hidden features for each device.
Your goal is to build a small static library with a couple of C++ objects to provide the device-specific functionality. The file bootable/recovery/default_device.cpp
is used by default, and makes a good starting point to copy when writing a version of this file for your device.
Note: You might see a message saying No Command here. To toggle text, hold the power button while you hit the volume up button. If your devices doesn't have both buttons, long press any button to toggle text.
device/yoyodyne/tardis/recovery/recovery_ui.cpp
#include <linux/input.h> #include "common.h" #include "device.h" #include "screen_ui.h"
Header and item functions
The Device class requires functions for returning headers and items that appear in the hidden recovery menu. Headers describe how to operate the menu (ie controls to change/select the highlighted item).
static const char* HEADERS[] = { "Volume up/down to move highlight;", "power button to select.", "", NULL }; static const char* ITEMS[] = {"reboot system now", "apply update from ADB", "wipe data/factory reset", "wipe cache partition", NULL };
Note: Long lines are truncated (not wrapped), so keep the width of your device screen in mind.
Customize CheckKey
Next, define your device's RecoveryUI implementation. This example assumes the tardis device has a screen, so you can inherit from the built-in ScreenRecoveryUIimplementation (see instructions for devices without a screen .) The only function to customize from ScreenRecoveryUI is CheckKey()
, which does the initial asynchronous key handling:
class TardisUI : public ScreenRecoveryUI { public: virtual KeyAction CheckKey(int key) { if (key == KEY_HOME) { return TOGGLE; } return ENQUEUE; } };
KEY constants
The KEY_* constants are defined in linux/input.h
. CheckKey()
is called no matter what is going on in the rest of recovery: when the menu is toggled off, when it is on, during package installation, during userdata wiping, etc. It can return one of four constants:
- TOGGLE . Toggle the display of the menu and/or text log on or off
- REBOOT . Immediately reboot the device
- IGNORE . Ignore this keypress
- ENQUEUE . Enqueue this keypress to be consumed synchronously (ie, by the recovery menu system if the display is enabled)
CheckKey()
is called each time a key-down event is followed by a key-up event for the same key. (The sequence of events A-down B-down B-up A-up results only in CheckKey(B)
being called.) CheckKey()
can call IsKeyPressed()
, to find out if other keys are being held down. (In the above sequence of key events, if CheckKey(B)
called IsKeyPressed(A)
it would have returned true.)
CheckKey()
can maintain state in its class; this can be useful to detect sequences of keys. This example shows a slightly more complex setup: the display is toggled by holding down power and pressing volume-up, and the device can be rebooted immediately by pressing the power button five times in a row (with no other intervening keys):
class TardisUI : public ScreenRecoveryUI { private: int consecutive_power_keys; public: TardisUI() : consecutive_power_keys(0) {} virtual KeyAction CheckKey(int key) { if (IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) { return TOGGLE; } if (key == KEY_POWER) { ++consecutive_power_keys; if (consecutive_power_keys >= 5) { return REBOOT; } } else { consecutive_power_keys = 0; } return ENQUEUE; } };
ScreenRecoveryUI
When using your own images (error icon, installation animation, progress bars) with ScreenRecoveryUI, you can set the variable animation_fps
to control the speed in frames per second (FPS) of animations.
Note: The current interlace-frames.py
script enables you to store the animation_fps
information in the image itself. In earlier versions of Android it was necessary to set animation_fps
yourself.
To set the variable animation_fps
, override the ScreenRecoveryUI::Init()
function in your subclass. Set the value, then call the parent Init()
function to complete initialization. The default value (20 FPS) corresponds to the default recovery images; when using these images you don't need to provide an Init()
function. For details on images, see Recovery UI Images .
ডিভাইস ক্লাস
After you have a RecoveryUI implementation, define your device class (subclassed from the built-in Device class). It should create a single instance of your UI class and return that from the GetUI()
function:
class TardisDevice : public Device { private: TardisUI* ui; public: TardisDevice() : ui(new TardisUI) { } RecoveryUI* GetUI() { return ui; }
StartRecovery
The StartRecovery()
method is called at the start of recovery, after the UI has been initialized and after the arguments have been parsed, but before any action has been taken. The default implementation does nothing, so you do not need to provide this in your subclass if you have nothing to do:
void StartRecovery() { // ... do something tardis-specific here, if needed .... }
Supply and manage recovery menu
The system calls two methods to get the list of header lines and the list of items. In this implementation, it returns the static arrays defined at the top of the file:
const char* const* GetMenuHeaders() { return HEADERS; } const char* const* GetMenuItems() { return ITEMS; }
HandleMenuKey
Next, provide a HandleMenuKey()
function, which takes a keypress and the current menu visibility, and decides what action to take:
int HandleMenuKey(int key, int visible) { if (visible) { switch (key) { case KEY_VOLUMEDOWN: return kHighlightDown; case KEY_VOLUMEUP: return kHighlightUp; case KEY_POWER: return kInvokeItem; } } return kNoAction; }
The method takes a key code (which has previously been processed and enqueued by the CheckKey()
method of the UI object), and the current state of the menu/text log visibility. ফেরত মান একটি পূর্ণসংখ্যা. If the value is 0 or higher, that is taken as the position of a menu item, which is invoked immediately (see the InvokeMenuItem()
method below). Otherwise it can be one of the following predefined constants:
- kHighlightUp . Move the menu highlight to the previous item
- kHighlightDown . Move the menu highlight to the next item
- kInvokeItem . Invoke the currently highlighted item
- kNoAction . Do nothing with this keypress
As implied by the visible argument, HandleMenuKey()
is called even if the menu is not visible. Unlike CheckKey()
, it is not called while recovery is doing something such as wiping data or installing a package—it's called only when recovery is idle and waiting for input.
Trackball mechanisms
If your device has a trackball-like input mechanism (generates input events with type EV_REL and code REL_Y), recovery synthesizes KEY_UP and KEY_DOWN keypresses whenever the trackball-like input device reports motion in the Y axis. All you need to do is map KEY_UP and KEY_DOWN events onto menu actions. This mapping does not happen for CheckKey()
, so you can't use trackball motions as triggers for rebooting or toggling the display.
পরিবর্তনকারী কী
To check for keys being held down as modifiers, call the IsKeyPressed()
method of your own UI object. For example, on some devices pressing Alt-W in recovery would start a data wipe whether the menu was visible or not. YOu could implement like this:
int HandleMenuKey(int key, int visible) { if (ui->IsKeyPressed(KEY_LEFTALT) && key == KEY_W) { return 2; // position of the "wipe data" item in the menu } ... }
Note: If visible is false, it doesn't make sense to return the special values that manipulate the menu (move highlight, invoke highlighted item) since the user can't see the highlight. However, you can return the values if desired.
InvokeMenuItem
Next, provide an InvokeMenuItem()
method that maps integer positions in the array of items returned by GetMenuItems()
to actions. For the array of items in the tardis example, use:
BuiltinAction InvokeMenuItem(int menu_position) { switch (menu_position) { case 0: return REBOOT; case 1: return APPLY_ADB_SIDELOAD; case 2: return WIPE_DATA; case 3: return WIPE_CACHE; default: return NO_ACTION; } }
This method can return any member of the BuiltinAction enum to tell the system to take that action (or the NO_ACTION member if you want the system to do nothing). This is the place to provide additional recovery functionality beyond what's in the system: Add an item for it in your menu, execute it here when that menu item is invoked, and return NO_ACTION so the system does nothing else.
BuiltinAction contains the following values:
- NO_ACTION . কিছুই করবেন না।
- REBOOT . Exit recovery and reboot the device normally.
- APPLY_EXT, APPLY_CACHE, APPLY_ADB_SIDELOAD . Install an update package from various places. For details, see Sideloading .
- WIPE_CACHE . Reformat the cache partition only. No confirmation required as this is relatively harmless.
- WIPE_DATA . Reformat the userdata and cache partitions, also known as a factory data reset. The user is asked to confirm this action before proceeding.
The last method, WipeData()
, is optional and is called whenever a data wipe operation is initiated (either from recovery via the menu or when the user has chosen to do a factory data reset from the main system). This method is called before the user data and cache partitions are wiped. If your device stores user data anywhere other than those two partitions, you should erase it here. You should return 0 to indicate success and another value for failure, though currently the return value is ignored. The user data and cache partitions are wiped whether you return success or failure.
int WipeData() { // ... do something tardis-specific here, if needed .... return 0; }
Make device
Finally, include some boilerplate at the end of the recovery_ui.cpp file for the make_device()
function that creates and returns an instance of your Device class:
class TardisDevice : public Device { // ... all the above methods ... }; Device* make_device() { return new TardisDevice(); }
Build and link to device recovery
After completing the recovery_ui.cpp file, built it and link it to recovery on your device. In Android.mk, create a static library that contains only this C++ file:
device/yoyodyne/tardis/recovery/Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := eng LOCAL_C_INCLUDES += bootable/recovery LOCAL_SRC_FILES := recovery_ui.cpp # should match TARGET_RECOVERY_UI_LIB set in BoardConfig.mk LOCAL_MODULE := librecovery_ui_tardis include $(BUILD_STATIC_LIBRARY)
Then, in the board configuration for this device, specify your static library as the value of TARGET_RECOVERY_UI_LIB.
device/yoyodyne/tardis/BoardConfig.mk [...] # device-specific extensions to the recovery UI TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis
Recovery UI images
The recovery user interface consists of images. Ideally, users never interact with the UI: During a normal update, the phone boots into recovery, fills the installation progress bar, and boots back into the new system without input from the user. In the event of a system update problem, the only user action that can be taken is to call customer care.
An image-only interface obviates the need for localization. However, as of Android 5.0 the update can display a string of text (eg "Installing system update...") along with the image. For details, see Localized recovery text .
Android 5.0 এবং পরবর্তী
The Android 5.0 and later recovery UI uses two main images: the error image and the installing animation.
![]() Figure 1. icon_error.png | ![]() Figure 2. icon_installing.png |
The installing animation is represented as a single PNG image with different frames of the animation interlaced by row (which is why Figure 2 appears squished). For example, for a 200x200 seven-frame animation, create a single 200x1400 image where first frame is rows 0, 7, 14, 21, ...; the second frame is rows 1, 8, 15, 22, ...; etc. The combined image includes a text chunk that indicates the number of animation frames and the number of frames per second (FPS). The tool bootable/recovery/interlace-frames.py
takes a set of input frames and combines them into the necessary composite image used by recovery.
Default images are available in different densities and are located in bootable/recovery/res-$DENSITY/images
(eg, bootable/recovery/res-hdpi/images
). To use a static image during installation, you need only provide the icon_installing.png image and set the number of frames in the animation to 0 (the error icon is not animated; it is always a static image).
Android 4.x and earlier
The Android 4.x and earlier recovery UI uses the error image (shown above) and the installing animation plus several overlay images:
![]() Figure 3. icon_installing.png | ![]() Figure 4. icon-installing_overlay01.png |
![]() Figure 5. icon_installing_overlay07.png |
During installation, the on-screen display is constructed by drawing the icon_installing.png image, then drawing one of the overlay frames on top of it at the proper offset. Here, a red box is superimposed to highlight where the overlay is placed on top of the base image:
![]() Figure 6. Installing animation frame 1 (icon_installing.png + icon_installing_overlay01.png) | ![]() Figure 7. Installing animation frame 7 (icon_installing.png + icon_installing_overlay07.png) |
Subsequent frames are displayed by drawing only the next overlay image atop what's already there; the base image is not redrawn.
The number of frames in the animation, desired speed, and x- and y-offsets of the overlay relative to the base are set by member variables of the ScreenRecoveryUI class. When using custom images instead of default images, override the Init()
method in your subclass to change these values for your custom images (for details, see ScreenRecoveryUI ). The script bootable/recovery/make-overlay.py
can assist in converting a set of image frames to the "base image + overlay images" form needed by recovery, including computing of the necessary offsets.
Default images are located in bootable/recovery/res/images
. To use a static image during installation, you need only provide the icon_installing.png image and set the number of frames in the animation to 0 (the error icon is not animated; it is always a static image).
Localized recovery text
Android 5.x displays a string of text (eg, "Installing system update...") along with the image. When the main system boots into recovery it passes the user's current locale as a command-line option to recovery. For each message to display, recovery includes a second composite image with pre-rendered text strings for that message in each locale.
Sample image of recovery text strings:

Figure 8. Localized text for recovery messages
Recovery text can display the following messages:
- Installing system update...
- ত্রুটি!
- Erasing... (when doing a data wipe/factory reset)
- No command (when a user boots into recovery manually)
The Android app in bootable/recovery/tools/recovery_l10n/
renders localizations of a message and creates the composite image. For details on using this app, refer to the comments in bootable/recovery/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java
.
When a user boots into recovery manually, the locale might not be available and no text is displayed. Do not make the text messages critical to the recovery process.
Note: The hidden interface that displays log messages and allows the user to select actions from the menu is available only in English.
অগ্রগতি বার
Progress bars can appear below the main image (or animation). The progress bar is made by combining two input images, which must be of the same size:

Figure 9. progress_empty.png

Figure 10. progress_fill.png
The left end of the fill image is displayed next to the right end of the empty image to make the progress bar. The position of the boundary between the two images is changed to indicate the progress. For example, with the above pairs of input images, display:

Figure 11. Progress bar at 1%>

Figure 12. Progress bar at 10%

Figure 13. Progress bar at 50%
You can provide device-specific versions of these images by placing them into (in this example) device/yoyodyne/tardis/recovery/res/images
. Filenames must match the ones listed above; when a file is found in that directory, the build system uses it in preference to the corresponding default image. Only PNGs in RGB or RGBA format with 8-bit color depth are supported.
Note: In Android 5.x, if the locale is known to recovery and is a right-to-left (RTL) language (Arabic, Hebrew, etc.), the progress bar fills from right to left.
Devices without screens
Not all Android devices have screens. If your device is a headless appliance or has an audio-only interface, you may need to do more extensive customization of recovery UI. Instead of creating a subclass of ScreenRecoveryUI, subclass its parent class RecoveryUI directly.
RecoveryUI has methods for handling a lower-level UI operations such as "toggle the display," "update the progress bar," "show the menu," "change the menu selection," etc. You can override these to provide an appropriate interface for your device. Maybe your device has LEDs where you can use different colors or patterns of flashing to indicate state, or maybe you can play audio. (Perhaps you don't want to support a menu or the "text display" mode at all; you can prevent accessing them with CheckKey()
and HandleMenuKey()
implementations that never toggle the display on or select a menu item. In this case, many of the RecoveryUI methods you need to provide can just be empty stubs.)
See bootable/recovery/ui.h
for the declaration of RecoveryUI to see what methods you must support. RecoveryUI is abstract—some methods are pure virtual and must be provided by subclasses—but it does contain the code to do processing of key inputs. You can override that too, if your device doesn't have keys or you want to process them differently.
আপডেটার
You can use device-specific code in the installation of the update package by providing your own extension functions that can be called from within your updater script. Here's a sample function for the tardis device:
device/yoyodyne/tardis/recovery/recovery_updater.c
#include <stdlib.h> #include <string.h> #include "edify/expr.h"
Every extension function has the same signature. The arguments are the name by which the function was called, a State*
cookie, the number of incoming arguments, and an array of Expr*
pointers representing the arguments. The return value is a newly-allocated Value*
.
Value* ReprogramTardisFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); }
Your arguments have not been evaluated at the time your function is called—your function's logic determines which of them get evaluated and how many times. Thus, you can use extension functions to implement your own control structures. Call Evaluate()
to evaluate an Expr*
argument, returning a Value*
. If Evaluate()
returns NULL, you should free any resources you're holding and immediately return NULL (this propagates aborts up the edify stack). Otherwise, you take ownership of the Value returned and are responsible for eventually calling FreeValue()
on it.
Suppose the function needs two arguments: a string-valued key and a blob-valued image . You could read arguments like this:
Value* key = EvaluateValue(state, argv[0]); if (key == NULL) { return NULL; } if (key->type != VAL_STRING) { ErrorAbort(state, "first arg to %s() must be string", name); FreeValue(key); return NULL; } Value* image = EvaluateValue(state, argv[1]); if (image == NULL) { FreeValue(key); // must always free Value objects return NULL; } if (image->type != VAL_BLOB) { ErrorAbort(state, "second arg to %s() must be blob", name); FreeValue(key); FreeValue(image) return NULL; }
Checking for NULL and freeing previously evaluated arguments can get tedious for multiple arguments. The ReadValueArgs()
function can make this easier. Instead of the code above, you could have written this:
Value* key; Value* image; if (ReadValueArgs(state, argv, 2, &key, &image) != 0) { return NULL; // ReadValueArgs() will have set the error message } if (key->type != VAL_STRING || image->type != VAL_BLOB) { ErrorAbort(state, "arguments to %s() have wrong type", name); FreeValue(key); FreeValue(image) return NULL; }
ReadValueArgs()
doesn't do type-checking, so you must do that here; it's more convenient to do it with one if statement at the cost of producing a somewhat less specific error message when it fails. But ReadValueArgs()
does handle evaluating each argument and freeing all the previously-evaluated arguments (as well as setting a useful error message) if any of the evaluations fail. You can use a ReadValueVarArgs()
convenience function for evaluating a variable number of arguments (it returns an array of Value*
).
After evaluating the arguments, do the work of the function:
// key->data is a NUL-terminated string // image->data and image->size define a block of binary data // // ... some device-specific magic here to // reprogram the tardis using those two values ...
The return value must be a Value*
object; ownership of this object will pass to the caller. The caller takes ownership of any data pointed to by this Value*
—specifically the datamember.
In this instance, you want to return a true or false value to indicate success. Remember the convention that the empty string is false and all other strings are true . You must malloc a Value object with a malloc'd copy of the constant string to return, since the caller will free()
both. Don't forget to call FreeValue()
on the objects you got by evaluating your arguments!
FreeValue(key); FreeValue(image); Value* result = malloc(sizeof(Value)); result->type = VAL_STRING; result->data = strdup(successful ? "t" : ""); result->size = strlen(result->data); return result; }
The convenience function StringValue()
wraps a string into a new Value object. Use to write the above code more succinctly:
FreeValue(key); FreeValue(image); return StringValue(strdup(successful ? "t" : "")); }
To hook functions into the edify interpreter, provide the function Register_ foo
where foo is the name of the static library containing this code. Call RegisterFunction()
to register each extension function. By convention, name device-specific functions device . whatever
to avoid conflicts with future built-in functions added.
void Register_librecovery_updater_tardis() { RegisterFunction("tardis.reprogram", ReprogramTardisFn); }
You can now configure the makefile to build a static library with your code. (This is the same makefile used to customize the recovery UI in the previous section; your device may have both static libraries defined here.)
device/yoyodyne/tardis/recovery/Android.mk
include $(CLEAR_VARS) LOCAL_SRC_FILES := recovery_updater.c LOCAL_C_INCLUDES += bootable/recovery
The name of the static library must match the name of the Register_ libname
function contained within it.
LOCAL_MODULE := librecovery_updater_tardis include $(BUILD_STATIC_LIBRARY)
Finally, configure the build of recovery to pull in your library. Add your library to TARGET_RECOVERY_UPDATER_LIBS (which may contain multiple libraries; they all get registered). If your code depends on other static libraries that are not themselves edify extensions (ie, they don't have a Register_ libname
function), you can list those in TARGET_RECOVERY_UPDATER_EXTRA_LIBS to link them to updater without calling their (non-existent) registration function. For example, if your device-specific code wanted to use zlib to decompress data, you would include libz here.
device/yoyodyne/tardis/BoardConfig.mk
[...] # add device-specific extensions to the updater binary TARGET_RECOVERY_UPDATER_LIBS += librecovery_updater_tardis TARGET_RECOVERY_UPDATER_EXTRA_LIBS +=
The updater scripts in your OTA package can now call your function as any other. To reprogram your tardis device, the update script might contain: tardis.reprogram("the-key", package_extract_file("tardis-image.dat"))
. This uses the single-argument version of the built-in function package_extract_file()
, which returns the contents of a file extracted from the update package as a blob to produce the second argument to the new extension function.
OTA package generation
The final component is getting the OTA package generation tools to know about your device-specific data and emit updater scripts that include calls to your extension functions.
First, get the build system to know about a device-specific blob of data. Assuming your data file is in device/yoyodyne/tardis/tardis.dat
, declare the following in your device's AndroidBoard.mk:
device/yoyodyne/tardis/AndroidBoard.mk
[...] $(call add-radio-file,tardis.dat)
You could also put it in an Android.mk instead, but then it must to be guarded by a device check, since all the Android.mk files in the tree are loaded no matter what device is being built. (If your tree includes multiple devices, you only want the tardis.dat file added when building the tardis device.)
device/yoyodyne/tardis/Android.mk
[...] # an alternative to specifying it in AndroidBoard.mk ifeq (($TARGET_DEVICE),tardis) $(call add-radio-file,tardis.dat) endif
These are called radio files for historical reasons; they may have nothing to do with the device radio (if present). They are simply opaque blobs of data the build system copies into the target-files .zip used by the OTA generation tools. When you do a build, tardis.dat is stored in the target-files.zip as RADIO/tardis.dat
. You can call add-radio-file
multiple times to add as many files as you want.
পাইথন মডিউল
To extend the release tools, write a Python module (must be named releasetools.py) the tools can call into if present. উদাহরণ:
device/yoyodyne/tardis/releasetools.py
import common def FullOTA_InstallEnd(info): # copy the data into the package. tardis_dat = info.input_zip.read("RADIO/tardis.dat") common.ZipWriteStr(info.output_zip, "tardis.dat", tardis_dat) # emit the script code to install this data on the device info.script.AppendExtra( """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
A separate function handles the case of generating an incremental OTA package. For this example, suppose you need to reprogram the tardis only when the tardis.dat file has changed between two builds.
def IncrementalOTA_InstallEnd(info): # copy the data into the package. source_tardis_dat = info.source_zip.read("RADIO/tardis.dat") target_tardis_dat = info.target_zip.read("RADIO/tardis.dat") if source_tardis_dat == target_tardis_dat: # tardis.dat is unchanged from previous build; no # need to reprogram it return # include the new tardis.dat in the OTA package common.ZipWriteStr(info.output_zip, "tardis.dat", target_tardis_dat) # emit the script code to install this data on the device info.script.AppendExtra( """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
মডিউল ফাংশন
You can provide the following functions in the module (implement only the ones you need).
-
FullOTA_Assertions()
- Called near the start of generating a full OTA. This is a good place to emit assertions about the current state of the device. Do not emit script commands that make changes to the device.
-
FullOTA_InstallBegin()
- Called after all the assertions about the device state have passed but before any changes have been made. You can emit commands for device-specific updates that must run before anything else on the device has been changed.
-
FullOTA_InstallEnd()
- Called at the end of the script generation, after the script commands to update the boot and system partitions have been emitted. You can also emit additional commands for device-specific updates.
-
IncrementalOTA_Assertions()
- Similar to
FullOTA_Assertions()
but called when generating an incremental update package. -
IncrementalOTA_VerifyBegin()
- Called after all assertions about the device state have passed but before any changes have been made. You can emit commands for device-specific updates that must run before anything else on the device has been changed.
-
IncrementalOTA_VerifyEnd()
- Called at the end of the verification phase, when the script has finished confirming the files it is going to touch have the expected starting contents. At this point nothing on the device has been changed. You can also emit code for additional device-specific verifications.
-
IncrementalOTA_InstallBegin()
- Called after files to be patched have been verified as having the expected before state but before any changes have been made. You can emit commands for device-specific updates that must run before anything else on the device has been changed.
-
IncrementalOTA_InstallEnd()
- Similar to its full OTA package counterpart, this is called at the end of the script generation, after the script commands to update the boot and system partitions have been emitted. You can also emit additional commands for device-specific updates.
Note: If the device loses power, OTA installation may restart from the beginning. Be prepared to cope with devices on which these commands have already been run, fully or partially.
Pass functions to info objects
Pass functions to a single info object that contains various useful items:
- info.input_zip . (Full OTAs only) The
zipfile.ZipFile
object for the input target-files .zip. - info.source_zip . (Incremental OTAs only) The
zipfile.ZipFile
object for the source target-files .zip (the build already on the device when the incremental package is being installed). - info.target_zip . (Incremental OTAs only) The
zipfile.ZipFile
object for the target target-files .zip (the build the incremental package puts on the device). - info.output_zip . Package being created; a
zipfile.ZipFile
object opened for writing. Use common.ZipWriteStr(info.output_zip, filename , data ) to add a file to the package. - info.script . Script object to which you can append commands. Call
info.script.AppendExtra( script_text )
to output text into the script. Make sure output text ends with a semicolon so it does not run into commands emitted afterwards.
For details on the info object, refer to the Python Software Foundation documentation for ZIP archives .
Specify module location
Specify the location of your device's releasetools.py script in your BoardConfig.mk file:
device/yoyodyne/tardis/BoardConfig.mk
[...] TARGET_RELEASETOOLS_EXTENSIONS := device/yoyodyne/tardis
If TARGET_RELEASETOOLS_EXTENSIONS is not set, it defaults to the $(TARGET_DEVICE_DIR)/../common
directory ( device/yoyodyne/common
in this example). It's best to explicitly define the location of the releasetools.py script. When building the tardis device, the releasetools.py script is included in the target-files .zip file ( META/releasetools.py
).
When you run the release tools (either img_from_target_files
or ota_from_target_files
), the releasetools.py script in the target-files .zip, if present, is preferred over the one from the Android source tree. You can also explicitly specify the path to the device-specific extensions with the -s
(or --device_specific
) option, which takes the top priority. This enables you to correct errors and make changes in the releasetools extensions and apply those changes to old target-files.
Now, when you run ota_from_target_files
, it automatically picks up the device-specific module from the target_files .zip file and uses it when generating OTA packages:
./build/make/tools/releasetools/ota_from_target_files \
-i PREVIOUS-tardis-target_files.zip \
dist_output/tardis-target_files.zip \
incremental_ota_update.zip
Alternatively, you can specify device-specific extensions when you run ota_from_target_files
.
./build/make/tools/releasetools/ota_from_target_files \
-s device/yoyodyne/tardis \
-i PREVIOUS-tardis-target_files.zip \
dist_output/tardis-target_files.zip \
incremental_ota_update.zip
Note: For a complete list of options, refer to the ota_from_target_files
comments in build/make/tools/releasetools/ota_from_target_files
.
Sideloading mechanism
Recovery has a sideloading mechanism for manually installing an update package without downloading it over-the-air by the main system. Sideloading is useful for debugging or making changes on devices where the main system can't be booted.
Historically, sideloading has been done through loading packages off the device's SD card; in the case of a non-booting device, the package can be put onto the SD card using some other computer and then the SD card inserted into the device. To accommodate Android devices without removable external storage, recovery supports two additional mechanisms for sideloading: loading packages from the cache partition, and loading them over USB using adb.
To invoke each sideload mechanism, your device's Device::InvokeMenuItem()
method can return the following values of BuiltinAction:
- APPLY_EXT . Sideload an update package from external storage (
/sdcard
directory). Your recovery.fstab must define the/sdcard
mount point. This is not usable on devices that emulate an SD card with a symlink to/data
(or some similar mechanism)./data
is typically not available to recovery because it may be encrypted. The recovery UI displays a menu of .zip files in/sdcard
and allows the user to select one. - APPLY_CACHE . Similar to loading a package from
/sdcard
except that the/cache
directory (which is always available to recovery) is used instead. From the regular system,/cache
is only writable by privileged users, and if the device isn't bootable then the/cache
directory can't be written to at all (which makes this mechanism of limited utility). - APPLY_ADB_SIDELOAD . Allows user to send a package to the device via a USB cable and the adb development tool. When this mechanism is invoked, recovery starts up its own mini version of the adbd daemon to let adb on a connected host computer talk to it. This mini version supports only a single command:
adb sideload filename
. The named file is sent from the host machine to the device, which then verifies and installs it just as if it had been on local storage.
কয়েকটি সতর্কতা:
- Only USB transport is supported.
- If your recovery runs adbd normally (usually true for userdebug and eng builds), that will be shut down while the device is in adb sideload mode and will be restarted when adb sideload has finished receiving a package. While in adb sideload mode, no adb commands other than
sideload
work (logcat
,reboot
,push
,pull
,shell
, etc. all fail). - You cannot exit adb sideload mode on the device. To abort, you can send
/dev/null
(or anything else that's not a valid package) as the package, and then the device will fail to verify it and stop the installation procedure. The RecoveryUI implementation'sCheckKey()
method will continue to be called for keypresses, so you can provide a key sequence that reboots the device and works in adb sideload mode.