- Android 更新模式介紹 -- Fastboot -- Recovery mode -- OTA
- Android Image 製作 -- Engineering image -- Recovery deploy -- OTA update image
- Android Image 客製化與 OTA -- OTA 更新模式 -- OTA Image 的客製化 -- 實作示範
有 3 種更新 Android 軟體的方式:
- Full update image
- Update files
- Wipe and re-flash partitions(使用 fastboot)
Full image 的做法,是製做出更新的 ROM,即 update.zip,再將手機切換至 Recovery mode 來更新。Update files 則是使用 bsdiff 來更新 /system 裡的部份檔案。
最後一個做法,是 re-flash 特定的 partition,例如更新存放 boot.img 的 partition;這種做法是使用一個稱為 fastboot 的工具。這種方式,手機上 Second bootloader 必須實現 Fastboot protocol。
release tools 能產生 signed update image,這個工具位於 build/tools/releasetools/,並透過 Android build system 來產生 update.zip。
如何產生 update.zip:
make target-files-package
target-files-package 也稱為 TFP。完成編譯後,可以找到以下二個 image file:
- out/target/product/mokoid/obj/PACKAGING/apkcerts_intermediates/full-apkcerts-eng.txt
- out/target/product/mokoid/obj/PACKAGING/target_files_intermediates/full-target_files-eng.zip
上述的 image 是利用 mkbookimg 來製作。針對使用 U-Boot 的裝置,請記得利用 mkimage 來製作 U-Boot 格式的 image file。
這是 Android framework 所提供的標準 API,用來驗證與安裝 update image。以 OTA 方式更新 Android 的話,就是使用這個 API 來驗證 update image。
在下載 Update image 後,要先利用 android.os.RecoverySystem 將 RC command files 寫至 /cache/recovery,再將手機重開機至 Recovery mode。
RC 是 Recovery Console 的意思,這其實是一個精簡的開機環境,有點像以往的 Embedded Linux 的 Initial Root Filesystem。進入 Recovery Console 後,它會自動驗證 update image,接著執行更新命令。
RC command files 採用一個稱為 Edify 的語言撰寫。請注意,RC 的 command file 並不是使用典型的 shell script 語法撰寫。
OTA 是 Over-The-Air 的意思,它會從製造商所提供的 Server 下載 update image,並透過 Recovery Console 來更新手機軟體。
市面上的 Android 裝置大多採用這種做法,因為對一般使用者來說,這是最簡單的方式。要使用 OTA,需要有以下的基礎建設:
- 存放 update image 的 Server
- 檢查並下載 update image 的 App(the Fetcher)
- 通知用戶有軟體更新的 Notification UI,一般是與上述的 App 整合在一起
要實現 OTA,需要 Server 與 App,這二個部份都沒有 Open Source,必須廠商自行開發。不過,去年(2012)出現了一個 OTA 的免費服務:
它提供了免費的 Server,以及 Open source 的手機端 App。只要將自已的 update image 放到 otaupdater.com 上,再配合它的 App,就可以在手機加入「第三方軟體更新」的機制。
例如,知名的 CM ROM 現在就能用這種方式更新,相當的方便。除了一些社群所製作的 update image 外,其它手機廠,都是使用自已的 Server 以及 update App。
Server 的部份沒有 Open Source 的解決方案,只能自行設計與實作。不過,它的原理並不複雜:
- 使用 HTTP 下載 update image
- Server 與 Device 需要定義簡單的協定(OTA Protocol)
從 Server 的角度來看,一個簡單的 RESTful Web Service,以及簡易的 Protocol 就能滿足 OTA 的需求。RESTful Web Service 使用 JSON 格式來回應 App 的請求,在 Android App 裡處理 JSON 也是很容易的事情。
OTA update 的流程如下:
- 安裝 Update Client 端 App,通常是每日檢查一次更新
- Client 端由 Server 下載 update ROM
- 將 update ROM 儲存至 /sdcard 目錄下
- 將裝置重開機至 Recovery Mode
- 可選擇性地清除 data partition 或 cache
研發重點:
- OTA Server 的架構,一般是以 HTTP Server 為主
- OTA Client 端開發,重點在使用 HTTP 下載 update ROM
- 製作 update ROM
- 過去有許多可行的架構方式,現在建議以 RESTful 架構為主
Boot Image 是利用 system/core/mkbootimg 工具,將 kernel image 與 ramdisk image 再打包而成。有時也會將 second bootloader image 加入。
Android Build System 會自動幫我們調用 mkbootimg,並製作出 boot.img。使用 TFP 時,也會自動調用 mkbootimg,以製作出 update image。
要了解 update.zip 的更新原理,必須先研究 flash 的 partition 結構。我目前使用的工程手機,將 flash 切割如下:
# mount -t
AOSP 階段的 partiton layout 通常只有 3 個:
- boot
- system
- data
Production 時,會增加至少 3 個 partition:
- recovery
- misc
- cache
實際的規劃方式,因不同的廠商以及裝置型號,也會有所不同,要依現況為主。此外,不管是採用什麼更新方式,都無法重新分割 partition。所以 Parititon Layout 在 Production 前就要定義好,後續無法再修改。
可以自行開發,或使用知名的 OTA Update Center。使用 OTA Update Center 前,需要修改 build.prop 檔案,加入 ROM image 的下載連結。oOTA Update Center 也提供一個用戶端 App。
OTA Update Center 的特點:
- 提供 Server 服務
- 每日檢查更新一次
- 自動下載並更新 ROM
將以下設定加入 build.prop:
otaupdater.otaid=(write your ota id here without spaces or brackets)
otaupdater.otaver=(write your ota version here without spaces or brackets)
otaupdater.otatime=(write the date+time here as: 20120820-1516 without spaces or backets)
支援 quirky sdcard 的裝置,可再加入以下設定:
otaupdater.sdcard.os=(sdcard name (e.g. sdcard2 for /sdcard2) in the main system here without spaces or brackets)
otaupdater.sdcard.recovery=(sdcard name (e.g. sdcard2 for /sdcard2) in recovery here without spaces or brackets)
otaupdater.otaid=SmoothROM7 otaupdater.otaver=201309 otaupdater.otatime=20120831-1516
Edify 是撰寫 Android update script 的語言,它的語法非常簡單。在 bootable/recovery/{edify,edifyscripting,updater} 目錄下可以找到 Edify。Edify 的幾個基本函數:
- apply_patch(source_filename, target_filename, target_sha1, target_size, sha1, patch, [[sha1, patch], ...])
- getprop
- install_zip
- package_extract_dir
- package_extract_file
- read_file
- run_program
Edify script 並非直接撰寫,而是透過 build/tools/releasetools/edify_generator.py 來生成。
Edify 的說明文件位於 bootable/recovery/edify/README
Recovery 怎麼知道 partition 與 mount point 的對應關係呢?方式是透過 recovery.fstab 文件。recovery.fstab 的寫法,與 Linux 的 fstab 相同。
RC 與 releasetools 都會用到 recovery.fstab 文件。
前面已介紹過,可以使用 target-files-package 這個 Makefile rule 來製作 update image。如果有額外的文件,想要另外加到 update image 裡,可以自行擴充 releasetoos。
如果 APK 是 signed,在 update image 裡的新版 APK,也必須使用同樣的 key 來 sign APK。否則新的 APK 將無法讀取原來的 app data。
APK 的 key 是利用 LOCAL_CERTIFICATE 來設定,這部份是在該 APK 的 Android.mk 裡處理。AOSP 提供 4 個 key,位於 build/target/product/security,廠商可自行新增 key:
- devkey (Development 階段使用)
- testkey (default、用於 engineering build 測試)
- platform (platform package)
- shared (與 Home/Contacts 共享資料)
- media (在 media/download 裡的 package)
TFP 會透過 ota_from_target_files 來製作最後的 update image。
Production 的裝置,不能使用上述由 AOSP 提供的 key。ota_from_target_files 的 --package_key 參數,用來指定 key。如何指定 production key?releasetools 的 sign_target_files_apks 工具會幫我們處理這個工作。
這是用於 BoardConfig.mk 的變數,用來撰寫 release tools 的 extension。可參考 ota_from_target_files。
$ reboot recovery
RC 與 bootloader 的共用 /misc partition,這個 partition 存放一種稱為 Bootloader Control Block (BCB) 的資料。BCB 分為 3 個區塊:
- BCB.command[32]:給 bootloader 的 command
- BCB.status[32]:bootloader 回傳的 status
- BCB.recovery[1024]:RC 的 command line
BCB.command 裡的資料,是由 Linux kernel 所寫入,基本上是一行 'boot-recovery' 命令;另外,Linux kernel 也要將 BCB.recovery 清空。BCB.command 是 bootloader 選擇 Boot Image 的依據。也有廠商用來實作 Dual OS 開機。
$(TARGET_DEVICE_DIR)/recovery/res 裡存放一個 8-bit PNG 圖檔。
Android Build System 會將 updater 打包到 update.zip。bootable/recovery/install.c
首先,要把你的 Nexus 7 Unlock,只要利用 Fastbook 即可輕鬆完成:
$ ./fastboot oem unlock