现在的位置: 首页 > 移动开发 > 正文

Android下编译OTA升级包

2019年09月04日 移动开发 ⁄ 共 10720字 ⁄ 字号 评论关闭

1)概念介绍    

     我们知道Android系统一般可以通过本地升级和空中升级两种,一般本地升级包括SD卡升级、U盘升级、串口升级等。而所谓的空中升级就是通过网络将升级包下载升级包到本地,进行升级。

      而OTA升级作为Android系统提供的标准软件升级方式,同时支持本地升级如SD卡或U盘 和 空中升级如网络。OTA升级一般分为全包升级和差分升级。

    全包升级:编译当前系统得到的软件包,不依赖于当前手机里的软件版本

    差分升级:对手机两个软件版本做差分,在第一个版本上打patch得到第二个升级包,所以差分升级只能对第一个版本的机器进行升级

 

2)编译方法

       在源码根目录下执行: make otapackage

       注意:执行这句命令之前需要在根目录下make编译整个源码。

       在out/target/product/$(PRODUCT_NAME)/$(BUILD_NAME)-target-files-$(BUILD_NUMBER).zip文件,其中$(PRODUCT_NAME)是编译产品名字,$(BUILD_NAME)是编译的版本名字,$(BUILD_NUMBER)一般是编译的版本号。以我的fsl的Qiyi版本为例。

    生成文件目录为:out/target/product/sabresd_6dq/Qiyi-target-files-20130725.zip文件

    拷贝到U盘下的upgrade目录下即可(有的是直接拷贝到U盘根目录下,各个代码不一样)。

3)编译过程

    我们主要分析build/core/Makefile,以我飞思卡尔Android sabresd_6dq 奇异版本为例。

# -----------------------------------------------------------------
# OTA update package

name := $(TARGET_PRODUCT)
ifeq ($(TARGET_BUILD_TYPE),debug)
  name := $(name)_debug
endif
name := $(name)-ota-$(FILE_NAME_TAG)
#$(FILE_NAME_TAG)就是$(BUILD_NUMBER)编译版本号,一般为build/core/build_id.mk文件中设置
name := $(BUILD_NAME)-target-files-$(BUILD_NUMBER)
#$(BUILD_NAME)就是编译名字,我的为Qiyi,所以最后升级包名字为:Qiyi-target-files-20130725.zip
INTERNAL_OTA_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip

# 编译升级包依赖于 $(KEY_CERT_PAIR)文件,我这里build/target/product/security/testkey文件
$(INTERNAL_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)

# 编译升级包依赖于$(BUILT_TARGET_FILES_PACKAGE) 和 $(OTATOOLS)
# 这是编译核心,通过一个python脚本ota_from_target_files 将前面生成的zip包打成ota升级包文件
$(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) \
		   -n \
           $(BUILT_TARGET_FILES_PACKAGE) $@

#-n 去掉时间戳标志,去掉该参数则不能回退版本
# 整个这句命令就是:./build/tools/releasetools/ota_from_target_files -v \
#		-p out/host/linux-x86 \
#		-k build/target/product/security/testkey \
#		-n \
#		out/target/product/sabresd_6dq/obj/PACKAGE/target-files_intermediates/Qiyi-target-files-20130725.zip \
#		out/target/product/sabresd_6dq/Qiyi-target-files-20130725.zip

# 伪目标,当执行make otapackage时执行
.PHONY: otapackage
otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)
 

下面我们看编译升级包的依赖文件:

# -----------------------------------------------------------------
# host tools needed to build OTA packages

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)

这个比较简单,就是编译升级包所需要的的工具。

 

$(BUILD_TARGET_FILES_PACKAGE)也就是:

     out/target/product/sabresd_6dq/obj/PACKAGE/target-files_intermediates/Qiyi-target-files-20130725.zip

 

name := $(TARGET_PRODUCT)
ifeq ($(TARGET_BUILD_TYPE),debug)
  name := $(name)_debug
endif
name := $(name)-target_files-$(FILE_NAME_TAG)
name := $(BUILD_NAME)-target-files-$(BUILD_NUMBER)

intermediates := $(call intermediates-dir-for,PACKAGING,target_files)
BUILT_TARGET_FILES_PACKAGE := $(intermediates)/$(name).zip
#intermediates 为out/target/product/sabresd_6dq/obj/PACKAGE/target-files_intermediates
$(BUILT_TARGET_FILES_PACKAGE): intermediates := $(intermediates)
# 依赖于文件out/target/product/sabresd_6dq/obj/PACKAGE/target-files_intermediates/Qiyi-target-files-20130725目录
$(BUILT_TARGET_FILES_PACKAGE): \
		zip_root := $(intermediates)/$(name)
	
# 下面定义一个宏用于拷贝文件	ls -A 不显示. 和 .. 文件
# $(1): Directory to copy
# $(2): Location to copy it to
# The "ls -A" is to prevent "acp s/* d" from failing if s is empty.
define package_files-copy-root
  if [ -d "$(strip $(1))" -a "$$(ls -A $(1))" ]; then \
    mkdir -p $(2) && \
    $(ACP) -rd $(strip $(1))/* $(2); \
  fi
endef

/**/
 #out/target/product/sabresd_6dq/obj/PACKAGING/target_files_intermediates/Qiyi-target-files-20130725.zip
$(BUILT_TARGET_FILES_PACKAGE): \
		$(INSTALLED_BOOTIMAGE_TARGET) \			#out/target/product/sabresd_6dq/boot.img
		$(INSTALLED_RADIOIMAGE_TARGET) \		#没有
		$(INSTALLED_RECOVERYIMAGE_TARGET) \		#out/target/product/sabresd_6dq/recovery.img
		$(INSTALLED_SYSTEMIMAGE) \				#out/target/product/sabresd_6dq/system.img
		$(INSTALLED_USERDATAIMAGE_TARGET) \		#out/target/product/sabresd_6dq/data.img
		$(INSTALLED_ANDROID_INFO_TXT_TARGET) \	#out/target/product/sabresd_6dq/anrdoid-info.txt
		$(built_ota_tools) \					#
		$(APKCERTS_FILE) \						#out/target/product/sabresd_6dq/obj/PACKAGING/apkcerts_intermediatessabresd_6dq-apkcerts-151001044.txt
		$(HOST_OUT_EXECUTABLES)/fs_config \		#out/host/linux-x86/bin/fs_config 
		| $(ACP)								# out/host/linux-x86/bin/acp
	@echo "Package target files: $@"
# 删除 目标文件 新建zip_root目录
	$(hide) rm -rf $@ $(zip_root)
	$(hide) mkdir -p $(dir $@) $(zip_root)
# RECOVERY 拷贝/out/target/product/sabresd_6dq/recovery/root下文件到zip_root/RECOVERY/RAMDISK
	@# 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)
# LOADER 拷贝/out/target/product/sabresd_6dq/u-boot-mx6*.bin下文件到zip_root/LOADER
ifeq ($(INSTALLED_LOADER_TARGET),true)
	$(hide) mkdir -p $(zip_root)/LOADER
	$(hide) cp  $(PRODUCT_OUT)/u-boot-mx6*.bin $(zip_root)/LOADER/
endif
# LOGO 拷贝/out/target/product/sabresd_6dq/logo.imx下文件到zip_root/LOGO/logo.imx
ifeq ($(INSTALLED_LOGO_TARGET),true)
	$(hide) mkdir -p $(zip_root)/LOGO
	$(hide) $(ACP) -f $(PRODUCT_OUT)/logo.img  $(zip_root)/LOGO/logo.img 
	$(hide) $(ACP) -f $(PRODUCT_OUT)/logoext.img  $(zip_root)/LOGO/logoext.img
endif
# RECOVERY 拷贝/out/target/product/sabresd_6dq/下文件到zip_root/RECOVERY/kernel
ifdef INSTALLED_KERNEL_RECOVERY_TARGET
	$(hide) $(ACP) $(INSTALLED_KERNEL_RECOVERY_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
# BOOT 拷贝/out/target/product/sabresd_6dq/root下文件到zip_root/BOOT/RAMDISK
	@# 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, \
# SYSTEM 拷贝out/target/product/sabresd_6dq/system 到zip_root/SYSTEM
		$(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM)
	@# Contents of the data image
# DATA 拷贝out/target/product/sabresd_6dq/data 到 zip_root/DATA
	$(hide) $(call package_files-copy-root, \
		$(TARGET_OUT_DATA),$(zip_root)/DATA)
	@# Extra contents of the OTA package
# android_info.txt 到 zip_root/OTA
	$(hide) mkdir -p $(zip_root)/OTA/bin
	$(hide) $(ACP) $(INSTALLED_ANDROID_INFO_TXT_TARGET) $(zip_root)/OTA/
# PRIVATE_OTA_TOOLS applypatch、applypatch_static、check_prereq、updater
	$(hide) $(ACP) $(PRIVATE_OTA_TOOLS) $(zip_root)/OTA/bin/
	@# Files that do not end up in any images, but are necessary to
	@# build them.
# zip_root/META 目录
	$(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
ifdef INTERNAL_USERIMAGES_SPARSE_EXT_FLAG
	$(hide) echo "extfs_sparse_flag=$(INTERNAL_USERIMAGES_SPARSE_EXT_FLAG)" >> $(zip_root)/META/misc_info.txt
endif
	$(hide) echo "default_system_dev_certificate=$(DEFAULT_SYSTEM_DEV_CERTIFICATE)" >> $(zip_root)/META/misc_info.txt
ifdef PRODUCT_EXTRA_RECOVERY_KEYS
	$(hide) echo "extra_recovery_keys=$(PRODUCT_EXTRA_RECOVERY_KEYS)" >> $(zip_root)/META/misc_info.txt
endif
# 进入zip_root目录,将zip_root目录下所有内容打包生成目标文件
	@# Zip everything up, preserving symlinks
	$(hide) (cd $(zip_root) && zip -qry ../$(notdir $@) .)
# 用HOST_OUT_EXECUTABLES/fs_config 获取文件系统信息保存到文件中去
	@# Run fs_config on all the system, boot ramdisk, and recovery ramdisk files in the zip, and save the output
	$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="SYSTEM/" } /^SYSTEM\// {print "system/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/filesystem_config.txt
	$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/boot_filesystem_config.txt
	$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="RECOVERY/RAMDISK/" } /^RECOVERY\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/recovery_filesystem_config.txt
# 将zip_root/META目录下生成的文件系统信息打包到 目标文件zip包中去
	$(hide) (cd $(zip_root) && zip -q ../$(notdir $@) META/ *filesystem_config.txt)

target-files-package: $(BUILT_TARGET_FILES_PACKAGE)

4)ota_from_target_file

     这是个python脚本文件,位于build/tools/releasetools/ota_from_target_files目录下。 

      1)从参数表和环境变量中解析options

      2)从zip包里的META/misc_info.txt中解析出key=value对

      3)从options对里找到tool_extensions 赋给OPTIONS.device_specific

      4)对于全包升级,调用WriteFullOTAPackage(input_zip, output_zip)

      5)签名临时包,生成最终签过名的全包升级包

 

5)生成全包过程介绍

   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文件,增加链接的语句

   8)从input_zip包的META/filesystem_config.txt中获取其中描述的/system下各个文件权限信息

   9)script增加语句,设置/system下文件权限和属主信息

  10)调用device特定函数FullOTA_InstallEnd

  11)调用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/updater-binary

         把metadata内容写入到output_zip里的META-INF/com/android/metadata

抱歉!评论已关闭.