OTA 研究笔记

转载:

[OTA本质与实现流程分析]https://blog.csdn.net/bi511304183/article/details/9340175

[OTA制作及升级过程笔记]https://blog.csdn.net/teliduxing1029/article/details/51536560

1.OTA

所谓OTA(Over-the-AirTechnology)是指手机终端通过无线网下载远程服务器上的升级包,对系统或应用进行升级的技术。进一步说,就是将升级包(update.zip压缩包)写入到(手机)系统存储区。

2.OTA 升级包(update.zip)

OTA 升级包有整包与差分包之分。

整包:包含整个system分区中的数据文件;利用整包升级好比对电脑进行重作系统,格式分系统分区,并将新系统数据写入分区;

差分包:仅包含新旧两个版本之间改动的部分。而利用差分包升级不会格式化system分区,只是对其中部分存储段的内容进行重写。

3.OTA 升级包(update.zip)制作

(1) 整包制作与说明

系统经过整编后,执行make otapackage命令,即可完成整包的制作。该命令执行分为两个阶段:

1) 将系统资源(包括system、recovery、boot等目录)重新打包,生成差分资源包(target-files zipfile)

2) 制作升级包

第一阶段,makfile文件(./build/core/Makefile)中,otapackage相关代码段:

# -----------------------------------------------------------------  
# OTA update package  
  
name := $(TARGET_PRODUCT)  
ifeq ($(TARGET_BUILD_TYPE),debug)  
  name := $(name)_debug  
endif  
name := $(name)-ota-$(FILE_NAME_TAG)  
  
INTERNAL_OTA_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip  
  
$(INTERNAL_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)  
  
$(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) \  
           $(ota_extra_flag) \  
           $(BUILT_TARGET_FILES_PACKAGE) $@  
.PHONY: otapackage  
otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)  
# -----------------------------------------------------------------  

首先,otapackage目标的执行只依赖于$(INTERNAL_OTA_PACKAGE_TARGET),而不存在任何规则(根据Makefile语法,规则必须以TAB键开始,而目标otapackage的定义之后却是变量name的声明,因此不存在规则),因此只需要关注目标$(INTERNAL_OTA_PACKAGE_TARGET)的生成。显然,此目标的生成依赖于目标文件:$(BUILT_TARGET_FILES_PACKAGE)和$(OTATOOLS),且其执行的命令为./build/tools/releasetools/ota_from_target_files。也就是说,make otapackage所完成的功能全是通过这两个目标文件和执行的命令完成的,我们将分别对这三个关键点进行分析。

1)$(OTATOOLS)

目标文件OTATOOLS的编译规则如下所示:

OTATOOLS :=  $(HOST_OUT_EXECUTABLES)/minigzip \  
         $(HOST_OUT_EXECUTABLES)/mkbootfs \  
         $(HOST_OUT_EXECUTABLES)/mkbootimg \  
         $(HOST_OUT_EXECUTABLES)/fs_config \  
         $(HOST_OUT_EXECUTABLES)/mkyaffs2image \  
         $(HOST_OUT_EXECUTABLES)/zipalign \  
         $(HOST_OUT_EXECUTABLES)/aapt \  
         $(HOST_OUT_EXECUTABLES)/bsdiff \  
         $(HOST_OUT_EXECUTABLES)/imgdiff \  
         $(HOST_OUT_JAVA_LIBRARIES)/dumpkey.jar \  
         $(HOST_OUT_JAVA_LIBRARIES)/signapk.jar \  
         $(HOST_OUT_EXECUTABLES)/mkuserimg.sh \  
         $(HOST_OUT_EXECUTABLES)/genext2fs \  
         $(HOST_OUT_EXECUTABLES)/tune2fs \  
         $(HOST_OUT_EXECUTABLES)/e2fsck \  
         $(HOST_OUT_EXECUTABLES)/make_ext4fs  

.PHONY: otatools  
otatools: $(OTATOOLS) 

变量OTATOOLS为系统中一系列文件的集合。这些文件用于压缩(minigzip:用于gzip文件;make_ext4fs:将文件转换为ext4类型;mkyaffs2image:用于yaffs文件系统;......)、解压缩、差分(bsdiff,imgdiff)、签名(singapk.jar)等功能。目标$(INTERNAL_OTA_PACKAGE_TARGET)的执行依赖于这一系列系统工具。也就是说,目标文件$(OTATOOLS)仅仅指定了命令执行所需要的工具,并未执行任何操作。

注:变量$(HOST_OUT_EXECUTABLES)指代的是out/host/linux-x86/bin目录,而变量$(HOST_OUT_JAVA_LIBRARIES)/表示的是out/host/linux-x86/framework目录,这意味着我们可以从此目录下找到上述工具,并为我们所用。

2)$(BUILT_TARGET_FILES_PACKAGE)

目标OTATOOLS指明了执行makeotapackage命令所需要的系统工具,而目标$(BUILT_TARGE_FILES_PACKAGE)的生成则完成了两件事:重新打包system.img文件和生成差分资源包。$(BUILT_TARGE_FILES_PACKAGE)的编译规则如下所示:

1. # -----------------------------------------------------------------  
2. # A zip of the directories that map to the target filesystem.  
3. # This zip can be used to create an OTA package or filesystem image  
4. # as a post-build step.  
5. #  
6. name := $(TARGET_PRODUCT)  
7. ifeq ($(TARGET_BUILD_TYPE),debug)  
8.   name := $(name)_debug  
9. endif  
10.name := $(name)-target_files-$(FILE_NAME_TAG)  
11.  
12.intermediates := $(call intermediates-dir-for,PACKAGING,target_files)  
13.BUILT_TARGET_FILES_PACKAGE := $(intermediates)/$(name).zip  
14.$(BUILT_TARGET_FILES_PACKAGE): intermediates := $(intermediates)  
15.$(BUILT_TARGET_FILES_PACKAGE): \  
16.        zip_root := $(intermediates)/$(name)  
17.  
18.# $(1): Directory to copy  
19.# $(2): Location to copy it to  
20.# The "ls -A" is to prevent "acp s/* d" from failing if s is empty.  
21.define package_files-copy-root  
22.  if [ -d "$(strip $(1))" -a "$$(ls -A $(1))" ]; then \  
23.    mkdir -p $(2) && \  
24.    $(ACP) -rd $(strip $(1))/* $(2); \  
25.  fi  
26.endef  
27.  
28.built_ota_tools := \  
29.    $(call intermediates-dir-for,EXECUTABLES,applypatch)/applypatch \  
30.    $(call intermediates-dir-for,EXECUTABLES,applypatch_static)/applypatch_static \  
31.    $(call intermediates-dir-for,EXECUTABLES,check_prereq)/check_prereq \  
32.    $(call intermediates-dir-for,EXECUTABLES,sqlite3)/sqlite3 \  
33.    $(call intermediates-dir-for,EXECUTABLES,updater)/updater  
34.$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_OTA_TOOLS := $(built_ota_tools)  
35.  
36.$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_RECOVERY_API_VERSION := $(RECOVERY_API_VERSION)  
37.  
38.ifeq ($(TARGET_RELEASETOOLS_EXTENSIONS),)  
39.# default to common dir for device vendor  
40.$(BUILT_TARGET_FILES_PACKAGE): tool_extensions := $(TARGET_DEVICE_DIR)/../common  
41.else  
42.$(BUILT_TARGET_FILES_PACKAGE): tool_extensions := $(TARGET_RELEASETOOLS_EXTENSIONS)  
43.endif  
44.  
45.# Depending on the various images guarantees that the underlying  
46.# directories are up-to-date.  
47.  
48.ifeq ($(TARGET_USERIMAGES_USE_EXT4),true)  
49.$(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_CACHEIMAGE_TARGET)  
50.endif  
51.  
52.$(BUILT_TARGET_FILES_PACKAGE): \  
53.        $(INSTALLED_BOOTIMAGE_TARGET) \  
54.        $(INSTALLED_RADIOIMAGE_TARGET) \  
55.        $(INSTALLED_RECOVERYIMAGE_TARGET) \  
56.        $(INSTALLED_FACTORYIMAGE_TARGET) \  
57.        $(INSTALLED_SYSTEMIMAGE) \  
58.        $(INSTALLED_CACHEIMAGE_TARGET) \  
59.        $(INSTALLED_USERDATAIMAGE_TARGET) \  
60.        $(INSTALLED_SECROIMAGE_TARGET) \  
61.        $(INSTALLED_ANDROID_INFO_TXT_TARGET) \  
62.        $(built_ota_tools) \  
63.        $(APKCERTS_FILE) \  
64.        $(HOST_OUT_EXECUTABLES)/fs_config \  
65.        | $(ACP)  
66.     @echo "Package target files: $@"  
67.    $(hide) rm -rf $@ $(zip_root)  
68.    $(hide) mkdir -p $(dir $@) $(zip_root)  
69.     @# Components of the recovery image  
70.    $(hide) mkdir -p $(zip_root)/RECOVERY  
71.    $(hide) $(call package_files-copy-root, \  
72.        $(TARGET_RECOVERY_ROOT_OUT),$(zip_root)/RECOVERY/RAMDISK)  
73.ifdef INSTALLED_KERNEL_TARGET  
74.    $(hide) $(ACP) $(INSTALLED_KERNEL_TARGET) $(zip_root)/RECOVERY/kernel  
75.    $(hide) $(ACP) $(recovery_ramdisk) $(zip_root)/RECOVERY/ramdisk  
76.endif  
77.ifdef INSTALLED_2NDBOOTLOADER_TARGET  
78.    $(hide) $(ACP) \  
79.        $(INSTALLED_2NDBOOTLOADER_TARGET) $(zip_root)/RECOVERY/second  
80.endif  
81.ifdef BOARD_KERNEL_CMDLINE  
82.    $(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/RECOVERY/cmdline  
83.endif  
84.ifdef BOARD_KERNEL_BASE  
85.    $(hide) echo "$(BOARD_KERNEL_BASE)" > $(zip_root)/RECOVERY/base  
86.endif  
87.     @# Components of the factory image  
88.    $(hide) mkdir -p $(zip_root)/FACTORY  
89.    $(hide) $(call package_files-copy-root, \  
90.        $(TARGET_FACTORY_ROOT_OUT),$(zip_root)/FACTORY/RAMDISK)  
91.ifdef INSTALLED_KERNEL_TARGET  
92.    $(hide) $(ACP) $(INSTALLED_KERNEL_TARGET) $(zip_root)/FACTORY/kernel  
93.endif  
94.ifdef BOARD_KERNEL_PAGESIZE  
95.    $(hide) echo "$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/RECOVERY/pagesize  
96.endif  
97.ifdef INSTALLED_2NDBOOTLOADER_TARGET  
98.    $(hide) $(ACP) \  
99.        $(INSTALLED_2NDBOOTLOADER_TARGET) $(zip_root)/FACTORY/second  
100.endif  
101.ifdef BOARD_KERNEL_CMDLINE  
102.    $(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/FACTORY/cmdline  
103.endif  
104.ifdef BOARD_KERNEL_BASE  
105.    $(hide) echo "$(BOARD_KERNEL_BASE)" > $(zip_root)/FACTORY/base  
106.endif  
107.    @# Components of the boot image  
108.    $(hide) mkdir -p $(zip_root)/BOOT  
109.    $(hide) $(call package_files-copy-root, \  
110.        $(TARGET_ROOT_OUT),$(zip_root)/BOOT/RAMDISK)  
111.ifdef INSTALLED_KERNEL_TARGET  
112.    $(hide) $(ACP) $(INSTALLED_KERNEL_TARGET) $(zip_root)/BOOT/kernel  
113.    $(hide) $(ACP) $(INSTALLED_RAMDISK_TARGET) $(zip_root)/BOOT/ramdisk  
114.endif  
115.ifdef INSTALLED_2NDBOOTLOADER_TARGET  
116.    $(hide) $(ACP) \  
117.        $(INSTALLED_2NDBOOTLOADER_TARGET) $(zip_root)/BOOT/second  
118.endif  
119.ifdef BOARD_KERNEL_CMDLINE  
120.    $(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/BOOT/cmdline  
121.endif  
122.ifdef BOARD_KERNEL_BASE  
123.    $(hide) echo "$(BOARD_KERNEL_BASE)" > $(zip_root)/BOOT/base  
124.endif  
125.ifdef BOARD_KERNEL_PAGESIZE  
126.    $(hide) echo "$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/BOOT/pagesize  
127.endif  
128.#wschen  
129.ifneq "" "$(CUSTOM_BUILD_VERNO)"  
130.    $(hide) echo "$(CUSTOM_BUILD_VERNO)" > $(zip_root)/BOOT/board  
131.endif  
132.  
133.#[eton begin]: added by LiuDekuan for u-boot update  
134.    $(hide) $(ACP) $(PRODUCT_OUT)/uboot_eyang77_ics2.bin $(zip_root)/uboot.bin  
135.#[eton end]  
136.  
137.    $(hide) $(foreach t,$(INSTALLED_RADIOIMAGE_TARGET),\  
138.                mkdir -p $(zip_root)/RADIO; \  
139.                $(ACP) $(t) $(zip_root)/RADIO/$(notdir $(t));)  
140.    @# Contents of the system image  
141.    $(hide) $(call package_files-copy-root, \  
142.        $(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM)  
143.    @# Contents of the data image  
144.    $(hide) $(call package_files-copy-root, \  
145.        $(TARGET_OUT_DATA),$(zip_root)/DATA)  
146.    @# Extra contents of the OTA package  
147.    $(hide) mkdir -p $(zip_root)/OTA/bin  
148.    $(hide) $(ACP) $(INSTALLED_ANDROID_INFO_TXT_TARGET) $(zip_root)/OTA/  
149.    $(hide) $(ACP) $(PRIVATE_OTA_TOOLS) $(zip_root)/OTA/bin/  
150.    @# Security information of the OTA package  
151.    @echo "[SEC OTA] Adding Security information to OTA package"  
152.    @echo "[SEC OTA] path : mediatek/custom/$(MTK_PROJECT)/security/recovery/SEC_VER.txt"  
153.    $(hide) $(ACP) mediatek/custom/$(MTK_PROJECT)/security/recovery/SEC_VER.txt $(zip_root)/OTA/  
154.    @# Files that do not end up in any images, but are necessary to  
155.    @# build them.  
156.    $(hide) mkdir -p $(zip_root)/META  
157.    $(hide) $(ACP) $(APKCERTS_FILE) $(zip_root)/META/apkcerts.txt  
158.    $(hide) echo "$(PRODUCT_OTA_PUBLIC_KEYS)" > $(zip_root)/META/otakeys.txt  
159.    $(hide) echo "recovery_api_version=$(PRIVATE_RECOVERY_API_VERSION)" > $(zip_root)/META/misc_info.txt  
160.ifdef BOARD_FLASH_BLOCK_SIZE  
161.    $(hide) echo "blocksize=$(BOARD_FLASH_BLOCK_SIZE)" >> $(zip_root)/META/misc_info.txt  
162.endif  
163.ifdef BOARD_BOOTIMAGE_PARTITION_SIZE  
164.    $(hide) echo "boot_size=$(BOARD_BOOTIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt  
165.endif  
166.ifdef BOARD_RECOVERYIMAGE_PARTITION_SIZE  
167.    $(hide) echo "recovery_size=$(BOARD_RECOVERYIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt  
168.endif  
169.ifdef BOARD_SYSTEMIMAGE_PARTITION_SIZE  
170.    $(hide) echo "system_size=$(BOARD_SYSTEMIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt  
171.endif  
172.ifdef BOARD_SECROIMAGE_PARTITION_SIZE  
173.    $(hide) echo "secro_size=$(BOARD_SECROIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt  
174.endif  
175.ifdef BOARD_CACHEIMAGE_PARTITION_SIZE  
176.    $(hide) echo "cache_size=$(BOARD_CACHEIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt  
177.endif  
178.ifdef BOARD_USERDATAIMAGE_PARTITION_SIZE  
179.    $(hide) echo "userdata_size=$(BOARD_USERDATAIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt  
180.endif  
181.    $(hide) echo "tool_extensions=$(tool_extensions)" >> $(zip_root)/META/misc_info.txt  
182.ifdef mkyaffs2_extra_flags  
183.    $(hide) echo "mkyaffs2_extra_flags=$(mkyaffs2_extra_flags)" >> $(zip_root)/META/misc_info.txt  
184.endif  
185.ifdef INTERNAL_USERIMAGES_SPARSE_EXT_FLAG  
186.    $(hide) echo "extfs_sparse_flag=$(INTERNAL_USERIMAGES_SPARSE_EXT_FLAG)" >> $(zip_root)/META/misc_info.txt  
187.endif  
188.    $(hide) echo "default_system_dev_certificate=$(DEFAULT_KEY_CERT_PAIR)" >> $(zip_root)/META/misc_info.txt  
189.ifdef PRODUCT_EXTRA_RECOVERY_KEYS  
190.    $(hide) echo "extra_recovery_keys=$(PRODUCT_EXTRA_RECOVERY_KEYS)" >> $(zip_root)/META/misc_info.txt  
191.endif  
192.     @# Zip everything up, preserving symlinks  
193.    $(hide) (cd $(zip_root) && zip -qry ../$(notdir $@) .)  
194.    @# Run fs_config on all the system, boot ramdisk, and recovery ramdisk files in the zip, and save the output  
195.    $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="SYSTEM/" } /^SYSTEM\// {print "system/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/filesystem_config.txt  
196.    $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/boot_filesystem_config.txt  
197.    $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="RECOVERY/RAMDISK/" } /^RECOVERY\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/recovery_filesystem_config.txt  
198.    $(hide) (cd $(zip_root) && zip -q ../$(notdir $@) META/*filesystem_config.txt)  
  
199.target-files-package: $(BUILT_TARGET_FILES_PACKAGE)  
  
200.ifneq ($(TARGET_PRODUCT),sdk)  
201.ifeq ($(filter generic%,$(TARGET_DEVICE)),)  
202.ifneq ($(TARGET_NO_KERNEL),true)  
203.ifneq ($(recovery_fstab),)

system.img文件的重新打包是通过$(BUILT_TARGE_FILES_PACKAGE)的依赖条件$(INSTALLED_SYSTEMIMAGE)目标文件的编译来完成的,而$(BUILT_TARGE_FILES_PACKAGE)所有的执行命令(代码第66行至最后)都只为完成一件事,生成差分资源包所对应的目录并将其打包为ZIP包。具体的操作包括:

创建$(zip_root)目录(代码第66~68行);

创建/$(zip_root)/RECOVERY目录并将COPY相关文件(代码69~86);

创建/$(zip_root)/FACTORY目录并将COPY相关文件(代码87~106);

创建/$(zip_root)/BOOT目录并将COPY相关文件(代码107~131);

创建其他目录并COPY文件(代码132~191);

将$(zip_root)目录压缩为资源差分包(代码192~198)等。

$(zip_root)即out/target/product/<product-name>/obj/PACKAGING/target_files_from_intermedias/<product-name>-target_files-<version-name>;

经过目标文件$(BUILT_TARGE_FILES_PACKAGE)的执行后,system.img已经被重新打包,且差分资源包也已经生成,剩下的工作就是将差分资源包(target-files zipfile)传递给ota_ from _target _files代码,由它来生成OTA整包。

我们可以看下差分资源包(target-files zipfile)中的文件结构,如下:


其中,OTA目录值得关注,因为在此目录下存在着一个至关重要的文件:OTA/bin/updater(后文会有详述)。生成的差分资源包被传递给./build/tools/releasetools/

第二阶段制作升级包。

 ./build/tools/releasetools目录下的文件如下:


这组文件是Google提供的用来制作升级包的代码工具,核心文件为:ota_from_target_files和img_from_target_files。其中,前者用来制作recovery模式下的升级包;后者则用来制作fastboot下的升级包(fastboot貌似是一种更底层的刷机操作,未过多研究,不再详述)。其他文件则是为此二者提供服务的,比如,common.py中包含有制作升级包所需操作的代码;edify_generator.py则用于生成recovery模式下升级的脚本文件:<升级包>.zip/ META-INF/com/google/android/updater-script。

文件ota_from_target_files是本文所关注的重点,其中定义了两个主要的方法:

WriteFullOTAPackage 、WriteIncrementalOTAPackage。

前者用于生成整包,后者用来生成差分包。接着上文,当Makefile调用ota_from_target_files,并将差分资源包传递进来时,会执行WriteFullOTAPackage。此方法完成的工作包括:(1)将system目录,boot.img等文件添加到整包中;(2)生成升级包中的脚本文件:<升级包>.zip/META-INF/com/google/android/updater-script;(3)将上文提到的可执行文件:OTA/bin/updater添加到升级包中:META-INF/com/google/android/updater-script。

WriteFullOTAPackage代码片段:

1.   script.FormatPartition("/system")  
2.     script. FormatPartition ("/system")  
3.     script.UnpackPackageDir("recovery", "/system")  
4.     script.UnpackPackageDir("system", "/system")  
5.     (symlinks, retouch_files) = CopySystemFiles(input_zip, output_zip)  
6.     script.MakeSymlinks(symlinks)  
7.     if OPTIONS.aslr_mode:  
8.       script.RetouchBinaries(retouch_files)  
9.     else:  
10.     script.UndoRetouchBinaries(retouch_files) 

其中的script为edify_generator对象,其FormatPartition、UnpackPackageDir等方法分别是向脚本文件update-script中写入格式化分区、解压包等指令。

edify_generator中的AddToZip方法:

1.  def AddToZip(self, input_zip, output_zip, input_path=None):  
2.      """Write the accumulated script to the output_zip file.  input_zip 
3.      is used as the source for the 'updater' binary needed to run 
4.      script.  If input_path is not None, it will be used as a local 
5.      path for the binary instead of input_zip."""  
6.    
7.      self.UnmountAll()  
8.        common.ZipWriteStr(output_zip, "META-INF/com/google/android/updater-script",  
9.                         "\n".join(self.script) + "\n")  
10.       if input_path is None:  
11.       data = input_zip.read("OTA/bin/updater")  
12.     else:  
13.       data = open(os.path.join(input_path, "updater")).read()  
14.     common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary",  
15.                        data, perms=0755) 

WriteFullOTAPackage执行的最后会调用此方法。将资源差分包中OTA/bin/updater文件copy到升级包中META-INF/com/google/android/update-binary。此文件是OTA升级的关键,其将在recovery模式下被执行,用来将代码段2中生成的指令转换为相应的函数去执行,从而完成对系统数据的重写。

(2) 差分包制作与说明

生成差分包调用的是文件./build/tools/releasetools/ota_from_target_files中的WriteIncrementalOTA方法,调用时需要将两个版本的差分资源包作为参数传进来,形如:

./build/tools/releasetools/ota_from_target_files –n –i ota_v1.zip ota_v2.zip update.zip

其中,参数n表示忽略时间戳;i表示生成增量包(即差分包);ota_v1.zip与ota_v2.zip分别代表前后两个版本的差分资源包;而update.zip则表示最终生成的差分包。

WriteIncrementalOTA函数会计算输入的两个差分资源包中版本的差异,并将其写入到差分包中;同时,将updater及生成脚本文件udpate-script添加到升级包中。

4. 将升级包写入系统存储区

制作完升级包后,之后便是将其写入到相应存储区中,这部分工作是在recovery模式下完成的。之前的几篇笔记亦有描述,recovery模式下通过创建一个新的进程读取并执行脚本文件META-INF/com/google/android/updater-script。见如下代码:

1.   const char** args = (const char**)malloc(sizeof(char*) * 5);  
2.   args[0] = binary;  
3.   args[1] = EXPAND(RECOVERY_API_VERSION);   // defined in Android.mk  
4.   char* temp = (char*)malloc(10);  
5.   sprintf(temp, "%d", pipefd[1]);  
6.   args[2] = temp;  
7.   args[3] = (char*)path;  
8.   args[4] = NULL;  
9.     
10.  pid_t pid = fork();  
11.  if (pid == 0) {  
12.      close(pipefd[0]);  
13.      execv(binary, (char* const*)args);  
14.      _exit(-1);  
15.  }  
16.  close(pipefd[1]); 
分析代码之前,首先介绍linux中函数fork与execv的用法。
pid_t fork( void)
        创建新的进程,fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
  1)在父进程中,fork返回新创建子进程的进程ID;
  2)在子进程中,fork返回0;
  3)如果出现错误,fork返回一个负值;
        在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程(http://os.chinaunix.net/a2012/0203/1306/000001306508.shtml)。

int execv(const char *progname, char *const argv[])
        execv会停止执行当前的进程,并且以progname应用进程替换被停止执行的进程,进程ID没有改变。
        progname: 被执行的应用程序。

        argv: 传递给应用程序的参数列表, 注意,这个数组的第一个参数应该是应用程序名字本身,并且最后一个参数应该为NULL,不参将多个参数合并为一个参数放入数组。

代码于bootable/recovery/install.c的try_update_binary函数中,是OTA升级的核心代码之一。通过对fork及execv函数的介绍可知,创建了一个新的进程并在新进程中运行升级包中的META-INF/com/google/android/updater-binary文件(参数binary已在此前赋值),此文件将按照META-INF/com/google/android/updater-script中的指令将升级包里的数据写入到存储区中。OK,我们来看下META-INF/com/google/android/updater-binary文件的来历。

在源代码的./bootable/recovery/updater目录下,存在着如下几个文件:


通过查看Android.mk代码可知,文件install.c、updater.c将会被编译为可执行文件updater存放到目录out/target/product/<product-name>/obj/EXECUTABLES/

updater_intermediates/中;而在生成差分资源包(target-files zipfile)时,会将此文件添加到压缩包中。

Makefile中定义的变量built_ota_tools:

1.   built_ota_tools := \  
2.       $(call intermediates-dir-for,EXECUTABLES,applypatch)/applypatch \  
3.       $(call intermediates-dir-for,EXECUTABLES,applypatch_static)/applypatch_static \  
4.       $(call intermediates-dir-for,EXECUTABLES,check_prereq)/check_prereq \  
5.       $(call intermediates-dir-for,EXECUTABLES,sqlite3)/sqlite3 \  
6.        $(call intermediates-dir-for,EXECUTABLES,updater)/updater 

复制built_ota_tools工具到差分资源包:

7.        $(hide) mkdir -p $(zip_root)/OTA/bin  
8.       $(hide) $(ACP) $(INSTALLED_ANDROID_INFO_TXT_TARGET) $(zip_root)/OTA/  
9.       $(hide) $(ACP) $(PRIVATE_OTA_TOOLS) $(zip_root)/OTA/bin/ 
如代码段5,Makefile中定义了执行OTA所需要的一组工具(built_ota_tools),其中便包括由图4中文件编译而成的文件updater;而在生成差分资源包时,会将这组工具拷贝到差分资源包的OTA/bin目录中(见代码段6);在生成升级包时(无论是执行WriteFullOTAPackage还是WriteIncrementalOTAPackage),最后都会调用edify_generator的AddToZip方法,将updater添加到升级包中(更名为"META-INF/com/google/android/update-binary");最终在recovery模式下被执行,这便是其来龙去脉。而关于updater的执行,也大致的描述下吧。

由前文可知,updater主要由bootable/recovery/updater目录下的install.c和updater.c编译而成,主函数位于updater.c。其中,在install.c中定义了读写系统存储区的操作函数(这才是重写系统数据的真正代码)并将这些函数与updater-script中的指令映射起来。而在updater.c会首先装载install.c定义的函数,之后便解析升级脚本updater-script,执行其对应的操作命令。与此同时,执行updater的进程还会与父进程通信,通知父进程进行UI的相关操作(代码见bootable/recovery/install.c中的try_update_binary函数)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值