Android OTA升级,顾名思义是指over-the-air升级方式。通过在线下载安装包的形式,对整个系统进行升级。
在说FOTA之前,先看看Android的系统分区。具体参考官方网页
Android分区
boot 包括Linux系统内核和最小的系统文件。它负责安装系统和其他分区。
recovery 用于系统升级的分区,里面有一个单独的Linux系统。它通过读取一个新的软件包,来逐步更新其他分区,最终达到系统更新的目的。
system 包含在Android开源项目(AOSP)上提供源代码的系统应用程序和库。 在正常操作中,此分区挂载为只读; 其内容仅在OTA更新期间更改。
userdata 存储由用户安装的应用程序保存的数据等。OTA更新过程通常不会触及该分区
cache 应用使用的临时储存区域,访问该区域需要特殊权限。同时要用于储存下载的FOTA包。其他程序使用这个空间,期望文件可以随时消失。某些OTA软件包安装可能会导致此分区被完全擦除。
FOTA升级流程
手机会定期检测是否有更新(也可手动检测),并通知用户有新版本可用。
将安装包下载到cache分区,若cache分区不够,下载到data分区(这时候要注意是否有写入和删除权限),并根据system/etc/security/otacerts.zip的证书验证其加密签名。系统提示用户安装更新。
系统重启到recovery模式,运行的是recovery分区中的系统内核。而不是boot中的系统。
init进程通过执行init.rc 脚本:service recovery /sbin/recovery 启动recovery程序
recovery首先校验下载的安装包是否与res/keys(ramdisk)中的公匙相匹配。
recovery根据脚本解析安装包,然后将修改分别更新到对应的分区中,在system 分区中包含了用于更新recovery分区的内容。
系统正常启动:启动更新后的boot,system分区。启动时检测是否对recovery分区有更新,若有差异,则更新到recovery分区(这里也是为什么修改了recovery的代码后,需要更新完,且在下个更新中才能得到验证)
设备通知服务器更新完成。
OTA包制作
在 build/tools/releasetools 中,ota_from_target_files脚本制作OTA安装包。它既可以制作全包,也可制作差分包。所谓完整版安装包,就是包中已经包含了当前要更新到的系统所有文件,只要设备下载了安装包,并启动recovery模式,该包就可以完成更新,而不管系统当前的状态是什么样的。
要制作OTA包,需要先编译target包。编译target包的指令如下:
. build/envsetup.sh && lunch full_E266L-user //编译E266L
make -j4 otapackage //编译target包,并将包放入新建的dist_output中
这其中,make otapackage 分为两个部分,一个是编译target包,一部分是编译FULL_OTA包。编译target包,是在build/core/Makefile中执行的。具体代码如下:
# -----------------------------------------------------------------
# A zip of the directories that map to the target filesystem.
# This zip can be used to create an OTA package or filesystem image
# as a post-build step.
#
name := $(TARGET_PRODUCT)
ifeq ($(TARGET_BUILD_TYPE),debug)
name := $(name)_debug
endif
name := $(name)-target_files-$(FILE_NAME_TAG)
intermediates := $(call intermediates-dir-for,PACKAGING,target_files)
BUILT_TARGET_FILES_PACKAGE := $(intermediates)/$(name).zip
$(BUILT_TARGET_FILES_PACKAGE): intermediates := $(intermediates)
$(BUILT_TARGET_FILES_PACKAGE): \
zip_root := $(intermediates)/$(name)
# $(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
built_ota_tools :=
# We can't build static executables when SANITIZE_TARGET=address
ifeq ($(strip $(SANITIZE_TARGET)),)
built_ota_tools += \
$(call intermediates-dir-for,EXECUTABLES,updater,,,$(TARGET_PREFER_32_BIT))/updater
endif
$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_OTA_TOOLS := $(built_ota_tools)
$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_RECOVERY_API_VERSION := $(RECOVERY_API_VERSION)
$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_RECOVERY_FSTAB_VERSION := $(RECOVERY_FSTAB_VERSION)
ifeq ($(TARGET_RELEASETOOLS_EXTENSIONS),)
# default to common dir for device vendor
$(BUILT_TARGET_FILES_PACKAGE): tool_extensions := $(TARGET_DEVICE_DIR)/../common
else
$(BUILT_TARGET_FILES_PACKAGE): tool_extensions := $(TARGET_RELEASETOOLS_EXTENSIONS)
endif
# Build OTA tools if not using the AB Updater.
ifneq ($(AB_OTA_UPDATER),true)
$(BUILT_TARGET_FILES_PACKAGE): $(built_ota_tools)
endif
# If we are using recovery as boot, output recovery files to BOOT/.
ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_RECOVERY_OUT := BOOT
else
$(BUILT_TARGET_FILES_PACKAGE): PRIV