OTA更新包内部

来源:互联网 发布:c语言播放音乐代码 编辑:程序博客网 时间:2024/04/30 04:38

系统从bootable/recovery/updater中构建updater二进制程序,并且在OTA更新包里面使用他.

更新包本身是一个.zip压缩包文件(ota_update.zip,incremental_ota_update.zip),压缩包内包含可执行二进制程序 META-INF/com.google/android/update-binary .

Updater包含几个内置函数和用于可扩展脚本语言(edify)的解释器,可扩展脚本语言支持与更新任务相关的命令.Updater从.zip中的 META-INF/com/google/android/updater-script查找脚本.

注意:使用edify脚本和内置的函数不是命令,但是如果你需要调试这个更新文件的话是非常有用的

Edify语法


一个edify脚本是一个单一的语句,在脚本中,所有的值都是字符串.空字符串在一个Boolean上下文中是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 then endif).字符串使用双引号因起来,下面是如何创建空格和其他不在上面集合中的自负值.\n,\t,\”,和\为转义字符.

&&和||操作符是和我们平时编程的时候一样的,下面两个是等价的:

e1 && e2if e1 then e2 endif

;操作符号是一个序列点;他的意思是,首先分析左边的表达式,然后分析右边的表达式.他的值是右边表达式的值.分号也用于一个表达式的后面,像是C语言风格的模拟.

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

内置函数


大多数更新功能都被包含在可用的函数中被脚本执行.(在Lisp意义上,严格的说这些是宏而不是函数,他们需要分析所有的参数).除非另有说明,函数返回true表示执行成功,返回false表示执行出错.如果你想在出错的时候停止脚本的执行,使用abort()或者是asset()函数.在updater中可用的函数集合也可以被扩展提供设备特定功能(后面会讲到).

  • abort([msg])
    立即结束脚本的执行,带有可选信息.如果用户已经切换到文本显示,msg会出现在recovery log中和屏幕上.

  • 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_sha1和tgt_size是期望的最终的SHA1哈希和目标文件的大小.剩下的参数必须是成对出现的:一个SHA1哈希(40位字符的16进制字符串)和一个块.当源码当前的内容已经有了SHA1,块就是要被应用的补丁.

    打补丁以一个安全的方式完成了,这保证了目标文件拥有期望的SHA1哈希和大小,或者是他是不变的.如果打包过程被中断,目标文件可能会在一个中间状态;位于cache分区的一个复制品,所以重启更新就能成功更新那个文件.

    把存储技术设备(MTD)分区当作文件的特殊语法也是支持的,允许对raw分区的打包,例如boot.为了读取一个MTD分区,既然该分区没有文件末尾的概念,你一定要知道你想要读取多少数据.你一定要使用字符串”MTD:partition:size_1:sha1_1:size_2: sha1_2”作为文件名称来读取给定的分区.你至少指定一个(size,sha-1)对;如果有多个可能性,但是对你想要读取的内容至少指定一个.

  • apply_patch_check(filename, sha1[, sha1, ...])
    如果文件名称或者是在cache分区中的临时复制品有一个和给定的sha1值相同的SHA1的话,就会返回true.sha1值被指定为40位的16进制数字.这个函数和sha1_check(read_file(filename), sha1 [, …]) 不同的是,他知道去检查cache分区中的copy,所以,apply_patch_check()将会成功即使文件被一个中断的apply_patch() 更新损坏了.

  • apply_patch_space(bytes)
    如果至少暂存空间对应用的二进制补丁可用的话返回true

  • concat(expr[, expr, ...])
    分析每一个语句并且连接他们.+操作在两个参数的特殊情况下是这个函数的语法糖(但是该函数能够接受任意数量的语句).语句必须是字符串,他不能连接块.

  • delete([filename, ...])
    删除列出文件名的所有.返回成功删除的文件的数量.

  • delete_recursive([dirname, ...])
    递归删除dirnames和其所有的内容.返回成功删除的目录的个数.

  • file_getprop(filename, key)
    读取给定的文件名的文件,作为属性文件解释(例如,/system/build.prop),返回给定的key的值,或者是如果key不存在,返回空字符串.

  • 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为0,文件系统采用整个分区.如果fs_size为一个正数,文件系统采用分区的fs_size大小位.如果fs_size是一个负数,文件系统采用除了|fs_size|大小的区域.

    • fs_type=”f2fs”并且partition_type=”EMMC”.位置一定要是分区设备文件.fs_size必须是非负数.如果fs_size为0,文件系统采用整个分区.如果fs_size为正数,文件系统采用这些大小位的分区.
      mount_point(挂载点)一定要是后来文件系统挂载的点.

  • getprop(key)
    返回系统属性key的值(如果没有定义,返回空字符串).被recovery分区定义的系统属性值不必和主系统定义的一样.这个函数在recovery模式中返回值.

  • greater_than_int(a, b)
    如果a比b大的话,返回true

  • ifelse(cond, e1[, e2])
    分析条件,如果条件为真,返回e1的值,如果条件为假,返回e2的值(如果存在的话).”if…else..then..endif”是该函数的一个语法糖.

  • is_mounted(mount_point)
    如果文件系统在挂载点被挂载了返回true

  • is_substring(needle, haystack)
    如果needle是haystack的子串的话返回true

  • less_than_int(a, b)
    如果a小于b的话返回true

  • mount(fs_type, partition_type, name, mount_point)
    挂载fs_type在mount_point的文件系统.partition_type一定是下面的一个:

    • MTD:名称是MTD分区的名称(例如,system,userdata;查看设备上的/proc/mtd获取完整的列表).

    • EMMC:Recovery默认情况下不会挂载任何文件系统(如果用户从SD卡中手动安装更新的话,SD开需要挂载);你的脚本必须挂载你需要修改的分区.

  • package_extract_dir(package_dir, dest_dir)
    从package_dir下提取所有的文件,并且将他们写到相应的dest_dir下面.任何存在的文件都要被重写.

  • package_extract_file(package_file[, dest_file])
    从更新包中提取一个单一的package_file,并且将他们写入到dest_file中,如果必要的话,重写存在的文件.如果没有dest_dir参数的话,将包文件的内容作为二进制块返回.

  • read_file(filename)
    读取文件并且返回他的内容作为一个二进制块.

  • rename(src_filename, tgt_filename)
    重命名src_filename为tgt_filename.他自动为tgt_filename创建一个必要的目录.例如:
    rename("system/app/Hangouts/Hangouts.apk", "system/priv-app/Hangouts/Hangouts.apk").

  • run_program(path[, arg, ...])
    在path中,通过传递args执行二进制程序.返回程序的退出状态.

  • set_metadata(filename, key1, value1[, key2 , value2, ...])
    给给定的文件名称的键赋值.举个例子:

    set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0).

  • set_metadata_recursive(dirname, key1, value1[, key2, value2, ...])
    递归设置给定目录和他的子文件的键和值.举个例子:

    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()返回的类型的块或者是package_extract_file()的一个参数形式.如果没有sha1参数,该函数返回块的SHA1哈希.如果存在一个或多个sha1参数,如果SHA1和一个参数相等的话,返回SHA1哈希,如果没有相等的,则返回空字符串.

  • show_progress(frac, secs)
    推进进度条在sec秒中到达frac长度.secs可能为0,在这种情况下,进度条不会被自动推进.

  • sleep(secs)
    睡眠secs秒(必须是整数)

  • stdout(expr[, expr, ...])
    分析每一个表达式并且将他的值转储到stdout.在调试的时候有用.

  • symlink(target[, source, ...])
    创建所有源码为链接到目标中.

  • tune2fs(device[, arg, …])
    在设备上调整可调参数args

  • ui_print([text, ...])
    连接所有的文本参数并且将结果打印到UI中(如果用户转换到文本显示的话结果就是可视的)

  • unmount(mount_point)
    卸载在挂载点挂载的文件系统

  • wipe_block_device(block_dev, len)
    清楚给定块设备block_dev的len位的数据.

  • wipe_cache()
    在成功安装之后,清空cache分区

  • write_raw_image(filename_or_blob, partition)
    在filename_or_blob中把镜像写入到MTD分区中. filename_or_blob可以是一个字符串名称是本地文件或者是一个包含数据的块值参数.为了能够从OTA包中复制一个文件到分区中,使用:

    write_raw_image(package_extract_file("zip_filename"), "partition_name")

    注意:之前Android 4.1,仅仅接收文件名称,所以,为了能够完成这个工作,数据需要首先去解压缩到一个临时本地文件中.

1 0
原创粉丝点击