写在前面:
系统创建通过“bootable/recovery/updater”创建一个二进制更新程序并在OTA包中使用进行更新的安装。
更新包实际上也就是一个.zip格式的压缩文件(如我们之前提到过的ota_update.zip,incremental_ota_update.zip)。在这个压缩包中包含了一个可执行的二进制程序-EMTA-INF/com/google/android/update-binary.这个二进制程序我们可以理解成一个升级程序,这个升级程序包含了一系列的内建函数和一个可扩展脚本语言(edify)的解释器。升级程序会执行同样在OTA包中的脚本(EMTA-INF/com/google/android/updater-script),来进行系统升级。
一、Edify 语法
一个edify脚本就是一个表达式,而这些表达式都是有字符串组成的。空字符表示false,反之为ture。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。但这些保留字是可以出现在双引号中的。使用双引号也是空格等没有出现在上面集合中的字符使用办法。
&&和||运算符同样支持最少运算,也就是说如果左边的逻辑能够决定最终结果的话,运算符右边的语句将不会执行。下面两条语句是等价的。
e1 && e2
if e1 then e2 endif
分号;运算符是一个顺序点。这也就意味着在顺序点左边的语句要先于右边的语句。分号也可以出现在表达式的末尾,这是延续了C语言的设计风格。
内建函数:
大部分更新功能都包含在更新脚本中,除非另有说明,如果函数返回true表示成功,返回false表示出错。如果我们想在程序出错时中止安装程序我们可以使用abort()和assert()函数。
下面为大家提供了更新程序可用的函数集(之前博文已经提到过的这里不再赘述,仅仅列出部分之前没有提到过的):
abort([msg])
终止执行脚本。msg参数是可选的,为了更人性化的设计我们可以针对本次终止的原因作出解释。如果用户打开了文本显示的功能,msg的内容会先是到屏幕中,同时也会输出到recovery的log中去。
assert(expr[, expr, ...])
按顺序执行参数中的语句,如果遇到false就会立即终止执行程序并提示“assert failed”和表达式执行为failed的源程序文本。
apply_patch(src_file, tgt_file, tgt_sha1, tgt_size, patch1_sha1, patch1_blob, [...])
申请一个从源文件到目标文件的二进制补丁。如果目标文件与源文件相同则跳过。
apply_patch_check(filename, sha1[, sha1, ...])
检查补丁是否已经完成
concat(expr[, expr, ...])
执行每一条语句,并将这些语句的执行结果连接起来。 +操作符就是这个函数的糖语法,也就是说我们可以直接使用+操作符来连接两个字符串。这里需要注意的就是表达式的执行结果必须是字符串。
greater_than_int(a, b)
Returns true if and only if (iff) a (interpreted as an integer) is greater than b (interpreted as an integer).
ifelse(cond, e1[, e2])
如果cond条件为true,则执行e1语句,否则执行e2. "if ... else ... then ... endif" 就是这个函数的糖语法.
is_mounted(mount_point)
如果在mount_point挂载点有文件系统被挂载的话,返回true。
is_substring(needle, haystack)
如果字符串haystack中包含字符串needle,返回true。
less_than_int(a, b)
如果a的值小于b返回true(a,b作为整形来计算)
read_file(filename)
根据文件名以二进制块的方式读取文件的内容
rename(src_filename, tgt_filename)
将原文件名src_filename重新命名为tgt_filename。而且会为tgt_filename自动创建相对应的目录。例如:ename("system/app/Hangouts/Hangouts.apk", "system/priv-app/Hangouts/Hangouts.apk").
set_metadata(filename, key1, value1[, key2 , value2, ...])
为filename对应的key设置对应的值。如: 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, ...])
递归地设置给定的目录dirname机器所有子目录,对应key的值。如:set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0).
sleep(secs)
休眠给定的时间-secs秒。.
stdout(expr[, expr, ...])
执行每个表达式,并将结果输出到stdout中,这种方式经常被用来进行调试。
tune2fs(device[, arg, …])
调整设备中可调整的参数。
ui_print([text, ...])
连接所有的参数,并将其输出到显示设备上。
下面为原文:
The system builds the updater binary from bootable/recovery/updater
and uses it in an OTA package.
The package itself is a .zip file (ota_update.zip
,incremental_ota_update.zip
)
that contains the executable binaryMETA-INF/com/google/android/update-binary
.
Updater contains several builtin functions and an interpreter for an extensible scripting language (edify) that supports commands for typical update-related tasks. Updater looks in the package .zip file for a script in the fileMETA-INF/com/google/android/updater-script
.
Note: Using the edify script and/or builtin functions is not a common activity, but can be helpful if you need to debug the update file.
Edify syntax
An edify script is a single expression in which all values are strings. Empty strings are false in a Boolean context and all other strings are true. Edify supports the following operators (with the usual meanings):
(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
Any string of the characters a-z, A-Z, 0-9, _, :, /, . that isn‘t a reserved word is considered a string literal. (Reserved words are if else then endif.) String literals may also appear in double-quotes; this is how
to create values with whitespace and other characters not in the above set. \n, \t, \", and \\ serve as escapes within quoted strings, as does \x##.
The && and || operators are short-circuiting; the right side is not evaluated if the logical result is determined by the left side. The following are equivalent:
e1 && e2 if e1 then e2 endif
The ; operator is a sequence point; it means to evaluate first the left side and then the right side. Its value is the value of the right-side expression. A semicolon can also appear after an expression, so the effect simulates C-style statements:
prepare(); do_other_thing("argument"); finish_up();
Built-in functions
Most update functionality is contained in the functions available for execution by scripts. (Strictly speaking these are macros rather than functions in the Lisp sense, since they need not evaluate all of their arguments.) Unless otherwise
noted, functions return true on success and false on error. If you want errors to abort execution of the script, use the
abort()
and/or assert()
functions.The set of functions available in updater can also be extended to provide device-specific functionality.
abort([msg])
- Aborts execution of the script immediately, with the optional msg. If the user has turned on text display, msgappears in the recovery log and on-screen.
assert(expr[, expr, ...])
- Evaluates each expr in turn. If any is false, immediately aborts execution with the message "assert failed" and the source text of the failed expression.
apply_patch(src_file, tgt_file, tgt_sha1, tgt_size, patch1_sha1, patch1_blob, [...])
- Applies a binary patch to the src_file to produce the tgt_file . If the desired target is the same as the source, pass "-" for tgt_file . tgt_sha1 and tgt_size are the expected
final SHA1 hash and size of the target file. The remaining arguments must come in pairs: a SHA1 hash (a 40-character hex string) and a blob. The blob is the patch to be applied whe the source file‘s current contents have the given SHA1.The patching is done in a safe manner that guarantees the target file either has the desired SHA1 hash and size, or it is untouched—it will not be left in an unrecoverable intermediate state. If the process is interrupted
during patching, the target file may be in an intermediate state; a copy exists in the cache partition so restarting the update can successfully update the file.Special syntax is supported to treat the contents of Memory Technology Device (MTD) partitions as files, allowing patching of raw partitions such as boot. To read an MTD partition, you must know how much data you
want to read since the partition does not have an end-of-file notion. You can use the string "MTD:partition:size_1:sha1_1:size_2: sha1_2" as a filename to read the given partition. You must specify at least one (size,
sha-1) pair; you can specify more than one if there are multiple possibilities for what you expect to read. apply_patch_check(filename, sha1[, sha1, ...])
- Returns true if the contents of filename or the temporary copy in the cache partition (if present) have a SHA1 checksum equal to one of the given sha1 values. sha1 values are specified as 40 hex
digits. This function differs fromsha1_check(read_file(filename), sha1 [, ...])
in that it knows to check the cache partition copy, soapply_patch_check()
will
succeed even if the file was corrupted by an interruptedapply_patch() update
. apply_patch_space(bytes)
- Returns true if at least bytes of scratch space is available for applying binary patches.
concat(expr[, expr, ...])
- Evaluates each expression and concatenates them. The + operator is syntactic sugar for this function in the special case of two arguments (but the function form can take any number of expressions). The expressions must be
strings; it can‘t concatenate blobs. delete([filename, ...])
- Deletes all the filenames listed. Returns the number of files successfully deleted.
delete_recursive([dirname, ...])
- Recursively deletes dirnames and all their contents. Returns the number of directories successfully deleted.
file_getprop(filename, key)
- Reads the given filename, interprets it as a properties file (e.g.
/system/build.prop
), and returns the value of the given key ,
or the empty string if key is not present. format(fs_type, partition_type, location, fs_size, mount_point)
- Reformats a given partition. Supported partition types:
- fs_type="yaffs2" and partition_type="MTD". Location must be the name of the MTD partition; an empty yaffs2 filesystem is constructed there. Remaining arguments are unused.
- fs_type="ext4" and partition_type="EMMC". Location must be the device file for the partition. An empty ext4 filesystem is constructed there. If fs_size is zero, the filesystem takes up the entire partition. If fs_size is
a positive number, the filesystem takes the first fs_size bytes of the partition. If fs_size is a negative number, the filesystem takes all except the last |fs_size| bytes of the partition. - fs_type="f2fs" and partition_type="EMMC". Location must be the device file for the partition. fs_size must be a non-negative number. If fs_size is zero, the filesystem takes up the entire partition. If fs_size is
a positive number, the filesystem takes the first fs_size bytes of the partition. - mount_point should be the future mount point for the filesystem.
getprop(key)
- Returns the value of system property key (or the empty string, if it‘s not defined). The system property values defined by the recovery partition are not necessarily the same as those of the main system. This function
returns the value in recovery. greater_than_int(a, b)
- Returns true if and only if (iff) a (interpreted as an integer) is greater than b (interpreted as an integer).
ifelse(cond, e1[, e2])
- Evaluates cond, and if it is true evaluates and returns the value of e1, otherwise it evaluates and returns e2 (if present). The "if ... else ... then ... endif" construct is just syntactic sugar
for this function. is_mounted(mount_point)
- Returns true iff there is a filesystem mounted at mount_point.
is_substring(needle, haystack)
- Returns true iff needle is a substring of haystack.
less_than_int(a, b)
- Returns true iff a (interpreted as an integer) is less than b (interpreted as an integer).
mount(fs_type, partition_type, name, mount_point)
- Mounts a filesystem of fs_type at mount_point. partition_type must be one of:
- MTD. Name is the name of an MTD partition (e.g., system, userdata; see
/proc/mtd
on the device for a complete list). - EMMC.
Recovery does not mount any filesystems by default (except the SD card if the user is doing a manual install of a package from the SD card); your script must mount any partitions it needs to modify.
- MTD. Name is the name of an MTD partition (e.g., system, userdata; see
package_extract_dir(package_dir, dest_dir)
- Extracts all files from the package underneath package_dir and writes them to the corresponding tree beneath dest_dir. Any existing files are overwritten.
package_extract_file(package_file[, dest_file])
- Extracts a single package_file from the update package and writes it to dest_file, overwriting existing files if necessary. Without the dest_file argument, returns the contents of the package file
as a binary blob. read_file(filename)
- Reads filename and returns its contents as a binary blob.
rename(src_filename, tgt_filename)
- Renames src_filename to tgt_filename. It automatically creates the necessary directories for the tgt_filename. Example:
rename("system/app/Hangouts/Hangouts.apk",
.
"system/priv-app/Hangouts/Hangouts.apk") run_program(path[, arg, ...])
- Executes the binary at path, passing args. Returns the program‘s exit status.
set_metadata(filename, key1, value1[, key2 , value2, ...])
- Sets the keys of the given filename to values. For example:
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, ...])
- Recursively sets the keys of the given dirname and all its children to values. For example:
set_metadata_recursive("/system", "uid", 0,
.
"gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0) set_progress(frac)
- Sets the position of the progress meter within the chunk defined by the most recent
show_progress()
call.frac must be in the range [0.0,
1.0]. The progress meter never moves backwards; attempts to make it do so are ignored. sha1_check(blob[, sha1])
- The blob argument is a blob of the type returned by
read_file()
or the one-argument form ofpackage_extract_file()
.
With no sha1 arguments, this function returns the SHA1 hash of the blob (as a 40-digit hex string). With one or more sha1 arguments, this function returns the SHA1 hash if it equals one of the arguments, or the empty string if it does not
equal any of them. show_progress(frac, secs)
- Advances the progress meter over the next frac of its length over the secs seconds (must be an integer). secsmay be 0, in which case the meter is not advanced automatically but by use of the
set_progress()
function
defined above. sleep(secs)
- Sleeps for secs seconds (must be an integer).
stdout(expr[, expr, ...])
- Evaluates each expression and dumps its value to stdout. Useful for debugging.
symlink(target[, source, ...])
- Creates all sources as symlinks to target.
tune2fs(device[, arg, …])
- Adjusts tunable parameters args on device.
ui_print([text, ...])
- Concatenates all text arguments and prints the result to the UI (where it will be visible if the user has turned on the text display).
unmount(mount_point)
- Unmounts the filesystem mounted at mount_point.
wipe_block_device(block_dev, len)
- Wipes the len bytes of the given block device block_dev.
wipe_cache()
- Causes the cache partition to be wiped at the end of a successful installation.
write_raw_image(filename_or_blob, partition)
- Writes the image in filename_or_blob to the MTD partition. filename_or_blob can be a string naming a local file or a blob-valued argument containing the data to write. To copy a file from the OTA
package to a partition, use:write_raw_image(package_extract_file("zip_filename"), "partition_name");
Note: Prior to Android 4.1, only filenames were accepted, so to accomplish this the data first had to be unzipped into a temporary local file.