TShopping

 找回密碼
 註冊
搜索
查看: 2038|回復: 0

[教學] Android 的 Recovery 模式分析

[複製鏈接]
發表於 2014-9-21 00:20:29 | 顯示全部樓層 |閱讀模式
 
Push to Facebook
  • 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 來指定,否則使用默認實現。
# 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))





 

臉書網友討論
*滑块验证:
您需要登錄後才可以回帖 登錄 | 註冊 |

本版積分規則



Archiver|手機版|小黑屋|免責聲明|TShopping

GMT+8, 2024-4-19 06:52 , Processed in 0.113525 second(s), 23 queries .

本論壇言論純屬發表者個人意見,與 TShopping綜合論壇 立場無關 如有意見侵犯了您的權益 請寫信聯絡我們。

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回復 返回頂部 返回列表