OTA 套件內部

系統會從 bootable/recovery/updater 建構更新器二進位檔,並在 OTA 套件中使用該檔案。

套件本身是 .zip 檔案 (ota_update.zipincremental_ota_update.zip),其中包含可執行的二進位檔 META-INF/com/google/android/update-binary

Updater 包含多個內建函式和可擴充指令碼語言 (edify) 的轉譯器,可支援一般更新相關工作的指令。更新程式會在套件 .zip 檔案中尋找 META-INF/com/google/android/updater-script 檔案中的指令碼。

注意:使用 edify 指令碼和/或內建函式並非常見的活動,但如果您需要對更新檔案進行偵錯,這項功能就很實用。

Edify 語法

edify 指令碼是單一表達式,其中所有值都是字串。在布林值的上下文中,空字串為 false,所有其他字串則為 true。Edify 支援下列運算子 (含一般意義):

(expr )
 expr + expr  # string concatenation, not integer addition
 expr == expr
 expr != expr
 expr && expr
 expr || expr
 ! expr
 if expr then expr endif
 if expr then expr else expr endif
 function_name(expr, expr,...)
 expr; expr

任何字串,包含 a-z、A-Z、0-9、_、:、/、. 等字元系統會將非保留字視為字串文字。(保留字詞為 if else endif)。字串常值也可以出現在雙引號中,這是建立包含空白字元和上述集合中未包含的其他字元的值的方式。\n、\t、\" 和 \\ 可用於在引號字串中逸出,\x## 也是如此。

&& 和 || 運算子會短路,如果邏輯結果由左側決定,則不會評估右側。以下會產生相同結果:

e1 && e2
if e1 then e2 endif

; 運算子是序列點,表示先評估左側,再評估右側。其值是右側運算式的值。分號也可以出現在運算式後方,模擬 C 樣式的陳述式:

prepare();
do_other_thing("argument");
finish_up();

內建函式

大部分更新功能都包含在可供指令碼執行的函式中。(嚴格來說,這些是 巨集,而非 Lisp 意義上的函式,因為它們不需要評估所有引數)。除非另有說明,否則函式會在成功時傳回 true,在發生錯誤時傳回 false。如果您希望錯誤終止指令碼執行作業,請使用 abort() 和/或 assert() 函式。更新器中可用的函式集合也可以擴充,以提供裝置專屬功能

abort([msg])
立即中止指令碼執行作業,並提供選用的 msg。如果使用者已開啟文字顯示功能,則復原記錄和畫面上會顯示 msg
assert(expr[, expr, ...])
依序評估每個 expr。如果任何值為 False,系統會立即中止執行作業,並顯示「assert failed」訊息和失敗運算式的原始文字。
apply_patch(src_file, tgt_file, tgt_sha1, tgt_size, patch1_sha1, patch1_blob, [...])
將二進位修補程式套用至 src_file,產生 tgt_file。如果所需目標與來源相同,請將「-」傳遞至 tgt_file tgt_sha1tgt_size 是預期的最終 SHA1 雜湊和目標檔案大小。其餘的引數必須成對出現:SHA1 雜湊 (40 個半形字元十六進位字串) 和 blob。當來源檔案的目前內容含有指定的 SHA1 時,這個 blob 就是要套用的修補程式。

系統會以安全的方式完成修補作業,確保目標檔案具有所需的 SHA1 雜湊和大小,或未經任何修改,不會處於無法復原的中繼狀態。如果修補期間中斷程序,目標檔案可能處於中間狀態;快取分區中會存在副本,因此重新啟動更新程序即可成功更新檔案。

系統支援特殊語法,可將 Memory Technology Device (MTD) 分割區的內容視為檔案,允許修補原始分割區 (例如啟動分割區)。如要讀取 MTD 分區,您必須知道要讀取多少資料,因為分區沒有檔案結束的概念。您可以使用字串「MTD:partition:size_1:sha1_1:size_2: sha1_2」做為檔案名稱,讀取指定的分區。您必須至少指定一個 (size, sha-1) 組合;如果預期讀取的內容有多種可能性,您可以指定多個組合。

apply_patch_check(filename, sha1[, sha1, ...])
如果 filename 的內容或快取分割區中的暫時副本 (如有) 的 SHA1 總和檢查碼等於其中一個指定的 sha1 值,則傳回「是」。sha1 值會以 40 個十六進位數字指定。這個函式與 sha1_check(read_file(filename), sha1 [, ...]) 的不同之處在於,它會檢查快取分割區副本,因此即使檔案因中斷的 apply_patch() update 而毀損,apply_patch_check() 仍會成功。
apply_patch_space(bytes)
如果至少有 bytes 的暫存空間可用於套用二進位修補程式,就會傳回 true。
concat(expr[, expr, ...])
評估每個運算式並串連。在兩個引數的特殊情況下,+ 運算子是此函式的語法糖 (但函式形式可接受任意數量的運算式)。運算式必須是字串,無法連結 Blob。
file_getprop(filename, key)
讀取指定的檔案名稱,將其解讀為屬性檔案 (例如 /system/build.prop),並傳回指定的值,如果不存在,則傳回空字串。
format(fs_type, partition_type, location, fs_size, mount_point)
重新格式化指定的分區。支援的分割區類型:
  • fs_type="yaffs2" 和 partition_type="MTD"。位置必須是 MTD 分割區的名稱,系統會在該位置建立空白的 yaffs2 檔案系統。剩餘的引數則不會使用。
  • fs_type="ext4" 和 partition_type="EMMC"。位置必須是分區的裝置檔案。並在其中建構空的 ext4 檔案系統。如果 fs_size 為零,檔案系統會占用整個分區。如果 fs_size 為正數,檔案系統會取用分割區的前 fs_size 位元組。如果 fs_size 是負數,則檔案系統會取用分割區的所有內容,除了最後 |fs_size| 位元組。
  • fs_type="f2fs" 和 partition_type="EMMC"。位置必須是分區的裝置檔案。fs_size 必須為非負數。如果 fs_size 為零,檔案系統會占用整個分區。如果 fs_size 為正數,檔案系統會擷取分割區的前 fs_size 位元組。
  • mount_point 應為檔案系統的未來掛接點。
getprop(key)
傳回系統屬性 key 的值 (如果未定義,則傳回空字串)。復原分區定義的系統屬性值不一定與主要系統相同。此函式會傳回復原值。
greater_than_int(a, b)
如果且僅當 a (解讀為整數) 大於 b (解讀為整數) 時,才會傳回 true。
ifelse(cond, e1[, e2])
評估 cond,如果為 true,則評估並傳回 e1 的值;如果為 false,則評估並傳回 e2 (如果有)。「if ... else ... then ... endif」結構體只是這個函式的語法糖衣。
is_mounted(mount_point)
如果 mount_point 已掛載檔案系統,則傳回 true。
is_substring(needle, haystack)
如果 needlehaystack 的子字串,則傳回 true。
less_than_int(a, b)
如果 a (解讀為整數) 小於 b (解讀為整數),則傳回 true。
mount(fs_type, partition_type, name, mount_point)
mount_point 上掛載 fs_type 的檔案系統。partition_type 必須為下列其中一種:
  • MTD。Name 是 MTD 分區的名稱 (例如 system、userdata;請參閱裝置上的 /proc/mtd 取得完整清單)。
  • EMMC。

根據預設,Recovery 不會掛載任何檔案系統 (如果使用者從 SD 卡手動安裝套件,則除外);您的指令碼必須掛載需要修改的任何分割區。

package_extract_dir(package_dir, dest_dir)
package_dir 底下的套件中擷取所有檔案,並將這些檔案寫入 dest_dir 底下的對應樹狀結構。任何現有檔案都會遭到覆寫。
package_extract_file(package_file[, dest_file])
從更新套件中擷取單一 package_file,並將其寫入 dest_file,必要時會覆寫現有檔案。如果沒有 dest_file 引數,則會以二進位 blob 的形式傳回套件檔案的內容。
read_file(filename)
讀取 filename,並以二進位 blob 的形式傳回其內容。
run_program(path[, arg, ...])
會在 path 上執行二進位檔,並傳遞 arg。傳回程式的結束狀態。
set_progress(frac)
設定最近一次 show_progress() 呼叫所定義的區塊中進度指示器的位置。frac 必須介於 [0.0, 1.0] 之間。進度計量器一律不會向後移動,系統會忽略任何嘗試讓進度計量器向後移動的動作。
sha1_check(blob[, sha1])
blob 引數是 read_file() 所傳回的 blob 類型,或 package_extract_file() 的單引數形式。如果沒有 sha1 引數,這個函式會傳回 Blob 的 SHA1 雜湊 (以 40 位十六進制字串的形式)。如果有一個或多個 sha1 引數,這個函式會傳回 SHA1 雜湊 (如果等於其中一個引數),或傳回空字串 (如果不等於任何引數)。
show_progress(frac, secs)
將進度指示器向前推進其長度的下一個 frac,並在 secs 秒內推進 (必須是整數)。secs 可以是 0,在這種情況下,指示器不會自動推進,而是使用上述定義的 set_progress() 函式。
sleep(secs)
休眠 secs 秒 (必須為整數)。
stdout(expr[, expr, ...])
會評估每個運算式,並將其值轉儲至 stdout。適合用於偵錯。
tune2fs(device[, arg, …])
調整 device 上的可調整參數 args
ui_print([text, ...])
會連結所有 text 引數,並將結果列印到 UI 中 (如果使用者已開啟文字顯示功能,則會顯示在該處)。
unmount(mount_point)
卸載已在 mount_point 掛載的檔案系統。
wipe_block_device(block_dev, len)
會清除指定區塊裝置 block_devlen 個位元組。
wipe_cache()
會在安裝成功後清除快取分區。
write_raw_image(filename_or_blob, partition)
filename_or_blob 中的圖片寫入 MTD partitionfilename_or_blob 可以是命名本機檔案的字串,或是包含要寫入資料的 blob 值引數。如要將檔案從 OTA 套件複製到分區,請使用: write_raw_image(package_extract_file("zip_filename"), "partition_name");

注意:在 Android 4.1 之前,系統只接受檔案名稱,因此要完成這項操作,必須先將資料解壓縮至暫時性本機檔案。