非 A/B 系統更新

非 AB 更新是舊版 Android 裝置 (Android 6 以下版本) 使用的已淘汰的 OTA 方法。這些裝置具有專屬的復原分割區,其中包含解開下載更新套件所需的軟體,並將更新套用至其他分割區。

在沒有 A/B 分割區的舊版 Android 裝置上,快閃記憶體空間通常包含下列分割區:

開機
包含 Linux 核心和最小根檔案系統 (載入至 RAM 磁碟)。它會掛載系統和其他分區,並啟動位於系統分區的執行階段。
系統
包含在 Android 開放原始碼計畫 (AOSP) 中提供原始碼的系統應用程式和程式庫。在正常運作期間,這個分割區會以唯讀方式掛載,其內容只會在 OTA 更新期間變更。
販賣機
包含 Android 開放原始碼計畫 (AOSP) 中「沒有」原始碼的系統應用程式和程式庫。在正常運作期間,這個分割區會以唯讀方式掛載,其內容只會在 OTA 更新期間變更。
userdata
儲存使用者安裝的應用程式等儲存的資料。OTA 更新程序通常不會觸及這個分割區。
快取
部分應用程式使用的暫時保留區 (存取此分區需要特殊應用程式權限),用於儲存下載的 OTA 更新套件。其他程式會使用這個空間,因為檔案隨時可能會消失。部分 OTA 套件安裝作業可能會導致這個分區完全遭到清除。快取資料也包含 OTA 更新的更新記錄。
復原
包含第二個完整的 Linux 系統,包括核心和特殊的復原二進位檔,可讀取套件並使用其內容更新其他分區。
其他
Recovery 使用的 Tiny 分割區,用於儲存一些資訊,以便在裝置在套用 OTA 套件時重新啟動時,儲存相關資訊。

OTA 更新的生命週期

典型的 OTA 更新包含下列步驟:

  1. 裝置會定期向 OTA 伺服器進行檢查,並收到更新可用性的通知,包括更新套件的網址和顯示給使用者的說明字串。
  2. 將下載內容更新至快取或資料分割區,並根據 /system/etc/security/otacerts.zip 中的憑證驗證其加密簽名。系統會提示使用者安裝更新。
  3. 裝置會重新啟動至復原模式,並在該模式中啟動復原分區中的核心和系統,而非啟動分區中的核心。
  4. 復原二進位檔是由 init 啟動。它會在 /cache/recovery/command 中尋找指向下載套件的指令列引數。
  5. 復原程序會根據 /res/keys (復原分割區中 RAM 磁碟的一部分) 中的公開金鑰,驗證套件的加密簽名。
  6. 系統會從套件中提取資料,並視需要用於更新啟動、系統和/或供應商分區。系統分區中留下的新檔案之一,包含新復原分區的內容。
  7. 裝置會正常重新啟動。
    1. 系統會載入新更新的啟動分區,並掛載及開始執行新更新的系統分區中的二進位檔。
    2. 在正常啟動程序中,系統會檢查復原分區的內容是否與所需內容相符 (先前儲存在 /system 中的檔案)。如果兩者不同,系統會使用所需內容重新刷新復原分區。(在後續啟動時,復原分區已包含新內容,因此不需要重新刷新)。

系統更新完成!您可以在 /cache/recovery/last_log.# 中找到更新記錄。

更新套件

更新套件是包含可執行二進位 META-INF/com/google/android/update-binary.zip 檔案。驗證套件上的簽名後,recovery 會將這個二進位檔案擷取至 /tmp,並執行二進位檔案,傳遞下列引數:

  • 更新二進位 API 版本號碼。如果傳遞至更新二進位檔案的引數有所變更,這個數字就會增加。
  • 指令管道的檔案描述元。更新程式可以使用這個管道將指令傳回至復原二進位檔,主要用於 UI 變更,例如向使用者顯示進度。
  • 更新套件 .zip 檔案的檔案名稱

更新套件可以使用任何靜態連結的二進位檔做為更新二進位檔。OTA 套件建構工具會使用更新程式 (bootable/recovery/updater),後者提供簡單的指令碼語言,可執行許多安裝作業。您可以替換裝置上執行的任何其他二進位檔。

如要進一步瞭解更新程式二進位檔、edify 語法和內建函式,請參閱「OTA 套件內部結構」。

從舊版遷移

從 Android 2.3/3.0/4.0 版本遷移時,主要變更是將所有裝置專屬功能從一組具有預先定義名稱的 C 函式轉換為 C++ 物件。下表列出舊函式和新方法,兩者可用於大致相同的用途:

C 函式 C++ 方法
device_recovery_start() Device::RecoveryStart()
device_toggle_display()
device_reboot_now()
RecoveryUI::CheckKey()
(也包括 RecoveryUI::IsKeyPressed())
device_handle_key() Device::HandleMenuKey()
device_perform_action() Device::InvokeMenuItem()
device_wipe_data() Device::WipeData()
device_ui_init() ScreenRecoveryUI::Init()

將舊函式轉換為新方法應該相當簡單。別忘了新增新的 make_device() 函式,以便建立並傳回新的 Device 子類別例項。