主要文件:build/core/Makefile
build/tools/releasetools/ota_from_target_files
第一阶段:update原材料目录生成,作为第二阶段的输入。
build/core/Makefile +line 1118 ~ line 1311
中间目录在:out/target/product/ginwave73_gb/obj/PACKAGING/target_files_intermediates/目录下,名字为:
ginwave73_gb-target_files-user.lizhiguo,生成的zip包为:ginwave73_gb-target_files-user.lizhiguo.zip
$(zip_root)下面包含了:
RECOVERY目录:kernel_ginwave73_gb.bin, ramdisk_recovery.bin, 还有一个RAMDISK的目录,就是recovery/root的内容。
second, cmdline, base都是可选的。
FACTORY目录:一个RAMDISK目录,存放factory的目录,可以生产ramdisk-factory.img
kernel, pagesize, second, cmdline, base可选。
没有用到
BOOT目录:一个RAMDISK目录,存在root目录下的内容,用于生产ramdisk.img
kernel_ginwave73_gb.bin, ramdisk.img
second, cmdline, base, pagesize, board,可选。
RADIO目录: 没有用到
SYSTEM目录:将system目录中的内容拷贝进去
DATA目录:将data目录内容拷贝进入
OTA/bin目录:拷贝android-info.txt到OTA下,而将applypatch, applypatch_static, check_prereq, updater拷贝进OTA/bin。
例如:./ginwave73_gb/obj/EXECUTABLES/updater_intermediates/updater‘
META目录:apkcrets.txt来自out/target/product/ginwave73_gb/obj/PACKAGING/apkcerts_intermediates/ginwave73_gb-apkcerts-user.lizhiguo.txt
otakeys.txt本来可以来自.../PACKAGING/ota_keys_intermediates/keys,但是这里为NULL。
生成misc_info.txt,这个文件包含的信息有:recovery_api_version, blocksize, boot_size, recovery_size, system_size
secro_size, userdata_size, tool_extensions, mkyaffs2_extra_flags。当然包含这些参数都是可选的。
所有目录内容呈现于:
out/target/product/ginwave73_gb/obj/PACKAGING/target_files_intermediates/ginwave73_gb-target_files-user.lizhiguo$ ls
BOOT DATA FACTORY META OTA RECOVERY SYSTEM
接下来就是zip打包了:
@# Zip everything up, preserving symlinks
$(hide) (cd $(zip_root) && zip -qry ../$(notdir $@) .)
返回ginwave73_gb-target_files-user.lizhiguo的上级目录target_files_intermediates,打包生成ginwave73_gb-target_files-user.lizhiguo.zip
@# Run fs_config on all the system files in the zip, and save the output
$(hide) zipinfo -1 $@ | awk -F/ 'BEGIN { OFS="/" } /^SYSTEM\// {$$1 = "system"; print}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/filesystem_config.txt
$(hide) (cd $(zip_root) && zip -q ../$(notdir $@) META/filesystem_config.txt)
生成 META/filesystem_config.txt 并将其加入到 zip 包中。该文件保存了 system 目录下各目录、文件的权限及 owner.
$ head META/filesystem_config.txt
system 0 0 755
system/usr 0 0 755
system/usr/srec 0 0 755
system/usr/srec/config 0 0 755
system/usr/srec/config/en.us 0 0 755
system/usr/srec/config/en.us/grammars 0 0 755
system/usr/srec/config/en.us/grammars/phone_type_choice.g2g 0 0 644
system/usr/srec/config/en.us/grammars/VoiceDialer.g2g 0 0 644
system/usr/srec/config/en.us/grammars/boolean.g2g 0 0 644
system/usr/srec/config/en.us/g2p 0 0 755
...
这里,目录由zipinfo –l提供, 而权限则由fs_config设定。
源码位于build/tools/fs_config ,其中fs_config.c 包含一个头文件:#include "private/android_filesystem_config.h"
这个文件(system/core/include/private/android_filesystem_config.h)以hardcoding的方式设定了android中各目录的权限和属主,
同时也包括system下各文件和目录的权限和属主。
注意:如果需要升级其它内容,比如bootloader, 则可以在这里加入。
第二阶段:运行python脚本
build/core/Makefile + line 1314 ~ line1342
name := $(TARGET_PRODUCT)
ifeq ($(TARGET_BUILD_TYPE),debug)
name := $(name)_debug
endif
name := $(name)-ota-$(FILE_NAME_TAG)
这里可以看出,最后生成的ota upadte包名字这个,例如:ginwave73_gb-ota-user.lizhiguo.zip
INTERNAL_OTA_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip // 最终安装的目录是ginwave73_gb下。
$(INTERNAL_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)
采用默认的签名密钥,位于build/target/product/security,其中有很多签名密钥:
media.pk8 media.x509.pem platform.pk8 platform.x509.pem README shared.pk8 shared.x509.pem testkey.pk8 testkey.x509.pem
我们使用的是testkey。
$(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS)// 这里的依赖就是前面第一步中完成的工作。
@echo "Package OTA: $@"
$(hide) ./build/tools/releasetools/ota_from_target_files -v \
-n \
-p $(HOST_OUT) \
-k $(KEY_CERT_PAIR) \
$(BUILT_TARGET_FILES_PACKAGE) $@
接下来就会进入执行脚本ota_from_target_files了,我们先来看看这个脚本的各个参数的具体意思。
.PHONY: otapackage
otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)
OTA升级包包括两种:完全OTA升级包,增量OTA升级包
Given a target-files zipfile, produces an OTA package that installs
that build. An incremental OTA is produced if -i is given, otherwise
a full OTA is produced.该脚本的输入时一个zip包,输出就是一个OTA包了。
如果-i参数存在,那么将会生成增量OTA包。
Usage: ota_from_target_files [flags] input_target_files output_ota_package
-b (--board_config) <file> // 过时,不再使用
Deprecated.
-k (--package_key) <key> // 签名用的密钥
Key to use to sign the package (default is "build/target/product/security/testkey").
-i (--incremental_from) <file> // 生成增量OTA包时用于定义对比包
Generate an incremental OTA using the given target-files zip as the starting build.
-w (--wipe_user_data) // 升级的时候会清除userdata分区
Generate an OTA package that will wipe the user data partition when installed.
-n (--no_prereq) // 有这个参数时在升级时不检查时间戳;没有这个参数时会检查时间戳,此时只能基于老的向新的版本升级。
// 脚本中默认情况下是忽略检查时间戳的。
Omit(忽略) the timestamp prereq check normally included at the top of
the build scripts (used for developer OTA packages which
legitimately need to go back and forth). // 用这个选项主要是为了方便开发者前后升级
-e (--extra_script) <file> // 定义额外运行的脚本
Insert the contents of file at the end of the update script.
/ 可以指定对preloader.img, logo.img , uboot.img, dsp_bl.img进行升级 ///
-r (--preloader) <file>
Specify 'preloader.img' to upgrade.
-l (--logo) <file>
Specify 'logo.img' to upgrade.
-u (--uboot) <file>
Specify 'uboot.img' to upgrade.
-d (--dsp) <file>
Specify 'dsp_bl.img' to upgrade.
/ 可以指定对preloader.img, logo.img , uboot.img, dsp_bl.img进行升级 ///
-p (--path) <dir> // 定义脚本用到的一些可执行文件的路径
Prepend <dir>/bin to the list of places to search for binaries
run by this script, and expect to find jars in <dir>/framework.
-s (--device_specific) <file>
Path to the python module containing device-specific releasetools code.
-x (--extra) <key=value> 定义额外运行的脚本可能用到的键/值对
Add a key/value pair to the 'extras' dict, which device-specific extension code may look at.
-v (--verbose)
Show command lines being executed.
-h (--help)
Display this usage message and exit.
综上所述,重要的参数有-k, -i, -w, -n, (-l == logo , -r == preloader , -u == uboot, -d = dsp_bl)
那么展开Makefile中调用ota_from_target_files脚本,如下:
./build/tools/releasetools/ota_from_target_files -v \
-n \
-p out/host/linux-x86 \
-k build/target/product/security/testkey \
out/target/product/ginwave73_gb/obj/PACKAGING/target_files_intermediates/ginwave73_gb-target_files-user.lizhiguo.zip out/target/product/ginwave73_gb/ginwave73_gb-ota-user.lizhiguo.zip
下面分析一下这个python脚本的代码
首先可以看到脚本语句中设置的默认情况:
OPTIONS = common.OPTIONS
OPTIONS.package_key = "build/target/product/security/testkey" // 默认签名用的密钥
OPTIONS.incremental_source = None // 默认无增量源
OPTIONS.require_verbatim = set()
OPTIONS.prohibit_verbatim = set(("system/build.prop",))
OPTIONS.patch_threshold = 0.95
OPTIONS.wipe_user_data = False // 默认不会清除userdata
OPTIONS.omit_prereq = True // 默认不会进行时间戳比较
OPTIONS.extra_script = None
OPTIONS.worker_threads = 3
#wschen
OPTIONS.preloader = None // 可以看出这一部分是mtk加的
OPTIONS.uboot = None
OPTIONS.logo = None
OPTIONS.dsp = None
scatter_path = "mediatek/source/misc/ota_scatter.txt" // 默认的散列文件
WriteIncrementalOTAPackage()生成增量OTA包, 需要-i参数,加上对比包,这个对比包是前次的中间zip包。
WriteFullOTAPackage()生成完全OTA包
总结:
昨天说的OTA包的内容,之前我们都存在一些误解,上午研究了下编译OTA的过程,下面总结一下:
1. OTA包生成分两步:
第一步生成输入源目录ginwave73_gb-target_files-user.lizhiguo,这里面就放了将会进入OTA包的原始数据,其中包括一些目录:
(这些目录中的数据来源于./mk –t n 之后在out/target/product/ginwave73_gb/下的内容)
BOOT DATA FACTORY META OTA RECOVERY SYSTEM
其中以BOOT RECOVERY SYSTEM为主;DATA和FACTORY没有使用,可以对其配置;而META和OTA是一些升级的辅助工具。
可以看出主要升级的内容又boot.img, recovery.img, system.img
最后将其打包成ginwave73_gb-target_files-user.lizhiguo.zip,供第二步使用。
接着会调用一个python脚本ota_from_target_files,这个脚本以第一步的结果为输入,输出的结果就是最终的OTA包:ginwave73_gb-ota-user.lizhiguo.zip
当然这个脚本还有一些重要的参数,mtk在原始的脚本文件中有做修改,加入了以下这些参数可以将u-boot之类的也加进入:
-r (--preloader) <file> Specify 'preloader.img' to upgrade.
-l (--logo) <file> Specify 'logo.img' to upgrade.
-u (--uboot) <file> Specify 'uboot.img' to upgrade.
-d (--dsp) <file> Specify 'dsp_bl.img' to upgrade.
但是,在MTK android的编译环境中,并没有加入这些img一起升级,要加的话我们可以自己修改。
另外一些中要参数有:
-i (--incremental_from) <file> // 生成增量OTA包时用于定义对比包
-w (--wipe_user_data) // 升级的时候会清除userdata分区
-n (--no_prereq) // 有这个参数时在升级时不检查时间戳;没有这个参数时会检查时间戳,此时只能基于老的向新的版本升级。
// 脚本代码中默认情况下是忽略检查时间戳的。
目前的编译系统内有加-n,忽略检查时间戳,但是没有-i和-w,就是说,目前我们编译的都是完全OTA包,并没有编译过增量OTA包,也不会清楚userdata区域。
2. OTA包分完全OTA包和增量OTA包
完全OTA包就是相当于我们用工具下载那些img,不过其中只有boot.img完整,而system不是提供的img,而是一整个目录;recovery.img是相对于boot.img的patch。
增量OTA包,需要在执行python脚本的时候加上-I <start_xxx.zip>作为对比包,输出就是两个包之间的差异。
我们目前编译出来的都是完全OTA包,里面只包含了boot.img, recovery.img, system。
最后建议以后编译出来的OTA包名字还是加上日期和项目名字,免得混淆,到时候给到用户那边的时候让用户在使用之间将名字修改为update.zip就行。