Android FOTA 概念
===
###### tags: `Android`
###### tags: `Android`, `OS`, `update`, `update`, `FOTA`, `Google Play`
<br>
[TOC]
<br>
## 討論
### Android FOTA 機制,是怎樣的機制?
- ### gpt-4o (2025/03/19)
> Android FOTA 機制介紹
Android FOTA(Firmware Over-The-Air)機制是一種透過無線網路(OTA)推送並更新裝置韌體或系統軟體的方法。這種機制廣泛用於智慧型手機、平板電腦及其他 Android 設備,允許製造商和電信業者在不需使用者手動下載更新或透過電腦刷機的情況下,遠端提供系統更新。
### **Android FOTA 機制的運作流程**
1. **更新檢查(Check for Update)**
- 設備定期向 FOTA 伺服器查詢是否有新的韌體或系統更新。
- 使用者也可以手動檢查更新(位於「設定」>「系統」>「系統更新」)。
2. **下載更新檔案(Download OTA Update)**
- 當伺服器確認設備符合更新條件,則提供相應的 OTA 更新檔案(通常是增量更新)。
- 更新檔案會先下載到設備的儲存空間(如 `/cache` 或 `/data/ota_package/`)。
3. **驗證更新檔案(Verify Update Package)**
- 下載完成後,系統會透過 SHA-256 驗證更新檔案的完整性,確保未被竄改。
- 如果驗證失敗,更新將會被取消。
4. **安裝更新(Apply Update)**
- 在 A/B 分區機制(Seamless Update)的裝置上,系統會將更新安裝到非作用中的分區,確保更新不影響當前系統運行。
- 在傳統單分區機制的裝置上,更新過程需要重新開機,並在 Recovery 模式下安裝。
5. **重新開機並切換至新系統(Reboot & Switch)**
- **A/B 分區機制**:重新開機後,設備會自動切換至新的分區並執行更新後的系統。
- **單分區機制**:設備在 Recovery 模式完成更新後,重新開機進入新的系統。
6. **後處理(Post-Update Processing)**
- 針對應用程式和數據庫進行遷移、最佳化(如 ART 快取重建)。
- 確保新系統能夠正常運行,如有問題則可以回滾至先前版本(僅適用於 A/B 分區機制)。
### **Android FOTA 機制的關鍵技術**
1. **A/B 分區(Seamless Update)**
- 透過兩個系統分區(A 和 B),可以在不影響使用者操作的情況下安裝更新,提高可靠性。
- 如果更新失敗,系統會自動回滾到原本的系統分區,降低裝置變磚的風險。
2. **增量更新(Delta Update)**
- 為了減少下載流量,FOTA 更新通常透過增量更新方式,只下載並安裝與舊版本不同的部分,而不是整個系統映像檔。
3. **Google Play 系統更新(Project Mainline)**
- 從 Android 10 開始,Google 引入了 Project Mainline,允許透過 Google Play Store 直接更新某些系統組件,而不需要完整的 FOTA 更新。
### **FOTA 機制的優勢**
- **使用者無需手動更新**:透過 OTA 自動推送,減少手動刷機的風險。
- **提升系統安全性**:可快速修補安全漏洞,提供最新的安全性修正。
- **減少數據浪費**:透過增量更新降低更新檔案的大小。
- **無縫更新(Seamless Update)**:對於支援 A/B 分區的裝置,更新過程幾乎不影響使用體驗。
### **FOTA 可能遇到的問題**
- **裝置儲存空間不足**:若設備儲存空間不足,更新可能會失敗。
- **網路環境影響**:若網路不穩定,下載更新檔案時可能會中斷。
- **設備相容性問題**:部分舊設備可能不支援 A/B 分區或無法獲得新版本更新。
- **電池電量不足**:更新過程中若電量過低,可能會導致更新失敗或設備無法正常啟動。
### **總結**
Android FOTA 是一種高效、方便且安全的系統更新機制,透過 OTA 更新技術,設備可以無需電腦直接升級系統。然而,FOTA 的成功部署仍依賴於裝置製造商和電信業者的支持,並且可能會受到設備硬體架構與儲存空間的限制。
<br>
<hr>
<br>
### 更新檔是長什麼樣子?系統、app是如何打包成更新檔?
- gpt-4o (2025/03/19)
> Android FOTA 機制與更新檔案格式
Android FOTA(Firmware Over-The-Air)更新檔的格式和打包方式主要取決於更新類型,主要分為 **系統更新(System OTA)** 和 **應用程式更新(App OTA)**。這些更新檔案在 Android 設備上通常以 .zip 格式存在,並且遵循特定的簽署與驗證機制。
---
### 1. 系統更新(System OTA)
#### (1) 更新檔的格式
Android FOTA 系統更新檔通常是一個壓縮檔(`.zip`),內部包含以下內容:
```
update.zip
│── META-INF/ # OTA 安裝腳本、簽名資訊
│── boot.img # 開機映像檔
│── recovery.img # Recovery 模式映像檔
│── system.new.dat # 系統映像檔(可能是增量更新)
│── vendor.new.dat # Vendor 映像檔(供應商驅動)
│── system.patch.dat # 增量更新時的補丁檔案
│── file_contexts.bin # SELinux 權限配置
│── payload.bin # A/B 分區機制的完整更新檔
│── payload_properties.txt # Payload 檔案的屬性
│── updater-script # OTA 安裝的指令腳本
│── update-binary # 更新執行檔
```
#### (2) OTA 更新檔的種類
- **完整映像檔(Full OTA)**:
- 包含整個系統的映像檔(system.new.dat、vendor.new.dat、boot.img 等)。
- 主要用於設備的重大升級(如從 Android 12 升級到 Android 13)。
- 檔案通常較大(1GB 以上)。
- **增量更新(Delta OTA)**:
- 只包含與當前系統不同的變更內容(system.patch.dat)。
- 下載量較小(通常數百 MB)。
- 透過 **bsdiff** 或 **imgdiff** 生成二進制補丁,應用時只改變不同部分,減少數據消耗。
#### (3) 打包方式
系統 OTA 更新檔通常由 **Android Build System** 打包:
```
# 產生完整 OTA 更新檔
ota_from_target_files -p out/host/linux-x86 -k keys/releasekey \
-o out/target/product/device-name/update-full.zip out/target_files.zip
# 產生增量 OTA 更新檔
ota_from_target_files -p out/host/linux-x86 -k keys/releasekey \
-i old_target_files.zip \
-o out/target/product/device-name/update-delta.zip new_target_files.zip
```
#### (4) 系統 OTA 更新流程
1. 設備向 FOTA 伺服器請求更新資訊。
2. 下載 OTA 更新包(完整或增量)。
3. 檢查 OTA 更新包的數位簽章(確保來自可信任來源)。
4. 進入 Recovery 模式,應用更新(使用 `updater-script` 或 `payload.bin`)。
5. 驗證並重啟設備,完成系統升級。
---
### 2. 應用程式更新(App OTA)
除了系統 OTA,Google Play 商店或 FOTA 伺服器也可以推送應用程式更新。應用更新的打包方式與系統更新不同。
#### (1) 應用更新檔的格式
應用程式的 OTA 更新檔通常是 `.apk` 或 `.aab`(Android App Bundle),主要格式如下:
```
app.apk
│── AndroidManifest.xml # 應用資訊
│── classes.dex # Dalvik/ART 執行檔
│── lib/ # 原生程式庫(如 ARM、x86)
│── res/ # UI 資源
│── META-INF/ # 簽名資訊
│── assets/ # 應用內部資源
```
- `.apk(Android Package)`:直接安裝的 Android 應用程式封裝檔。
- `.aab(Android App Bundle)`:Google Play 會根據裝置規格自動產生適合的 APK。
#### (2) 增量更新(Delta Patch APK)
- **Google Play Store** 透過 **bsdiff** 生成 **delta APK**,減少流量。
- **Android App Bundles(.aab)** 允許設備僅下載適用的程式碼與資源,減少安裝包大小。
#### (3) 應用程式 OTA 更新流程
1. Google Play 商店或第三方應用商店推送更新資訊。
2. 使用者確認後,設備開始下載新的 `.apk` 或 **增量補丁(Delta APK)**。
3. 系統驗證簽章並應用更新,舊版本 APK 可能被覆蓋或增量修補。
4. 完成更新後,應用程式可立即運行新版本。
---
### 3. A/B 分區機制與 OTA
在新的 Android 設備上(Android 7.0+),Google 推出了 **A/B(Seamless)更新機制**:
- 系統分為 A 和 B 兩個分區,設備運行時不影響系統更新。
- OTA 下載後,更新安裝到「非作用分區」,確保即使更新失敗,設備仍可回滾至原版本。
#### (1) `payload.bin` 更新檔案結構
```
├── payload.bin # 系統映像壓縮檔
├── payload_properties.txt # 版本資訊
├── care_map.pb # 分區對應表
├── compatibility.zip # 兼容性資訊
```
#### (2) A/B OTA 更新命令
```
adb shell update_engine_client --payload=file:///path/to/payload.bin --update
```
---
### 4. 總結
| 更新類型 | 檔案格式 | 更新方式 | 檔案內容 |
|-----------|---------|----------|---------|
| **系統 OTA** | `.zip`(update.zip / payload.bin) | Recovery 模式 / A/B 分區 | `system.new.dat`, `boot.img`, `payload.bin` |
| **應用 OTA** | `.apk` / `.aab` | Google Play 更新 / 手動安裝 | `classes.dex`, `res/`, `lib/` |
| **增量更新** | `.patch.dat` / `.bsdiff` | 只下載變更部分 | `system.patch.dat`, `delta APK` |
| **A/B OTA** | `payload.bin` | A/B 分區更新 | `payload.bin`, `update_engine_client` |
Android FOTA 更新透過 `.zip` 檔案包含完整或增量系統映像,透過 Recovery 或 A/B 機制安裝。而應用程式更新則透過 `.apk` 或 `.aab` 格式,並可透過增量補丁減少下載流量。
這套機制確保 Android 設備能夠持續獲得系統與應用更新,提升安全性與功能性。
<br>
<hr>
<br>
### Updater_script 會做哪些事情?
- gpt-4o (2025/03/19)
> **Android OTA 更新機制中的 `updater-script`**
### **`updater-script` 在 Android OTA 更新中的角色**
在傳統的 **Recovery-based OTA(單分區系統)** 更新機制中,`updater-script`(位於 OTA 更新包內的 `META-INF/com/google/android/updater-script`)負責指示 **Recovery 模式** 執行系統更新的步驟,包括:
1. **檢查裝置相容性**
2. **掛載(Mount)系統分區**
3. **刪除/複製/修補系統檔案**
4. **寫入 boot.img 或其他映像檔**
5. **清除快取與資料**
6. **完成更新並重啟**
---
### **`updater-script` 的結構與內容**
`updater-script` 是一個類似 Shell Script 的指令集,由 **Edify 語言** 撰寫(Android 6.0 以前),控制 Recovery 來執行更新作業。主要包含以下指令:
#### **1. 檢查設備資訊**
```bash
getprop("ro.product.device") == "device_codename" || abort("This package is for device_codename; this device is " + getprop("ro.product.device"));
```
- **作用**:檢查裝置名稱是否符合,避免錯誤刷入。
#### **2. 顯示 UI 訊息**
```bash
ui_print("Starting OTA update...");
```
- **作用**:顯示更新訊息。
#### **3. 掛載(Mount)分區**
```bash
mount("ext4", "EMMC", "/dev/block/platform/bootdevice/by-name/system", "/system");
```
- **作用**:將 `system` 分區掛載到 `/system` 以進行修改。
#### **4. 解壓縮並寫入檔案**
```bash
package_extract_dir("system", "/system");
```
- **作用**:將 OTA 更新包中的 `system/` 目錄內容解壓縮到 `/system` 分區。
#### **5. 寫入 Boot / Recovery 映像檔**
```bash
package_extract_file("boot.img", "/dev/block/bootdevice/by-name/boot");
```
- **作用**:將 `boot.img` 寫入 boot 分區。
#### **6. 刪除與修補檔案**
```bash
delete_recursive("/system/app/OldApp");
```
- **作用**:刪除 `/system/app/OldApp` 目錄(移除舊應用)。
```bash
apply_patch("/system/bin/app_process", "-",
"new_checksum",
"old_checksum",
"patch_data");
```
- **作用**:透過二進制補丁修補 `/system/bin/app_process`,避免覆蓋整個檔案。
#### **7. 清除 Cache 與 Data**
```bash
delete_recursive("/cache");
delete_recursive("/data/dalvik-cache");
```
- **作用**:刪除 Cache 分區,清理 Dalvik/ART 快取。
#### **8. 設定權限**
```bash
set_perm(0, 0, 0755, "/system/bin/new_binary");
set_perm_recursive(0, 0, 0755, 0644, "/system/app/NewApp");
```
- **作用**:設定執行檔與應用程式的權限。
#### **9. 重啟設備**
```bash
ui_print("OTA update complete. Rebooting...");
reboot("recovery");
```
- **作用**:更新完成後重新開機。
---
### **`updater-script` 在不同機制下的變化**
| OTA 更新機制 | `updater-script` 作用 | 替代機制 |
|-------------|-----------------|--------|
| **單分區(Legacy Recovery)** | `updater-script` 控制所有更新過程 | 無 |
| **A/B 分區(Seamless Update)** | 不使用 `updater-script`,改用 `payload.bin` | `update_engine` |
| **增量更新(Delta OTA)** | 使用 `apply_patch` 修補系統檔案 | `payload.bin` |
**A/B OTA 更新機制(Android 7.0+)** 已經不再使用 `updater-script`,而是改由 `payload.bin` 搭配 `update_engine` 自動處理更新。
---
### **結論**
- `updater-script` 主要用於 **Recovery-based OTA 更新**,控制掛載分區、寫入映像檔、更新檔案、清理快取、設定權限等步驟。
- **在 A/B OTA 更新機制中,`updater-script` 已被 `payload.bin` 取代**,改由 `update_engine` 自動處理更新作業。
- 透過 `updater-script`,可以直接操作 `/system`、`/boot` 等分區,適合舊設備的 OTA 更新或自訂 ROM 刷機。
<br>
<hr>
<br>
### payload.bin 搭配 update_engine,如何自動處理更新?
- ### gpt-4o (2025/03/19)
> **`payload.bin` 搭配 `update_engine` 如何自動處理 OTA 更新**
在 **A/B 分區 OTA 更新機制(Seamless Update)** 中,傳統的 `updater-script` 不再使用,取而代之的是 **`payload.bin`**,搭配 **`update_engine`** 自動處理系統更新。
這種機制主要透過:
1. **Payload Metadata(更新資訊)**
2. **增量更新演算法(Delta Update)**
3. **異步更新應用(Background Update)**
4. **自動回滾機制(Automatic Rollback)**
---
### **1. `payload.bin` 檔案的結構**
在 A/B OTA 更新機制中,更新包內的主要檔案是 **`payload.bin`**,而非傳統的 `update.zip`。`payload.bin` 是一個二進制檔案,內含完整的更新資訊。
#### **`payload.bin` 內部結構**
```
payload.bin
│── Manifest # 更新描述資訊
│── Metadata # 檔案雜湊與分區資訊
│── Signatures # 安全簽章
│── Data Blobs # 實際的更新數據
```
這些資訊允許 **`update_engine`** 在背景中將更新應用到「非作用中的分區」,確保不影響裝置運行。
---
### **2. `update_engine` 如何處理 OTA 更新**
在 A/B OTA 機制下,更新是透過 `update_engine` 自動管理的,步驟如下:
#### **(1) 下載並驗證更新**
- 設備檢查 Google/FOTA 伺服器,確認是否有新版本可用。
- 下載 `payload.bin`(完整或增量更新)。
- 使用 `metadata` 進行 SHA-256 驗證,確保更新檔案未被竄改。
#### **(2) 安裝更新到非作用中的分區**
- 目前運行的系統(假設為 **Slot A**)。
- `update_engine` 會將 `payload.bin` 內容寫入到 **Slot B**(非作用分區)。
- 透過 `diff patch` 技術,**只寫入變更部分**,減少寫入時間與儲存空間佔用。
#### **(3) 設定更新後的啟動分區**
- 當 `update_engine` 安裝完成後,不會立即重啟設備,而是:
- 記錄新的 **Boot Slot(啟動分區)**。
- 設定 **Slot B** 為「下一次開機」的作用分區。
#### **(4) 重新開機並測試**
- 重新開機後,設備從 **Slot B** 啟動。
- `update_engine` 檢查新系統是否正常運行(如是否進入系統,是否發生錯誤)。
- **如果系統崩潰(Bootloop 或錯誤過多),則會自動回滾至 Slot A**,保證系統可用性。
---
### **3. `update_engine` 相關指令**
我們可以透過 **ADB 指令** 手動觸發 OTA 更新,以測試 `update_engine`。
#### **(1) 查詢目前系統運行的分區**
```
adb shell getprop ro.boot.slot_suffix
```
- 可能回傳 `_a` 或 `_b`,代表目前作用中的分區。
#### **(2) 手動觸發 OTA 更新**
```
adb shell update_engine_client --payload=file:///data/ota_package/payload.bin --update
```
- 手動執行 `update_engine` 並應用 OTA 更新。
#### **(3) 監控更新進度**
```
adb logcat -s update_engine
```
- 查看 `update_engine` 的日誌輸出。
#### **(4) 設定新分區為啟動分區**
```
adb shell bootctl set-active-boot-slot 1
```
- 設定設備在下次重啟時使用 **Slot B**。
#### **(5) 強制回滾**
```
adb shell bootctl mark-boot-successful
```
- 記錄當前分區更新成功,防止回滾。
---
### **4. `update_engine` 更新失敗時的回滾機制**
當 OTA 更新失敗時,設備會自動回滾至舊版本,具體流程如下:
1. **`update_engine` 監控開機過程**
- 若新分區 **開機成功並運行穩定**,則標記更新成功。
- 若 **開機失敗或錯誤過多(Bootloop)**,則觸發回滾。
2. **回滾機制(Rollback)**
- `bootloader` 監測系統開機是否成功。
- 若 **N 次內開機失敗(通常 2-3 次)**,自動回滾到舊分區(Slot A)。
- **避免設備變磚(Bricking)**,確保至少有一個可用的系統。
---
### **5. 與傳統 `updater-script` 的比較**
| OTA 更新機制 | `updater-script` | `payload.bin` + `update_engine` |
|-------------|-----------------|-------------------------------|
| 更新方式 | Recovery 模式(手動進入) | 背景更新(無縫更新) |
| 更新過程 | `update.zip` 解壓後寫入 | `update_engine` 自動管理 |
| 分區機制 | 單分區(Single Slot) | A/B 分區(Seamless Update) |
| 更新失敗影響 | 可能導致裝置變磚 | 自動回滾至舊版本 |
| 下載檔案大小 | `system.new.dat` 或 `patch.dat` | `payload.bin`(增量更新) |
| 使用設備 | 舊版 Android(6.0 以下) | Android 7.0+ |
---
### **6. 總結**
- **`payload.bin`** 是 A/B 分區 OTA 更新的核心檔案,內含完整的系統映像與增量補丁。
- **`update_engine`** 負責自動將 `payload.bin` 應用到「非作用分區」,確保系統無縫更新。
- **`bootloader` 會監測開機狀態**,若更新失敗,則自動回滾到舊版本,避免裝置變磚。
- **這種機制提高了 OTA 更新的安全性與穩定性**,可確保裝置始終有一個可開機的系統。
**A/B 分區 OTA 更新機制已經成為現代 Android 系統的標準**,可提升用戶體驗並減少更新失敗的風險。
<br>
<hr>
<br>
### payload.bin 搭配 update_engine,如何自動處理更新?
- ### gpt-4o (2025/03/19)
> **`payload.bin` 是壓縮檔嗎?**
### **1. `payload.bin` 的本質**
**`payload.bin` 不是傳統的壓縮檔(如 `.zip` 或 `.tar`)**,但它內部包含了多個系統映像(`system.img`、`vendor.img`、`boot.img` 等),以及額外的 metadata(中繼數據)來描述更新過程。
它是一個 **二進制封裝文件**,內含:
- **完整或增量的系統更新數據**
- **分區更新資訊**
- **檔案哈希值**
- **數位簽章**
這個檔案格式由 **Google 的 Brillo Update Engine**(`update_engine`)處理,而不是透過一般的 `tar` 或 `zip` 來解壓縮。
---
### **2. `payload.bin` 內部結構**
#### **(1) `payload.bin` 內部的主要部分**
```
payload.bin
│── Header(標頭)
│── Manifest(更新描述資訊)
│── Metadata(檔案哈希值、分區資訊)
│── Data Blobs(實際的映像數據)
│── Signatures(數位簽章)
```
- **Header**:包含 `payload.bin` 版本、更新格式資訊。
- **Manifest**:描述 OTA 更新的詳細資訊,如哪些檔案需要更新、大小、類型等。
- **Metadata**:包含哈希值、分區映射資訊,以確保完整性。
- **Data Blobs**:包含系統映像的增量或完整數據。
- **Signatures**:Google 或 OEM 的簽章,確保 OTA 更新的安全性,防止未授權的修改。
---
### **3. 如何解開 `payload.bin`**
雖然 `payload.bin` 不是傳統壓縮檔,但我們可以使用 `payload-dumper` 工具來解析它並提取系統映像。
#### **(1) 安裝 `payload-dumper`**
```
git clone https://github.com/cyxx/payload-dumper-go.git
cd payload-dumper-go
go build
```
#### **(2) 解壓 `payload.bin`**
```
./payload-dumper-go -o extracted_payload payload.bin
```
這將會提取 `payload.bin` 內的映像檔,通常包含:
```
extracted_payload/
│── boot.img
│── system.img
│── vendor.img
│── product.img
│── system_ext.img
│── odm.img
```
這些 `.img` 檔案是標準的 Android 映像檔,可以使用 `fastboot` 或 `dd` 命令刷入裝置。
#### **(3) 解析 `payload.bin` 的資訊**
```
./payload-dumper-go -p payload.bin
```
這將會顯示 `payload.bin` 內部的詳細資訊,如:
```
Payload Version: 2
Partitions: system, boot, vendor
Block Size: 4096
```
---
### **4. `payload.bin` 與傳統 `update.zip` 的比較**
| | `update.zip`(舊 OTA 機制) | `payload.bin`(A/B OTA 機制) |
|----------------|------------------------|--------------------------|
| **格式** | `.zip` 壓縮檔 | 二進制封裝檔 |
| **更新方式** | Recovery Mode + `updater-script` | `update_engine` |
| **數據結構** | 分開的 `.img`、`.dat` 檔案 | 壓縮在 `payload.bin` 內 |
| **安全性** | SHA-256 驗證 | 簽章 + metadata 檢查 |
| **支援 A/B OTA** | ❌(只能單分區更新) | ✅(可在背景更新並回滾) |
---
### **5. 總結**
- **`payload.bin` 不是傳統的壓縮檔**,它是一個二進制封裝檔,內含完整或增量更新的系統映像。
- **它只能透過 `update_engine` 來解析與應用更新**,但可以使用工具(如 `payload-dumper-go`)手動解開。
- **相較於舊的 `update.zip`,`payload.bin` 提供更安全、可靠的 OTA 更新機制**,並支援 A/B 分區無縫更新與回滾機制。
如果你需要手動提取 `payload.bin` 內的映像檔,可以使用 `payload-dumper` 工具來解壓它。
<br>
{%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}