ডিভাইস-নির্দিষ্ট কোড

পুনরুদ্ধার সিস্টেমে ডিভাইস-নির্দিষ্ট কোড ঢোকানোর জন্য বেশ কয়েকটি হুক রয়েছে যাতে 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)।

Android 3.0 থেকে শুরু করে, recovery.fstab ফাইলটি একটি অতিরিক্ত ঐচ্ছিক ক্ষেত্র, বিকল্পগুলি লাভ করে। বর্তমানে শুধুমাত্র সংজ্ঞায়িত বিকল্প হল length , যা আপনাকে পার্টিশনের দৈর্ঘ্য স্পষ্টভাবে উল্লেখ করতে দেয়। এই দৈর্ঘ্যটি পার্টিশনটি পুনরায় ফরম্যাট করার সময় ব্যবহার করা হয় (যেমন, ডেটা ওয়াইপ/ফ্যাক্টরি রিসেট অপারেশনের সময় ব্যবহারকারী ডেটা পার্টিশনের জন্য, অথবা সম্পূর্ণ OTA প্যাকেজ ইনস্টল করার সময় সিস্টেম পার্টিশনের জন্য)। যদি দৈর্ঘ্যের মান ঋণাত্মক হয়, তাহলে প্রকৃত পার্টিশনের আকারে দৈর্ঘ্যের মান যোগ করে বিন্যাসের আকার নেওয়া হয়। উদাহরণস্বরূপ, "length=-16384" সেট করার অর্থ হল পার্টিশনটির শেষ 16k ওভাররাইট করা হবে না যখন সেই পার্টিশনটি পুনরায় ফর্ম্যাট করা হয়। এটি ব্যবহারকারী ডেটা পার্টিশনের এনক্রিপশনের মতো বৈশিষ্ট্যগুলিকে সমর্থন করে (যেখানে এনক্রিপশন মেটাডেটা পার্টিশনের শেষে সংরক্ষণ করা হয় যা ওভাররাইট করা উচিত নয়)।

দ্রষ্টব্য: ডিভাইস2 এবং বিকল্প ক্ষেত্রগুলি ঐচ্ছিক, পার্সিংয়ের ক্ষেত্রে অস্পষ্টতা তৈরি করে। যদি লাইনের চতুর্থ ক্ষেত্রের এন্ট্রিটি '/' অক্ষর দিয়ে শুরু হয়, তাহলে এটি একটি device2 এন্ট্রি হিসেবে বিবেচিত হবে; যদি এন্ট্রিটি '/' অক্ষর দিয়ে শুরু না হয় তবে এটি একটি বিকল্প ক্ষেত্র হিসাবে বিবেচিত হয়।

বুট অ্যানিমেশন

ডিভাইস নির্মাতাদের একটি Android ডিভাইস বুট করার সময় দেখানো অ্যানিমেশন কাস্টমাইজ করার ক্ষমতা আছে। এটি করার জন্য, বুটানিমেশন ফরম্যাটে স্পেসিফিকেশন অনুযায়ী সংগঠিত এবং অবস্থিত একটি .zip ফাইল তৈরি করুন।

অ্যান্ড্রয়েড থিংস ডিভাইসগুলির জন্য, নির্বাচিত পণ্যে ছবিগুলি অন্তর্ভুক্ত করার জন্য আপনি 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

এরপরে, একটি 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 নিম্নলিখিত মান ধারণ করে:

  • কোন কর্ম . কিছু করনা.
  • রিবুট করুন । পুনরুদ্ধার থেকে প্রস্থান করুন এবং ডিভাইসটি স্বাভাবিকভাবে রিবুট করুন।
  • APPLY_EXT, APPLY_CACHE, APPLY_ADB_SIDELOAD । বিভিন্ন জায়গা থেকে একটি আপডেট প্যাকেজ ইনস্টল করুন। বিস্তারিত জানার জন্য, সাইডলোডিং দেখুন।
  • গোপন সংগ্রহ মুছে ফেলুন . শুধুমাত্র ক্যাশে পার্টিশন রিফর্ম্যাট করুন। কোন নিশ্চিতকরণের প্রয়োজন নেই কারণ এটি তুলনামূলকভাবে ক্ষতিকারক।
  • মুছে ফেল . ব্যবহারকারীর ডেটা এবং ক্যাশে পার্টিশনগুলিকে পুনরায় ফর্ম্যাট করুন, যা ফ্যাক্টরি ডেটা রিসেট হিসাবেও পরিচিত। ব্যবহারকারীকে এগিয়ে যাওয়ার আগে এই ক্রিয়াটি নিশ্চিত করতে বলা হয়৷

শেষ পদ্ধতি, 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 দুটি প্রধান চিত্র ব্যবহার করে: ত্রুটি চিত্র এবং ইনস্টল করা অ্যানিমেশন।

OTA ত্রুটির সময় দেখানো চিত্র

চিত্র 1. icon_error.png

Ota ইনস্টল করার সময় দেখানো ছবি

চিত্র 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 ত্রুটি চিত্র (উপরে দেখানো হয়েছে) এবং ইনস্টল করা অ্যানিমেশন এবং বেশ কিছু ওভারলে চিত্র ব্যবহার করে:

Ota ইনস্টল করার সময় দেখানো ছবি

চিত্র 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

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

1% এ অগ্রগতি বার

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

অগ্রগতি বার 10%

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

50% এ অগ্রগতি বার

চিত্র 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" : ""));
}

edify ইন্টারপ্রেটারে ফাংশনগুলিকে হুক করতে, 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_filesota_from_target_files মন্তব্যগুলি দেখুন।

সাইডলোডিং মেকানিজম

পুনরুদ্ধারের একটি সাইডলোডিং মেকানিজম রয়েছে যা মূল সিস্টেমের মাধ্যমে ওভার-দ্য-এয়ার ডাউনলোড না করে ম্যানুয়ালি একটি আপডেট প্যাকেজ ইনস্টল করার জন্য। সাইডলোডিং ডিভাইসে ডিবাগিং বা পরিবর্তন করার জন্য দরকারী যেখানে প্রধান সিস্টেম বুট করা যায় না।

ঐতিহাসিকভাবে, ডিভাইসের এসডি কার্ড থেকে প্যাকেজ লোড করার মাধ্যমে সাইডলোডিং করা হয়েছে; একটি নন-বুটিং ডিভাইসের ক্ষেত্রে, প্যাকেজটি অন্য কোনো কম্পিউটার ব্যবহার করে SD কার্ডে রাখা যেতে পারে এবং তারপর ডিভাইসে SD কার্ড ঢোকানো যেতে পারে। অপসারণযোগ্য বাহ্যিক সঞ্চয়স্থান ছাড়াই অ্যান্ড্রয়েড ডিভাইসগুলিকে মিটমাট করতে, পুনরুদ্ধার সাইডলোডিংয়ের জন্য দুটি অতিরিক্ত প্রক্রিয়া সমর্থন করে: ক্যাশে পার্টিশন থেকে প্যাকেজগুলি লোড করা এবং অ্যাডবি ব্যবহার করে USB-এর মাধ্যমে লোড করা৷

প্রতিটি সাইডলোড মেকানিজম চালু করতে, আপনার ডিভাইসের Device::InvokeMenuItem() পদ্ধতি বিল্টিন অ্যাকশনের নিম্নলিখিত মানগুলি ফিরিয়ে দিতে পারে:

  • APPLY_EXT । বাহ্যিক সঞ্চয়স্থান ( /sdcard ডিরেক্টরি) থেকে একটি আপডেট প্যাকেজ সাইডলোড করুন। আপনার recovery.fstab অবশ্যই /sdcard মাউন্ট পয়েন্ট সংজ্ঞায়িত করবে। এটি এমন ডিভাইসগুলিতে ব্যবহারযোগ্য নয় যেগুলি /data (বা কিছু অনুরূপ প্রক্রিয়া) এর সিমলিঙ্ক সহ একটি SD কার্ড অনুকরণ করে৷ /data সাধারণত পুনরুদ্ধারের জন্য উপলভ্য নয় কারণ এটি এনক্রিপ্ট করা যেতে পারে। পুনরুদ্ধার ইউআই /sdcard .zip ফাইলগুলির একটি মেনু প্রদর্শন করে এবং ব্যবহারকারীকে একটি নির্বাচন করতে দেয়।
  • প্রয়োগ_ক্যাচ/sdcard থেকে প্যাকেজ লোড করার অনুরূপ /cache ডিরেক্টরি (যা সর্বদা পুনরুদ্ধারের জন্য উপলব্ধ ) এর পরিবর্তে ব্যবহৃত হয়। নিয়মিত সিস্টেম থেকে, /cache কেবল সুবিধাবঞ্চিত ব্যবহারকারীদের দ্বারা লিখিত হয় এবং যদি ডিভাইসটি বুটেবল না হয় তবে /cache ডিরেক্টরিটি মোটেও লেখা যায় না (যা সীমিত ইউটিলিটির এই প্রক্রিয়াটিকে তৈরি করে)।
  • প্রয়োগ_এডবি_সাইডেলড । ব্যবহারকারীকে একটি ইউএসবি কেবল এবং এডিবি বিকাশ সরঞ্জামের মাধ্যমে ডিভাইসে একটি প্যাকেজ প্রেরণের অনুমতি দেয়। যখন এই প্রক্রিয়াটি আহ্বান করা হয়, তখন কোনও সংযুক্ত হোস্ট কম্পিউটারের সাথে এডিবিকে এটির সাথে আলাপের জন্য এডিবিডি ডেমনের নিজস্ব মিনি সংস্করণটি পুনরুদ্ধার শুরু করে। এই মিনি সংস্করণটি কেবলমাত্র একটি একক কমান্ড সমর্থন করে: adb sideload filename । নামযুক্ত ফাইলটি হোস্ট মেশিন থেকে ডিভাইসে প্রেরণ করা হয়, যা পরে এটি যাচাই করে এবং ইনস্টল করে ঠিক যেমন এটি স্থানীয় স্টোরেজে ছিল।

কয়েকটি সতর্কতা:

  • শুধুমাত্র ইউএসবি পরিবহন সমর্থিত।
  • যদি আপনার পুনরুদ্ধারটি সাধারণত এডিবিডি চালায় (সাধারণত ইউজারডেবাগ এবং ইঞ্জি বিল্ডগুলির জন্য সত্য), ডিভাইসটি এডিবি সাইডেললোড মোডে থাকাকালীন এটি বন্ধ হয়ে যাবে এবং এডিবি সিডেললোড একটি প্যাকেজ গ্রহণ শেষ করার সময় পুনরায় চালু করা হবে। এডিবি সাইডেলোড মোডে থাকাকালীন, কোনও এডিবি sideload কাজ ( logcat , reboot , push , pull , shell ইত্যাদি ব্যতীত অন্য কোনও কমান্ড দেয় না।
  • আপনি ডিভাইসে এডিবি সাইডেললোড মোড থেকে প্রস্থান করতে পারবেন না। বাতিল করার জন্য, আপনি প্যাকেজ হিসাবে /dev/null (বা অন্য যে কোনও কিছু যা বৈধ প্যাকেজ নয়) প্রেরণ করতে পারেন এবং তারপরে ডিভাইসটি এটি যাচাই করতে ব্যর্থ হবে এবং ইনস্টলেশন পদ্ধতিটি বন্ধ করতে পারে। রিকভারিউআইআই বাস্তবায়নের CheckKey() পদ্ধতিটি কীপ্রেসগুলির জন্য কল করা অব্যাহত থাকবে, যাতে আপনি একটি মূল ক্রম সরবরাহ করতে পারেন যা ডিভাইসটিকে পুনরায় বুট করে এবং এডিবি সিডেললোড মোডে কাজ করে।