המרכז לעדכונים

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

  1. מוכן: לא מתבצע עדכון.
  2. הכנה: כלי ניהול העדכונים כותב את העדכון בדיסק, אבל לא הופך אותו לפעיל.
  3. הפעלה: כלי ניהול העדכונים מפעיל את העדכון שהוכן כדי שהוא ייכנס לתוקף אחרי הפעלה מחדש.
  4. COMMIT: מנהל העדכונים הופך את העדכון לקבוע.

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

איור 1. פעולה כללית של Update Manager.

הכלי לניהול עדכונים תומך בעדכוני מערכת ובעדכונים של חבילות שירותים, שמתוארים בדף הזה.

עדכוני מערכת

מערכת ההפעלה Android משתמשת בשני סטים של מחיצות שנקראות משבצות, ורק משבצת אחת פעילה בכל פעם. עדכון מערכת כותב קבוצה חדשה של מחיצות למשבצת הלא פעילה, והמערכת מחליפה את המשבצת הפעילה בהפעלה הבאה מחדש. מידע נוסף על בניית עדכוני מערכת זמין במאמר בנושא עדכוני מערכת מסוג A/B.

עדכונים בחבילות שירות

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

מכונת מצבים

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

מכונת מצבים שממחישה את תהליך העבודה של מרכז העדכונים

איור 2. עדכון של מכונת המצבים של Update Manager.

API

מנהל העדכונים מספק API שמפעיל את תהליך העדכון דרך מכונת המצבים. ה-API משתמש ב-VSIDL, שתומך בלקוחות שנמצאים בכל מכונה וירטואלית שתומכת ב-SDV Comms, ומספק התראה על כשל בבקשה.

אבטחה וגישה

המערכת מגבילה את הגישה ל-API באמצעות מדיניות הרשאות. רק לקוח מורשה יכול להתקשר אל Update Manager.

עדכוני סטטוס

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

ניהול מינויים

  • הרשמה: לקוחות נרשמים לקבלת עדכוני סטטוס באמצעות קריאה לשיטה SubscribeToStatusUpdates():

    rpc SubscribeToStatusUpdates(SubscribeToStatusUpdatesRequest)
        returns (SubscribeToStatusUpdatesResponse) {}
    
    message SubscribeToStatusUpdatesRequest {}
    
    message SubscribeToStatusUpdatesResponse {}
    

    לפני שמתקשרים אל SubscribeToStatusUpdates(), הלקוח צריך להפעיל ממשק RPC שמיישם את UpdateManagerListenerService.

  • ביטול הרשמה: לקוחות יכולים להפסיק לקבל עדכוני סטטוס על ידי התקשרות אל UnsubscribeFromStatusUpdates():

    rpc UnsubscribeFromStatusUpdates(UnsubscribeFromStatusUpdatesRequest)
        returns (UnsubscribeFromStatusUpdatesResponse) {}
    
    message UnsubscribeFromStatusUpdatesRequest {}
    
    message UnsubscribeFromStatusUpdatesResponse {}
    

UpdateManagerListenerService

לקוחות שמתקשרים אל SubscribeToStatusUpdates() ב-UpdateManagerService צריכים להטמיע את השירות הבא כדי לקבל עדכוני סטטוס:

service UpdateManagerListenerService {
  /* Called when there is a status update from the Update Manager. */
  rpc OnStatusUpdate(OnStatusUpdateRequest) returns (OnStatusUpdateResponse) {}
}

message OnStatusUpdateRequest {
  oneof status_update {
    UpdateManagerStatus update_manager_status = 1;
    UpdateProgress update_progress = 2;
  }
}

message OnStatusUpdateResponse {}

OnStatusUpdateRequest מעביר אחת משתי הודעות אפשריות באמצעות השדה status_update:

  1. UpdateManagerStatus: נשלח כשמצב מנהל העדכונים משתנה.
  2. UpdateProgress: נשלח כדי לציין את התקדמות העדכון במהלך המצבים PREPARE ו-ACTIVATE_PRE_REBOOT, כי התהליך יכול להימשך זמן רב.

סטטוס והודעות שגיאה

הודעות הסטטוס כוללות פרטים על המצב ועל כשלים:

  • UpdateManagerStatus: מדווח על השלב הנוכחי של העדכון ועל כל סיבה לכשל:

    message UpdateManagerStatus {
      /* The current state of the update */
      UpdateState update_state = 1;
      /* The reason for the failure, if the update failed */
      FailureReason failure_reason = 2;
    }
    
    enum UpdateState {
      /* The Update Manager is ready to accept a new update. */
      READY = 0;
      /* An update is being prepared. */
      PREPARE = 1;
      /* The update failed during the prepare step. Roll back the update to start a
       *   new update. */
      PREPARE_FAILURE = 2;
      /* The update was prepared successfully. */
      PREPARE_COMPLETE = 3;
      /* A rollback has started from the prepare step. When complete, transitions
       *   to READY. */
      PREPARE_ROLLBACK = 4;
      /* The prepared update is being activated. */
      ACTIVATE_PRE_REBOOT = 5;
      /* The update failed during the activate step before the reboot. Roll back the
       *   update to start a new update. */
      ACTIVATE_PRE_REBOOT_FAILURE = 6;
      /* The update was activated successfully. Reboot to complete activation. */
      ACTIVATE_PRE_REBOOT_COMPLETE = 7;
      /* A rollback has started from the activate pre-reboot step. When complete,
       *   transitions to READY. */
      ACTIVATE_PRE_REBOOT_ROLLBACK = 8;
      /* An update was successfully activated after the reboot. The update needs to
       *   be committed or rolled back to be completed. */
      ACTIVATE_POST_REBOOT_COMPLETE = 9;
      /* A rollback has started from the activate post-reboot step. */
      ACTIVATE_POST_REBOOT_ROLLBACK = 10;
      /* The rollback was completed successfully. Reboot to complete the
       *   rollback. */
      ACTIVATE_POST_REBOOT_ROLLBACK_COMPLETE = 11;
      /* The update is being committed. When complete, transitions to READY */
      COMMIT = 12;
      /* The prepare request is being cancelled */
      PREPARE_CANCEL = 13;
      /* The system update has started suspending */
      PREPARE_SUSPEND = 14;
      /* The system update has finished suspending */
      PREPARE_SUSPEND_COMPLETE = 15;
    }
    
    message FailureReason {
      /* The original error that triggered the failure */
      ErrorCode error_code = 1;
      /* Binder error message for most ErrorCodes. */
      string error_message = 2;
    }
    
    enum ErrorCode {
      Unspecified = 0;
      /* Error from UpdateEngine service */
      UpdateEngineError = 1;
      // Error from the ApexService
      ApexServiceError = 2;
      // Error from the BootControlService
      BootControlServiceError = 3;
      // Error from the VoldService
      VoldServiceError = 4;
    }
    
  • UpdateProgress: מדווח על הסטטוס הנוכחי מ-Update Engine במהלך עדכוני מערכת:

    message UpdateProgress {
      /* Matches the enum UpdateStatus from the UpdateEngine service. */
      int32 status_code = 1;
    
      /* A value ranging from 0.0 to 1.0, 1.0 representing the process is complete. */
      float percentage = 2;
    }
    
    

קבלת סטטוס מיידי

אפשר לאחזר את המצב הנוכחי ואת מטען הייעודי בכל שלב באמצעות קריאה ל-GetStatus(). ההודעות SystemUpdatePayload ו-ServiceBundleUpdatePayload מתוארות במאמר הכנה.

rpc GetStatus(GetStatusRequest) returns (GetStatusResponse) {}

message GetStatusRequest {}

message GetStatusResponse {
  /* The status of the Update Manager */
  UpdateManagerStatus update_manager_status = 1;
  /* The current update payload, if one has been set through the Prepare() request */
  oneof payload {
    SystemUpdatePayload system_update_payload = 2;
    ServiceBundleUpdatePayload service_bundle_update_payload = 3;
  }
}

היערכות

הבקשה Prepare מתחילה את תהליך העדכון על ידי העברת מטען הייעודי (payload) למצב ביניים, אבל המערכת ממתינה להפעלת העדכון:

rpc Prepare(PrepareRequest) returns (PrepareResponse) {}

message PrepareRequest {
  oneof payload {
    SystemUpdatePayload system_update_payload = 1;
    ServiceBundleUpdatePayload service_bundle_update_payload = 2;
  }
}

message PrepareResponse {}

אם הבקשה תקינה, המצב משתנה ל-PREPARE, והכלי Update Manager מתחיל את העדכון.

סוג המטען הייעודי (Payload) קובע את סוג העדכון.

מטען ייעודי (payload) של עדכון מערכת

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

message SystemUpdatePayload {
  /* Absolute path to the update image (e.g., /updates/ota_update.zip) */
  string payload = 1;

  /* Offset (in bytes) into the payload where the payload binary starts. */
  optional int64 payload_offset = 2;

  /* The amount of data (in bytes) to read from "payload" as the update payload. */
  optional int64 payload_size = 3;

  /* The header key value pairs to apply with the payload. */
  map<string, string> header_key_value_pairs = 4;
}

מנהל העדכונים מעבד את קובץ האימג' לעדכון OTA (שמסופק על ידי הלקוח בספרייה /data/ota_package) כדי להפעיל שלבים אחרי ההתקנה, אבל הוא לא מחליף את משבצת האתחול הפעילה. לאחר מכן, המערכת עוברת למצב PREPARE_COMPLETE אם הפעולה הצליחה או למצב PREPARE_FAILURE אם היא נכשלה.

השהיית עדכון המערכת

אפשר להשהות את תהליך העדכון רק לעדכוני מערכת. הבקשה הזו תקפה רק כשהיא במצב PREPARE.

  • השהיה: העדכון מושהה והמצב משתנה דרך PREPARE_SUSPEND.

    rpc Suspend(SuspendRequest) returns (SuspendResponse) {}
    
    message SuspendRequest {}
    
    message SuspendResponse {}
    

    אם הפעולה מצליחה, המצב משתנה ל-PREPARE_SUSPEND_COMPLETE. אם הפעולה נכשלת, המצב משתנה לPREPARE_FAILURE.

  • המשך: ממשיך את העדכון שהושהה. האפשרות הזו תקפה רק במדינת PREPARE_SUSPEND_COMPLETE.

    rpc Resume(ResumeRequest) returns (ResumeResponse) {}
    
    message ResumeRequest {}
    
    message ResumeResponse {}
    

    המעבר בין המצבים חוזר למצב PREPARE.

מטען ייעודי (payload) לעדכון חבילת שירותים

עדכון של חבילת שירות משתמש ב-ServiceBundleUpdatePayload, שמכיל את הנתיבים לקובצי ה-APEX ומגדיר את מגבלת ניסיונות ההפעלה.

message ServiceBundleUpdatePayload {
  /* Absolute path to an .apex file. Multiple .apex files can be included. */
  repeated string apex_path = 1;

  /* Number of boots to attempt activation before aborting. Must be > 0. */
  int32 boot_attempts = 2;
}

מנהל העדכונים מוודא שקובצי ה-APEX חתומים בצורה נכונה ומכין אותם להפעלה בסשן. אם הפעולה מצליחה, המצב משתנה ל-PREPARE_COMPLETE. אם הפעולה נכשלת, המצב משתנה לPREPARE_FAILURE.

הפעלה

הבקשה Activate מפעילה את העדכון המוכן בהפעלה הבאה מחדש.

rpc Activate(ActivateRequest) returns (ActivateResponse) {}

message ActivateRequest {}

message ActivateResponse {}

לפני ההפעלה מחדש

מנהל העדכונים עובר למצב ACTIVATE_PRE_REBOOT בזמן הפעלת העדכון. בנוסף, כלי ניהול העדכונים יוצר נקודת ביקורת של נתוני המשתמשים שנכנסת לתוקף כשהמערכת מופעלת מחדש.

פעולות ההפעלה משתנות בהתאם לסוג העדכון:

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

אם המערכת מפעילה את העדכון בהצלחה, המצב משתנה ל-ACTIVATE_PRE_REBOOT_COMPLETE, שמציין שהמכונה הווירטואלית מוכנה להפעלה מחדש. אחרת, המצב משתנה ל-ACTIVATE_PRE_REBOOT_FAILURE.

לאחר הפעלה מחדש

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

מגבלת אתחול

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

  • הלקוח שולח בקשת Rollback() מפורשת ומפעיל מחדש את המערכת.
  • המערכת מבצעת אתחול יותר מדי פעמים בלי שהלקוח יתקשר אל Commit() או אל Rollback(). מגבלת האתחול שונה לכל סוג עדכון:
    • עדכון מערכת: ההגדרה הזו נקבעת על ידי ההטמעה של BootControl. לדוגמה, המגבלה שמוגדרת כברירת מחדל בהטמעה שמשמשת מכשירי Cuttlefish היא שבע הפעלות.
    • עדכון חבילת שירותים: השדה boot_attempts של ServiceBundleUpdatePayload שסופק על ידי הלקוח מוגדר כשמתבצעת בקשת Prepare().
אימות

המערכת מאמתת את העדכון:

  • עדכון מערכת: dm-verity בודק אם יש נתונים פגומים במשבצת המעודכנת.
  • עדכון של חבילת שירותים: apexd בודק את החתימה של כל APEX ומעלה את תמונת ה-APEX למערכת הקבצים.

אם האימות יצליח, המצב ישתנה לACTIVATE_POST_REBOOT_COMPLETE. הכלי לניהול עדכונים ימתין עד Commit() או עד Rollback().

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

  • עדכון מערכת: המערכת חוזרת לחריץ המקורי.
  • עדכון חבילת שירותים: קובצי ה-APEX המעודכנים מושמטים, וקובצי ה-APEX המקוריים מופעלים מחדש.

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

חזרה לגרסה קודמת

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

rpc Rollback(RollbackRequest) returns (RollbackResponse) {}

message RollbackRequest {}

message RollbackResponse {}

אפשר לשלוח את הבקשה Rollback() במהלך הרבה מצבים. בהתאם למצב ההתחלתי, המערכת מבצעת פעולות שונות, ומתקבלים מצבים שונים:

המצב כשמבצעים החזרה לגרסה קודמת מעבר בין מצבים פעולת מערכת
(עדכון מערכת בלבד) PREPARE, PREPARE_SUSPEND_COMPLETE ‫&rightarrow; PREPARE_CANCEL &rightarrow; PREPARE_ROLLBACK &rightarrow; READY עדכון מערכת: ביטול עדכון המערכת.
PREPARE_FAILURE, PREPARE_COMPLETE ‫&rightarrow; PREPARE_ROLLBACK &rightarrow; READY עדכון מערכת: ביטול עדכון המערכת.

עדכון חבילת שירותים: ביטול שלב ההכנה של סשן APEX.
ACTIVATE_PRE_REBOOT_COMPLETE, ACTIVATE_PRE_REBOOT_FAILURE ‫&rightarrow; ACTIVATE_PRE_REBOOT_ROLLBACK &rightarrow; READY ההגדרה משביתה את נקודת הבדיקה של נתוני המשתמש.

עדכון מערכת: ביטול המעבר לחריץ האתחול.

עדכון חבילת שירותים: הסרת APEX שהועבר להמתנה.
ACTIVATE_POST_REBOOT_COMPLETE &rightarrow; ACTIVATE_POST_REBOOT_ROLLBACK &rightarrow; ACTIVATE_POST_REBOOT_ROLLBACK_COMPLETE ההגדרה הזו משביתה את נקודת הבדיקה של נתוני המשתמשים.

עדכון מערכת: מחזיר את משבצת האתחול.

עדכון חבילת שירותים: מחזיר את סשני ה-APEX הפעילים.

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

לביצוע הבדיקה

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

rpc Commit(CommitRequest) returns (CommitResponse) {}

message CommitRequest {}

message CommitResponse {}

הסטטוס משתנה ל-COMMIT במהלך ביצוע פעולות האישור:

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

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

הסרת חבילות APEX

הבקשה UninstallApex מסירה את גרסה /data של חבילות השירות. אפשר להתקשר אל UninstallApex בכל מצב, אבל כדי שההסרה תיכנס לתוקף צריך להפעיל מחדש את ה-VM. לכן, אל תתקשרו ל-UninstallApex בזמן שמתבצע עדכון. ‫UninstallApex לא מסיר קובצי APEX שהותקנו מראש, לא מוחק נתוני APEX ולא מסיר גרסאות לא פעילות של APEX.

rpc UninstallApex(UninstallApexRequest) returns (UninstallApexResponse) {}

message UninstallApexRequest {
  message ApexInfo {
    string module_name = 1;
    int64 version_code = 2;
  }
  repeated ApexInfo apexes = 1;
}

message UninstallApexResponse {}