डिवाइस-विशिष्ट कोड

पुनर्प्राप्ति प्रणाली में डिवाइस-विशिष्ट कोड डालने के लिए कई हुक शामिल हैं ताकि ओटीए अपडेट एंड्रॉइड सिस्टम (उदाहरण के लिए, बेसबैंड या रेडियो प्रोसेसर) के अलावा डिवाइस के हिस्सों को भी अपडेट कर सकें।

निम्नलिखित अनुभाग और उदाहरण योयोडाइन विक्रेता द्वारा निर्मित टार्डिस डिवाइस को अनुकूलित करते हैं।

विभाजन का नक्शा

Android 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 फ़ाइल सिस्टम। "डिवाइस" MTD विभाजन का नाम होना चाहिए और /proc/mtd में प्रदर्शित होना चाहिए।
एम.टी.डी
एक कच्चा MTD विभाजन, बूट और पुनर्प्राप्ति जैसे बूट करने योग्य विभाजन के लिए उपयोग किया जाता है। एमटीडी वास्तव में माउंट नहीं किया गया है, लेकिन माउंट पॉइंट का उपयोग विभाजन का पता लगाने के लिए एक कुंजी के रूप में किया जाता है। "डिवाइस" /proc/mtd में MTD विभाजन का नाम होना चाहिए।
ext4
एक eMMc फ़्लैश डिवाइस के ऊपर एक ext4 फ़ाइल सिस्टम। "डिवाइस" ब्लॉक डिवाइस का पथ होना चाहिए।
ईएमएमसी
एक कच्चा ईएमएमसी ब्लॉक डिवाइस, जिसका उपयोग बूट और रिकवरी जैसे बूट करने योग्य विभाजन के लिए किया जाता है। एमटीडी प्रकार के समान, ईएमएमसी वास्तव में कभी भी माउंट नहीं किया जाता है, लेकिन माउंट पॉइंट स्ट्रिंग का उपयोग तालिका में डिवाइस का पता लगाने के लिए किया जाता है।
vfat
एक ब्लॉक डिवाइस के ऊपर एक FAT फाइल सिस्टम, आमतौर पर एसडी कार्ड जैसे बाहरी स्टोरेज के लिए। डिवाइस ब्लॉक डिवाइस है; डिवाइस 2 एक दूसरा ब्लॉक डिवाइस है जिसे सिस्टम माउंट करने का प्रयास करता है यदि प्राथमिक डिवाइस माउंट करना विफल हो जाता है (एसडी कार्ड के साथ संगतता के लिए जो विभाजन तालिका के साथ स्वरूपित हो भी सकता है और नहीं भी)।

सभी विभाजनों को रूट डायरेक्टरी में माउंट किया जाना चाहिए (अर्थात माउंट पॉइंट मान एक स्लैश से शुरू होना चाहिए और कोई अन्य स्लैश नहीं होना चाहिए)। यह प्रतिबंध केवल पुनर्प्राप्ति में बढ़ते फ़ाइल सिस्टम पर लागू होता है; मुख्य प्रणाली उन्हें कहीं भी स्थापित करने के लिए स्वतंत्र है। निर्देशिकाएं /boot , /recovery , और /misc कच्चे प्रकार (mtd या emmc) होनी चाहिए, जबकि निर्देशिकाएं /system , /data , /cache , और /sdcard (यदि उपलब्ध हो) फाइलसिस्टम प्रकार (yaffs2, ext4, या) होनी चाहिए वीएफएटी)।

एंड्रॉइड 3.0 में शुरू होने पर, पुनर्प्राप्ति.fstab फ़ाइल को एक अतिरिक्त वैकल्पिक फ़ील्ड, विकल्प प्राप्त होता है। वर्तमान में एकमात्र परिभाषित विकल्प length है, जो आपको विभाजन की लंबाई स्पष्ट रूप से निर्दिष्ट करने देता है। इस लंबाई का उपयोग विभाजन को पुन: स्वरूपित करते समय किया जाता है (उदाहरण के लिए, डेटा वाइप/फ़ैक्टरी रीसेट ऑपरेशन के दौरान उपयोगकर्ता डेटा विभाजन के लिए, या पूर्ण ओटीए पैकेज की स्थापना के दौरान सिस्टम विभाजन के लिए)। यदि लंबाई मान ऋणात्मक है, तो वास्तविक विभाजन आकार में लंबाई मान जोड़कर स्वरूपित करने का आकार लिया जाता है। उदाहरण के लिए, "लंबाई=-16384" सेट करने का मतलब है कि उस विभाजन के पुन: स्वरूपित होने पर उस विभाजन का अंतिम 16k अधिलेखित नहीं किया जाएगा। यह उपयोगकर्ता डेटा विभाजन के एन्क्रिप्शन जैसी सुविधाओं का समर्थन करता है (जहां एन्क्रिप्शन मेटाडेटा विभाजन के अंत में संग्रहीत होता है जिसे ओवरराइट नहीं किया जाना चाहिए)।

नोट: डिवाइस2 और विकल्प फ़ील्ड वैकल्पिक हैं, जो पार्सिंग में अस्पष्टता पैदा करते हैं। यदि लाइन पर चौथे फ़ील्ड में प्रविष्टि '/' वर्ण से शुरू होती है, तो इसे डिवाइस2 प्रविष्टि माना जाता है; यदि प्रविष्टि '/' वर्ण से शुरू नहीं होती है, तो इसे एक विकल्प फ़ील्ड माना जाता है।

बूट एनीमेशन

डिवाइस निर्माताओं के पास एंड्रॉइड डिवाइस बूट होने पर दिखाए गए एनीमेशन को कस्टमाइज़ करने की क्षमता होती है। ऐसा करने के लिए, बूटएनिमेशन प्रारूप में विशिष्टताओं के अनुसार व्यवस्थित और स्थित एक .zip फ़ाइल बनाएं।

एंड्रॉइड थिंग्स डिवाइस के लिए, आप चयनित उत्पाद में छवियों को शामिल करने के लिए एंड्रॉइड थिंग्स कंसोल में ज़िपित फ़ाइल अपलोड कर सकते हैं।

ध्यान दें: इन छवियों को Android ब्रांड दिशानिर्देशों के अनुरूप होना चाहिए।

पुनर्प्राप्ति यूआई

विभिन्न उपलब्ध हार्डवेयर (भौतिक बटन, एलईडी, स्क्रीन इत्यादि) वाले उपकरणों का समर्थन करने के लिए, आप स्थिति प्रदर्शित करने और प्रत्येक डिवाइस के लिए मैन्युअल रूप से संचालित छिपी सुविधाओं तक पहुंचने के लिए पुनर्प्राप्ति इंटरफ़ेस को अनुकूलित कर सकते हैं।

आपका लक्ष्य डिवाइस-विशिष्ट कार्यक्षमता प्रदान करने के लिए कुछ 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 };

नोट: लंबी लाइनों को छोटा किया जाता है (लिपटे नहीं), इसलिए अपनी डिवाइस स्क्रीन की चौड़ाई को ध्यान में रखें।

चेककी को अनुकूलित करें

इसके बाद, अपने डिवाइस के रिकवरीयूआई कार्यान्वयन को परिभाषित करें। यह उदाहरण मानता है कि टार्डिस डिवाइस में एक स्क्रीन है, इसलिए आप अंतर्निहित स्क्रीनरिकवरीयूआई कार्यान्वयन से प्राप्त कर सकते हैं ( स्क्रीन के बिना डिवाइस के लिए निर्देश देखें।) स्क्रीनरिकवरीयूआई से अनुकूलित करने का एकमात्र फ़ंक्शन CheckKey() है, जो प्रारंभिक एसिंक्रोनस कुंजी हैंडलिंग करता है:

class TardisUI : public ScreenRecoveryUI {
  public:
    virtual KeyAction CheckKey(int key) {
        if (key == KEY_HOME) {
            return TOGGLE;
        }
        return ENQUEUE;
    }
};

प्रमुख स्थिरांक

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 के साथ अपनी स्वयं की छवियों (त्रुटि आइकन, इंस्टॉलेशन एनीमेशन, प्रगति बार) का उपयोग करते समय, आप एनिमेशन के फ्रेम प्रति सेकंड (एफपीएस) में गति को नियंत्रित करने के लिए वेरिएबल 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() विधि देखें)। अन्यथा यह निम्नलिखित पूर्वनिर्धारित स्थिरांकों में से एक हो सकता है:

  • kHighlightUp । मेनू हाइलाइट को पिछले आइटम पर ले जाएँ
  • kहाइलाइटडाउन । मेनू हाइलाइट को अगले आइटम पर ले जाएँ
  • kInvokeआइटम । वर्तमान में हाइलाइट किए गए आइटम को आमंत्रित करें
  • kNoAction . इस कीप्रेस के साथ कुछ न करें

जैसा कि दृश्यमान तर्क में निहित है, यदि मेनू दिखाई नहीं दे रहा है तो भी HandleMenuKey() कॉल किया जाता है। CheckKey() के विपरीत, इसे तब कॉल नहीं किया जाता है जब पुनर्प्राप्ति कुछ कर रही हो जैसे कि डेटा मिटाना या पैकेज स्थापित करना - इसे केवल तभी कॉल किया जाता है जब पुनर्प्राप्ति निष्क्रिय हो और इनपुट की प्रतीक्षा कर रही हो।

ट्रैकबॉल तंत्र

यदि आपके डिवाइस में ट्रैकबॉल जैसा इनपुट तंत्र है (ईवी_आरईएल और कोड आरईएल_वाई प्रकार के साथ इनपुट इवेंट उत्पन्न करता है), जब भी ट्रैकबॉल जैसा इनपुट डिवाइस वाई अक्ष में गति की रिपोर्ट करता है तो रिकवरी KEY_UP और KEY_DOWN कुंजी दबाती है। आपको बस मेनू क्रियाओं पर KEY_UP और KEY_DOWN ईवेंट को मैप करना है। यह मैपिंग 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
        }
        ...
    }

ध्यान दें: यदि दृश्य गलत है, तो मेनू में हेरफेर करने वाले विशेष मानों को वापस करने का कोई मतलब नहीं है (हाइलाइट को स्थानांतरित करें, हाइलाइट किए गए आइटम को लागू करें) क्योंकि उपयोगकर्ता हाइलाइट को नहीं देख सकता है। हालाँकि, यदि आप चाहें तो आप मान वापस कर सकते हैं।

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;
        }
    }

यह विधि बिल्टइनएक्शन एनम के किसी भी सदस्य को सिस्टम को वह कार्रवाई करने के लिए कहने के लिए लौटा सकती है (या यदि आप चाहते हैं कि सिस्टम कुछ न करे तो NO_ACTION सदस्य)। यह सिस्टम में मौजूद चीज़ों से परे अतिरिक्त पुनर्प्राप्ति कार्यक्षमता प्रदान करने का स्थान है: अपने मेनू में इसके लिए एक आइटम जोड़ें, उस मेनू आइटम के लागू होने पर इसे यहां निष्पादित करें, और NO_ACTION लौटाएं ताकि सिस्टम कुछ और न करे।

बिल्टइनएक्शन में निम्नलिखित मान शामिल हैं:

  • कोई कार्रवाई नहीं । कुछ भी नहीं है।
  • रीबूट करें । पुनर्प्राप्ति से बाहर निकलें और डिवाइस को सामान्य रूप से रीबूट करें।
  • APPLY_EXT, APPLY_CACHE, APPLY_ADB_SIDELOAD । विभिन्न स्थानों से अद्यतन पैकेज़ स्थापित करें. विवरण के लिए, साइडलोडिंग देखें।
  • कैश पोंछ । केवल कैश विभाजन को पुन: स्वरूपित करें। किसी पुष्टि की आवश्यकता नहीं है क्योंकि यह अपेक्षाकृत हानिरहित है।
  • डेटा मिटा दें । उपयोगकर्ताडेटा और कैश विभाजन को पुन: स्वरूपित करें, जिसे फ़ैक्टरी डेटा रीसेट के रूप में भी जाना जाता है। आगे बढ़ने से पहले उपयोगकर्ता को इस कार्रवाई की पुष्टि करने के लिए कहा जाता है।

अंतिम विधि, WipeData() वैकल्पिक है और जब भी डेटा वाइप ऑपरेशन शुरू किया जाता है तो इसे कॉल किया जाता है (या तो मेनू के माध्यम से पुनर्प्राप्ति से या जब उपयोगकर्ता ने मुख्य सिस्टम से फ़ैक्टरी डेटा रीसेट करना चुना है)। उपयोगकर्ता डेटा और कैश विभाजन मिटाए जाने से पहले इस विधि को कॉल किया जाता है। यदि आपका डिवाइस उन दो विभाजनों के अलावा कहीं भी उपयोगकर्ता डेटा संग्रहीत करता है, तो आपको इसे यहां मिटा देना चाहिए। आपको सफलता दर्शाने के लिए 0 और विफलता के लिए दूसरा मान लौटाना चाहिए, हालांकि वर्तमान में वापसी मान को नजरअंदाज कर दिया जाता है। उपयोगकर्ता डेटा और कैश विभाजन मिटा दिए जाते हैं, चाहे आप सफलता लौटाएँ या विफलता।

   int WipeData() {
       // ... do something tardis-specific here, if needed ....
       return 0;
    }

उपकरण बनाओ

अंत में, make_device() फ़ंक्शन के लिए पुनर्प्राप्ति_ui.cpp फ़ाइल के अंत में कुछ बॉयलरप्लेट शामिल करें जो आपके डिवाइस क्लास का एक उदाहरण बनाता है और लौटाता है:

class TardisDevice : public Device {
   // ... all the above methods ...
};

Device* make_device() {
    return new TardisDevice();
}

पुनर्प्राप्ति_यूआई.सीपीपी फ़ाइल को पूरा करने के बाद, इसे बनाएं और इसे अपने डिवाइस पर पुनर्प्राप्ति से लिंक करें। 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

पुनर्प्राप्ति यूआई छवियाँ

पुनर्प्राप्ति उपयोगकर्ता इंटरफ़ेस में छवियां शामिल हैं। आदर्श रूप से, उपयोगकर्ता कभी भी यूआई के साथ इंटरैक्ट नहीं करते हैं: सामान्य अपडेट के दौरान, फोन रिकवरी में बूट होता है, इंस्टॉलेशन प्रगति बार भरता है, और उपयोगकर्ता से इनपुट के बिना नए सिस्टम में वापस बूट होता है। सिस्टम अपडेट समस्या की स्थिति में, उपयोगकर्ता द्वारा की जाने वाली एकमात्र कार्रवाई ग्राहक सेवा को कॉल करना है।

एक छवि-केवल इंटरफ़ेस स्थानीयकरण की आवश्यकता को समाप्त करता है। हालाँकि, एंड्रॉइड 5.0 के अनुसार अपडेट छवि के साथ टेक्स्ट की एक स्ट्रिंग प्रदर्शित कर सकता है (उदाहरण के लिए "सिस्टम अपडेट इंस्टॉल करना...")। विवरण के लिए, स्थानीयकृत पुनर्प्राप्ति टेक्स्ट देखें।

एंड्रॉइड 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 पर सेट करनी होगी (त्रुटि आइकन एनिमेटेड नहीं है; यह हमेशा एक स्थिर छवि है)।

Android 4.x और इससे पहले का संस्करण

एंड्रॉइड 4.x और पहले के पुनर्प्राप्ति यूआई में त्रुटि छवि (ऊपर दिखाया गया है) और इंस्टॉलिंग एनीमेशन और कई ओवरले छवियों का उपयोग किया जाता है:

ओटीए इंस्टाल के दौरान दिखाई गई छवि

चित्र 3. आइकन_इंस्टॉलिंग.पीएनजी

छवि को पहले ओवरले के रूप में दिखाया गया है

चित्र 4. आइकन-इंस्टॉलिंग_ओवरले01.पीएनजी

छवि को सातवें ओवरले के रूप में दिखाया गया है

चित्र 5. आइकन_इंस्टॉलिंग_ओवरले07.पीएनजी

इंस्टालेशन के दौरान, ऑन-स्क्रीन डिस्प्ले का निर्माण आइकन_इंस्टॉलिंग.पीएनजी छवि को खींचकर किया जाता है, फिर उसके ऊपर उचित ऑफसेट पर एक ओवरले फ्रेम को खींचकर किया जाता है। यहां, आधार छवि के शीर्ष पर जहां ओवरले रखा गया है, उसे उजागर करने के लिए एक लाल बॉक्स लगाया गया है:

इंस्टाल प्लस प्रथम ओवरले की समग्र छवि

चित्र 6. एनीमेशन फ्रेम 1 स्थापित करना (icon_installing.png + आइकन_installing_overlay01.png)

इंस्टाल प्लस सातवें ओवरले की समग्र छवि

चित्र 7. एनीमेशन फ्रेम 7 स्थापित करना (icon_installing.png + आइकन_installing_overlay07.png)

बाद के फ़्रेमों को पहले से मौजूद चीज़ों के ऊपर केवल अगली ओवरले छवि बनाकर प्रदर्शित किया जाता है; आधार छवि दोबारा नहीं बनाई गई है.

एनीमेशन में फ़्रेम की संख्या, वांछित गति और आधार के सापेक्ष ओवरले के x- और y-ऑफ़सेट ScreenRecoveryUI वर्ग के सदस्य चर द्वारा निर्धारित किए जाते हैं। डिफ़ॉल्ट छवियों के बजाय कस्टम छवियों का उपयोग करते समय, अपनी कस्टम छवियों के लिए इन मानों को बदलने के लिए अपने उपवर्ग में Init() विधि को ओवरराइड करें (विवरण के लिए, ScreenRecoveryUI देखें)। स्क्रिप्ट 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. प्रगति_रिक्त.png

पूर्ण प्रगति पट्टी

चित्र 10. प्रगति_भरण.पीएनजी

प्रगति पट्टी बनाने के लिए भरण छवि का बायाँ सिरा खाली छवि के दाएँ छोर के बगल में प्रदर्शित होता है। प्रगति को इंगित करने के लिए दो छवियों के बीच सीमा की स्थिति बदल दी गई है। उदाहरण के लिए, इनपुट छवियों के उपरोक्त जोड़े के साथ, प्रदर्शित करें:

1% पर प्रगति पट्टी

चित्र 11. प्रगति पट्टी 1%> पर

10% पर प्रगति पट्टी

चित्र 12. 10% पर प्रगति पट्टी

50% पर प्रगति पट्टी

चित्र 13. 50% पर प्रगति पट्टी

आप इन छवियों को (इस उदाहरण में) device/yoyodyne/tardis/recovery/res/images में रखकर डिवाइस-विशिष्ट संस्करण प्रदान कर सकते हैं। फ़ाइल नाम ऊपर सूचीबद्ध नाम से मेल खाने चाहिए; जब उस निर्देशिका में कोई फ़ाइल मिलती है, तो बिल्ड सिस्टम संबंधित डिफ़ॉल्ट छवि की प्राथमिकता में इसका उपयोग करता है। केवल 8-बिट रंग गहराई वाले आरजीबी या आरजीबीए प्रारूप में पीएनजी समर्थित हैं।

नोट: एंड्रॉइड 5.x में, यदि लोकेल पुनर्प्राप्ति के लिए जाना जाता है और दाएँ-से-बाएँ (RTL) भाषा (अरबी, हिब्रू, आदि) है, तो प्रगति पट्टी दाएँ से बाएँ भरती है।

बिना स्क्रीन वाले उपकरण

सभी Android उपकरणों में स्क्रीन नहीं होती हैं. यदि आपका डिवाइस एक हेडलेस उपकरण है या इसमें केवल-ऑडियो इंटरफ़ेस है, तो आपको पुनर्प्राप्ति यूआई का अधिक व्यापक अनुकूलन करने की आवश्यकता हो सकती है। ScreenRecoveryUI का उपवर्ग बनाने के बजाय, सीधे इसके मूल वर्ग पुनर्प्राप्तिUI को उपवर्गित करें।

रिकवरीयूआई में निचले स्तर के यूआई संचालन को संभालने के तरीके हैं जैसे "डिस्प्ले को टॉगल करें," "प्रगति पट्टी को अपडेट करें," "मेनू दिखाएं," "मेनू चयन बदलें," आदि। आप उचित इंटरफ़ेस प्रदान करने के लिए इन्हें ओवरराइड कर सकते हैं आपके डिवाइस के लिए. हो सकता है कि आपके डिवाइस में एलईडी हों जहां आप स्थिति बताने के लिए अलग-अलग रंगों या फ्लैशिंग पैटर्न का उपयोग कर सकते हैं, या हो सकता है कि आप ऑडियो चला सकें। (शायद आप किसी मेनू या "टेक्स्ट डिस्प्ले" मोड का बिल्कुल भी समर्थन नहीं करना चाहते हैं; आप उन तक पहुंच को 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() 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() टाइप-चेकिंग नहीं करता है, इसलिए आपको इसे यहां करना होगा; विफल होने पर कुछ हद तक कम विशिष्ट त्रुटि संदेश उत्पन्न करने की कीमत पर इसे एक if कथन के साथ करना अधिक सुविधाजनक है। लेकिन 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)

अंत में, अपनी लाइब्रेरी को खींचने के लिए पुनर्प्राप्ति के निर्माण को कॉन्फ़िगर करें। अपनी लाइब्रेरी को 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 +=

आपके ओटीए पैकेज में अपडेटर स्क्रिप्ट अब आपके फ़ंक्शन को किसी अन्य की तरह कॉल कर सकती है। आपके टार्डिस डिवाइस को रीप्रोग्राम करने के लिए, अपडेट स्क्रिप्ट में ये शामिल हो सकते हैं: tardis.reprogram("the-key", package_extract_file("tardis-image.dat")) यह अंतर्निहित फ़ंक्शन package_extract_file() के एकल-तर्क संस्करण का उपयोग करता है, जो नए एक्सटेंशन फ़ंक्शन के लिए दूसरा तर्क उत्पन्न करने के लिए अद्यतन पैकेज से निकाली गई फ़ाइल की सामग्री को ब्लॉब के रूप में लौटाता है।

ओटीए पैकेज जनरेशन

अंतिम घटक आपके डिवाइस-विशिष्ट डेटा के बारे में जानने और अपडेटर स्क्रिप्ट को उत्सर्जित करने के लिए ओटीए पैकेज जेनरेशन टूल प्राप्त कर रहा है जिसमें आपके एक्सटेंशन फ़ंक्शंस में कॉल शामिल हैं।

सबसे पहले, डेटा के डिवाइस-विशिष्ट ब्लॉब के बारे में जानने के लिए बिल्ड सिस्टम प्राप्त करें। यह मानते हुए कि आपकी डेटा फ़ाइल device/yoyodyne/tardis/tardis.dat में है, अपने डिवाइस के AndroidBoard.mk में निम्नलिखित घोषित करें:

device/yoyodyne/tardis/AndroidBoard.mk
  [...]

$(call add-radio-file,tardis.dat)

आप इसे इसके बजाय Android.mk में भी डाल सकते हैं, लेकिन फिर इसे डिवाइस जांच द्वारा संरक्षित किया जाना चाहिए, क्योंकि ट्री में सभी Android.mk फ़ाइलें लोड की जाती हैं, इससे कोई फर्क नहीं पड़ता कि कौन सा डिवाइस बनाया जा रहा है। (यदि आपके ट्री में एकाधिक डिवाइस शामिल हैं, तो आप टार्डिस डिवाइस बनाते समय केवल 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 में कॉपी करता है। जब आप कोई निर्माण करते हैं, तो tardis.dat को target-files.zip में RADIO/tardis.dat के रूप में संग्रहीत किया जाता है। आप जितनी चाहें उतनी फ़ाइलें जोड़ने के लिए add-radio-file कई बार कॉल कर सकते हैं।

पायथन मॉड्यूल

रिलीज़ टूल का विस्तार करने के लिए, एक पायथन मॉड्यूल लिखें (रिलीज़ टूल्स.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"));""")

एक अलग फ़ंक्शन वृद्धिशील ओटीए पैकेज उत्पन्न करने के मामले को संभालता है। इस उदाहरण के लिए, मान लीजिए कि आपको टार्डिस को केवल तभी पुन: प्रोग्राम करने की आवश्यकता है जब 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()
पूर्ण ओटीए उत्पन्न करने की शुरुआत के करीब कॉल किया गया। डिवाइस की वर्तमान स्थिति के बारे में दावा करने के लिए यह एक अच्छी जगह है। डिवाइस में परिवर्तन करने वाले स्क्रिप्ट कमांड न छोड़ें।
FullOTA_InstallBegin()
डिवाइस स्थिति के बारे में सभी दावे बीत जाने के बाद लेकिन कोई भी बदलाव किए जाने से पहले कॉल किया गया। आप डिवाइस-विशिष्ट अपडेट के लिए कमांड जारी कर सकते हैं जो डिवाइस पर कुछ भी बदलने से पहले चलना चाहिए।
FullOTA_InstallEnd()
बूट और सिस्टम विभाजन को अपडेट करने के लिए स्क्रिप्ट कमांड जारी होने के बाद, स्क्रिप्ट जेनरेशन के अंत में कॉल किया जाता है। आप डिवाइस-विशिष्ट अपडेट के लिए अतिरिक्त कमांड भी भेज सकते हैं।
IncrementalOTA_Assertions()
FullOTA_Assertions() के समान लेकिन वृद्धिशील अद्यतन पैकेज बनाते समय इसे कॉल किया जाता है।
IncrementalOTA_VerifyBegin()
डिवाइस स्थिति के बारे में सभी दावे बीत जाने के बाद लेकिन कोई भी बदलाव किए जाने से पहले कॉल किया गया। आप डिवाइस-विशिष्ट अपडेट के लिए कमांड जारी कर सकते हैं जो डिवाइस पर कुछ भी बदलने से पहले चलना चाहिए।
IncrementalOTA_VerifyEnd()
सत्यापन चरण के अंत में कॉल किया जाता है, जब स्क्रिप्ट यह पुष्टि कर लेती है कि जिन फ़ाइलों को वह छूने जा रही है उनमें अपेक्षित प्रारंभिक सामग्री है। इस बिंदु पर डिवाइस पर कुछ भी नहीं बदला गया है. आप अतिरिक्त डिवाइस-विशिष्ट सत्यापन के लिए कोड भी उत्सर्जित कर सकते हैं।
IncrementalOTA_InstallBegin()
पैच की जाने वाली फ़ाइलों को अपेक्षित स्थिति के रूप में सत्यापित किए जाने के बाद कॉल किया जाता है, लेकिन कोई भी बदलाव किए जाने से पहले। आप डिवाइस-विशिष्ट अपडेट के लिए कमांड जारी कर सकते हैं जो डिवाइस पर कुछ भी बदलने से पहले चलना चाहिए।
IncrementalOTA_InstallEnd()
इसके पूर्ण ओटीए पैकेज समकक्ष के समान, इसे स्क्रिप्ट पीढ़ी के अंत में कहा जाता है, बूट और सिस्टम विभाजन को अपडेट करने के लिए स्क्रिप्ट कमांड उत्सर्जित होने के बाद। आप डिवाइस-विशिष्ट अपडेट के लिए अतिरिक्त कमांड भी भेज सकते हैं।

नोट: यदि डिवाइस की पावर खत्म हो जाती है, तो OTA इंस्टॉलेशन शुरुआत से पुनः आरंभ हो सकता है। उन उपकरणों से निपटने के लिए तैयार रहें जिन पर ये आदेश पहले ही पूर्ण या आंशिक रूप से चलाए जा चुके हैं।

सूचना वस्तुओं को फ़ंक्शन पास करें

फ़ंक्शंस को एक ही सूचना ऑब्जेक्ट में पास करें जिसमें विभिन्न उपयोगी आइटम हों:

  • info.input_zip . (केवल पूर्ण ओटीए) इनपुट लक्ष्य-फ़ाइलों .zip के लिए zipfile.ZipFile ऑब्जेक्ट।
  • info.source_zip . (केवल वृद्धिशील ओटीए) स्रोत लक्ष्य-फ़ाइलों .zip के लिए zipfile.ZipFile ऑब्जेक्ट (वृद्धिशील पैकेज स्थापित होने पर डिवाइस पर पहले से ही बिल्ड)।
  • जानकारी.target_zip . (केवल वृद्धिशील ओटीए) लक्ष्य लक्ष्य-फ़ाइलों .zip के लिए zipfile.ZipFile ऑब्जेक्ट (वृद्धिशील पैकेज डिवाइस पर डालता है)।
  • जानकारी.आउटपुट_ज़िप । पैकेज बनाया जा रहा है; एक zipfile.ZipFile ऑब्जेक्ट लिखने के लिए खोला गया। पैकेज में फ़ाइल जोड़ने के लिए Common.ZipWriteStr(info.output_zip, filename , data ) का उपयोग करें।
  • जानकारी.स्क्रिप्ट । स्क्रिप्ट ऑब्जेक्ट जिसमें आप कमांड जोड़ सकते हैं। स्क्रिप्ट में टेक्स्ट आउटपुट करने के लिए info.script.AppendExtra( script_text ) पर कॉल करें। सुनिश्चित करें कि आउटपुट टेक्स्ट अर्धविराम के साथ समाप्त होता है ताकि यह बाद में उत्सर्जित आदेशों में न चले।

सूचना ऑब्जेक्ट पर विवरण के लिए, ज़िप अभिलेखागार के लिए पायथन सॉफ्टवेयर फाउंडेशन दस्तावेज़ देखें।

मॉड्यूल स्थान निर्दिष्ट करें

अपनी 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 स्क्रिप्ट के स्थान को स्पष्ट रूप से परिभाषित करना सबसे अच्छा है। टार्डिस डिवाइस बनाते समय,releasetools.py स्क्रिप्ट को लक्ष्य-फ़ाइल्स .zip फ़ाइल ( META/releasetools.py ) में शामिल किया जाता है।

जब आप रिलीज़ टूल (या तो img_from_target_files या ota_from_target_files ) चलाते हैं, तो 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 टिप्पणियों को देखें।

साइडलोडिंग तंत्र

रिकवरी में अपडेट पैकेज को मुख्य सिस्टम द्वारा ओवर-द-एयर डाउनलोड किए बिना मैन्युअल रूप से इंस्टॉल करने के लिए एक साइडलोडिंग तंत्र है। साइडलोडिंग उन उपकरणों पर डिबगिंग या परिवर्तन करने के लिए उपयोगी है जहां मुख्य सिस्टम को बूट नहीं किया जा सकता है।

ऐतिहासिक रूप से, डिवाइस के एसडी कार्ड से पैकेज लोड करके साइडलोडिंग की जाती रही है; गैर-बूटिंग डिवाइस के मामले में, पैकेज को किसी अन्य कंप्यूटर का उपयोग करके एसडी कार्ड पर रखा जा सकता है और फिर एसडी कार्ड को डिवाइस में डाला जा सकता है। रिमूवेबल एक्सटर्नल स्टोरेज के बिना एंड्रॉइड डिवाइस को समायोजित करने के लिए, रिकवरी साइडलोडिंग के लिए दो अतिरिक्त तंत्रों का समर्थन करती है: कैश विभाजन से पैकेज लोड करना, और एडीबी का उपयोग करके उन्हें यूएसबी पर लोड करना।

प्रत्येक साइडलोड तंत्र को शुरू करने के लिए, आपके डिवाइस की Device::InvokeMenuItem() विधि बिल्टइनएक्शन के निम्नलिखित मान लौटा सकती है:

  • APPLY_EXT . बाह्य भंडारण ( /sdcard निर्देशिका) से एक अद्यतन पैकेज़ को साइडलोड करें। आपके पुनर्प्राप्ति.fstab को /sdcard माउंट बिंदु को परिभाषित करना होगा। यह उन उपकरणों पर प्रयोग करने योग्य नहीं है जो एसडी कार्ड को एक सिम्लिंक /data (या कुछ समान तंत्र) के साथ अनुकरण करते हैं। /data आमतौर पर रिकवरी के लिए उपलब्ध नहीं है क्योंकि इसे एन्क्रिप्ट किया जा सकता है। रिकवरी UI /sdcard में .zip फ़ाइलों का एक मेनू प्रदर्शित करता है और उपयोगकर्ता को एक का चयन करने की अनुमति देता है।
  • Apply_cache/sdcard से एक पैकेज लोड करने के समान है, सिवाय इसके कि /cache निर्देशिका (जो हमेशा रिकवरी के लिए उपलब्ध है ) का उपयोग किया जाता है। नियमित प्रणाली से, /cache केवल विशेषाधिकार प्राप्त उपयोगकर्ताओं द्वारा लिखित है, और यदि डिवाइस बूट करने योग्य नहीं है, तो /cache निर्देशिका को बिल्कुल भी नहीं लिखा जा सकता है (जो सीमित उपयोगिता का यह तंत्र बनाता है)।
  • Apply_adb_sideload । उपयोगकर्ता को USB केबल और ADB विकास उपकरण के माध्यम से डिवाइस को एक पैकेज भेजने की अनुमति देता है। जब इस तंत्र को आमंत्रित किया जाता है, तो रिकवरी ADBD डेमॉन के अपने स्वयं के मिनी संस्करण को शुरू करती है ताकि ADB को एक कनेक्टेड होस्ट कंप्यूटर पर बात करने दिया जा सके। यह मिनी संस्करण केवल एक ही कमांड का समर्थन करता है: adb sideload filename । नामित फ़ाइल को होस्ट मशीन से डिवाइस पर भेजा जाता है, जो तब सत्यापित करता है और इसे स्थापित करता है जैसे कि यह स्थानीय भंडारण पर था।

कुछ चेतावनियाँ:

  • केवल USB परिवहन समर्थित है।
  • यदि आपकी पुनर्प्राप्ति ADBD सामान्य रूप से चलती है (आमतौर पर UserDebug और ENG बिल्ड के लिए सही है), तो यह बंद हो जाएगा जबकि डिवाइस ADB साइडलोड मोड में है और ADB साइडलोड को एक पैकेज प्राप्त करने के बाद फिर से शुरू किया जाएगा। ADB साइडलोड मोड में, कोई भी ADB sideload कार्य ( logcat , reboot , push , pull , shell , आदि के अलावा अन्य सभी विफल नहीं होता है)।
  • आप डिवाइस पर ADB साइडलोड मोड से बाहर नहीं निकल सकते। गर्भपात करने के लिए, आप पैकेज के रूप में /dev/null (या कुछ और जो एक वैध पैकेज नहीं है) भेज सकते हैं, और फिर डिवाइस इसे सत्यापित करने और स्थापना प्रक्रिया को रोकने में विफल रहेगा। Recoveryui कार्यान्वयन की CheckKey() विधि को KeyPresses के लिए बुलाया जाना जारी रहेगा, इसलिए आप एक महत्वपूर्ण अनुक्रम प्रदान कर सकते हैं जो डिवाइस को रिबूट करता है और ADB साइडलोड मोड में काम करता है।