OTA升级首要是生成OTA升级包,升级包又分为升级全包和升级差分包(或要增量包)。升级全包是编译当前系统得到的软件包,这个包很大,有上百兆,但是不依赖与当前手机里的软件版本;升级差分包是对手机两个软件版本做差分,在第一个版本上打patch,得到第二个升级包,所以差分包只能对第一个版本的机器进行升级。
本文主要讲述升级全包的生成过程。
编译升级全包,用下面指令:
#make otapackage
最终生成INTERNAL_OTA_PACKAGE_TARGET,也就是$(PRODUCT_OUT)/$(name).zip。
一、升级全包($(PRODUCT_OUT)/$(name).zip)的生成
INTERNAL_OTA_PACKAGE_TARGET依赖于BUILT_TARGET_FILES_PACKAGE
生成规则【在build/core/Makefile中】:
$(INTERNAL_OTA_PACKAGE_TARGET):$(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS)
@echo"Package OTA: $@"
$(hide)./build/tools/releasetools/ota_from_target_files -v \
-p $(HOST_OUT) \
-k $(KEY_CERT_PAIR) \
$(BUILT_TARGET_FILES_PACKAGE) $@
ota_from_target_files是python脚本,需要中间文件$(BUILT_TARGET_FILES_PACKAGE)。所以,在分析完中间文件的生成之后再看最终升级全包的生成过程。
二、中间文件包($(TARGET_PRODUCT)-target_files-$(FILE_NAME_TAG).zip)的生成
BUILT_TARGET_FILES_PACKAGE是$(intermediates)/$( TARGET_PRODUCT)-target_files-$(FILE_NAME_TAG).zip
形如:out/target/product/<product>/obj/PACKAGING/target_files_intermediates/<product>-target_files-<eng>.haili.tian
生成规则【在build/core/Makefile中】:
$(BUILT_TARGET_FILES_PACKAGE):\
$(INSTALLED_BOOTIMAGE_TARGET) \
$(INSTALLED_RADIOIMAGE_TARGET) \
$(INSTALLED_RECOVERYIMAGE_TARGET)\
$(INSTALLED_SYSTEMIMAGE) \
$(INSTALLED_USERDATAIMAGE_TARGET)\
$(INSTALLED_ANDROID_INFO_TXT_TARGET)\
$(built_ota_tools) \
$(APKCERTS_FILE) \
$(HOST_OUT_EXECUTABLES)/fs_config\
| $(ACP)
@echo "Package target files:$@"
$(hide) rm -rf $@ $(zip_root)
$(hide) mkdir -p $(dir $@) $(zip_root)
@# Components of the recovery image
$(hide) mkdir -p $(zip_root)/RECOVERY
$(hide) $(call package_files-copy-root, \
$(TARGET_RECOVERY_ROOT_OUT),$(zip_root)/RECOVERY/RAMDISK)
ifdef INSTALLED_KERNEL_TARGET
$(hide) $(ACP) $(INSTALLED_KERNEL_TARGET)$(zip_root)/RECOVERY/kernel
endif
ifdef INSTALLED_2NDBOOTLOADER_TARGET
$(hide) $(ACP) \
$(INSTALLED_2NDBOOTLOADER_TARGET)$(zip_root)/RECOVERY/second
endif
ifdef BOARD_KERNEL_CMDLINE
$(hide) echo"$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/RECOVERY/cmdline
endif
ifdef BOARD_KERNEL_BASE
$(hide) echo"$(BOARD_KERNEL_BASE)" > $(zip_root)/RECOVERY/base
endif
ifdef BOARD_KERNEL_PAGESIZE
$(hide) echo "$(BOARD_KERNEL_PAGESIZE)"> $(zip_root)/RECOVERY/pagesize
endif
@# Components of the boot image
$(hide) mkdir -p $(zip_root)/BOOT
$(hide) $(call package_files-copy-root, \
$(TARGET_ROOT_OUT),$(zip_root)/BOOT/RAMDISK)
ifdef INSTALLED_KERNEL_TARGET
$(hide) $(ACP) $(INSTALLED_KERNEL_TARGET)$(zip_root)/BOOT/kernel
endif
ifdef INSTALLED_2NDBOOTLOADER_TARGET
$(hide) $(ACP) \
$(INSTALLED_2NDBOOTLOADER_TARGET)$(zip_root)/BOOT/second
endif
ifdef BOARD_KERNEL_CMDLINE
$(hide) echo"$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/BOOT/cmdline
endif
ifdef BOARD_KERNEL_BASE
$(hide) echo"$(BOARD_KERNEL_BASE)" > $(zip_root)/BOOT/base
endif
ifdef BOARD_KERNEL_PAGESIZE
$(hide) echo"$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/BOOT/pagesize
endif
$(hide) $(foreach t,$(INSTALLED_RADIOIMAGE_TARGET),\
mkdir -p $(zip_root)/RADIO; \
$(ACP) $(t)$(zip_root)/RADIO/$(notdir $(t));)
@# Contents of the system image
$(hide) $(call package_files-copy-root, \
$(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM)
@# Contents of the data image
$(hide) $(call package_files-copy-root, \
$(TARGET_OUT_DATA),$(zip_root)/DATA)
@# Extra contents of the OTA package
$(hide) mkdir -p $(zip_root)/OTA/bin
$(hide) $(ACP)$(INSTALLED_ANDROID_INFO_TXT_TARGET) $(zip_root)/OTA/
$(hide) $(ACP) $(PRIVATE_OTA_TOOLS)$(zip_root)/OTA/bin/
@# Files that do not end up in anyimages, but are necessary to
@# build them.
$(hide) mkdir -p $(zip_root)/META
$(hide) $(ACP) $(APKCERTS_FILE)$(zip_root)/META/apkcerts.txt
$(hide) echo"$(PRODUCT_OTA_PUBLIC_KEYS)" > $(zip_root)/META/otakeys.txt
$(hide) echo"recovery_api_version=$(PRIVATE_RECOVERY_API_VERSION)" >$(zip_root)/META/misc_info.txt
ifdef BOARD_FLASH_BLOCK_SIZE
$(hide) echo"blocksize=$(BOARD_FLASH_BLOCK_SIZE)" >> $(zip_root)/META/misc_info.txt
endif
ifdef BOARD_BOOTIMAGE_PARTITION_SIZE
$(hide) echo"boot_size=$(BOARD_BOOTIMAGE_PARTITION_SIZE)" >>$(zip_root)/META/misc_info.txt
endif
ifdef BOARD_RECOVERYIMAGE_PARTITION_SIZE
$(hide) echo"recovery_size=$(BOARD_RECOVERYIMAGE_PARTITION_SIZE)" >>$(zip_root)/META/misc_info.txt
endif
ifdef BOARD_SYSTEMIMAGE_PARTITION_SIZE
$(hide) echo"system_size=$(BOARD_SYSTEMIMAGE_PARTITION_SIZE)" >>$(zip_root)/META/misc_info.txt
endif
ifdef BOARD_USERDATAIMAGE_PARTITION_SIZE
$(hide) echo "userdata_size=$(BOARD_USERDATAIMAGE_PARTITION_SIZE)">> $(zip_root)/META/misc_info.txt
endif
$(hide) echo"tool_extensions=$(tool_extensions)" >>$(zip_root)/META/misc_info.txt
ifdef mkyaffs2_extra_flags
$(hide) echo"mkyaffs2_extra_flags=$(mkyaffs2_extra_flags)" >>$(zip_root)/META/misc_info.txt
endif
@# Zip everything up, preserving symlinks
$(hide) (cd $(zip_root) && zip-qry ../$(notdir $@) .)
@# Run fs_config on all the system filesin 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)
其中,变量定义:
- TARGET_RECOVERY_ROOT_OUT也就是$(TARGET_RECOVERY_OUT)/root;TARGET_RECOVERY_OUT是$(PRODUCT_OUT)/recovery;PRODUCT_OUT是out/target/product/<product>。所以,TARGET_RECOVERY_ROOT_OUT也就是out/target/product/<product>/recovery/root;
- zip_root是$(intermediates)/$( TARGET_PRODUCT)-target_files-$(FILE_NAME_TAG)路径,也就是out/target/product/<product>/obj/PACKAGING/target_files_intermediates/<product>-target_files-<eng>.haili.tian;
- TARGET_ROOT_OUT是$(PRODUCT_OUT)/root,也就是out/target/product/<product>/root;
- INSTALLED_RADIOIMAGE_TARGET;
- SYSTEMIMAGE_SOURCE_DIR是$(TARGET_OUT),也就是out/target/product/<product>/system/;
- TARGET_OUT_DATA是$(PRODUCT_OUT)/data,也就是out/target/product/<product>/data;
- INSTALLED_ANDROID_INFO_TXT_TARGET是$(PRODUCT_OUT)/android-info.txt,也就是out/target/product/<product>/android-info.txt;
- PRIVATE_OTA_TOOLS是$(built_ota_tools),也就是包含了:
out/target/product/<product>/obj/EXECUTABLES/applypatch_intermediates/applypatch
out/target/product/<product>/obj/EXECUTABLES/applypatch_static_intermediates/applypatch_static
out/target/product/<product>/obj/EXECUTABLES/check_prereq_intermediates/check_prereq
out/target/product/<product>/obj/EXECUTABLES/updater_intermediates/updater
- APKCERTS_FILE是out/target/product/<product>/obj/PACKAGING/apkcerts_intermediates/<product>-apkcerts-<eng>.haili.tian.txt
- PRODUCT_OTA_PUBLIC_KEYS目前为空;
- PRIVATE_RECOVERY_API_VERSION也就是RECOVERY_API_VERSION,RecoveryAPI的版本号;
- tool_extensions如果定义了TARGET_RELEASETOOLS_EXTENSIONS,tool_extensions也就是TARGET_RELEASETOOLS_EXTENSIONS;
- DEFAULT_SYSTEM_DEV_CERTIFICATE目前为空;
- HOST_OUT_EXECUTABLES是$(HOST_OUT)/bin,也就是out/host/linux-x86/bin;
脚本的执行:
1. #清理以前残存的目录和文件,并创建$(zip_root)目录(也就是out/target/product/<product>/obj/PACKAGING/target_files_intermediates/<product>-target_files-<eng>.haili.tian);
2. 创建$(zip_root)/RECOVERY目录,把$(TARGET_RECOVERY_ROOT_OUT)(也就是out/target/product/<product>/recovery/root)下的所有文件和目录都拷贝到$(zip_root)/RECOVERY/RAMDISK/下;
3. 创建$(zip_root)/BOOT目录,然后把$(TARGET_ROOT_OUT)(也就是out/target/product/<product>/root)下的所有文件和目录都拷贝到$(zip_root)/BOOT/RAMDISK/下;
4. 创建$(zip_root)/RADIO目录,然后把$(INSTALLED_RADIOIMAGE_TARGET)下的所有文件和目录都拷贝到$(zip_root)/ RADIO/下;
5. 把$(SYSTEMIMAGE_SOURCE_DIR)【也就是out/target/product/<product>/system/】下的所有文件和目录都拷贝到$(zip_root)/SYSTEM/下;
6. 把$(TARGET_OUT_DATA)【也就是out/target/product/<product>/data】下的所有文件和目录都拷贝到$(zip_root)/DATA/下;
7. 创建$(zip_root)/OTA/bin目录,然后把INSTALLED_ANDROID_INFO_TXT_TARGET【也就是out/target/product/<product>/android-info.txt】放到$(zip_root)/OTA/下;
8. 把PRIVATE_OTA_TOOLS【也就是applypatch、applypatch_static、check_prereq、updater】放到$(zip_root)/OTA/bin下。
9. 创建$(zip_root)/META目录,搜集META信息并保存到文件里:
把APKCERTS_FILE【也就是out/target/product/<product>/obj/PACKAGING/apkcerts_intermediates/<product>-apkcerts-<eng>.haili.tian.txt】放到$(zip_root)/META/apkcerts.txt;
把$(PRODUCT_OTA_PUBLIC_KEYS)追加到$(zip_root)/META/otakeys.txt;【】
把recovery_api_version=$(PRIVATE_RECOVERY_API_VERSION)这行追加到$(zip_root)/META/misc_info.txt;
把tool_extensions=$(tool_extensions)这行追加到$(zip_root)/META/misc_info.txt;
把default_system_dev_certificate=$(DEFAULT_SYSTEM_DEV_CERTIFICATE)这行追加到$(zip_root)/META/misc_info.txt;
10. 拷贝Image文件
把$(PRODUCT_OUT)/ramdisk.img放到$(zip_root)/下;
把$(PRODUCT_OUT)/ramdisk-recovery.img放到(zip_root)/
把$(PRODUCT_OUT)/../../../../boot/out/u-boot.bin放到$(zip_root)/
把$(PRODUCT_OUT)/../../../../kernel/out/uImage放到(zip_root)/
11. 进入$(zip_root),把$(zip_root)下所有的内容打进zip包<product>-target_files-<eng>.haili.tian.zip;
12. 用$(HOST_OUT_EXECUTABLES)/fs_config获取文件系统信息并保存在文件里
“SYSTEM/”下的文件系统信息保存在$(zip_root)/META/filesystem_config.txt中;
“BOOT/RAMDISK/”下的文件系统信息保存在$(zip_root)/META/boot_filesystem_config.txt中;
“RECOVERY/RAMDISK/”下的文件系统信息保存在$(zip_root)/META/recovery_filesystem_config.txt中;
13. 把META/*filesystem_config.txt文件打到zip包<product>-target_files-<eng>.haili.tian.zip里。
三、ota_from_target_file分析
Ota_from_target_file是python脚本,从main()开始分析。
3.1 生成总过程 – main()
Main()里主要做下列工作:
1. 从参数和环境中解析OPTIONS;
2. 从中间zip包里的META/misc_info.txt中解析出{<key>=<value>}OPTIONS对,比如recovery_api_version=3;tool_extensions=device/<company>/<product>/recovery;
3. 从OPTIONS对里找到tool_extensions,赋值给OPTIONS.device_specific;
4. input_zip为上文的中间zip包;output_zip为最终生成的临时zip包;
5. 对于全包升级包,调用WriteFullOTAPackage(input_zip,output_zip);
6. 签名临时包,生成最终签过名的最终全包升级包。
上述过程中,我们最关注的是WriteFullOTAPackage(input_zip,output_zip)做的工作。
3.2 生成全包 – WriteFullOTAPackage()
WriteFullOTAPackage[file:build/tools/releasetools/ota_from_target_files]的定义如下:
1. def WriteFullOTAPackage(input_zip, output_zip):
2. # TODO:how to determine this? We don't knowwhat version it will
3. # beinstalled on top of. For now, we expectthe API just won't
4. # changevery often.
5. script =edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
6.
7. "post-build": GetBuildProp("ro.build.fingerprint",input_zip),
8. "pre-device": GetBuildProp("ro.product.device",input_zip),
9. "post-timestamp":GetBuildProp("ro.build.date.utc", input_zip),
10. }
11.
12. device_specific = common.DeviceSpecificParams(
13. input_zip=input_zip,
14. "recovery_api_version"],
15. output_zip=output_zip,
16. script=script,
17. input_tmp=OPTIONS.input_tmp,
18. metadata=metadata,
19. info_dict=OPTIONS.info_dict,
20. trusted_boot=OPTIONS.trusted_boot)
21.
22. # if not OPTIONS.omit_prereq:
23. # ts =GetBuildProp("ro.build.date.utc", input_zip)
24. # script.AssertOlderBuild(ts)
25.
26. # AppendAssertions(script, input_zip)
27. # device_specific.FullOTA_Assertions()
28.
29. script.ShowProgress(0.9, 16)
30.
31. if
32. "/data")
33.
34. "/system")
35. "/system")
36. # script.UnpackPackageDir("recovery", "/system")
37. "system", "/system")
38.
39. symlinks= CopySystemFiles(input_zip, output_zip)
40. script.MakeSymlinks(symlinks)
41.
42. # boot_img = common.File("boot.img", common.BuildBootableImage(
43. # os.path.join(OPTIONS.input_tmp, "BOOT")))
44. # recovery_img = common.File("recovery.img",common.BuildBootableImage(
45. # os.path.join(OPTIONS.input_tmp, "RECOVERY")))
46. # MakeRecoveryPatch(output_zip, recovery_img, boot_img)
47. Item.GetMetadata(input_zip)
48. "system").SetPermissions(script)
49.
50. # common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
51. # common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
52. # script.ShowProgress(0.2, 0)
53.
54. # script.ShowProgress(0.2, 10)
55. # script.WriteRawImage("/boot", "boot.img")
56.
57. # script.ShowProgress(0.1, 0)
58. device_specific.FullOTA_InstallEnd()
59.
60. if
61. script.AppendExtra(OPTIONS.extra_script)
62.
63. script.UnmountAll()
64. script.AddToZip(input_zip, output_zip)
65. WriteMetadata(metadata,output_zip)
def WriteFullOTAPackage(input_zip, output_zip):
# TODO:how to determine this? We don't knowwhat version it will
# beinstalled on top of. For now, we expectthe API just won't
# changevery often.
script =edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
metadata= {"post-build": GetBuildProp("ro.build.fingerprint",input_zip),
"pre-device": GetBuildProp("ro.product.device",input_zip),
"post-timestamp":GetBuildProp("ro.build.date.utc", input_zip),
}
device_specific = common.DeviceSpecificParams(
input_zip=input_zip,
input_version=OPTIONS.info_dict["recovery_api_version"],
output_zip=output_zip,
script=script,
input_tmp=OPTIONS.input_tmp,
metadata=metadata,
info_dict=OPTIONS.info_dict,
trusted_boot=OPTIONS.trusted_boot)
# if not OPTIONS.omit_prereq:
# ts =GetBuildProp("ro.build.date.utc", input_zip)
# script.AssertOlderBuild(ts)
# AppendAssertions(script, input_zip)
# device_specific.FullOTA_Assertions()
script.ShowProgress(0.9, 16)
if OPTIONS.wipe_user_data:
script.FormatPartition("/data")
script.FormatPartition("/system")
script.Mount("/system")
# script.UnpackPackageDir("recovery", "/system")
script.UnpackPackageDir("system", "/system")
symlinks= CopySystemFiles(input_zip, output_zip)
script.MakeSymlinks(symlinks)
# boot_img = common.File("boot.img", common.BuildBootableImage(
# os.path.join(OPTIONS.input_tmp, "BOOT")))
# recovery_img = common.File("recovery.img",common.BuildBootableImage(
# os.path.join(OPTIONS.input_tmp, "RECOVERY")))
# MakeRecoveryPatch(output_zip, recovery_img, boot_img)
Item.GetMetadata(input_zip)
Item.Get("system").SetPermissions(script)
# common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
# common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
# script.ShowProgress(0.2, 0)
# script.ShowProgress(0.2, 10)
# script.WriteRawImage("/boot", "boot.img")
# script.ShowProgress(0.1, 0)
device_specific.FullOTA_InstallEnd()
if OPTIONS.extra_script is not None:
script.AppendExtra(OPTIONS.extra_script)
script.UnmountAll()
script.AddToZip(input_zip, output_zip)
WriteMetadata(metadata,output_zip)
OTA全包生成的过程:
1. script用来生成Edify脚本,在edify_generator.py中实现;
2. script中增加语句:显示进度;
3. script中增加语句:擦除“/system”分区;
4. script中增加语句:安装system分区到“/system”;
5. script中增加语句:把system中的内容复制到/system下;
6. 把input_zip包/system中的内容,复制到output_zip包中,不包含其中的link文件;
7. 对于link文件,script中增加指向链接的语句;
8. 从input_zip包的META/filesystem_config.txt中获取其中描述的/system下各个文件的权限信息;
9. script中增加语句:设置/system下文件的权限和属主信息;
10. 调用具体device特定的函数FullOTA_InstallEnd。
main()函数中已经获取OPTIONS.device_specific为/device/<company>/<product>/recovery;这里的device_specific是common.DeviceSpecificParams。
releasetools.py脚本。所以这里执行releasetools.py中的FullOTA_InstallEnd。
11. 如果特别指定了其他脚本,script中加入;
12. 通过script.AddToZip()写META-INF
把前面所有的脚本,写入到output_zip里的META-INF/com/google/android/updater-script这个edify脚本中;
把input_zip里的OTA/bin/updater写入到output_zip里的META-INF/com/google/android/update-binary
13. 把metadata的内容写入到output_zip里的META-INF/com/android/metadata