天天看點

Android OTA系統更新---原理三

最近公司的一個老的項目,現在客戶在專網方面遇到一點問題,進行版本更新時,由于客戶是公安,比較強硬,要求更新時不能擦除資料,這個可以簡單的通過改下打包腳本下參數就能解決。還是花了很長時間來跟蹤OTA打包的過程,對深入了解還是有很大幫助。

### 相關變量 

184 PRODUCT_OUT := $(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE)    

187   

188 HOST_OUT_EXECUTABLES:= $(HOST_OUT)/bin     ###  HOST_OUT=\out\host\linux-x86\bin

189 HOST_OUT_SHARED_LIBRARIES:= $(HOST_OUT)/lib  

190 HOST_OUT_JAVA_LIBRARIES:= $(HOST_OUT)/framework  

191 HOST_OUT_SDK_ADDON := $(HOST_OUT)/sdk_addon  

intermediates := $(call intermediates-dir-for,PACKAGING,target_files)

BUILT_TARGET_FILES := $(intermediates)/target.zip

BUILT_TARGET_FILES_PACKAGE := $(intermediates)/$(name).zip

$(BUILT_TARGET_FILES_PACKAGE): intermediates := $(intermediates)

$(BUILT_TARGET_FILES) $(BUILT_TARGET_FILES_PACKAGE): \

zip_root := $(intermediates)/$(name)

DEFAULT_SYSTEM_DEV_CERTIFICATE  ##--->>build/target/product/security/testkey

ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/testkey)

BUILD_KEYS := test-keys

else

BUILD_KEYS := release-keys

endif

# The dev key is used to sign this package, and as the key required

# for future OTA packages installed by this system.  Actual product

# deliverables will be re-signed by hand.  We expect this file to

# exist with the suffixes ".x509.pem" and ".pk8".

DEFAULT_KEY_CERT_PAIR := $(DEFAULT_SYSTEM_DEV_CERTIFICATE)

# -----------------------------------------------------------------

# Build a keystore with the authorized keys in it, used to verify the

# authenticity of downloaded OTA packages.

#

# This rule adds to ALL_DEFAULT_INSTALLED_MODULES, so it needs to come

# before the rules that use that variable to build the image.

ALL_DEFAULT_INSTALLED_MODULES += $(TARGET_OUT_ETC)/security/otacerts.zip

$(TARGET_OUT_ETC)/security/otacerts.zip: KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)

$(TARGET_OUT_ETC)/security/otacerts.zip: $(addsuffix .x509.pem,$(DEFAULT_KEY_CERT_PAIR))

$(hide) rm -f [email protected]

$(hide) mkdir -p $(dir [email protected])

$(hide) zip -qj [email protected] $<

.PHONY: otacerts

otacerts: $(TARGET_OUT_ETC)/security/otacerts.zip

# Keys authorized to sign OTA packages this build will accept.  The

# build always uses dev-keys for this; release packaging tools will

# substitute other keys for this one.

OTA_PUBLIC_KEYS := $(DEFAULT_SYSTEM_DEV_CERTIFICATE).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): extra_keys := $(patsubst %,%.x509.pem,$(PRODUCT_EXTRA_RECOVERY_KEYS))

$(RECOVERY_INSTALL_OTA_KEYS): $(OTA_PUBLIC_KEYS) $(DUMPKEY_JAR) $(extra_keys)

@echo "DumpPublicKey: [email protected] <= $(PRIVATE_OTA_PUBLIC_KEYS) $(extra_keys)"

@rm -rf [email protected]

@mkdir -p $(dir [email protected])

java -jar $(DUMPKEY_JAR) $(PRIVATE_OTA_PUBLIC_KEYS) $(extra_keys) > [email protected]

$(INSTALLED_RECOVERYIMAGE_TARGET): $(MKBOOTFS) $(MKBOOTIMG) $(MINIGZIP) $(RECOVERYIMAGE_EXTRA_DEPS) \

$(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)

編譯OTA需要的工具

# -----------------------------------------------------------------

# host tools needed to build dist and OTA packages

DISTTOOLS :=  $(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)/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)/make_ext4fs \

 $(HOST_OUT_EXECUTABLES)/simg2img \

 $(HOST_OUT_EXECUTABLES)/e2fsck

OTATOOLS := $(DISTTOOLS) \

 $(HOST_OUT_EXECUTABLES)/aapt

.PHONY: otatools

otatools: $(OTATOOLS)

//生成的OTA的路徑

# -----------------------------------------------------------------

# 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 := $(intermediates)/target.zip

BUILT_TARGET_FILES_PACKAGE := $(intermediates)/$(name).zip

$(BUILT_TARGET_FILES_PACKAGE): intermediates := $(intermediates)

$(BUILT_TARGET_FILES) $(BUILT_TARGET_FILES_PACKAGE): \

zip_root := $(intermediates)/$(name)

# Depending on the various images guarantees that the underlying

# directories are up-to-date.

$(BUILT_TARGET_FILES_PACKAGE): \

$(INSTALLED_BOOTIMAGE_TARGET) \

$(INSTALLED_RADIOIMAGE_TARGET) \

$(INSTALLED_RECOVERYIMAGE_TARGET) \

$(INSTALLED_SYSTEMIMAGE) \

$(INSTALLED_USERDATAIMAGE_TARGET) \

$(INSTALLED_CACHEIMAGE_TARGET) \

$(INSTALLED_VENDORIMAGE_TARGET) \

$(INSTALLED_ANDROID_INFO_TXT_TARGET) \

$(SELINUX_FC) \

$(built_ota_tools) \    ###

$(APKCERTS_FILE) \

$(HOST_OUT_EXECUTABLES)/fs_config \

$(HOST_OUT_EXECUTABLES)/checksparse.py \

$(HOST_OUT_EXECUTABLES)/rawprogram0.xml \

| $(ACP)

$(BUILT_TARGET_FILES) $(BUILT_TARGET_FILES_PACKAGE):

ifeq ($(TARGET_USERIMAGES_USE_EXT4),true)

@echo "unsparse the sparse ext4 image"

$(hide) python $(HOST_OUT_EXECUTABLES)/checksparse.py -i $(HOST_OUT_EXECUTABLES)/rawprogram0.xml -o $(PRODUCT_OUT)/sparse_images/rawprogram0_unsparse.xml -s $(PRODUCT_OUT) -t $(PRODUCT_OUT)/sparse_images

endif

//OTA 的工具集

built_ota_tools := \

$(call intermediates-dir-for,EXECUTABLES,applypatch)/applypatch \

$(call intermediates-dir-for,EXECUTABLES,applypatch_static)/applypatch_static \

$(call intermediates-dir-for,EXECUTABLES,check_prereq)/check_prereq \

$(call intermediates-dir-for,EXECUTABLES,sqlite3)/sqlite3 \

$(call intermediates-dir-for,EXECUTABLES,updater)/updater

ifneq ($(TARGET_FOTA_UPDATE_LIB),)

built_ota_tools += $(call intermediates-dir-for,EXECUTABLES,ipth_dua)/ipth_dua

endif

//OTA 打包名稱

INTERNAL_OTA_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip

//預設的簽名  , build/target/product/security/testkey  或是 release-keys

$(INTERNAL_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)

執行到這裡才開始真正打包,可以看出是通過./build/tools/releasetools/ota_from_target_files的工具腳本進行打包的:

$(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(DISTTOOLS)

@echo "Package OTA: [email protected]"

$(hide) ./build/tools/releasetools/ota_from_target_files -n -v -w \

  -p $(HOST_OUT) \

           -d $(device_type) \

           -k $(KEY_CERT_PAIR) \

           -f $(fota) \

           $(BUILT_TARGET_FILES_PACKAGE) [email protected]

.PHONY: otapackage

otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)。

   ota_from_target_files腳本的作用是以第一步生成的zip原始包作為輸入,最終生成可用的OTA更新zip包。 

用法---Usage: ota_from_target_files [flags] input_target_files output_ota_package 

                        -b 過時的。 

                        -k簽名所使用的密鑰 

                        -i生成增量OTA包時使用此選項。後面我們會用到這個選項來生成OTA增量包。 

                        -w是否清除userdata分區 

                        -n在更新時是否不檢查時間戳,預設要檢查,即預設情況下隻能基于舊版本更新。 

                        -e是否有額外運作的腳本 

                        -m執行過程中生成腳本(updater-script)所需要的格式,目前有兩種即amend和edify。對應上兩種版本更新時會采用不同的解釋器。預設會同時生成兩種格式 

        的腳 本。 

                        -p定義腳本用到的一些可執行檔案的路徑。 

                        -s定義額外運作腳本的路徑。 

                        -x定義額外運作的腳本可能用的鍵值對。 

                        -v執行過程中列印出執行的指令。 

                        -h指令幫助 

其中-w參數可配置更新時是否擦除使用者已經使用的資料,如安裝的app,内置存儲的檔案等等。大多數廠商都加有這個參數,安裝時擦除資料即wipe data.

文檔說明如下:

Usage:  ota_from_target_files [flags] input_target_files output_ota_package

  -b  (--board_config)  <file>

      Deprecated.

  -k (--package_key) <key> Key to use to sign the package (default is

      the value of default_system_dev_certificate from the input

      target-files's META/misc_info.txt, or

      "build/target/product/security/testkey" if that value is not

      specified).

      For incremental OTAs, the default value is based on the source

      target-file, not the target build.

  -i  (--incremental_from)  <file>

      Generate an incremental OTA using the given target-files zip as

      the starting build.

  -w  (--wipe_user_data)

      Generate an OTA package that will wipe the user data partition

      when installed.

  -n  (--no_prereq)

      Omit the timestamp prereq check normally included at the top of

      the build scripts (used for developer OTA packages which

      legitimately need to go back and forth).

  -e  (--extra_script)  <file>

      Insert the contents of file at the end of the update script.

  -a  (--aslr_mode)  <on|off>

      Specify whether to turn on ASLR for the package (on by default).

  -d  (--device_type) <type>

      Specify MMC or MTD type device. MTD by default

  -f  (--fota) <fota>

      Specify if fota upgrade is used or not. not used by default

"""

進入ota_from_target_files:

進入腳本函數後:

    main(sys.argv[1:])

打完整包    WriteFullOTAPackage(input_zip, output_zip, OPTIONS.fota):

f OPTIONS.incremental_source is None:

    WriteFullOTAPackage(input_zip, output_zip, OPTIONS.fota)

    if OPTIONS.package_key is None:

簽名包資訊配置,會對簽名的輸入檔案進行簽名資訊校驗

      OPTIONS.package_key = OPTIONS.info_dict.get(

          "default_system_dev_certificate",

          "build/target/product/security/testkey")

  else:

打增量包:

    print "unzipping source target-files..."

    OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)

    OPTIONS.target_info_dict = OPTIONS.info_dict

    OPTIONS.source_info_dict = common.LoadInfoDict(source_zip, OPTIONS.device_type)

    if OPTIONS.package_key is None:

      OPTIONS.package_key = OPTIONS.source_info_dict.get(

          "default_system_dev_certificate",

          "build/target/product/security/testkey")

 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip, OPTIONS.fota)

打包中都有進度提示,如

script.ShowProgress(0.5, 0)

如果OPTIONS.wipe_user_data為true,則擦除資料:

  if OPTIONS.wipe_user_data:

    script.FormatPartition("/data")

  if "selinux_fc" in OPTIONS.info_dict:

    WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)

  script.FormatPartition("/system")

  script.Mount("/system")

  script.UnpackPackageDir("recovery", "/system")

  script.UnpackPackageDir("system", "/system")