- Recovery Binary: ()
Recovery Binary 是 Android 进入 Recovery 模式所运行的程序,实现了 Recovery 模式下的功能。它由目录 bootable/recovery 下的源代码编译生成。头文件 bootable/recovery/recovery_ui.h 定义了 Recovery UI 的接口,bootable/recovery/default_recovery_ui.c 是其默认实现,每个设备可以有自己不同的实现,然后通过变量 TARGET_RECOVERY_UI_LIB 来指定,否则使用默认实现。
- Recovery Image:
Recovery Image 的生成规则在文件 build/core/Makefile 中定义,具体分析如下:
# If neither TARGET_NO_KERNEL nor TARGET_NO_RECOVERY are true
ifeq (,$(filter true, $(TARGET_NO_KERNEL) $(TARGET_NO_RECOVERY) $(BUILD_TINY_ANDROID)))INSTALLED_RECOVERYIMAGE_TARGET := $(PRODUCT_OUT)/recovery.img
recovery_initrc := $(call include-path-for, recovery)/etc/init.rc
recovery_kernel := $(INSTALLED_KERNEL_TARGET) # same as a non-recovery system recovery_ramdisk := $(PRODUCT_OUT)/ramdisk-recovery.img recovery_build_prop := $(INSTALLED_BUILD_PROP_TARGET) recovery_binary := $(call intermediates-dir-for,EXECUTABLES,recovery)/recovery recovery_resources_common := $(call include-path-for, recovery)/res recovery_resources_private := $(strip $(wildcard$(TARGET_DEVICE_DIR)/recovery/res)) recovery_resource_deps := $(shell find $(recovery_resources_common) \$(recovery_resources_private) -type f) recovery_fstab := $(strip $(wildcard $(TARGET_DEVICE_DIR)/recovery.fstab)) recovery_mmc_fstab := $(strip $(wildcard$(TARGET_DEVICE_DIR)/recovery_mmc.fstab))ifeq ($(recovery_resources_private),)
$(info No private recovery resources for TARGET_DEVICE $(TARGET_DEVICE))endififeq ($(recovery_fstab),)
$(info No recovery.fstab for TARGET_DEVICE $(TARGET_DEVICE))endifINTERNAL_RECOVERYIMAGE_ARGS := \
$(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \ --kernel $(recovery_kernel) \ --ramdisk $(recovery_ramdisk)# Assumes this has already been stripped
ifdef BOARD_KERNEL_CMDLINE INTERNAL_RECOVERYIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE)"endififdef BOARD_KERNEL_BASE INTERNAL_RECOVERYIMAGE_ARGS += --base $(BOARD_KERNEL_BASE)endif BOARD_KERNEL_PAGESIZE := $(strip $(BOARD_KERNEL_PAGESIZE))ifdef BOARD_KERNEL_PAGESIZE INTERNAL_RECOVERYIMAGE_ARGS += --pagesize $(BOARD_KERNEL_PAGESIZE)endifINSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
kernel: $(INSTALLED_BOOTIMAGE_TARGET) .PHONY: kernel# Keys authorized to sign OTA packages this build will accept. The
# build always uses test-keys for this; release packaging tools will# substitute other keys for this one. OTA_PUBLIC_KEYS := $(SRC_TARGET_DIR)/product/security/testkey.x509.pem# Generate a file containing the keys that will be read by the
# recovery binary. RECOVERY_INSTALL_OTA_KEYS := \$(call intermediates-dir-for,PACKAGING,ota_keys)/keys DUMPKEY_JAR := $(HOST_OUT_JAVA_LIBRARIES)/dumpkey.jar$(RECOVERY_INSTALL_OTA_KEYS): PRIVATE_OTA_PUBLIC_KEYS := $(OTA_PUBLIC_KEYS)$(RECOVERY_INSTALL_OTA_KEYS): $(OTA_PUBLIC_KEYS) $(DUMPKEY_JAR) @echo "DumpPublicKey: $@ <= $(PRIVATE_OTA_PUBLIC_KEYS)" @rm -rf $@ -p $(dir $@) java -jar $(DUMPKEY_JAR) $(PRIVATE_OTA_PUBLIC_KEYS) > $@$(INSTALLED_RECOVERYIMAGE_TARGET): $(MKBOOTFS) $(MKBOOTIMG) $(MINIGZIP) \
$(INSTALLED_RAMDISK_TARGET) \$(INSTALLED_BOOTIMAGE_TARGET) \$(recovery_binary) \$(recovery_initrc) $(recovery_kernel) \$(INSTALLED_2NDBOOTLOADER_TARGET) \$(recovery_build_prop) $(recovery_resource_deps) \$(recovery_fstab) \$(RECOVERY_INSTALL_OTA_KEYS)/* 以正常系统的根文件系统为基础构建 Recovery 的根文件系统 */ ----- Making recovery image ------
rm -rf $(TARGET_RECOVERY_OUT) mkdir -p $(TARGET_RECOVERY_OUT) mkdir -p $(TARGET_RECOVERY_ROOT_OUT) mkdir -p $(TARGET_RECOVERY_ROOT_OUT)/etc mkdir -p $(TARGET_RECOVERY_ROOT_OUT)/tmpecho Copying baseline ramdisk... cp -R $(TARGET_ROOT_OUT) $(TARGET_RECOVERY_OUT)/* 删除所有的 Init 脚本,使用 Recovery 特定的 Init 脚本 */
rm $(TARGET_RECOVERY_ROOT_OUT)/init*.rcecho Modifying ramdisk contents... cp -f $(recovery_initrc) $(TARGET_RECOVERY_ROOT_OUT)//* 添加 Recovery Binary */
cp -f $(recovery_binary) $(TARGET_RECOVERY_ROOT_OUT)/sbin//* 添加通用的和设备特定的 Recovery 资源 */
cp -rf $(recovery_resources_common) $(TARGET_RECOVERY_ROOT_OUT)/$(foreach item,$(recovery_resources_private), \ cp -rf $(item) $(TARGET_RECOVERY_ROOT_OUT)/)/* 添加设备特定的文件系统表 */$(foreach item,$(recovery_fstab), \
cp -f $(item) $(TARGET_RECOVERY_ROOT_OUT)/etc/recovery.fstab)$(foreach item,$(recovery_mmc_fstab), \ cp -f $(item) $(TARGET_RECOVERY_ROOT_OUT)/etc/recovery_mmc.fstab)/* 内嵌验证签名的公钥 */
cp $(RECOVERY_INSTALL_OTA_KEYS) $(TARGET_RECOVERY_ROOT_OUT)/res/keys/* 生成 Recovery 模式的默认属性文件 */
cat $(INSTALLED_DEFAULT_PROP_TARGET) $(recovery_build_prop) \ > $(TARGET_RECOVERY_ROOT_OUT)/default.prop/* 生成 Recovery 的根文件系统 ramdisk-recovery.img */
$(MKBOOTFS) $(TARGET_RECOVERY_ROOT_OUT) | $(MINIGZIP) > $(recovery_ramdisk)/* 把正常系统的内核跟 ramdisk-recovery.img 打包生成 Recovery Image */
$(MKBOOTIMG) $(INTERNAL_RECOVERYIMAGE_ARGS) --output $@ ----- Made recovery image -------- $@/* 验证生成的 Recovery Image 有没有超出 Recovery 分区的大小 */
$(hide) $(call assert-max-image-size,$@,$(BOARD_RECOVERYIMAGE_PARTITION_SIZE),raw)else
INSTALLED_RECOVERYIMAGE_TARGET :=endif.PHONY: recoveryimage
recoveryimage: $(INSTALLED_RECOVERYIMAGE_TARGET)- Recovery Init Script:
从上面的分析可以看出 recovery.img 和 boot.img 的区别不大,主要是 init 脚本不一样,recovery 的 init 脚本相对简单,系统起来后只运行 ueventd、recovery、adbd 三个服务。
on init
export PATH /sbinexport ANDROID_ROOT /systemexport ANDROID_DATA /dataexport EXTERNAL_STORAGE /sdcardsymlink /system/etc /etc
mkdir /sdcard
mkdir /system mkdir /data mkdir /cache mount /tmp /tmp tmpfson boot
ifup lo hostname localhost domainname localdomainclass_start default
service ueventd /sbin/ueventd
criticalservice recovery /sbin/recovery
service adbd /sbin/adbd recovery
disabledon property:persist.service.adb.enable=1
start adbdon property:persist.service.adb.enable=0
stop adbd- Android <----> Recovery Binary <----> Bootloader:
有时候 Android 需要不同的模式互相协助来完成一项任务,这样不同模式之间就要有一种机制来交换信息。Recovery Binary 和 Bootloader 之间是通过 misc 分区来传递信息的,如果是 MTD 设备,则使用 misc 分区的第二个页面,如果是块设备,则使用 misc 分区的第一块,交换的信息通过如下结构体封装。Recovery Binary 和 Android 之间是通过 cache 分区下的如下几个固定文件来传递信息的。
/* Recovery Binary <----> Android */
/cache/recovery/command/cache/recovery/intent/cache/recovery/log/cache/recovery/last_log- Updater Binary:
Updater Binary 是 OTA package 的安装程序,被打包到 OTA package 中一起发布。Updater Binary 的源代码位于目录 bootable/recovery/updater 中。每个设备都可以为 Updater Binary 添加自己特定的扩展,然后通过变量TARGET_RECOVERY_UPDATER_LIBS 和 TARGET_RECOVERY_UPDATER_EXTRA_LIBS 来指定。
# Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function
# named "Register_<libname>()". Here we emit a little C function that# gets #included by updater.c. It calls all those registration# functions.# Devices can also add libraries to TARGET_RECOVERY_UPDATER_EXTRA_LIBS.
# These libs are also linked in with updater, but we don't try to call# any sort of registration function for these. Use this variable for# any subsidiary static libraries required for your registered# extension libs.inc := $(call intermediates-dir-for,PACKAGING,updater_extensions)/register.inc
# During the first pass of reading the makefiles, we dump the list of
# extension libs to a temp file, then copy that to the ".list" file if# it is different than the existing .list (if any). The register.inc# file then uses the .list as a prerequisite, so it is only rebuilt# (and updater.o recompiled) when the list of extension libs changes.junk := $(shell mkdir -p $(dir $(inc));\
echo $(TARGET_RECOVERY_UPDATER_LIBS) > $(inc).temp;\ diff -q $(inc).temp $(inc).list || cp -f $(inc).temp $(inc).list)$(inc) : libs := $(TARGET_RECOVERY_UPDATER_LIBS)
$(inc) : $(inc).list$(hide) mkdir -p $(dir $@)$(hide) echo "" > $@$(hide) $(foreach lib,$(libs),echo "extern void Register_$(lib)(void);" >> $@)$(hide) echo "void RegisterDeviceExtensions() {" >> $@$(hide) $(foreach lib,$(libs),echo " Register_$(lib)();" >> $@)$(hide) echo "}" >> $@$(call intermediates-dir-for,EXECUTABLES,updater)/updater.o : $(inc)
LOCAL_C_INCLUDES += $(dir $(inc))