קוד ספציפי למכשיר

מערכת השחזור כוללת מספר ווים להכנסת קוד ספציפי למכשיר כך שעדכוני OTA יכולים גם לעדכן חלקים של המכשיר מלבד מערכת האנדרואיד (למשל, פס הבסיס או מעבד הרדיו).

הסעיפים והדוגמאות הבאים מתאימים אישית את מכשיר הטארדיס המיוצר על ידי ספק yoyodyne .

מפת חלוקה

החל מ-Android 2.3, הפלטפורמה תומכת במכשירי eMMc flash ובמערכת הקבצים ext4 שפועלת על אותם מכשירים. הוא תומך גם בהתקני פלאש של התקן טכנולוגיית זיכרון (MTD) ובמערכת הקבצים yaffs2 מהדורות ישנות יותר.

קובץ מפת המחיצות מצוין על ידי 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 , שהוא אופציונלי, יש להגדיר את כל נקודות ההרכבה בדוגמה זו (התקנים עשויים גם להוסיף מחיצות נוספות). ישנם חמישה סוגי מערכות קבצים נתמכים:

yaffs2
מערכת קבצים yaffs2 על גבי התקן פלאש MTD. "device" חייב להיות השם של מחיצת MTD ועליו להופיע ב- /proc/mtd .
mtd
מחיצת MTD גולמית, המשמשת למחיצות הניתנות לאתחול כגון אתחול ושחזור. MTD אינו מותקן בפועל, אך נקודת ההרכבה משמשת כמפתח לאיתור המחיצה. "device" חייב להיות השם של מחיצת MTD ב- /proc/mtd .
ext4
מערכת קבצים ext4 על גבי התקן פלאש eMMc. "התקן" חייב להיות הנתיב של התקן החסימה.
emmc
התקן בלוק eMMc גולמי, המשמש למחיצות הניתנות לאתחול כגון אתחול ושחזור. בדומה לסוג mtd, eMMc לעולם אינו מותקן בפועל, אך מחרוזת נקודת ההרכבה משמשת לאיתור ההתקן בטבלה.
vfat
מערכת קבצים FAT על גבי התקן בלוק, בדרך כלל לאחסון חיצוני כגון כרטיס SD. המכשיר הוא מכשיר החסימה; device2 הוא התקן בלוק שני שהמערכת מנסה לטעון אם ההרכבה של ההתקן הראשי נכשלת (למען תאימות לכרטיסי SD שעשויים להיות מפורמטים עם טבלת מחיצות או לא).

כל המחיצות חייבות להיות נטענות בספריית השורש (כלומר, ערך נקודת הטעינה חייב להתחיל בקו סלאש ואין להן לוכסניות אחרות). הגבלה זו חלה רק על הרכבה של מערכות קבצים בשחזור; המערכת הראשית חופשית להרכיב אותם בכל מקום. הספריות /boot , /recovery ו- /misc צריכות להיות סוגי גולמיים (mtd או emmc), בעוד שהספריות /system , /data , /cache ו- /sdcard (אם זמין) צריכות להיות סוגי מערכת קבצים (yaffs2, ext4, או vfat).

החל מאנדרואיד 3.0, הקובץ recovery.fstab מקבל שדה אופציונלי נוסף, options . כרגע האפשרות המוגדרת היחידה היא length , המאפשרת לציין במפורש את אורך המחיצה. אורך זה משמש בעת עיצוב מחדש של המחיצה (למשל, עבור מחיצת הנתונים של המשתמש במהלך פעולת מחיקת נתונים/איפוס מפעל, או עבור מחיצת המערכת במהלך התקנה של חבילת OTA מלאה). אם ערך האורך שלילי, הגודל לעיצוב נלקח על ידי הוספת ערך האורך לגודל המחיצה האמיתי. לדוגמה, הגדרה של "אורך=-16384" פירושה שה-16k האחרונים של המחיצה הזו לא יוחלפו כאשר המחיצה הזו תפורמט מחדש. זה תומך בתכונות כגון הצפנה של מחיצת נתוני המשתמש (כאשר מטא-נתונים של הצפנה מאוחסנים בסוף המחיצה שאסור לדרוס).

הערה: השדות device2 והאפשרויות הם אופציונליים, ויוצרים אי בהירות בניתוח. אם הערך בשדה הרביעי בשורה מתחיל בתו '/', הוא נחשב כערך device2 ; אם הערך אינו מתחיל בתו '/', הוא נחשב לשדה אפשרויות .

אתחול אנימציה

ליצרני מכשירים יש את היכולת להתאים אישית את האנימציה המוצגת כאשר מכשיר אנדרואיד מופעל. לשם כך, בנה קובץ .zip מאורגן וממוקם בהתאם למפרטים בפורמט bootanimation .

עבור מכשירי Android Things , אתה יכול להעלות את הקובץ הדחוס בקונסולת Android Things כדי שהתמונות ייכללו במוצר הנבחר.

הערה: תמונות אלה חייבות לעמוד בהנחיות המותג של 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"

פונקציות כותרת ופריטים

המחלקה Device דורשת פונקציות להחזרת כותרות ופריטים המופיעים בתפריט השחזור הנסתר. כותרות מתארות כיצד להפעיל את התפריט (כלומר פקדים לשינוי/בחירת הפריט המודגש).

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 יש מסך, כך שתוכלו לרשת מהיישום המובנה של ScreenRecoveryUI (ראה הוראות למכשירים ללא מסך .) הפונקציה היחידה להתאמה אישית מ- ScreenRecoveryUI היא 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() נקרא בכל פעם שאירוע הורדת מפתח מלווה באירוע מפתח עבור אותו מפתח. (רצף האירועים A-down B-down B-up A-up מביא רק לקריאה של CheckKey(B) . CheckKey() יכול לקרוא ל- IsKeyPressed() , כדי לברר אם מקשים אחרים מוחזקים. (ברצף אירועי המפתח לעיל, אם CheckKey(B) נקרא IsKeyPressed(A) הוא היה חוזר כ-true.)

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, אתה יכול להגדיר את המשתנה animation_fps כדי לשלוט במהירות במסגרות לשנייה (FPS) של אנימציות.

הערה: הסקריפט הנוכחי interlace-frames.py מאפשר לך לאחסן את המידע animation_fps בתמונה עצמה. בגרסאות קודמות של אנדרואיד היה צורך להגדיר animation_fps בעצמך.

כדי להגדיר את המשתנה animation_fps , החלף את הפונקציה ScreenRecoveryUI::Init() בתת המחלקה שלך. הגדר את הערך ולאחר מכן קרא לפונקציית parent Init() כדי להשלים את האתחול. ערך ברירת המחדל (20 FPS) מתאים לתמונות השחזור המוגדרות כברירת מחדל; בעת שימוש בתמונות אלו אינך צריך לספק פונקציה Init() . לפרטים על תמונות, ראה תמונות ממשק המשתמש לשחזור .

כיתת מכשיר

לאחר יישום RecoveryUI, הגדר את מחלקת המכשיר שלך (מחלקה ממחלקת ההתקן המובנית). זה אמור ליצור מופע יחיד של מחלקת ממשק המשתמש שלך ולהחזיר את זה מהפונקציה 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

לאחר מכן, ספק פונקציה 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() של אובייקט ממשק המשתמש שלך. לדוגמה, במכשירים מסוימים לחיצה על 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() לפעולות. עבור מערך הפריטים בדוגמה של 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;
        }
    }

שיטה זו יכולה להחזיר כל חבר ב-BuiltinAction enum כדי לומר למערכת לבצע את הפעולה הזו (או לחבר NO_ACTION אם אתה רוצה שהמערכת לא תעשה כלום). זה המקום לספק פונקציונליות שחזור נוספת מעבר למה שקיים במערכת: הוסף פריט עבורו בתפריט שלך, הפעל אותו כאן כאשר פריט התפריט הזה מופעל, והחזר NO_ACTION כדי שהמערכת לא תעשה שום דבר אחר.

BuiltinAction מכיל את הערכים הבאים:

  • שום פעולה . לעשות כלום.
  • אתחול מחדש . צא מהשחזור והפעל מחדש את המכשיר כרגיל.
  • APPLY_EXT, APPLY_CACHE, APPLY_ADB_SIDELOAD . התקן חבילת עדכון ממקומות שונים. לפרטים, ראה טעינת צד .
  • WIPE_CACHE . לאתחל מחדש את מחיצת המטמון בלבד. אין צורך באישור מכיוון שזה יחסית לא מזיק.
  • WIPE_DATA . פורמט מחדש את מחיצות הנתונים והמטמון של המשתמש, המכונה גם איפוס נתוני יצרן. המשתמש מתבקש לאשר פעולה זו לפני שימשיך.

השיטה האחרונה, WipeData() , היא אופציונלית ונקראת בכל פעם שמתחילה פעולת מחיקת נתונים (בין אם מהשחזור דרך התפריט או כאשר המשתמש בחר לבצע איפוס לנתוני היצרן מהמערכת הראשית). שיטה זו נקראת לפני מחיצות נתוני המשתמש ומחיצות המטמון. אם המכשיר שלך מאחסן נתוני משתמש בכל מקום אחר מלבד שתי המחיצות האלה, עליך למחוק אותם כאן. עליך להחזיר 0 כדי לציין הצלחה וערך נוסף לכישלון, אם כי כרגע מתעלמים מערך ההחזרה. נתוני המשתמש ומחיצות המטמון נמחקים בין אם אתה מחזיר הצלחה או כישלון.

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

עשה מכשיר

לבסוף, כלול איזשהו לוחית בקצה הקובץ recovery_ui.cpp עבור הפונקציה make_device() שיוצרת ומחזירה מופע של מחלקה 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

תמונות ממשק המשתמש לשחזור

ממשק המשתמש לשחזור מורכב מתמונות. באופן אידיאלי, משתמשים לעולם אינם מקיימים אינטראקציה עם ממשק המשתמש: במהלך עדכון רגיל, הטלפון מאתחל להתאוששות, ממלא את סרגל ההתקדמות של ההתקנה ומאתחול בחזרה למערכת החדשה ללא קלט מהמשתמש. במקרה של בעיית עדכון מערכת, פעולת המשתמש היחידה שניתן לבצע היא להתקשר לשירות הלקוחות.

ממשק לתמונה בלבד מייתר את הצורך בלוקליזציה. עם זאת, החל מ-Android 5.0 העדכון יכול להציג מחרוזת טקסט (למשל "התקנת עדכון מערכת...") יחד עם התמונה. לפרטים, ראה טקסט שחזור מקומי .

אנדרואיד 5.0 ואילך

ממשק המשתמש לשחזור אנדרואיד 5.0 ואילך משתמש בשתי תמונות עיקריות: תמונת השגיאה והאנימציה של ההתקנה .

תמונה המוצגת במהלך שגיאת 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 (סמל השגיאה אינו מונפש; זו תמיד תמונה סטטית).

אנדרואיד 4.x ומעלה

ממשק המשתמש לשחזור אנדרואיד 4.x ומעלה משתמש בתמונת השגיאה (המוצגת למעלה) ובאנימציית ההתקנה בתוספת מספר תמונות שכבת-על:

תמונה המוצגת במהלך התקנת 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 (סמל השגיאה אינו מונפש; זו תמיד תמונה סטטית).

טקסט שחזור מקומי

אנדרואיד 5.x מציגה מחרוזת טקסט (למשל, "מתקין עדכון מערכת...") יחד עם התמונה. כאשר המערכת הראשית מאתחלת לשחזור, היא מעבירה את המקום הנוכחי של המשתמש כאפשרות שורת פקודה לשחזור. עבור כל הודעה שתוצג, השחזור כולל תמונה מורכבת שנייה עם מחרוזות טקסט שעובדו מראש עבור אותה הודעה בכל אזור.

תמונה לדוגמה של מחרוזות טקסט לשחזור:

תמונה של טקסט שחזור

איור 8. טקסט מקומי עבור הודעות שחזור

טקסט שחזור יכול להציג את ההודעות הבאות:

  • מתקין עדכון מערכת...
  • שְׁגִיאָה!
  • מוחק... (בעת ביצוע מחיקת נתונים/איפוס להגדרות היצרן)
  • אין פקודה (כאשר משתמש מתחיל לשחזור באופן ידני)

אפליקציית Android ב- 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 (בדוגמה זו). שמות הקבצים חייבים להתאים לשמות הרשומים לעיל; כאשר קובץ נמצא בספריה זו, מערכת הבנייה משתמשת בו בהעדפה על תמונת ברירת המחדל המתאימה. רק PNGs בפורמט RGB או RGBA עם עומק צבע של 8 סיביות נתמכים.

הערה: באנדרואיד 5.x, אם המקום ידוע לשחזור והוא שפה מימין לשמאל (RTL) (ערבית, עברית וכו'), סרגל ההתקדמות מתמלא מימין לשמאל.

מכשירים ללא מסכים

לא לכל מכשירי האנדרואיד יש מסכים. אם המכשיר שלך הוא מכשיר ללא ראש או בעל ממשק אודיו בלבד, ייתכן שיהיה עליך לבצע התאמה אישית נרחבת יותר של ממשק המשתמש לשחזור. במקום ליצור תת-מחלקה של ScreenRecoveryUI, תת-סיווג את מחלקת האב RecoveryUI ישירות.

ל-RecoveryUI יש שיטות לטיפול בפעולות ממשק משתמש ברמה נמוכה יותר כגון "החלפת התצוגה", "עדכן את שורת ההתקדמות", "הצג את התפריט", "שנה את בחירת התפריט" וכו'. אתה יכול לעקוף אותן כדי לספק ממשק מתאים עבור המכשיר שלך. אולי למכשיר שלך יש נוריות שבהן אתה יכול להשתמש בצבעים שונים או בדפוסי מהבהבים כדי לציין מצב, או אולי אתה יכול לנגן אודיו. (אולי אינך רוצה לתמוך בתפריט או במצב "הצגת טקסט" בכלל; אתה יכול למנוע גישה אליהם עם יישומי CheckKey() ו- HandleMenuKey() שלעולם אינם מעבירים את התצוגה או בוחרים פריט בתפריט. במקרה זה , רבות משיטות ה-RecoveryUI שאתה צריך לספק יכולות להיות רק בדלי ריקים.)

ראה bootable/recovery/ui.h להצהרה של RecoveryUI כדי לראות באילו שיטות אתה חייב לתמוך. RecoveryUI הוא מופשט - שיטות מסוימות הן וירטואליות טהורות וחייבות להיות מסופקות על ידי תת-מחלקות - אך הוא מכיל את הקוד לעיבוד כניסות מפתח. אתה יכול לעקוף גם את זה, אם למכשיר שלך אין מפתחות או שאתה רוצה לעבד אותם אחרת.

מעדכן

אתה יכול להשתמש בקוד ספציפי למכשיר בהתקנה של חבילת העדכון על-ידי מתן פונקציות הרחבה משלך שניתן לקרוא להן מתוך סקריפט העדכון שלך. להלן פונקציה לדוגמה עבור מכשיר הטארדיס:

device/yoyodyne/tardis/recovery/recovery_updater.c
#include <stdlib.h>
#include <string.h>

#include "edify/expr.h"

לכל פונקציית הרחבה יש את אותה חתימה. הארגומנטים הם השם שלפיו נקראה הפונקציה, קובץ Cookie 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 (זה מפיץ הפסקות במעלה ערימת ה-edify). אחרת, אתה לוקח בעלות על הערך המוחזר ואחראי בסופו של דבר לקרוא עליו 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* - במיוחד חבר הנתונים.

במקרה זה, אתה רוצה להחזיר ערך אמיתי או שקר כדי לציין הצלחה. זכור את המוסכמה לפיה המחרוזת הריקה היא שקר וכל המחרוזות האחרות נכונות . עליך להחזיר אובייקט Value עם עותק של 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" : ""));
}

כדי לחבר פונקציות למתורגמן edify, ספק את הפונקציה Register_ foo כאשר foo הוא השם של הספרייה הסטטית המכילה קוד זה. התקשר ל- RegisterFunction() כדי לרשום כל פונקציית הרחבה. לפי המוסכמה, תן שם לפונקציות ספציפיות device . whatever כדי למנוע התנגשויות עם פונקציות מובנות עתידיות שנוספו.

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

כעת אתה יכול להגדיר את ה-makefile לבנות ספרייה סטטית עם הקוד שלך. (זהו אותו makefile המשמש להתאמה אישית של ממשק המשתמש לשחזור בסעיף הקודם; ייתכן שלמכשיר שלך שתי הספריות הסטטיות מוגדרות כאן).

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 (שעשויה להכיל מספר ספריות; כולן נרשמות). אם הקוד שלך תלוי בספריות סטטיות אחרות שאינן עצמן הרחבות edify (כלומר, אין להן פונקציית 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 כדי לדעת על הנתונים הספציפיים למכשיר שלך ולפלוט סקריפטים של עדכון הכוללים שיחות לפונקציות התוסף שלך.

ראשית, למד את מערכת הבנייה על גוש נתונים ספציפי למכשיר. בהנחה שקובץ הנתונים שלך נמצא 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

אלה נקראים קבצי רדיו מסיבות היסטוריות; ייתכן שאין להם שום קשר לרדיו של המכשיר (אם קיים). הם פשוט קוביות אטומות של נתונים שמערכת ה-build מעתיקה לקובצי המטרה .zip המשמשים את הכלים ליצירת OTA. כאשר אתה מבצע בנייה, tardis.dat מאוחסן ב- target-files.zip בתור RADIO/tardis.dat . אתה יכול להתקשר add-radio-file מספר פעמים כדי להוסיף כמה קבצים שתרצה.

מודול פייתון

כדי להרחיב את כלי השחרור, כתוב מודול 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 השתנה בין שני builds.

def IncrementalOTA_InstallEnd(info):
  # copy the data into the package.
  source_tardis_dat = info.source_zip.read("RADIO/tardis.dat")
  target_tardis_dat = info.target_zip.read("RADIO/tardis.dat")

  if source_tardis_dat == target_tardis_dat:
      # tardis.dat is unchanged from previous build; no
      # need to reprogram it
      return

  # include the new tardis.dat in the OTA package
  common.ZipWriteStr(info.output_zip, "tardis.dat", target_tardis_dat)

  # emit the script code to install this data on the device
  info.script.AppendExtra(
      """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")

פונקציות מודול

אתה יכול לספק את הפונקציות הבאות במודול (ליישם רק את אלה שאתה צריך).

FullOTA_Assertions()
התקשר לקראת תחילת יצירת OTA מלא. זהו מקום טוב לפלוט הצהרות לגבי המצב הנוכחי של המכשיר. אין לשדר פקודות סקריפט המבצעות שינויים במכשיר.
FullOTA_InstallBegin()
התקשר לאחר שכל הטענות לגבי מצב המכשיר חלפו אך לפני שבוצעו שינויים כלשהם. אתה יכול לשלוח פקודות עבור עדכונים ספציפיים למכשיר שחייבים לפעול לפני שמשהו אחר במכשיר ישתנה.
FullOTA_InstallEnd()
נקרא בסוף יצירת הסקריפט, לאחר שנפלטו פקודות הסקריפט לעדכון האתחול ומחיצות המערכת. אתה יכול גם לשלוח פקודות נוספות עבור עדכונים ספציפיים למכשיר.
IncrementalOTA_Assertions()
דומה ל- FullOTA_Assertions() אך נקרא בעת יצירת חבילת עדכון מצטברת.
IncrementalOTA_VerifyBegin()
התקשר לאחר שכל ההצהרות לגבי מצב המכשיר עברו אך לפני שבוצעו שינויים כלשהם. אתה יכול לשלוח פקודות עבור עדכונים ספציפיים למכשיר שחייבים לפעול לפני שמשהו אחר במכשיר ישתנה.
IncrementalOTA_VerifyEnd()
נקרא בסוף שלב האימות, כשהסקריפט סיים לאשר שלקבצים שהוא הולך לגעת בהם יש את תוכן ההתחלה הצפוי. בשלב זה שום דבר במכשיר לא השתנה. אתה יכול גם לשדר קוד לאימות ספציפיות נוספות למכשיר.
IncrementalOTA_InstallBegin()
נקרא לאחר שקבצים לתיקון אומתו כבעלי המצב הצפוי לפני אך לפני שבוצעו שינויים כלשהם. אתה יכול לשלוח פקודות עבור עדכונים ספציפיים למכשיר שחייבים לפעול לפני שמשהו אחר במכשיר ישתנה.
IncrementalOTA_InstallEnd()
בדומה למקבילה המלאה של חבילת OTA, זה נקרא בסוף יצירת הסקריפט, לאחר שנפלטו פקודות הסקריפט לעדכון האתחול ומחיצות המערכת. אתה יכול גם לשלוח פקודות נוספות עבור עדכונים ספציפיים למכשיר.

הערה: אם המכשיר מאבד מתח, התקנת OTA עשויה להתחיל מחדש מההתחלה. היו מוכנים להתמודד עם מכשירים שבהם הפקודות הללו כבר הופעלו, באופן מלא או חלקי.

העבר פונקציות לאובייקטי מידע

העבר פונקציות לאובייקט מידע יחיד המכיל פריטים שימושיים שונים:

  • info.input_zip . (OTAs מלא בלבד) אובייקט zipfile.ZipFile עבור קבצי היעד הקלט .zip.
  • info.source_zip . (OTAs מצטבר בלבד) אובייקט zipfile.ZipFile עבור קבצי היעד המקור .zip (ה-build כבר במכשיר כאשר החבילה המצטברת מותקנת).
  • info.target_zip . (OTAs מצטבר בלבד) אובייקט zipfile.ZipFile עבור קבצי היעד .zip (ה-build שהחבילה המצטברת שמה במכשיר).
  • 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 של target-files ( META/releasetools.py ).

כאשר אתה מפעיל את כלי השחרור (או img_from_target_files או ota_from_target_files ), הסקריפט releasetools.py ב-target-files .zip, אם קיים, מועדף על פני זה מעץ המקור של Android. אתה יכול גם לציין במפורש את הנתיב להרחבות הספציפיות למכשיר עם האפשרות -s (או --device_specific ), אשר מקבלת את העדיפות העליונה. זה מאפשר לך לתקן שגיאות ולבצע שינויים בהרחבות כלי השחרור ולהחיל את השינויים הללו על קבצי יעד ישנים.

כעת, כאשר אתה מפעיל את ota_from_target_files , הוא קולט באופן אוטומטי את המודול הספציפי למכשיר מקובץ ה-.zip target_files ומשתמש בו בעת יצירת חבילות 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 .

מנגנון העמסת צד

לשחזור יש מנגנון טעינת צד להתקנה ידנית של חבילת עדכון מבלי להוריד אותה באוויר על ידי המערכת הראשית. טעינת צד שימושית לניפוי באגים או ביצוע שינויים במכשירים שבהם לא ניתן לאתחל את המערכת הראשית.

היסטורית, טעינת צד נעשתה באמצעות טעינת חבילות מכרטיס ה-SD של המכשיר; במקרה של מכשיר שאינו מאתחל, ניתן להכניס את החבילה לכרטיס ה-SD באמצעות מחשב אחר ולאחר מכן להכניס את כרטיס ה-SD למכשיר. כדי להכיל מכשירי אנדרואיד ללא אחסון חיצוני נשלף, השחזור תומך בשני מנגנונים נוספים לטעינת צד: טעינת חבילות ממחיצת המטמון וטעינתן דרך USB באמצעות adb.

כדי להפעיל כל מנגנון עומס צד, השיטה Device::InvokeMenuItem() של המכשיר שלך יכולה להחזיר את הערכים הבאים של BuiltinAction:

  • APPLY_EXT . Sideared חבילת עדכון מאחסון חיצוני ( /sdcard ). ההחלמה שלך. FSTAB חייבת להגדיר את נקודת הרכבה /sdcard . זה לא ניתן לשימוש במכשירים המחקים כרטיס SD עם קישור סימל ל /data (או מנגנון דומה כלשהו). /data בדרך כלל אינם זמינים לשחזור מכיוון שהם עשויים להיות מוצפנים. ממשק המשתמש של השחזור מציג תפריט של קבצי .zip ב- /sdcard ומאפשר למשתמש לבחור אחד.
  • Apply_Cache . בדומה לטעינת חבילה מ- /sdcard פרט לכך שמשתמש במקום זאת בספריית /cache ( שתמיד זמין לשחזור) משמשת. מהמערכת הרגילה, /cache ניתן לכתוב רק על ידי משתמשים מיוחסים, ואם המכשיר אינו ניתן לאתחול, לא ניתן לכתוב את ספריית /cache (מה שהופך את המנגנון הזה של כלי עזר מוגבל).
  • Apply_adb_sideload . מאפשר למשתמש לשלוח חבילה למכשיר באמצעות כבל USB וכלי הפיתוח של ADB. כאשר מופעל מנגנון זה, ההחלמה מפעילה את גרסת המיני משלה של ה- ADBD DAEMEN כדי לאפשר ל- ADB במחשב מארח מחובר לדבר איתו. גרסת מיני זו תומכת רק בפקודה יחידה: adb sideload filename . הקובץ שנקרא נשלח מהמחשב המארח למכשיר, אשר אז מאמת ומתקין אותו בדיוק כאילו היה באחסון מקומי.

כמה אזהרות:

  • נתמך רק הובלת USB.
  • אם ההתאוששות שלך מפעילה את ADBD כרגיל (בדרך כלל נכונה עבור UserDebug ו- ENG בונה), זה יושבת בזמן שההתקן נמצא במצב Hadide ADB ויופעל מחדש כאשר ADB Side Hade סיימה לקבל חבילה. בעוד שבמצב טעינה של ADB, אין פקודות ADB שאינן עבודות sideload ( logcat , reboot , push , pull , shell וכו '. כולם נכשלים).
  • אינך יכול לצאת ממצב Hadide ADB במכשיר. כדי לבטל, אתה יכול לשלוח /dev/null (או כל דבר אחר שאינו חבילה תקפה) כחבילה ואז המכשיר לא יצליח לאמת אותה ולעצור את נוהל ההתקנה. שיטת ה- CheckKey() של יישום השחזור תמשיך להיקרא לחיצות מקשים, כך שתוכל לספק רצף מפתח שמאפשר מחדש את המכשיר ועובד במצב של ADB Sidead.