更新管理員

更新管理員會為 VM 執行更新。更新管理員會與系統整合服務供應商提供的用戶端協調。用戶端會提供更新酬載,並協調整體車輛更新。更新程序包含下列步驟:

  1. 就緒:沒有更新正在進行。
  2. 準備:更新管理員會將更新寫入磁碟,但不會啟用更新。
  3. 啟用:更新管理員會啟用準備好的更新,以便在重新啟動後生效。
  4. 提交:更新管理工具會永久套用更新。

簡化狀態機,說明 Update Manager 的工作流程

圖 1. Update Manager 的高階作業。

更新管理員支援系統更新和服務套件更新,詳情請參閱本頁說明。

系統更新

Android 作業系統會使用兩組稱為「插槽」的分區,但一次只會啟用一個插槽。系統更新會將一組新的分割區寫入非作用中插槽,並在下次重新啟動時切換作用中插槽。如要進一步瞭解如何建構系統更新,請參閱「A/B 系統更新」。

服務組合更新

在 AAOS SDV 中,服務套件會將服務封裝在 APEX 內。服務套件更新會在暫時性工作階段中,暫存新的 APEX 檔案。系統會在重新啟動後啟用這些更新的套件組合。如要進一步瞭解如何建構服務套件 APEX,請參閱「服務套件更新」。

狀態機器

用戶端的要求和系統服務的事件會驅動 Update Manager 狀態機器。更新管理員的設計目標是具備復原能力,即使在發生非預期的重新啟動或當機情況後,也能復原狀態並繼續更新程序。

狀態機:說明 Update Manager 的工作流程

圖 2. 更新 Manager 狀態機器。

API

更新管理工具提供 API,可透過狀態機驅動更新程序。API 使用 VSIDL,支援位於任何 VM 的用戶端 (支援 SDV Comms),並提供要求失敗通知。

安全性與存取權

系統會使用授權政策限制 API 存取權。只有授權用戶端可以呼叫 Update Manager。

最新動態

由於更新作業可能需要長時間執行,因此 Update Manager 提供非同步狀態更新。用戶端必須訂閱狀態更新,才能監控狀態。

管理訂閱

  • 訂閱:用戶端會呼叫 SubscribeToStatusUpdates() 方法,訂閱狀態更新:

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

    呼叫 SubscribeToStatusUpdates() 之前,用戶端必須啟動實作 UpdateManagerListenerService 的 RPC 介面。

  • 取消訂閱:如要停止接收狀態更新,用戶端可以呼叫 UnsubscribeFromStatusUpdates()

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

UpdateManagerListenerService

呼叫 UpdateManagerService 上的 SubscribeToStatusUpdates() 的用戶端必須實作下列服務,才能接收狀態更新:

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:在 PREPAREACTIVATE_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() 擷取目前狀態和酬載。SystemUpdatePayloadServiceBundleUpdatePayload 訊息的說明請參閱「準備」一節。

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 要求會開始更新程序 (暫存酬載),但系統會等待啟動更新:

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 會開始更新。

酬載類型會決定更新類型。

系統更新酬載

系統更新會使用 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 狀態。

服務套裝組合更新酬載

服務套件更新會使用 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,表示 VM 已準備好重新啟動。否則,狀態會轉換為 ACTIVATE_PRE_REBOOT_FAILURE

重新啟動後

重新啟動後,系統會以檢查點模式啟動。在此模式下,系統不會將任何變更提交至永久儲存空間的使用者資料分割區。如果系統無法順利提交更新,就會將這些變更還原為初始狀態。

啟動次數上限

在下列任一情況下,系統會將使用者資料分割區的變更還原:

  • 用戶端會傳送明確的 Rollback() 要求,並重新啟動系統。
  • 系統啟動次數過多,但用戶端未呼叫 Commit()Rollback()。每種更新類型的啟動次數上限不同:
    • 系統更新:BootControl 實作設定。舉例來說,Cuttlefish 裝置所用實作的預設限制為七次啟動
    • 服務套件更新:用戶端提供的 ServiceBundleUpdatePayloadboot_attempts 欄位會在提出 Prepare() 要求時設定此值。
驗證

系統隨後會驗證更新:

  • 系統更新: dm-verity 會檢查更新後的插槽是否損毀。
  • 服務套件更新: apexd 會檢查每個 APEX 的簽章,並將 APEX 的映像檔掛接到檔案系統。

如果驗證成功,狀態會轉換為 ACTIVATE_POST_REBOOT_COMPLETE。Update Manager 會等待 Commit()Rollback()

如果驗證失敗,系統會重新啟動。當系統達到啟動限制時,系統會還原為原始狀態:

  • 系統更新:系統會還原至原始插槽。
  • 服務套件更新:系統會捨棄更新的 APEX,並重新啟用原始 APEX。

如果任何更新類型的驗證失敗,系統會在還原原始狀態後,將狀態轉換為 ACTIVATE_PRE_REBOOT_FAILURE

復原

Rollback 要求會開始將系統還原至更新前的狀態。

rpc Rollback(RollbackRequest) returns (RollbackResponse) {}

message RollbackRequest {}

message RollbackResponse {}

您可以在許多狀態下提出 Rollback() 要求。系統會根據初始狀態採取不同動作,並進入不同狀態:

發出回溯時的狀態 狀態轉換 系統動作
(僅限系統更新) PREPAREPREPARE_SUSPEND_COMPLETE &rightarrow; PREPARE_CANCEL &rightarrow; PREPARE_ROLLBACK &rightarrow; READY 系統更新:取消系統更新。
PREPARE_FAILUREPREPARE_COMPLETE &rightarrow; PREPARE_ROLLBACK &rightarrow; READY 系統更新:取消系統更新。

服務套件更新:中止暫存 APEX 工作階段。
ACTIVATE_PRE_REBOOT_COMPLETEACTIVATE_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 必須重新啟動,解除安裝才會生效。因此,請避免在更新期間呼叫 UninstallApexUninstallApex 不會移除預先安裝的 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 {}