סיבת האתחול הקנונית

Android 9 כולל את השינויים הבאים במפרט של סיבות האתחול של מנהל האתחול.

סיבות להפעלה מחדש

תוכנת אתחול משתמשת במשאבי חומרה וזיכרון שזמינים באופן ייחודי כדי לקבוע למה המכשיר הופעל מחדש, ואז מדווחת על כך על ידי הוספת androidboot.bootreason=<reason> לשורת הפקודה בליבה (kernel) של Android לצורך ההפעלה. לאחר מכן, init מתרגם את שורת הפקודה הזו כדי להעביר אותה לנכס Android‏ bootloader_boot_reason_prop (ro.boot.bootreason). במכשירים שפועלים עם Android מגרסה 12 ואילך, שמשתמשים בליבה בגרסה 5.10 ואילך, הערך androidboot.bootreason=<reason> מתווסף ל-bootconfig במקום לשורת הפקודה של הליבה.

מפרט הסיבות להפעלה

במהדורות קודמות של Android פורסם פורמט של סיבה להפעלה ללא רווחים, שבו כל התווים היו קטנים, וכללו כמה דרישות (למשל, לדיווח על kernel_panic, watchdog, cold/warm/hard) ואפשרו להשתמש בסיבות ייחודיות אחרות. המפרט המרושל הזה הוביל להפצה של מאות מחרוזות מותאמות אישית (ולפעמים חסרות משמעות) של סיבות לאתחול, וכתוצאה מכך למצב בלתי מנוהל. נכון לגרסה הנוכחית של Android, המומנטום העצום של תוכן כמעט בלתי ניתן לניתוח או ללא משמעות שנשלח על ידי מנהל האתחול יצר בעיות תאימות ב-bootloader_boot_reason_prop.

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

  • יצירת קשר עם מפתחי תוכנות אתחול כדי לעודד אותם:
    • צריך לציין סיבות קנוניות, ניתנות לניתוח וניתנות לזיהוי ל-bootloader_boot_reason_prop.
    • להשתתף ברשימה system/core/bootstat/bootstat.cpp kBootReasonMap.
  • הוספת מקור מבוקר של system_boot_reason_prop (sys.boot.reason) שאפשר לשכתב בזמן ריצה. קבוצה מוגבלת של אפליקציות מערכת (כמו bootstat ו-init) יכולה לשכתב את המאפיין הזה, אבל אפשר להעניק לכל האפליקציות הרשאות לקריאה של מדיניות האבטחה.
  • להודיע למשתמשים על סיבה לאתחול ולבקש מהם להמתין עד שמתקינים את userdata לפני שהם נותנים אמון בתוכן במאפיין של סיבה לאתחול המערכת system_boot_reason_prop.

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

  • לפני שמתקינים את userdata, הערך ב-system_boot_reason_prop יהיה זהה לערך ב-bootloader_boot_reason_prop.
  • אחרי הרכבת userdata, יכול להיות ש-system_boot_reason_prop יתעדכן כדי לעמוד בדרישות או כדי לדווח על מידע מדויק יותר.

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

הלוגיקה של Bootstat תלויה ב-bootloader_boot_reason_prop שמכיל מידע נוסף ועונה על דרישות התאימות. כשהמאפיין משתמש בפורמט צפוי, הוא משפר את הדיוק של כל התרחישים של הפעלה מחדש וכיבוי מבוקרים. הפעולה הזו משפרת ומרחיבה את הדיוק והמשמעות של system_boot_reason_prop.

הפורמט הקנוני של הסיבה להפעלה

הפורמט הקנוני של הסיבה להפעלה של bootloader_boot_reason_prop ב-Android 9 כולל את התחביר הבא:

<reason>,<subreason>,<detail>…

כללי עיצוב:

  • אותיות קטנות
  • אין שדות ריקים (משתמשים בקו תחתון)
  • כל התווים שאפשר להדפיס
  • reason, ‏ subreason ומופעים אחדים של detail, מופרדים בפסיקים.
    • השדה reason הנדרש מייצג את הסיבה בעדיפות הגבוהה ביותר לכך שהמכשיר הופעל מחדש או כבוי.
    • השדה האופציונלי subreason מייצג סיכום קצר של הסיבה להפעלה מחדש או לכיבוי של המכשיר (או מי הפעיל מחדש או כיבו את המכשיר).
    • אחד או יותר מהערכים של השדה detail אופציונלי. השדה detail יכול להפנות למערכת משנה כדי לעזור לקבוע איזו מערכת ספציפית גרמה ל-subreason. אפשר לציין כמה ערכים של detail, ובדרך כלל כדאי לפעול לפי היררכיית חשיבות. עם זאת, מותר גם לדווח על כמה ערכים של detail בעלי חשיבות שווה.

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

דרישות לגבי הסיבה

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

  • הגדרת הליבה:
    • "watchdog"
    • "kernel_panic"
  • קבוצה חזקה:
    • "recovery"
    • "bootloader"
  • מוגדר קהה:
    • "cold". מציין בדרך כלל איפוס מלא של כל המכשירים, כולל זיכרון.
    • "hard". המשמעות היא באופן כללי, שהמצב של החומרה מתאפס ו-ramoops צריך לשמור תוכן קבוע.
    • "warm". בדרך כלל מציין שהזיכרון והמכשירים שומרים מצב כלשהו, ושאחסון ה-back-end של ramoops (ראו הנהג pstore בליבה) מכיל תוכן עקבי.
    • "shutdown"
    • "reboot". בדרך כלל המשמעות היא שהמצב ramoops לא ידוע ומצב החומרה לא ידוע. הערך הזה הוא ערך כללי, כי הערכים cold, ‏ hard ו-warm מספקים רמזים לגבי עומק האיפוס של המכשיר.

מנהלי האתחול חייבים לספק קבוצת ליבה או קבוצה קהה reason, ומומלץ מאוד לספק subreason אם אפשר לקבוע אותו. לדוגמה, לחיצה ארוכה על לחצן ההפעלה, עם או בלי גיבוי של ramoops, תהיה עם הסיבה לטעינה "reboot,longkey".

reason לא יכול להיות חלק מ-subreason או מ-detail. עם זאת, מכיוון שמרחב המשתמש לא יכול לייצר את הסיבות להגדרת הליבה, ניתן לעשות שימוש חוזר ב-"watchdog" לאחר סיבה קהה, יחד עם פרטי המקור (לדוגמה, "reboot,watchdog,service_manager_unresponsive" או "reboot,software,watchdog").

הסיבות להפעלה לא צריכות לדרוש ידע פנימי מורחב כדי לפענח אותן, ו/או צריך להיות אפשר לקרוא אותן בדוח אינטואיטיבי. דוגמאות: "shutdown,vbxd" (רע), "shutdown,uv" (טוב יותר), "shutdown,undervoltage" (מועדף).

שילובים של סיבה משנית

ל-Android יש קבוצה של שילובים של reason-subreason שאסור להעמיס עליהם במהלך שימוש רגיל, אבל אפשר להשתמש בהם על בסיס כל מקרה לגופו אם השילוב משקף במדויק את התנאי המשויך. דוגמאות לשילובים שמורים:

  • "reboot,userrequested"
  • "shutdown,userrequested"
  • "shutdown,thermal" (החל מ-thermald)
  • "shutdown,battery"
  • "shutdown,battery,thermal" (מ-BatteryStatsService)
  • "reboot,adb"
  • "reboot,shell"
  • "reboot,bootloader"
  • "reboot,recovery"

פרטים נוספים זמינים בקטע kBootReasonMap ב-system/core/bootstat/bootstat.cpp ובהיסטוריית השינויים ב-git במאגר המקור של Android.

דיווח על סיבות לאתחול

כל הסיבות לאתחול, מה-bootloader או מהסיבה הקנונית לאתחול, חייבות להירשם בקטע kBootReasonMap בקובץ system/core/bootstat/bootstat.cpp. רשימת kBootReasonMap היא שילוב של סיבות תואמות וסיבות לא תואמות מדור קודם. מפתחי אתחול צריכים לרשום כאן רק סיבות חדשות ותואמות (ואסור לרשום סיבות לא תואמות, אלא אם המוצר כבר נשלח ולא ניתן לשנות אותו).

מומלץ מאוד להשתמש ברשומים קיימים ותואמים ב-system/core/bootstat/bootstat.cpp ולהפעיל שיקול דעת לפני שמשתמשים במחרוזת לא תואמת. להלן כמה הנחיות:

  • OK לדיווח על "kernel_panic" מה-bootloader, כי יכול להיות ש-bootstat יוכל לבדוק את ramoops עבור kernel_panic signatures כדי לשפר את הסיבות המשניות ל-system_boot_reason_prop הקנוני.
  • אסור לדווח על מחרוזת לא תואמת ב-kBootReasonMap (כמו "panic") מה-bootloader, כי בסופו של דבר זה יפגע ביכולת לשפר את ה-reason.

לדוגמה, אם kBootReasonMap מכיל את "wdog_bark", מפתח של מנהל האתחול צריך:

  • עוברים ל-"watchdog,bark" ומוסיפים לרשימה ב-kBootReasonMap.
  • כדאי לחשוב מה המשמעות של "bark" לאנשים שלא מכירים את הטכנולוגיה, ולבדוק אם יש "bark" משמעותי יותר שזמין.subreason

אימות התאימות של הסיבה לאתחול

נכון לעכשיו, Android לא מספק בדיקת CTS פעילה שיכולה להפעיל או לבדוק בצורה מדויקת את כל הסיבות האפשריות להפעלה של מנהל האתחול. עם זאת, השותפים עדיין יכולים לנסות להריץ בדיקה פסיבית כדי לקבוע את התאימות.

כתוצאה מכך, כדי לעמוד בדרישות התאימות של תוכנת האתחול, מפתחי תוכנת האתחול צריכים לפעול מרצונם בהתאם לרוח הכללים וההנחיות שמפורטים למעלה. אנחנו ממליצים למפתחים כאלה לתרום ל-AOSP (במיוחד ל-system/core/bootstat/bootstat.cpp) ולהשתמש בהזדמנות הזו כפורום לדיון בבעיות שקשורות לגורם האתחול.