รหัสเฉพาะอุปกรณ์

ระบบกู้คืนมีฮุกจำนวนมากสำหรับใส่โค้ดเฉพาะอุปกรณ์เพื่อให้ OTA สามารถอัปเดตส่วนต่างๆ ของอุปกรณ์นอกเหนือจากระบบ Android ได้ด้วย (เช่น ช่วงเบสแบนด์ หรืออุปกรณ์ประมวลผลวิทยุ)

ส่วนและตัวอย่างต่อไปนี้ปรับแต่งอุปกรณ์ tardis ที่ผลิตโดย yoyodyne

แผนที่พาร์ติชัน

สำหรับ Android 2.3 แพลตฟอร์มนี้สนับสนุนอุปกรณ์ eMMc Flash และระบบไฟล์ ext4 ที่ทำงาน บนอุปกรณ์เหล่านั้น นอกจากนี้ยังรองรับอุปกรณ์แฟลชของอุปกรณ์เทคโนโลยีหน่วยความจำ (MTD) และ Yaff2 ระบบไฟล์จากรุ่นก่อนหน้า

ไฟล์แมปพาร์ติชันระบุโดย TARGET_RECOVERY_FSTAB ไฟล์นี้ถูกใช้โดยทั้ง ไบนารีการกู้คืน และเครื่องมือสร้างแพ็กเกจ คุณสามารถระบุชื่อของไฟล์แผนที่ใน TARGET_RECOVERY_FSTAB ใน BoardConfig.mk

ตัวอย่างไฟล์การแมปพาร์ติชันอาจมีลักษณะดังนี้

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 ซึ่งไม่บังคับ ต้องกำหนดตัวอย่าง (อุปกรณ์อาจเพิ่มพาร์ติชันเพิ่มเติมได้ด้วย) รองรับอยู่ 5 รูปแบบ ประเภทระบบไฟล์

yaffs2
ระบบไฟล์ yaffs2 บนอุปกรณ์แฟลช MTD "อุปกรณ์" ต้องเป็นชื่อของพาร์ติชัน MTD และต้องปรากฏใน /proc/mtd
Mtd
พาร์ติชัน MTD แบบ Raw ใช้สำหรับพาร์ติชันที่เปิดเครื่องได้ เช่น การเปิดเครื่องและการกู้คืน MTD ไม่ใช่ แต่จะใช้จุดต่อเชื่อมเป็นคีย์ในการค้นหาพาร์ติชัน "อุปกรณ์" ต้องเป็นชื่อของพาร์ติชัน MTD ใน /proc/mtd
ต่อ4
ระบบไฟล์ ext4 บนอุปกรณ์แฟลช eMMc "อุปกรณ์" ต้องเป็นเส้นทางของอุปกรณ์บล็อก
เอ็มเอ็มซี
อุปกรณ์บล็อก eMMc แบบ Raw ที่ใช้สำหรับพาร์ติชันที่เปิดเครื่องได้ เช่น การเปิดเครื่องและการกู้คืน คล้ายกับ ประเภท mtd จะไม่มีการต่อเชื่อม eMMc จริงๆ แต่จะใช้สตริงจุดต่อเชื่อมเพื่อค้นหา อุปกรณ์ในตาราง
Vfat
ระบบไฟล์ FAT จะอยู่บนอุปกรณ์บล็อก ซึ่งโดยปกติแล้วมีไว้สำหรับที่จัดเก็บข้อมูลภายนอก เช่น การ์ด SD อุปกรณ์คืออุปกรณ์บล็อก device2 เป็นอุปกรณ์บล็อกที่ 2 ที่ระบบพยายามต่อเชื่อม การต่อเชื่อมอุปกรณ์หลักล้มเหลว (ในกรณีที่ใช้งานร่วมกันได้กับการ์ด SD ซึ่งอาจใช่หรือไม่ ที่มีการจัดรูปแบบด้วยตารางพาร์ติชัน)

พาร์ติชันทั้งหมดต้องต่อเชื่อมในไดเรกทอรีราก (เช่น ค่าของจุดต่อเชื่อมต้อง ขึ้นต้นด้วยเครื่องหมายทับและต้องไม่มีเครื่องหมายทับอื่นๆ) ข้อจำกัดนี้มีผลกับการต่อเชื่อมเท่านั้น ระบบไฟล์ของคุณในการกู้คืน ระบบหลักนำไปติดตั้งได้ทุกที่ ไดเรกทอรี /boot, /recovery และ /misc ควรเป็นประเภทข้อมูลดิบ (mtd หรือ emmc) ในขณะที่ไดเรกทอรี /system, /data, /cache และ /sdcard (หากมี) ควรเป็นประเภทระบบไฟล์ (yaffs2, ext4 หรือ vfat)

ตั้งแต่ Android 3.0 เป็นต้นไป ไฟล์recovery.fstab จะมีช่องให้ใส่เพิ่มเติมซึ่งไม่บังคับ ตัวเลือก ปัจจุบันตัวเลือกเดียวที่กำหนดไว้คือ length ซึ่งให้คุณระบุอย่างชัดเจน ระบุความยาวของพาร์ติชัน ความยาวนี้ใช้เมื่อจัดรูปแบบพาร์ติชันใหม่ (เช่น สำหรับพาร์ติชันข้อมูลผู้ใช้ระหว่างการดำเนินการล้างข้อมูล/รีเซ็ตเป็นค่าเริ่มต้น หรือสำหรับฟังก์ชัน พาร์ติชันระบบระหว่างการติดตั้งแพ็กเกจ OTA แบบเต็ม) หากค่าความยาวเป็นลบ จะมีการใช้ขนาดเพื่อจัดรูปแบบโดยการเพิ่มค่าความยาวเป็นขนาดพาร์ติชันจริง สำหรับ เช่น การตั้งค่า "length=-16384" หมายความว่า 16K สุดท้ายของพาร์ติชันนั้นจะไม่ ซึ่งจะเขียนทับเมื่อมีการจัดรูปแบบพาร์ติชันใหม่ ซึ่งรองรับฟีเจอร์ต่างๆ เช่น การเข้ารหัส พาร์ติชันข้อมูลผู้ใช้ (ซึ่งเก็บข้อมูลเมตาการเข้ารหัสไว้ที่ตอนท้ายของพาร์ติชันที่ ไม่ควรเขียนทับ)

หมายเหตุ: ช่องdevice2และตัวเลือกเป็นช่องที่ไม่บังคับเพื่อสร้าง ความคลุมเครือในการแยกวิเคราะห์ ถ้าข้อมูลในฟิลด์ที่สี่ในบรรทัดขึ้นต้นด้วย "/" ก็ถือว่าเป็นรายการ device2 หากรายการไม่ได้ขึ้นต้นด้วย "/" ก็ถือว่าเป็นช่องตัวเลือก

ภาพเคลื่อนไหวขณะเปิดเครื่อง

ผู้ผลิตอุปกรณ์สามารถปรับแต่งภาพเคลื่อนไหวที่แสดงเมื่ออุปกรณ์ Android ได้ กำลังเปิดเครื่อง โดยให้สร้างไฟล์ .zip ที่มีการจัดระเบียบและจัดไว้ตาม ใน bootanimation

สำหรับ อุปกรณ์ Android Things คุณอาจอัปโหลดไฟล์ ZIP ในคอนโซล Android Things เพื่อให้มีรูปภาพรวมอยู่ด้วย ผลิตภัณฑ์ที่เลือก

หมายเหตุ: รูปภาพเหล่านี้ต้องเป็นไปตามหลักเกณฑ์การใช้แบรนด์ Android สำหรับหลักเกณฑ์การใช้แบรนด์ โปรดดูส่วน Android ของ การตลาดของพาร์ทเนอร์ Hub

UI การกู้คืน

เพื่อรองรับอุปกรณ์ที่มีฮาร์ดแวร์อื่นที่พร้อมใช้งาน (ปุ่มจริง, LED, หน้าจอ ฯลฯ) คุณสามารถปรับแต่งอินเทอร์เฟซการกู้คืนเพื่อแสดงสถานะและเข้าถึง ฟีเจอร์ที่ซ่อนอยู่ของอุปกรณ์แต่ละเครื่อง

เป้าหมายของคุณคือการสร้างไลบรารีแบบคงที่ขนาดเล็กที่มีออบเจ็กต์ C++ 2 รายการเพื่อให้ฟังก์ชัน ฟังก์ชันเฉพาะอุปกรณ์ ไฟล์ ระบบจะใช้ bootable/recovery/default_device.cpp เป็นค่าเริ่มต้นและ เมื่อเขียนเวอร์ชันของไฟล์นี้สำหรับอุปกรณ์ของคุณ

หมายเหตุ: คุณอาจเห็นข้อความไม่มีคำสั่งที่นี่ เพื่อเปิด/ปิด กดปุ่มเปิด/ปิดค้างไว้ขณะกดปุ่มเพิ่มระดับเสียง หากอุปกรณ์ของคุณไม่มี ทั้ง 2 ปุ่ม ให้กดปุ่มใดก็ได้ค้างไว้เพื่อสลับข้อความ

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

ถัดไป ให้กำหนดการใช้งาน RecoveryUI ของอุปกรณ์ ตัวอย่างนี้ถือว่า อุปกรณ์ tardis มีหน้าจอ คุณจึงสามารถรับค่าจากอุปกรณ์ ScreenRecoveryUIimplementation (ดูคำแนะนำสำหรับ อุปกรณ์ที่ไม่มีหน้าจอ) ฟังก์ชันเดียวที่ช่วยให้ กำหนดค่าจาก 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() คือ ไม่ว่าจะเกิดอะไรขึ้นในระหว่างการกู้คืนส่วนที่เหลือ คือเมื่อมีการสลับเมนู เปิดอยู่ ระหว่างการติดตั้งแพ็กเกจ ระหว่างการล้างข้อมูลผู้ใช้ ฯลฯ อาจแสดงผลหนึ่งใน 4 ประเภท ค่าคงที่:

  • สลับ สลับการแสดงเมนูและ/หรือการบันทึกข้อความเป็นเปิดหรือปิด
  • รีบูต รีบูตอุปกรณ์ทันที
  • เพิกเฉย ละเว้นการกดแป้นนี้
  • คิว จัดคิวการกดแป้นนี้แบบซิงโครนัส (เช่น ตามการกู้คืน) ระบบเมนูหากจอแสดงผลเปิดอยู่)

ระบบจะเรียก CheckKey() ทุกครั้งที่เหตุการณ์คีย์ดาวน์ตามด้วยเหตุการณ์สําคัญสําหรับ คีย์เดียวกัน (ลำดับเหตุการณ์ A-down B-down B-up A-up จะส่งผลเฉพาะ กำลังโทรหา CheckKey(B)) CheckKey() สามารถโทรหาได้ IsKeyPressed() เพื่อดูว่ามีการกดคีย์อื่นๆ ค้างไว้ไหม (ในกรณีข้างต้น ลำดับของเหตุการณ์สำคัญ หาก CheckKey(B) เรียกใช้IsKeyPressed(A) จะแสดงผลเป็น "จริง")

CheckKey() จะคงสถานะไว้ในคลาสได้ ซึ่งอาจเป็นประโยชน์ในการตรวจสอบ ลำดับของคีย์ ตัวอย่างนี้แสดงการตั้งค่าที่ซับซ้อนมากขึ้นเล็กน้อย โดยสลับจอแสดงผลเป็น กดปุ่มเปิด/ปิดค้างไว้และกดปุ่มเพิ่มระดับเสียง จากนั้นอุปกรณ์จะรีบูตได้ทันทีโดย กดปุ่มเปิด/ปิด 5 ครั้งติดต่อกัน (โดยไม่ใช้แป้นอื่นๆ):

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

UI การกู้คืนหน้าจอ

เมื่อใช้รูปภาพของคุณเอง (ไอคอนข้อผิดพลาด ภาพเคลื่อนไหวการติดตั้ง แถบความคืบหน้า) กับ ScreenRecoveryUI คุณสามารถตั้งตัวแปร animation_fps เพื่อควบคุมความเร็วใน เฟรมต่อวินาที (FPS) ของภาพเคลื่อนไหว

หมายเหตุ: สคริปต์ interlace-frames.py ปัจจุบันช่วยให้คุณสามารถทำสิ่งต่อไปนี้ เก็บข้อมูล animation_fps ไว้ในรูปภาพนั้น ในเวอร์ชันก่อนหน้านี้ของ Android ต้องตั้ง animation_fps ด้วยตัวเอง

หากต้องการตั้งค่าตัวแปร animation_fps ให้ลบล้าง ScreenRecoveryUI::Init() ในคลาสย่อยของคุณ กำหนดค่า แล้วเรียก parent Init() เพื่อการเริ่มต้นให้เสร็จสมบูรณ์ ค่าเริ่มต้น (20 FPS) สอดคล้องกับอิมเมจการกู้คืนเริ่มต้น เมื่อใช้รูปภาพเหล่านี้ คุณจะ ฟังก์ชัน Init() ดูรายละเอียดเกี่ยวกับรูปภาพได้ที่ อิมเมจ UI การกู้คืน

คลาสอุปกรณ์

หลังจากที่คุณใช้งาน RecoveryUI แล้ว ให้ระบุคลาสของอุปกรณ์ (โดยแบ่งประเภทย่อยจาก คลาสอุปกรณ์ในตัว) ซึ่งควรสร้างอินสแตนซ์ของคลาส 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 ....
    }

ระบุและจัดการเมนูการกู้คืน

ระบบจะเรียกใช้เมธอด 2 วิธีในการรับรายการบรรทัดส่วนหัวและรายการข้อมูล ด้วยวิธีนี้ แต่จะแสดงอาร์เรย์แบบคงที่ที่กำหนดไว้ที่ด้านบนของไฟล์

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() เมธอดของออบเจ็กต์ UI) และสถานะปัจจุบันของบันทึกเมนู/ข้อความ การมองเห็น ผลลัพธ์จะเป็นจำนวนเต็ม หากค่าเป็น 0 ขึ้นไป ระบบจะใช้ค่า ตำแหน่งรายการในเมนู ซึ่งจะถูกเรียกใช้ทันที (ดูส่วน InvokeMenuItem() วิธีด้านล่าง) มิฉะนั้นอาจเป็นข้อใดข้อหนึ่งต่อไปนี้ ค่าคงที่ที่กำหนดไว้ล่วงหน้า:

  • khighlightUp ย้ายไฮไลต์เมนูไปยังรายการก่อนหน้า
  • khighlightDown ย้ายไฮไลต์เมนูไปยังรายการถัดไป
  • kInvokeItem เรียกใช้รายการที่ไฮไลต์ในปัจจุบัน
  • kNoAction ไม่ต้องดำเนินการใดๆ กับการกดแป้นนี้

ตามที่กล่าวโดยนัยของอาร์กิวเมนต์ที่ปรากฏ จะมีการเรียก HandleMenuKey() แม้ว่าเมนูจะ ไม่แสดง ระบบจะไม่เรียกใช้ฟังก์ชันนี้ขณะกู้คืน ซึ่งต่างจาก CheckKey() เช่น ล้างข้อมูลหรือติดตั้งแพ็กเกจ ซึ่งจะเรียกใช้งานเมื่อไม่มีการใช้งานการกู้คืนเท่านั้น และกำลังรออินพุต

กลไกของแทร็กบอล

หากอุปกรณ์มีกลไกการป้อนข้อมูลที่คล้ายแทร็กบอล (สร้างเหตุการณ์การป้อนข้อมูลประเภท EV_REL และโค้ด REL_Y) จะสังเคราะห์การกู้คืน KEY_UP และ KEY_DOWN เมื่อมีการกดแป้น อุปกรณ์อินพุตที่มีลักษณะคล้ายแทร็กบอลจะรายงานการเคลื่อนไหวในแกน Y ทั้งหมดที่คุณต้องทำคือแผนที่ KEY_UP และ KEY_DOWN เหตุการณ์เข้าสู่การทำงานของเมนู การแมปนี้ไม่ได้เกิดขึ้นในกรณี CheckKey() คุณจึงจะใช้การเคลื่อนไหวของแทร็กบอลเป็นทริกเกอร์สำหรับการรีบูตไม่ได้หรือ สลับจอแสดงผล

แป้นกดร่วม

หากต้องการตรวจสอบว่ามีการกดคีย์ค้างไว้เป็นคีย์ตัวปรับแต่งหรือไม่ ให้เรียกใช้เมธอด IsKeyPressed() ของออบเจ็กต์ UI ของคุณเอง ตัวอย่างเช่น ในบางอุปกรณ์ การกด Alt-W ในการกู้คืนจะเริ่ม การล้างข้อมูลที่แสดงว่าเมนูปรากฏให้เห็นหรือไม่ YOu สามารถใช้สิ่งเหล่านี้

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

หมายเหตุ: หาก visible เป็น false ก็ไม่ควรส่งคืนข้อเสนอพิเศษ ที่เปลี่ยนแปลงเมนู (ย้ายไฮไลต์, เรียกใช้รายการที่ไฮไลต์) เนื่องจากผู้ใช้ไม่สามารถ ให้ดูไฮไลต์ แต่คุณสามารถแสดงผลค่าได้หากต้องการ

รายการเมนูเรียกใช้

ถัดไป ให้ระบุเมธอด InvokeMenuItem() ที่แมปตำแหน่งจำนวนเต็มในอาร์เรย์ ของรายการที่ GetMenuItems() แสดงผลสำหรับการดำเนินการ สำหรับอาร์เรย์ของรายการใน ตัวอย่าง tardis ให้ใช้

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

เมธอดนี้สามารถแสดงผลสมาชิกของ Enum ของ BuiltinAction เพื่อบอกให้ระบบใช้ การดำเนินการ (หรือสมาชิก NO_ACTION ถ้าคุณต้องการให้ระบบไม่ดำเนินการใดๆ) นี่คือสถานที่ที่จะ ให้ฟังก์ชันการกู้คืนเพิ่มเติมนอกเหนือจากในระบบ: เพิ่มรายการสำหรับการกู้คืน เมนูของคุณ ให้เรียกใช้ที่นี่เมื่อมีการเรียกใช้รายการในเมนู และส่งคืนค่า NO_ACTION เพื่อให้ระบบ ไม่ดำเนินการใดๆ เพิ่มเติม

BuiltinAction มีค่าต่อไปนี้

  • ไม่มีการดำเนินการ ไม่ดำเนินการใดๆ
  • รีบูต ออกจากการกู้คืนและรีบูตอุปกรณ์ตามปกติ
  • APPLY_EXT, APPLY_CACHE, APPLY_ADB_SIDELOAD ติดตั้งแพ็กเกจอัปเดตจาก สถานที่ โปรดดูรายละเอียดที่หัวข้อไซด์โหลด
  • WIPE_CACHE โปรดฟอร์แมตพาร์ติชันแคชใหม่เท่านั้น ไม่จำเป็นต้องยืนยัน เนื่องจาก ที่ไม่เป็นอันตรายเลย
  • WIPE_DATA เปลี่ยนรูปแบบข้อมูลผู้ใช้และพาร์ติชันแคช หรือที่เรียกว่าข้อมูลเริ่มต้น รีเซ็ต ระบบจะขอให้ผู้ใช้ยืนยันการดำเนินการนี้ก่อนดำเนินการต่อ

วิธีสุดท้าย WipeData() คือตัวเลือกที่ไม่บังคับ และจะถูกเรียกใช้ทุกครั้งที่มีการล้างข้อมูล ได้เริ่มต้นขึ้น (จากการกู้คืนผ่านทางเมนู หรือเมื่อผู้ใช้เลือกที่จะดำเนินการ รีเซ็ตข้อมูลเป็นค่าเริ่มต้นจากระบบหลัก) วิธีการนี้จะถูกเรียกก่อนข้อมูลผู้ใช้และแคช ระบบจะล้างข้อมูลพาร์ติชัน หากอุปกรณ์จัดเก็บข้อมูลผู้ใช้ไว้ที่อื่นนอกเหนือจาก 2 รายการนี้ คุณควรลบพาร์ติชันที่นี่ คุณควรกลับ 0 เพื่อแสดงถึงความสำเร็จและอีก ค่าไม่สำเร็จ แม้ว่าในขณะนี้ระบบจะไม่สนใจค่าที่ส่งคืน ข้อมูลผู้ใช้และแคช ระบบจะล้างข้อมูลพาร์ติชัน ไม่ว่าคุณจะแสดงผลสำเร็จหรือล้มเหลว

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

สร้างอุปกรณ์

สุดท้าย ให้ใส่ข้อความสำเร็จรูปที่ส่วนท้ายของไฟล์recovery_ui.cpp สำหรับ ฟังก์ชัน make_device() ที่สร้างและแสดงผลอินสแตนซ์ของคลาสอุปกรณ์:

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 เลย ในระหว่างการอัปเดตปกติ โทรศัพท์จะเริ่มเข้าสู่การกู้คืน แสดงแถบความคืบหน้าในการติดตั้ง และเริ่มระบบใหม่ได้โดยที่ผู้ใช้ไม่ต้องป้อนข้อมูล ในกรณีที่ระบบ ปัญหาอัปเดต การดำเนินการของผู้ใช้อย่างเดียวที่ทำได้คือโทรติดต่อฝ่ายดูแลลูกค้า

อินเทอร์เฟซแบบรูปภาพเท่านั้นทำให้ไม่จำเป็นต้องแปล แต่ใน Android 5.0 อัปเดตสามารถแสดงสตริงข้อความ (เช่น "กำลังติดตั้งการอัปเดตระบบ...") คู่กับรูปภาพ โปรดดูรายละเอียดที่หัวข้อ ข้อความการกู้คืนที่แปลแล้ว

Android 5.0 ขึ้นไป

UI การกู้คืนของ Android 5.0 ขึ้นไปใช้ 2 รูปภาพหลัก ได้แก่ รูปภาพข้อผิดพลาด และภาพเคลื่อนไหวการติดตั้ง

รูปภาพที่แสดงระหว่างข้อผิดพลาด OTA

รูปที่ 1 icon_error.png

รูปภาพที่แสดงระหว่างการติดตั้งแบบ OTA

รูปที่ 2 icon_installing.png

ภาพเคลื่อนไหวที่ติดตั้งจะแสดงเป็นรูปภาพ PNG รูปเดียวที่มีเฟรมต่างกัน ภาพเคลื่อนไหวทับซ้อนกันตามแถว (ซึ่งเป็นเหตุผลที่รูปที่ 2 ดูเหมือนถูกบล็อก) ตัวอย่างเช่น สำหรับ ภาพเคลื่อนไหวแบบ 7 เฟรมขนาด 200x200 สร้างรูปภาพขนาด 200x1400 ภาพเดียว โดยเฟรมแรกคือแถว 0, 7 14, 21, ...; เฟรมที่ 2 คือแถว 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 และเก่ากว่า

UI การกู้คืนของ Android 4.x และรุ่นก่อนหน้าใช้อิมเมจข้อผิดพลาด (แสดงด้านบน) และ การติดตั้งภาพเคลื่อนไหวพร้อมทั้งการซ้อนทับหลายๆ ภาพ

รูปภาพที่แสดงระหว่างการติดตั้งแบบ OTA

รูปที่ 3 icon_installing.png

แสดงเป็นภาพแรก
ซ้อนทับ

รูปที่ 4 icon-installing_overlay01.png

รูปที่ 7
ซ้อนทับ

รูปที่ 5 icon_installing_overlay07.png

ระหว่างการติดตั้ง การแสดงผลบนหน้าจอจะสร้างขึ้นโดยวาด icon_installing.png แล้ววาดเฟรมภาพซ้อนทับภาพหนึ่งที่ด้านบนของภาพนั้นในออฟเซ็ตที่เหมาะสม ตรงนี้ ถูกวางซ้อนเพื่อเน้นตำแหน่งที่วางการวางซ้อนบนรูปภาพฐาน:

รูปภาพประกอบของ
ติดตั้งรวมกับการวางซ้อนแรก

รูปที่ 6 กำลังติดตั้งเฟรมภาพเคลื่อนไหว 1 (icon_installing.png + icon_installing_overlay01.png)

รูปภาพประกอบของ
ติดตั้งพร้อมด้วยการวางซ้อนที่ 7

รูปที่ 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 ข้อความที่แปลแล้วสำหรับข้อความการกู้คืน

ข้อความการกู้คืนจะแสดงข้อความต่อไปนี้

  • กำลังติดตั้งการอัปเดตระบบ...
  • ข้อผิดพลาด!
  • กำลังลบ... (เมื่อล้างข้อมูล/รีเซ็ตเป็นค่าเริ่มต้น)
  • ไม่มีคำสั่ง (เมื่อผู้ใช้เปิดเครื่องในการกู้คืนด้วยตนเอง)

แอป Android ใน bootable/recovery/tools/recovery_l10n/ แสดงผลการแปลเป็นภาษาท้องถิ่น ของข้อความและสร้างภาพผสม ดูรายละเอียดเกี่ยวกับการใช้แอปนี้ได้ที่ ความคิดเห็นใน bootable/recovery/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java

เมื่อผู้ใช้เปิดเครื่องในการกู้คืนด้วยตนเอง ภาษาอาจไม่พร้อมใช้งานและไม่มีข้อความ แสดงอยู่ อย่าทำให้ข้อความตัวอักษรสำคัญต่อกระบวนการกู้คืน

หมายเหตุ: อินเทอร์เฟซที่ซ่อนอยู่ซึ่งแสดงข้อความบันทึกและทำให้ผู้ใช้ดำเนินการต่อไปนี้ได้ "การทำงานที่เลือก" จากเมนูมีให้บริการเป็นภาษาอังกฤษเท่านั้น

แถบความคืบหน้า

แถบความคืบหน้าอาจปรากฏใต้รูปภาพหลัก (หรือภาพเคลื่อนไหว) แถบความคืบหน้าสร้างขึ้นจาก รวมรูปภาพอินพุต 2 รูป ซึ่งต้องมีขนาดเดียวกัน ดังนี้

แถบความคืบหน้าว่างเปล่า

รูปที่ 9progress_existing.png

แถบความคืบหน้าแบบเต็ม

รูปที่ 10progress_fill.png

ปลายด้านซ้ายของรูปภาพเติมจะแสดงถัดจากด้านขวาสุดของ เว้นว่าง เพื่อสร้างแถบความคืบหน้า ตำแหน่งของขอบเขตระหว่างสองส่วน เปลี่ยนเป็นภาพที่แสดงความคืบหน้า ตัวอย่างเช่น ด้วยภาพอินพุตคู่ด้านบน แสดงผล:

แถบความคืบหน้าอยู่ที่ 1%

รูปที่ 11 แถบความคืบหน้าที่ 1%>

แถบความคืบหน้าอยู่ที่ 10%

รูปที่ 12 แถบความคืบหน้าที่ 10%

แถบความคืบหน้าที่ 50%

รูปที่ 13 แถบความคืบหน้าที่ 50%

คุณสามารถจัดเตรียมรูปภาพเหล่านี้ในเวอร์ชันเฉพาะอุปกรณ์ได้ด้วยการวางลงใน (ใน ตัวอย่าง) device/yoyodyne/tardis/recovery/res/images ที่ใช้เวลาเพียง 2 นาที ชื่อไฟล์ต้องตรงกับชื่อในรายการด้านบน เมื่อพบไฟล์ในไดเรกทอรีนั้น ระบบบิลด์จะใช้ค่าดังกล่าวตามอิมเมจเริ่มต้นที่เกี่ยวข้อง เฉพาะ PNG ในรูปแบบ RGB หรือ รองรับรูปแบบ RGBA ที่มีความลึกของสี 8 บิต

หมายเหตุ: ใน Android 5.x หากทราบว่าภาษาถิ่นการกู้คืนและเป็นภาษา ภาษาจากขวาไปซ้าย (RTL) (อาหรับ ฮีบรู ฯลฯ) แถบความคืบหน้าจะเติมจากขวาไปซ้าย ออกไปแล้ว

อุปกรณ์ที่ไม่มีหน้าจอ

อุปกรณ์ Android บางรุ่นไม่มีหน้าจอ ถ้าอุปกรณ์ของคุณเป็นอุปกรณ์แบบไม่มีส่วนหัวหรือมี อินเทอร์เฟซสำหรับเสียงเท่านั้น คุณอาจต้องปรับแต่ง UI การกู้คืนเพิ่มเติมที่ครอบคลุมมากขึ้น แทน ของการสร้างคลาสย่อยของ ScreenRecoveryUI ให้คลาสย่อย RecoveryUI คลาสระดับบนสุดโดยตรง

RecoveryUI มีวิธีจัดการกับการดำเนินการ UI ระดับล่าง เช่น "สลับการแสดงผล" "อัปเดตแถบความคืบหน้า" "แสดงเมนู" "เปลี่ยนการเลือกเมนู" ฯลฯ คุณสามารถลบล้าง เหล่านี้เพื่อมอบอินเทอร์เฟซที่เหมาะสมสำหรับอุปกรณ์ของคุณ อุปกรณ์อาจมีไฟ LED คุณสามารถใช้สีหรือรูปแบบต่างๆ ในการกะพริบเพื่อระบุสถานะ หรือลองเล่น เสียง (คุณอาจไม่ต้องการรองรับเมนูหรือโหมด "การแสดงข้อความ" เลย คุณสามารถ ป้องกันไม่ให้เข้าถึงด้วย CheckKey() และ การติดตั้งใช้งาน HandleMenuKey() ที่ไม่เคยเปิด/ปิดจอแสดงผลหรือเลือกเมนู รายการ ในกรณีนี้ เมธอด RecoveryUI จำนวนมากที่คุณต้องระบุอาจว่างเปล่า ต้นขั้ว)

โปรดดูbootable/recovery/ui.hสำหรับการประกาศ RecoveryUI เพื่อดูวิธี คุณต้องสนับสนุน RecoveryUI เป็นนามธรรม—บางวิธีการเป็นแบบออนไลน์ล้วน และต้องให้บริการโดย คลาสย่อย แต่มีโค้ดสำหรับประมวลผลอินพุตหลัก คุณสามารถลบล้าง หรือหากอุปกรณ์ของคุณไม่มีกุญแจ หรือคุณต้องการประมวลผลคีย์ในลักษณะที่ต่างออกไป

Updater

คุณสามารถใช้รหัสเฉพาะอุปกรณ์ในการติดตั้งแพ็กเกจการอัปเดตโดยแจ้ง ฟังก์ชันส่วนขยายของตัวเอง ซึ่งสามารถเรียกจากภายในสคริปต์โปรแกรมอัปเดตของคุณ นี่คือตัวอย่าง ฟังก์ชันของอุปกรณ์ tardis:

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

ยังไม่มีการประเมินอาร์กิวเมนต์ในขณะที่เรียกใช้ฟังก์ชัน ตรรกะจะเป็นตัวกำหนดว่ากลุ่มเป้าหมายใดจะได้รับการประเมินและจํานวนครั้ง คุณจึงใช้ส่วนขยาย เพื่อนำโครงสร้างการควบคุม มาใช้เอง Call Evaluate()เพื่อประเมิน อาร์กิวเมนต์ Expr* แสดงผล Value* หาก Evaluate() แสดงผลค่า NULL คุณควรเพิ่มพื้นที่ว่างในทรัพยากรที่มีอยู่และแสดงผล NULL ทันที การเผยแพร่ จะยกเลิกสแต็กการแก้ไข) ไม่เช่นนั้น คุณจะเป็นเจ้าของค่าที่ส่งกลับมาและ มีหน้าที่รับผิดชอบในการเรียก FreeValue() ในนั้น

สมมติว่าฟังก์ชันต้องการอาร์กิวเมนต์ 2 ตัว ได้แก่ คีย์ที่มีค่าสตริงและ blob-valued image คุณสามารถอ่านอาร์กิวเมนต์ได้ดังนี้

   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() จะไม่ตรวจสอบการพิมพ์ คุณจึงต้องดำเนินการที่นี่ มากขึ้น สะดวกในการนำมาใช้ด้วยเงื่อนไข 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* โดยเฉพาะสมาชิกข้อมูล

ในกรณีนี้ คุณต้องการส่งคืนค่าจริงหรือเท็จเพื่อแสดงถึงความสำเร็จ อย่าลืม กฎที่ว่าสตริงว่างคือ false และสตริงอื่นๆ ทั้งหมดจะเป็น true คุณ ต้อง Malloc กระทำออบเจ็กต์ค่าที่มีสำเนาของสตริงค่าคงที่ที่จะถูกส่งคืน เนื่องจากค่า ผู้โทรจะ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() จะรวมสตริงไว้ในออบเจ็กต์ Value ใหม่ ใช้เพื่อเขียนโค้ดด้านบนให้กระชับยิ่งขึ้น

   FreeValue(key);
    FreeValue(image);

    return StringValue(strdup(successful ? "t" : ""));
}

หากต้องการฮุกฟังก์ชันเข้ากับอินเทอร์พรีเตอร์ของการแก้ไข ให้ระบุฟังก์ชัน Register_foo โดย foo คือชื่อของไลบรารีแบบคงที่ที่มี โค้ดนี้ เรียกใช้ RegisterFunction() เพื่อลงทะเบียนฟังก์ชันของส่วนขยายแต่ละรายการ โดย แบบแผน ให้ตั้งชื่อฟังก์ชันเฉพาะอุปกรณ์ device.whatever ที่จะหลีกเลี่ยง ขัดแย้งกับฟังก์ชันในตัวที่เพิ่มเข้ามาในอนาคต

void Register_librecovery_updater_tardis() {
    RegisterFunction("tardis.reprogram", ReprogramTardisFn);
}

ตอนนี้คุณกำหนดค่า Makefile เพื่อสร้างไลบรารีแบบคงที่ด้วยโค้ดได้แล้ว (และ 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() ซึ่งจะแสดงเนื้อหาของไฟล์ที่ดึงมาจากแพ็กเกจการอัปเดตเป็น BLOB ที่จะสร้างขึ้น อาร์กิวเมนต์ที่สองไปยังฟังก์ชันส่วนขยายใหม่

การสร้างแพ็กเกจ OTA

องค์ประกอบสุดท้ายคือให้เครื่องมือสร้างแพ็กเกจ OTA ทราบเกี่ยวกับ ข้อมูลเฉพาะอุปกรณ์และปล่อยสคริปต์อัปเดตที่รวมการเรียกฟังก์ชันส่วนขยายของคุณด้วย

ขั้นแรก ให้ระบบบิลด์ทราบเกี่ยวกับ Blob ของข้อมูลเฉพาะอุปกรณ์ กำลังสมมติว่าข้อมูลของคุณ อยู่ใน device/yoyodyne/tardis/tardis.dat โปรดประกาศข้อมูลต่อไปนี้ใน AndroidBoard.mk ของอุปกรณ์:

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

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

คุณอาจวางคีย์ไว้ใน Android.mk แทนก็ได้ แต่ต้องได้รับการปกป้องโดยอุปกรณ์ เนื่องจากระบบจะโหลดไฟล์ Android.mk ทั้งหมดในโครงสร้าง ไม่ว่าจะใช้อุปกรณ์ใดก็ตาม สร้าง (หากแผนผังของคุณมีอุปกรณ์หลายเครื่อง คุณต้องเพิ่มเฉพาะไฟล์ tardis.dat เมื่อ สร้างอุปกรณ์ tardis)

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 คือ เก็บไว้ใน target-files.zip เป็น RADIO/tardis.dat คุณสามารถโทรหา add-radio-file หลายครั้งเพื่อเพิ่มไฟล์ได้มากเท่าที่ต้องการ

โมดูล Python

หากต้องการขยายเครื่องมือการเผยแพร่ ให้เขียนโมดูล Python (ต้องตั้งชื่อว่า 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 มีการเปลี่ยนแปลง ระหว่าง 2 บิลด์

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()
มีการเรียกหลังจากไฟล์ที่จะแพตช์ได้รับการยืนยันแล้วว่าเป็นไปตามที่คาดไว้ สถานะ before แต่ก่อนการเปลี่ยนแปลงใดๆ คุณสามารถออกคำสั่งสำหรับ จะมีการเปลี่ยนแปลงการอัปเดตเฉพาะอุปกรณ์ที่จำเป็นต้องเรียกใช้ก่อนส่วนอื่นๆ ในอุปกรณ์
IncrementalOTA_InstallEnd()
ซึ่งคล้ายกับแพ็กเกจ OTA ที่สมบูรณ์ โดยจะเรียกใช้เมื่อสิ้นสุดสคริปต์ หลังจากคำสั่งสคริปต์เพื่ออัปเดตพาร์ติชันการเปิดเครื่องและพาร์ติชันระบบ ปล่อยออกมา นอกจากนี้ยังแสดงคำสั่งเพิ่มเติมสำหรับการอัปเดตเฉพาะอุปกรณ์ได้ด้วย

หมายเหตุ: หากอุปกรณ์ไม่มีกระแสไฟเข้า การติดตั้ง OTA อาจรีสตาร์ทจาก เริ่มต้น เตรียมรับมือกับอุปกรณ์ที่มีการเรียกใช้คำสั่งเหล่านี้ไปแล้ว ทั้งหมดหรือบางส่วน

ส่งฟังก์ชันไปยังออบเจ็กต์ข้อมูล

ส่งฟังก์ชันไปยังออบเจ็กต์ข้อมูลเดียวที่มีรายการที่เป็นประโยชน์ต่างๆ ดังนี้

  • info.input_zip (OTA เต็มรูปแบบเท่านั้น) ออบเจ็กต์ zipfile.ZipFile สำหรับ ป้อนไฟล์เป้าหมาย .zip
  • info.source_zip (OTA ที่เพิ่มขึ้นเท่านั้น) ออบเจ็กต์ zipfile.ZipFile สำหรับ ไฟล์เป้าหมายต้นทาง .zip (บิลด์ที่มีอยู่ในอุปกรณ์เมื่อแพ็กเกจที่เพิ่มขึ้น กำลังติดตั้ง)
  • info.target_zip (OTA ที่เพิ่มขึ้นเท่านั้น) ออบเจ็กต์ zipfile.ZipFile สำหรับ ไฟล์เป้าหมาย .zip (สร้างแพ็กเกจที่เพิ่มขึ้นในอุปกรณ์)
  • info.output_zip กำลังสร้างแพ็กเกจ เปิดออบเจ็กต์ zipfile.ZipFile แล้ว เพื่อการเขียน ใช้ Common.ZipWriteStr(info.output_zip, filename, data) เพื่อเพิ่ม ลงในแพ็กเกจ
  • info.script ออบเจ็กต์สคริปต์ที่คุณสามารถต่อท้ายคำสั่งได้ โทร info.script.AppendExtra(script_text) เพื่อเอาต์พุตข้อความลงในสคริปต์ ตรวจสอบว่าข้อความเอาต์พุตลงท้ายด้วยเครื่องหมายอัฒภาค เพื่อไม่ให้เจอคำสั่งที่ปล่อยออกมา หลังจากนั้น

ดูรายละเอียดเกี่ยวกับออบเจ็กต์ข้อมูลได้ที่ เอกสารประกอบของ Python Software Foundation สำหรับที่เก็บถาวรของ ZIP

ระบุตำแหน่งโมดูล

ระบุตำแหน่งของสคริปต์ Releasetools.py ของอุปกรณ์ในไฟล์ BoardConfig.mk

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) สคริปต์ Releasetools.py ในไฟล์เป้าหมาย .zip หาก ที่มีอยู่ จะเลือกใช้มากกว่ารูปแบบที่มาจากโครงสร้างแหล่งที่มาของ 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

หมายเหตุ: หากต้องการดูรายการตัวเลือกทั้งหมด โปรดดู ota_from_target_files ความคิดเห็นใน build/make/tools/releasetools/ota_from_target_files

กลไกการโหลดจากแหล่งที่ไม่รู้จัก

การกู้คืนมีกลไกการโหลดจากแหล่งที่ไม่รู้จักสำหรับการติดตั้งแพ็กเกจอัปเดตด้วยตนเองโดยไม่ต้อง การดาวน์โหลดผ่านอากาศ (OTA) โดยระบบหลัก ไซด์โหลดมีประโยชน์ในการแก้ไขข้อบกพร่องหรือทำให้ การเปลี่ยนแปลงในอุปกรณ์ที่ไม่สามารถบูตระบบหลักได้

ที่ผ่านมา การโหลดจากแหล่งที่ไม่รู้จักจะดำเนินการผ่านการโหลดแพ็กเกจออกจากการ์ด SD ของอุปกรณ์ ใน สำหรับอุปกรณ์ที่ไม่ใช่เปิดเครื่อง แพ็กเกจสามารถใส่ลงในการ์ด SD โดยใช้ คอมพิวเตอร์ แล้วใส่การ์ด SD เข้าไปในอุปกรณ์ เพื่อรองรับอุปกรณ์ Android ที่ไม่มี ที่จัดเก็บข้อมูลภายนอกแบบถอดได้ การกู้คืนรองรับกลไกเพิ่มเติม 2 กลไกสำหรับไซด์โหลด กำลังโหลดแพ็กเกจจากพาร์ติชันแคช และโหลดแพ็กเกจผ่าน USB โดยใช้ adb

หากต้องการเรียกใช้กลไกไซด์โหลดแต่ละรายการ เมธอด Device::InvokeMenuItem() ของอุปกรณ์ จะแสดงผลค่า BuiltinAction ต่อไปนี้

  • APPLY_EXT โหลดแพ็กเกจอัปเดตจากที่จัดเก็บข้อมูลภายนอก ( /sdcard) ) Recovery.fstab ต้องกำหนดจุดต่อเชื่อม /sdcard นี่คือ ใช้ไม่ได้ในอุปกรณ์ที่จำลองการ์ด SD ที่มีลิงก์สัญลักษณ์ไปยัง /data (หรือ กลไกที่คล้ายกัน) โดยทั่วไป /data จะไม่สามารถกู้คืนได้เนื่องจาก อาจได้รับการเข้ารหัส UI การกู้คืนแสดงเมนูของไฟล์ .zip ใน /sdcard และ ให้ผู้ใช้เลือกได้
  • APPLY_CACHE คล้ายกับการโหลดแพ็กเกจจาก /sdcard เว้นแต่ว่า ระบบจะใช้ไดเรกทอรี /cache (ซึ่งมีให้กู้คืนเสมอ) แทน จากระบบปกติ /cache เขียนได้โดยผู้ใช้ที่ได้รับสิทธิ์เท่านั้น และหากเปิดเครื่องไม่ได้ก็จะเขียนไดเรกทอรี /cache ไม่ได้ เลย (ซึ่งทำให้กลไกนี้มีขอบเขตประโยชน์ที่จำกัด)
  • APPLY_ADB_SIDELOAD อนุญาตให้ผู้ใช้ส่งแพ็กเกจไปยังอุปกรณ์ผ่านสาย USB และ เครื่องมือการพัฒนา adb เมื่อเรียกใช้กลไกนี้ การกู้คืนจะเริ่มต้นมินิของตัวเอง เวอร์ชัน adbd daemon เพื่อให้ adb ในคอมพิวเตอร์โฮสต์ที่เชื่อมต่อสื่อสารได้ รูปโปรไฟล์จิ๋วนี้ เวอร์ชันรองรับเพียงคำสั่งเดียวคือ adb sideload filename ไฟล์ที่มีชื่อจะส่งจากเครื่องโฮสต์ไปยังอุปกรณ์ ซึ่งจะยืนยันและ ติดตั้งได้ราวกับว่าเป็นพื้นที่เก็บข้อมูลในเครื่อง

ข้อควรระวังบางประการมีดังนี้

  • รองรับเฉพาะการส่งผ่าน USB เท่านั้น
  • หากการกู้คืนของคุณเรียกใช้ adbd ตามปกติ (โดยปกติจะเป็นจริงสำหรับบิลด์ userdebug และ eng) ระบบจะดำเนินการเช่นนั้น ปิดขณะที่อุปกรณ์อยู่ในโหมด adb ไซด์โหลด และจะรีสตาร์ทเมื่อ adb ไซด์โหลดรับแพ็กเกจเสร็จแล้ว ขณะอยู่ในโหมด adb ไซด์โหลด ไม่มีคำสั่ง adb อื่นๆ มากกว่าที่ทำงาน sideload แห่ง ( logcat, reboot push, pull , shell และอื่นๆ ล้มเหลวทั้งหมด)
  • คุณออกจากโหมดไซด์โหลด adb ในอุปกรณ์ไม่ได้ หากต้องการล้มเลิก คุณสามารถส่งได้ /dev/null (หรือสิ่งใดก็ตามที่ไม่ใช่แพ็กเกจที่ถูกต้อง) เป็นแพ็กเกจ และ อุปกรณ์จะไม่สามารถยืนยันได้และหยุดขั้นตอนการติดตั้ง RecoveryUI ระบบจะยังคงเรียกใช้เมธอด CheckKey() ของการติดตั้งใช้งานสำหรับการกดแป้นต่อไป เพื่อให้คุณระบุลำดับการกดแป้นที่รีบูตอุปกรณ์และทำงานในโหมด adb ไซด์โหลดได้