מערכת השחזור כוללת מספר קטעי הוק (hooks) להוספת קוד ספציפי למכשיר כדי OTA עדכונים יכולים גם לעדכן חלקים של המכשיר שאינם מערכת Android (למשל, פס הבסיס או מעבד רדיו).
בקטעים ובדוגמאות הבאים מתבצעת התאמה אישית של מכשיר ה-tardis שמופק על ידי של yoyodyne.
מפת מחיצות
החל מ-Android 2.3, הפלטפורמה תומכת במכשירי Flash מסוג eMMc ובמערכת הקבצים ext4 שפועלת במכשירים האלה. הוא תומך גם בהתקני הבזק מסוג 'מכשיר טכנולוגיית זיכרון' (MTD) וב-yaffs2 במערכת קבצים מגרסאות ישנות יותר.
קובץ מפת המחיצות מצוין על ידי TARGET_recovery_FSTAB; משתמשים בקובץ הזה הקובץ הבינארי לשחזור והכלים לבניית החבילות. ניתן לציין את השם של קובץ המפה ב TARGET_recovery_FSTAB ב-BardConfig.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 על גבי התקן Flash של MTD. 'מכשיר' חייב להיות השם של מחיצת MTD
וחייבות להופיע ב
/proc/mtd
. - MD
-
מחיצת MTD גולמית, שמשמשת למחיצות שניתנות לאתחול כמו אתחול ושחזור. MTD הוא לא
אבל נקודת הטעינה משמשת כמפתח לאיתור של המחיצה. 'מכשיר'
חייב להיות השם של מחיצת MTD ב-
/proc/mtd
. - ext4
- מערכת קבצים מסוג ext4 על גבי מכשיר Flash eMMc. 'מכשיר' חייב להיות הנתיב של התקן הבלוק.
- emmc
- התקן בלוק eMMc גולמי, המשמש למחיצות הניתנות להפעלה כמו הפעלה ושחזור. דומה ל- מסוג mtd, ה-eMMc אף פעם לא מותקן בפועל, אבל מחרוזת נקודת הטעינה משמשת לאיתור את המכשיר שבטבלה.
- Vfat
-
מערכת קבצים מסוג FAT שמעל למכשיר בלוק, בדרך כלל לאחסון חיצוני, כמו כרטיס SD.
המכשיר הוא המכשיר הבלוקים, device2 הוא מכשיר בלוק שני שהמערכת מנסה לטעון אם
טעינת המכשיר הראשי נכשלה (עקב תאימות לכרטיסי SD שעשויה להיות
בפורמט של טבלת מחיצות).
צריך לטעון את כל המחיצות בתיקיית השורש (כלומר, ערך נקודת הטעינה חייב להיות טעון להתחיל בקו נטוי וללא לוכסנים אחרים. ההגבלה הזו חלה רק על טעינה מערכות קבצים בשחזור; המערכת הראשית יכולה להתקין אותם בחינם בכל מקום. הספריות
/boot
,/recovery
ו-/misc
צריכים להיות סוגים גולמיים (mtd או emmc), ואילו הספריות/system
,/data
,/cache
ו-/sdcard
(אם זמין) צריכים להיות מהסוגים של מערכות הקבצים (yaffs2 , ext4 או vfat).
החל מ-Android 3.0, הקובץ recovery.fstab מקבל שדה אופציונלי נוסף, אפשרויות. כרגע האפשרות היחידה שמוגדרת היא length , שמאפשרת לכם לציין את אורך המחיצה. האורך הזה משמש לפרמט מחדש את המחיצה (לדוגמה, בשביל מחיצת נתוני המשתמשים במהלך פעולה של איפוס נתונים או איפוס להגדרות המקוריות, או על מחיצת המערכת במהלך ההתקנה של חבילת OTA מלאה). אם ערך האורך הוא שלילי, הגודל לפורמט נלקח על ידי הוספת ערך האורך לגודל המחיצה האמיתי. עבור למשל, הגדרה של 'length=-16384' כלומר, 16,000 הנתונים האחרונים של המחיצה לא יהיו מוחלפת כאשר המחיצה מעוצבת מחדש. זה תומך בתכונות כמו הצפנה של המחיצה של נתוני המשתמשים (שבה המטא-נתונים של ההצפנה מאוחסנים בסוף המחיצה שאין להחליף).
הערה: השדות device2 ו-options הם אופציונליים, וכך יוצרים עמימות בניתוח. אם הערך בשדה הרביעי בשורה מתחיל ב-'/' הוא נחשב כרשומת device2 ; אם הרשומה לא מתחילה ב-'/' הוא נחשב לשדה options.
אנימציית האתחול
יצרני המכשירים יכולים להתאים אישית את האנימציה שמוצגת במכשירי Android בתהליך אתחול. לשם כך, צרו קובץ ZIP שמאורגן וממוקם בהתאם מפרטים ב: פורמט אתחול.
עבור מכשירי Android Things, אפשר להעלות את הקובץ הדחוס במסוף Android Things כדי שהתמונות ייכללו בו המוצר שנבחר.
הערה: התמונות האלה חייבות לעמוד בהנחיות המותג של Android. כדי לקבל הנחיות לגבי המותג: לעיין בסעיף Android שיווק שותפים מפצל.
ממשק המשתמש לשחזור
כדי לתמוך במכשירים עם פריטי חומרה זמינים שונים (לחצנים פיזיים, נורות LED, מסכים וכו'), אפשר להתאים אישית את ממשק השחזור כדי להציג את הסטטוס ולגשת לרכיבים שמופעלים באופן ידני בתכונות המוסתרות בכל מכשיר.
המטרה שלכם היא ליצור ספרייה סטטית קטנה עם כמה אובייקטים של C++ כדי לספק
פונקציונליות ספציפית למכשיר. הקובץ
bootable/recovery/default_device.cpp
משמש כברירת מחדל, והוא
נקודת ההתחלה להעתקה בזמן כתיבת גרסה של קובץ זה עבור המכשיר שלך.
הערה: יכול להיות שתופיע כאן ההודעה No Command. כדי להחליף מצב טקסט, לוחצים לחיצה ארוכה על לחצן ההפעלה בזמן שאתם לוחצים על הלחצן להגברת עוצמת הקול. אם במכשירים שלכם אין שני הלחצנים, לוחצים לחיצה ארוכה על לחצן כלשהו כדי להחליף את מצב הטקסט.
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 };
הערה: קווים ארוכים נחתכים (לא נכללים), לכן חשוב לשמור על רוחב את מסך המכשיר.
התאמה אישית של מפתח הביקורת
בשלב הבא יש להגדיר את ההטמעה של RecoverUI במכשיר. הדוגמה הזו מבוססת על ההנחה
למכשיר tardis יש מסך, כך שאפשר לקבל בירושה
ScreenrecoveryUIקלט (יש לעיין בהוראות של
מכשירים ללא מסך). הפונקציה היחידה
מותאם אישית מ-ScreenRecoveryUI הוא CheckKey()
, שעושה את הפקודה
טיפול במפתח אסינכרוני:
class TardisUI : public ScreenRecoveryUI { public: virtual KeyAction CheckKey(int key) { if (key == KEY_HOME) { return TOGGLE; } return ENQUEUE; } };
קבועים של KEY
הקבועים KEY_* מוגדרים ב-linux/input.h
. CheckKey()
הוא
בלי קשר למה שיקרה בהמשך תהליך השחזור: כשהתפריט במצב מושבת,
הוא מופעל, במהלך התקנת החבילה, במהלך איפוס נתוני המשתמש וכו'. הוא יכול להחזיר אחד
קבועים:
- לוחצים על TOGGLE. הפעלה או כיבוי של תצוגת התפריט ו/או יומן הטקסט
- REBOOT. הפעלה מחדש מיידית של המכשיר
- התעלמות. התעלמות מהקשה על המקש הזה
- כאן. מגדירים את לחיצה על המקש הזו לתור לצריכה באופן סינכרוני (כלומר, באמצעות השחזור) מערכת תפריטים אם התצוגה מופעלת)
נשלחת קריאה לפונקציה CheckKey()
בכל פעם שמתרחש אירוע מרכזי בעקבות אירוע מרכזי של
אותו מקש. (רצף האירועים A-למטה 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, אפשר להגדיר את המשתנה animation_fps
כדי לשלוט במהירות
פריימים לשנייה (FPS) של אנימציות.
הערה: הסקריפט interlace-frames.py
הנוכחי מאפשר לך
לאחסן את המידע של animation_fps
בתמונה עצמה. בגרסאות קודמות של
היה צורך להגדיר את animation_fps
בעצמך ב-Android.
כדי להגדיר את המשתנה 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()
, שמקבלת לחיצה על מקש
הרשאות הגישה של התפריט, ולהחליט איזו פעולה לבצע:
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. העברת הדגשת התפריט לפריט הקודם
- 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 } ... }
הערה: אם הערך של visible הוא False, לא כדאי להחזיר את הערך ערכים שמשפיעים על התפריט (העברת ההדגשה, הפעלת הפריט המודגש) מאחר שהמשתמש לא יכול כדי לראות את רגע השיא. עם זאת, אפשר להחזיר את הערכים האלה אם רוצים.
InvokeתפריטItem
בשלב הבא, צריך לספק שיטה 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 כדי לומר למערכת לבצע הפעולה (או את החבר NO_ACTION אם ברצונך שהמערכת לא תבצע שום פעולה). זה המקום מספקים פונקציונליות שחזור נוספת, מעבר למה שיש במערכת: הוספת פריט עבורו התפריט שלך, להפעיל אותו כאן כאשר האפשרות בתפריט מופעלת, ולהחזיר NO_ACTION כדי שהמערכת לא עושה שום דבר נוסף.
BuiltinAction מכיל את הערכים הבאים:
- NO_ACTION. לא לעשות דבר.
- REBOOT. יוצאים מהשחזור ומפעילים מחדש את המכשיר כרגיל.
- 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()
שיוצרת ומחזירה מופע של מחלקת המכשיר:
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, יכול להציג מחרוזת טקסט (למשל, "התקנת עדכון מערכת...") יחד עם התמונה. פרטים נוספים מופיעים במאמר טקסט לשחזור מותאם לשוק המקומי.
Android 5.0 ואילך
בממשק המשתמש לשחזור Android 5.0 ואילך יש שתי תמונות עיקריות: תמונת שגיאה והאנימציה התקנה.
האנימציה המותקנת מיוצגת כתמונת PNG יחידה עם פריימים שונים
אנימציה משולבת בשורה (וזו הסיבה שאיור 2 נראה מכווץ). לדוגמה, עבור
אנימציית 7 פריימים בגודל 200x200. יוצרים תמונה אחת בגודל 200x1400 כאשר הפריים הראשון הוא שורות 0, 7.
14, 21, ...; המסגרת השנייה היא שורות 1, 8, 15, 22, .... וכו'. התמונה המשולבת כוללת
גוש טקסט שמציין את מספר מסגרות האנימציה ואת מספר הפריימים בשנייה
(FPS). הכלי bootable/recovery/interlace-frames.py
לוקח קבוצה של פריימים של קלט
ולשלב אותם לתמונה המורכבת הנדרשת שמשמשת לשחזור.
תמונות ברירת המחדל זמינות בדחיסות שונות ונמצאות ב:
bootable/recovery/res-$DENSITY/images
(למשל,
bootable/recovery/res-hdpi/images
). כדי להשתמש בתמונה סטטית במהלך ההתקנה,
יש לספק רק את התמונה icon_installing.png ולהגדיר את מספר הפריימים
אנימציה ל-0 (סמל השגיאה לא מונפש, מדובר תמיד בתמונה סטטית).
Android 4.x וגרסאות קודמות
בממשק המשתמש של Android 4.x ובדגמים קודמים משתמשים בתמונת שגיאה (מוצגת למעלה) אנימציה מתקינים וגם כמה תמונות שכבת-על:
במהלך ההתקנה, התצוגה על המסך נבנית על ידי שרטוט הסמל icon_installing.png ואז משרטטים מעליה את אחת מהמסגרות של שכבת-העל בסטייה המתאימה. כאן מופיע סמל אדום מופיעה מעל לתמונה הבסיסית, כדי להדגיש את המיקום של שכבת-העל מעל לתמונה הבסיסית:
הפריימים הבאים מוצגים על ידי ציור רק של תמונת שכבת-העל הבאה מעל כבר שם; שתמונת הבסיס לא משורטטת מחדש.
מספר הפריימים באנימציה, המהירות הרצויה וערכי x ו-y בשכבת-העל
ביחס לבסיס מוגדרים על ידי משתני החבר של המחלקה ScreenRecoveryUI. בזמן השימוש
תמונות בהתאמה אישית במקום תמונות ברירת מחדל, מבטלים את השיטה Init()
ב
מחלקה משנית כדי לשנות את הערכים האלה לתמונות מותאמות אישית (לפרטים נוספים:
ScreenrecoveryUI). התסריט
bootable/recovery/make-overlay.py
יכול לסייע בהמרה של קבוצה של פריימים של תמונות
אל 'תמונת בסיס + תמונות שכבת-על' שנדרש לשחזור, כולל מחשוב
את הקיזוזים ההכרחיים.
תמונות ברירת המחדל נמצאות ב-bootable/recovery/res/images
. כדי להשתמש בתמונה סטטית
במהלך ההתקנה, צריך לספק רק את התמונה icon_installing.png ולהגדיר את מספר
הפריימים באנימציה ל-0 (סמל השגיאה לא מונפש, מדובר תמיד בתמונה סטטית).
טקסט שחזור מקומי
במערכת Android 5.x מוצגת מחרוזת טקסט (למשל, "מתבצעת התקנה של עדכון מערכת...") וגם תמונה. כאשר המערכת הראשית נכנסת לשחזור, היא מעבירה את הלוקאל הנוכחי של המשתמש בתור בשורת הפקודה לשחזור החשבון. לכל הודעה שמוצגת, השחזור כולל שנייה תמונה מורכבת עם מחרוזות טקסט שעברו עיבוד מראש להודעה הזו בכל לוקאל.
תמונה לדוגמה של מחרוזות טקסט לשחזור החשבון:
בטקסט השחזור יכולות להופיע ההודעות הבאות:
- עדכון המערכת בהתקנה...
- שגיאה!
- מתבצעת מחיקה... (כשמבצעים איפוס נתונים או איפוס להגדרות המקוריות)
- אין פקודה (כשמשתמש מבצע שחזור באופן ידני)
האפליקציה ל-Android ב-bootable/recovery/tools/recovery_l10n/
מעבדת התאמות מקומיות
של הודעה, ויוצר את התמונה המורכבת. כדי לקבל פרטים על השימוש באפליקציה הזו, אפשר לעיין ב
תגובות ב:
bootable/recovery/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java
כאשר משתמש יבצע שחזור באופן ידני, ייתכן שהלוקאל לא יהיה זמין ולא יהיה טקסט מוצגת. אל תשתמשו בהודעות הטקסט האלה כחיוניות לתהליך השחזור.
הערה: הממשק המוסתר שמציג הודעות ביומן ומאפשר למשתמש פעולות נבחרות מהתפריט זמינות באנגלית בלבד.
סרגלי התקדמות
סרגלי התקדמות יכולים להופיע מתחת לתמונה הראשית (או לאנימציה). סרגל ההתקדמות נוצר על ידי שמשלבים שתי תמונות קלט שגודלן חייב להיות זהה:
הקצה הימני של תמונת המילוי מוצג ליד הקצה הימני של ריק כדי ליצור את סרגל ההתקדמות. מיקום הגבול בין שני תחומים התמונות ישתנו כדי להצביע על ההתקדמות. לדוגמה, עם הצמדים שלמעלה של תמונות קלט, תצוגה:
ניתן לספק גרסאות ספציפיות למכשיר של התמונות האלה על ידי הצבתן במקומות
דוגמה) device/yoyodyne/tardis/recovery/res/images
הקצר הזה. התשובות שלך יעזרו לנו להשתפר. שמות הקבצים חייבים להיות תואמים לשמות שרשומים למעלה. כשקובץ נמצא בספרייה הזו,
מערכת build משתמשת בו בעדיפות של קובץ האימג' התואם בברירת המחדל. רק קובצי PNG ב-RGB או
יש תמיכה בפורמט RGBA עם עומק צבעים של 8 ביט.
הערה: ב-Android 5.x, אם המקום ידוע לצורך שחזור והוא בשפה מימין לשמאל (RTL) (ערבית, עברית וכו'), סרגל ההתקדמות מתמלא מימין לשמאל שמאלה.
מכשירים ללא מסכים
לא לכל מכשירי Android יש מסכים. אם המכשיר הוא מכשיר ללא GUI או שיש בו ממשק אודיו בלבד, יכול להיות שתצטרכו לבצע התאמה אישית נרחבת יותר של ממשק המשתמש לשחזור. במקום זאת של יצירת מחלקה משנית של ScreenRecoveryUI, מחלקה משנית ישירות RecoverUI.
ב-recoveryUI יש שיטות לטיפול בפעולות ברמה נמוכה יותר בממשק המשתמש, כמו "החלפת המסך".
"לעדכן את סרגל ההתקדמות", "show the תפריט", "שינוי הבחירה בתפריט", וכו'. אפשר לשנות
כדי לספק ממשק מתאים למכשיר. יכול להיות שבמכשיר שלך יש נורות LED,
אתם יכולים להשתמש בצבעים שונים או בדפוסים שונים של הבהוב כדי לציין את מצבם, או שאפשר לשחק
אודיו. (אולי אתם לא רוצים לתמוך בכלל בתפריט או במצב "תצוגת טקסט"; אפשר
למנוע את הגישה אליהם באמצעות CheckKey()
יישומי HandleMenuKey()
שלעולם לא מאפשרים להפעיל את התצוגה או בוחרים תפריט
שימושי. במקרה הזה, הרבה משיטות השחזור שצריך לספק יכולות להיות ריקות
stubs.)
בהצהרה של RecoverUI אפשר לראות באילו שיטות מדובר ב-bootable/recovery/ui.h
שבהם צריך לתמוך. recoveryUI הוא מופשט — שיטות מסוימות הן וירטואליות בלבד וצריך לספק אותן
מחלקות משנה, אבל הוא מכיל את הקוד לביצוע עיבוד של קלט מפתח. אפשר לשנות זאת
אם למכשיר אין מפתחות, או שאתם רוצים לעבד אותם באופן שונה.
מעדכן
ניתן להשתמש בקוד ספציפי למכשיר בהתקנה של חבילת העדכון על ידי אספקת לפונקציות תוסף, שניתן לקרוא להן מתוך סקריפט העדכון. הנה דוגמה למכשיר tardis:
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()
עליהם.
נניח שלפונקציה נדרשים שני ארגומנטים: מפתח עם ערך blob 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; }
חיפוש ערכים של 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*
– במיוחד חבר הנתונים.
במקרה כזה, אתם רוצים להחזיר ערך true או false כדי לציין שהצלחה. חשוב לזכור
המוסכמה שהמחרוזת הריקה היא false וכל שאר המחרוזות הן true. שלך
חייב להיות אובייקט 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" : "")); }
כדי לחבר פונקציות הוק (hook) לתרגום ב‐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)
לבסוף, מגדירים את ה-build של השחזור כדי למשוך את הספרייה. הוספת הספרייה שלך אל
TARGET_recovery_UPDATER_LIBS (שעשוי להכיל מספר ספריות; כולן רשומות).
אם הקוד תלוי בספריות סטטיות אחרות שאינן מפעילות תוספים בעצמן (כלומר
אין להם פונקציית Register_libname
), אפשר לציין אותם
TARGET_recovery_UPDATER_חוץ_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 נתונים ספציפיים למכשיר ופולטים סקריפטים של עדכונים שכוללים קריאות לפונקציות של התוספים.
קודם כול, מעדכנים את מערכת ה-build על נתונים blob ספציפיים למכשיר. הנחת הנתונים
הקובץ נמצא ב-device/yoyodyne/tardis/tardis.dat
. צריך להצהיר על הדברים הבאים ב
AndroidBoard.mk של המכשיר:
device/yoyodyne/tardis/AndroidBoard.mk
[...] $(call add-radio-file,tardis.dat)
אפשר גם לשמור אותו בקובץ Android.mk, אבל צריך להגן עליו באמצעות מכשיר כי כל הקבצים של Android.mk בעץ נטענים בלי קשר למכשיר של BERT. (אם העץ כולל מספר מכשירים, מומלץ להוסיף רק את הקובץ 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
קובצי רדיו מהסוג הזה נקראים קובצי רדיו מסיבות היסטוריות. יכול להיות שאין להם קשר
רדיו של המכשיר (אם קיים). הם פשוט blobs אטומים של נתונים שמערכת ה-build מעתיקה אליהם
קובצי ה-ZIP שמשמשים את כלי היצירה של OTA. כשמבצעים build, 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 השתנה בין שני פיתוחים.
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()
- בוצעה שיחה אחרי שכל הטענות הנכונות (assertions) לגבי מצב המכשיר חלפו, אבל לפני שינויים כלשהם של BERT. אפשר להשמיע פקודות לעדכונים ספציפיים למכשיר, שחייבים לרוץ לפני כל דבר אחר במכשיר השתנה.
FullOTA_InstallEnd()
- קריאה בסוף יצירת הסקריפט, לאחר פקודות הסקריפט לעדכן את האתחול בוצעו מחיצות מערכת. אפשר גם להוציא פקודות נוספות עבור עדכונים ספציפיים למכשיר.
IncrementalOTA_Assertions()
-
דומה ל-
FullOTA_Assertions()
, אבל נקרא כאשר מייצרים עדכון החבילה. IncrementalOTA_VerifyBegin()
- בוצעה שיחה אחרי שכל הטענות נכונות (assertions) לגבי מצב המכשיר חלפו, אבל לפני שהשינויים בוצעו. אפשר לפלוט פקודות לעדכונים ספציפיים למכשיר, שחייבים לרוץ לפני כל דבר אחר אחר במכשיר השתנה.
IncrementalOTA_VerifyEnd()
- בקשה נשלחת בסוף שלב האימות, כאשר הסקריפט סיים לאשר את הקבצים שאליהם הם עומדים לגעת כוללים את תוכן ההתחלה הצפוי. בשלב הזה שום דבר המכשיר הוחלף. אפשר גם לפלוט קוד כדי לעמוד בדרישות נוספות של מכשיר ספציפי, אימותים אישיים.
IncrementalOTA_InstallBegin()
- בוצעה שיחה לאחר שהקבצים לתיקון אומתו כמצופה לפני אבל לפני שנעשו שינויים. אפשר לשלוח פקודות עבור עדכונים ספציפיים למכשיר שחייבים לפעול לפני שינוי של כל דבר אחר במכשיר.
IncrementalOTA_InstallEnd()
- בדומה לחבילת ה-OTA המלאה, היא נקראת בסוף הסקריפט אחרי שפקודות הסקריפט לעדכן את מחיצות המערכת והאתחול הונפקה. אפשר גם להוציא פקודות נוספות לעדכונים ספציפיים למכשיר.
הערה: אם סוללת המכשיר מתרוקנת, ייתכן שהתקנת OTA תופעל מחדש מההתחלה. להיות מוכנים להתמודד עם מכשירים שבהם הפקודות האלה כבר פעלו, באופן מלא או חלקי.
העברת פונקציות לאובייקטים עם מידע
מעבירים פונקציות לאובייקט מידע אחד שמכיל מגוון פריטים שימושיים:
-
info.input_zip. (זמני OTA מלאים בלבד) האובייקט
zipfile.ZipFile
של מזינים קובץ ZIP עם קובצי יעד. -
info.source_zip. (OTA מצטבר בלבד) האובייקט
zipfile.ZipFile
עבור קובץ ה-ZIP המקורי עם קובצי היעד (ה-build כבר נמצא במכשיר כשהחבילה המצטברת מותקנת). -
info.target_zip. (OTA מצטבר בלבד) האובייקט
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 (META/releasetools.py
).
כשמריצים את כלי ההפצה (img_from_target_files
או
ota_from_target_files
), הסקריפט Releasetools.py בקובץ ה-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 שמכניסים למכשיר. כדי להתאים למכשירי Android שלא: אחסון חיצוני נשלף, במסגרת השחזור יש תמיכה בשני מנגנונים נוספים להתקנה ממקור לא ידוע: לטעון חבילות ממחיצת המטמון, ולטעון אותן בחיבור USB באמצעות adb.
כדי להפעיל כל מנגנון של העלאה משנית, שיטת Device::InvokeMenuItem()
של המכשיר
יכול להחזיר את הערכים הבאים של BuiltinAction:
-
APPLY_EXT. טעינה בצד של חבילת עדכון מאחסון חיצוני (
/sdcard
). השחזור.fstab צריך להגדיר את נקודת הטעינה של/sdcard
. הדבר לא ניתנת לשימוש במכשירים שמבצעים אמולציה של כרטיס SD עם קישור סימבולי ל-/data
(או בחלק מהמכשירים) מנגנון דומה). בדרך כלל,/data
לא זמינה לשחזור כי עשוי להיות מוצפן. בממשק המשתמש של השחזור מוצג תפריט של קובצי .zip ב-/sdcard
וב- מאפשרת למשתמש לבחור אחת. -
APPLY_CACHE דומה לטעינת חבילה מ-
/sdcard
, למעט נעשה שימוש בספרייה/cache
(שזמינה תמיד לשחזור) במקום זאת. במערכת הרגילה, ניתן לכתוב/cache
רק על ידי משתמשים בעלי הרשאות, ואם המכשיר לא ניתן לאתחול, לא ניתן יהיה לכתוב את הספרייה/cache
בכלל (ולכן המנגנון הזה הוא בעל תועלת מוגבלת). -
APPLY_ADB_SIDELOAD. מאפשר למשתמש לשלוח חבילה למכשיר באמצעות כבל USB ו
הכלי לפיתוח adb. כשמפעילים את המנגנון הזה, השחזור מתחיל במכשיר מיני משלו
של adbd דימון (daemon), כדי לאפשר ל-adb במחשב מארח מחובר לדבר אליו. המיני הזה
הגרסה תומכת רק בפקודה אחת:
adb sideload filename
. הקובץ בעל השם נשלח מהמכונה המארחת למכשיר, ואז מאמת מתקין אותו כאילו היה באחסון מקומי.
כמה נקודות שכדאי לשים לב אליהן:
- יש תמיכה רק בהעברת USB.
-
אם השחזור מפעיל adbd בדרך כלל (בדרך כלל נכון ל-userdebug ול-נג builds), אז זה יקרה
ייכבה כשהמכשיר במצב adbload, ויופעל מחדש לאחר adb
הקובץ המצורף סיים לקבל חבילה. במצב adbload, אין פקודות adb אחרות
מ-
sideload
עבודה (logcat
,reboot
,push
,pull
,shell
וכו'). -
לא ניתן לצאת ממצב adbload במכשיר. כדי לבטל, אפשר לשלוח
/dev/null
(או כל דבר אחר שאינו חבילה תקפה) בתור החבילה, וכן המכשיר לא יאמת אותו ויפסיק את תהליך ההתקנה. ממשק המשתמש לשחזור ה-methodCheckKey()
של ההטמעה תמשיך לקרוא ללחיצות המקשים, כדי לספק רצף מקשים שמפעיל מחדש את המכשיר ופועל במצב adbload.