OTA升级Google官方文档翻译——OTA 软件包内部

本文介绍了Android系统的OTA更新机制,包括更新程序二进制文件的构建、更新包的组成以及Edify脚本语言的使用。详细解释了Edify语法、运算符、内建函数等关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文网址:https://source.android.com/devices/tech/ota/inside_packages


系统从 bootable/recovery/updater 构建更新程序二进制文件并将其用于 OTA 更新包。

更新包本身是包含可执行二进制文件  META-INF/com/google/android/update-binary  的 .zip 文件( ota_update.zip incremental_ota_update.zip )。

更新程序包含多个内建函数和一个可扩展脚本语言 (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

由非保留字符 az、AZ、0-9 _、:、/、. 组成的任何字符串均视为字符串字面量。(保留字为 if else、then 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_filetgt_filetgt_sha1tgt_sizepatch1_sha1patch1_blob, [...])
将二进制补丁程序应用于 src_file 以生成 tgt_file。 如果所需的目标文件与源文件相同,则传递“-”作为 tgt_file。tgt_sha1 和 tgt_size 分别是目标文件的预期最终 SHA1 哈希值和文件大小。 其余参数必须成对出现:一个 SHA1 哈希值(40 个字符的十六进制字符串)和一个 Blob。如果源文件当前的内容含有给定的 SHA1,该 Blob 即为要应用的补丁程序。

打补丁以一种安全的方式完成,该方式可保证目标文件要么具有所需的 SHA1 哈希值和大小,要么不发生变化,而不会处于不可恢复的中间状态。如果在打补丁过程中进程中断,目标文件可能会处于中间状态;这时缓存分区中会存在一个副本,重新启动更新便可成功更新文件。

支持特殊语法将内存技术设备 (MTD) 分区的内容作为文件处理,以便为引导分区这样的原始分区打补丁。由于 MTD 分区没有文件结束标记,因此要读取该分区,您必须知道您要读取的数据量。您可以使用字符串“MTD:partition:size_1:sha1_1:size_2:sha1_2”作为文件名来读取给定的分区。您必须至少指定一个(size,sha-1)对;如果您希望读取的内容有多种可能,则可以指定多个对。

apply_patch_check(filenamesha1[, sha1, ...])
如果 filename 的内容或缓存分区中的临时副本(如果存在)中的内容具有与给定的 sha1 值之一相等的 SHA1 校验和,则返回 True。sha1 值指定为 40 位十六进制数字。 此函数与  sha1_check(read_file(filename), sha1 [, ...]) 的不同之处在于,它知道检查缓存分区副本。因此,即使文件被中断的  apply_patch() update 损坏, apply_patch_check() 仍会成功执行。
apply_patch_space(bytes)
如果至少有 bytes 字节暂存空间可用于应用二进制补丁程序,则返回 True。
concat(expr[, expr, ...])
评估每个表达式并将它们连接起来。在只有两个参数的特殊情况下,+ 运算符就是该函数的语法糖(但该函数形式可以包含任意数量的表达式)。表达式必须为字符串;该函数不能连接 Blob。
delete([filename, ...])
删除列出的所有 filename。 返回成功删除的文件数。
delete_recursive([dirname, ...])
递归删除 dirname 及目录中的所有内容。返回成功删除的目录数。
file_getprop(filenamekey)
读取给定的 filename,将其解释为属性文件(例如: /system/build.prop),并返回给定 key 的值,如果 key 不存在,则返回空字符串。
format(fs_typepartition_typelocationfs_sizemount_point)
重新格式化给定的分区。支持的分区类型如下:
  • fs_type =“yaffs2”和 partition_type =“MTD”。Location 必须为 MTD 分区的名称;将在该位置构建一个空的 yaffs2 文件系统。其余参数未使用。
  • fs_type =“ext4”和 partition_type =“EMMC”。Location 必须为该分区的设备文件。将在该位置构建一个空的 ext4 文件系统。如果 fs_size 为零,则文件系统将占用整个分区。如果 fs_size 为正数,则文件系统将占用分区的前 fs_size 个字节。如果 fs_size 为负数,则文件系统将占用分区中除最后 |fs_size| 个字节以外的所有字节。
  • fs_type =“f2fs” 和 partition_type =“EMMC”。Location 必须为该分区的设备文件。fs_size 必须为非负数。如果 fs_size 为零,则文件系统将占用整个分区。如果 fs_size 为正数,则文件系统将占用分区的前 fs_size 个字节。
  • mount_point 应为文件系统的未来挂载点。
getprop(key)
返回系统属性 key 的值(或者,如果未定义,则为空字符串)。 由恢复分区定义的系统属性值未必与主系统属性值相同。此函数返回恢复分区中的值。
greater_than_int(ab)
当且仅当 (iff) a(解析为整数)大于 b(解析为整数)时,才返回 True。
ifelse(conde1[, e2])
评估 cond,如果为 True,则评估并返回 e1 的值,否则评估并返回 e2(如果存在)。 “if ... else ... then ... endif”结构就是此函数的语法糖。
is_mounted(mount_point)
当且仅当 mount_point 挂载文件系统时,才返回 True。
is_substring(needlehaystack)
当且仅当 needle 是 haystack 的子字符串时,才返回 True。
less_than_int(ab)
当且仅当 a(解析为整数)小于 b(解析为整数)时,才返回 True。
mount(fs_typepartition_typenamemount_point)
在 mount_point 挂载 fs_type 的文件系统。  partition_type  必须为以下类型之一:
  • MTD。Name 是 MTD 分区的名称(例如:system、userdata;有关完整列表,请参见设备上的/proc/mtd)。
  • EMMC。

默认情况下,恢复分区不挂载任何文件系统(如果用户正在手动从 SD 卡安装软件包,则 SD 卡除外);您的脚本必须挂载需要修改的所有分区。

package_extract_dir(package_dirdest_dir)
从 package_dir 下的文件包中提取所有文件,并将它们写入 dest_dir 下相应的树形结构中。 所有现有文件都将被覆盖。
package_extract_file(package_file[, dest_file])
从更新包中提取单个 package_file 并将其写入 dest_file,如有必要,覆盖现有文件。 在没有 dest_file 参数的情况下,将更新包文件的内容作为二进制 blob 返回。
read_file(filename)
读取 filename 并将其内容作为二进制 Blob 返回。
rename(src_filenametgt_filename)
将 src_filename 重命名为 tgt_filename。 系统会自动为 tgt_filename 创建必要的目录。 例如: rename("system/app/Hangouts/Hangouts.apk", "system/priv-app/Hangouts/Hangouts.apk")
run_program(path[, arg, ...])
在 path 上执行二进制文件,以传递 arg。 返回程序的退出状态。
set_metadata(filenamekey1value1[, key2 value2, ...])
将给定 filename 的 key 设置为 value。 例如:  set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0)
set_metadata_recursive(dirnamekey1value1[, key2value2, ...])
递归地将给定 dirname 及其所有子项的 key 设置为 value。 例如: set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0)
set_progress(frac)
在最新的  show_progress() 调用所定义的块内设置进度条的位置。frac 必须介于 [0.0,1.0] 的范围内。 进度条从不向后移动;向后移动的尝试会被忽略。
sha1_check(blob[, sha1])
该 blob 参数是  read_file() 返回类型的 Blob 或  package_extract_file() 的单参数形式的 Blob。 在没有 sha1 参数的情况下,此函数返回 Blob 的 SHA1 哈希值(作为 40 位十六进制字符串)。 在使用一个或多个 sha1 参数的情况下,如果 SHA1 哈希值等于其中一个参数,则该函数返回 SHA1 哈希值;如果与其中的任何一个参数都不相等,则返回空字符串。
show_progress(fracsecs)
在 secs 秒(必须为整数)内推动进度条向前移动下一个 frac 的长度。secs 可能为 0,在这种情况下,进度条不会自动向前移动,而是通过使用上面所定义的  set_progress() 函数实现进度递增。
sleep(secs)
休眠 secs 秒(必须为整数)。
stdout(expr[, expr, ...])
评估每个表达式并将其值转储到 stdout。这在调试时很有用。
symlink(target[, source, ...])
将所有 source 创建为 target 的符号链接。
tune2fs(device[, arg, …])
调整 device 上的可调参数 arg。
ui_print([text, ...])
连接所有 text 参数并将结果输出到界面(如果用户已打开文本显示功能,界面上将显示该结果)。
unmount(mount_point)
卸载挂载在 mount_point 上的文件系统。
wipe_block_device(block_devlen)
擦除给定块设备 block_dev 的 len 字节。
wipe_cache()
可实现在安装过程成功结束时擦除缓存分区。
write_raw_image(filename_or_blobpartition)
将 filename_or_blob 中的映像写入 MTD 分区。  filename_or_blob 可以是一个命名本地文件的字符串或一个包含要写入的数据的 blob 值参数。 要将文件从 OTA 包复制到分区,请使用: write_raw_image(package_extract_file("zip_filename"), "partition_name");

注意:对于 Android 4.1 之前的版本,仅接受 filename。因此要完成该操作,必须先将数据解压到临时本地文件中。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值