zoukankan      html  css  js  c++  java
  • Android 的 Recovery 分析

      Recovery Binary 是 Android 进入 Recovery 模式所运行的程序,实现了 Recovery 模式下的功能。它由目录 bootable/recovery 下的源代码编译生成。头文件 bootable/recovery/recovery_ui.h 定义了 Recovery UI 的接口,bootable/recovery/default_recovery_ui.c 是其默认实现,每个设备可以有自己不同的实现,然后通过变量 TARGET_RECOVERY_UI_LIB 来指定,否则使用默认实现。

    # bootable/recovery/Android.mk

    ifeq ($(TARGET_RECOVERY_UI_LIB),)
    LOCAL_SRC_FILES +=default_recovery_ui.c
    else
    LOCAL_STATIC_LIBRARIES +=$(TARGET_RECOVERY_UI_LIB)
    endif
    • Recovery Image:

      Recovery Image 的生成规则在文件 build/core/Makefile 中定义,具体分析如下:

    # build/core/Makefile

    # -----------------------------------------------------------------
    # Recovery image

    # 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 resourcesfor TARGET_DEVICE$(TARGET_DEVICE))
    endif

    ifeq ($(recovery_fstab),)
    $(info No recovery.fstabfor TARGET_DEVICE $(TARGET_DEVICE))
    endif

    INTERNAL_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)"
    endif
    ifdef 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)
    endif

    INSTALLED_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 $@
    @mkdir -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 的根文件系统 */
    @echo ----- 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)/tmp
    echo Copying baseline ramdisk...
    cp -R $(TARGET_ROOT_OUT) $(TARGET_RECOVERY_OUT)

    /* 删除所有的 Init 脚本,使用 Recovery 特定的 Init 脚本 */
    rm $(TARGET_RECOVERY_ROOT_OUT)/init*.rc
    echo 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$@
    @echo ----- 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 三个服务。

    # bootable/recovery/etc/init.rc

    on early-init
    start ueventd

    on init
    export PATH /sbin
    export ANDROID_ROOT /system
    export ANDROID_DATA /data
    export EXTERNAL_STORAGE /sdcard

    symlink /system/etc /etc

    mkdir /sdcard
    mkdir /system
    mkdir /data
    mkdir /cache

    mount /tmp /tmp tmpfs

    on boot
    ifup lo
    hostname localhost
    domainname localdomain

    class_start default

    service ueventd /sbin/ueventd
    critical

    service recovery /sbin/recovery

    service adbd /sbin/adbd recovery
    disabled

    on property:persist.service.adb.enable=1
    start adbd

    on 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 <----> Bootloader */

    struct bootloader_message {
    char command[32];
    char status[32];
    char recovery[1024];
    };

    /* 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 来指定。

    # bootable/recovery/updater/Android.mk

    LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) \
    $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
    LOCAL_STATIC_LIBRARIES +=libapplypatch libedify libmtdutils libminzip libz
    LOCAL_STATIC_LIBRARIES +=libmincrypt libbz
    LOCAL_STATIC_LIBRARIES +=libcutils libstdc++ libc
    LOCAL_C_INCLUDES +=$(LOCAL_PATH)/..

    # 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))

  • 相关阅读:
    遗传算法(Genetic Algorithm, GA)及MATLAB实现
    CCF CSP 201809-2 买菜
    PAT (Basic Level) Practice (中文)1008 数组元素循环右移问题 (20 分)
    PAT (Basic Level) Practice (中文)1006 换个格式输出整数 (15 分)
    PAT (Basic Level) Practice (中文)1004 成绩排名 (20 分)
    PAT (Basic Level) Practice (中文)1002 写出这个数 (20 分)
    PAT (Advanced Level) Practice 1001 A+B Format (20 分)
    BP神经网络(原理及MATLAB实现)
    问题 1676: 算法2-8~2-11:链表的基本操作
    问题 1744: 畅通工程 (并查集)
  • 原文地址:https://www.cnblogs.com/yuzaipiaofei/p/4124270.html
Copyright © 2011-2022 走看看