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