一、前言
recovery的最主要功能就是升級,而升級文件就是升級包了,那么升級包時如何編譯出來的呢?文就這個問題做個簡要的分析。
注:本文中的敘述純屬個人理解,歡迎批評指正。
二、升級包編譯命令
1.source build/envsetup.sh
2.lunch (選擇合適的配置)
3.make otapackage
注:有些平臺可能沒有將“recoveryimage”、“bootimage”等目標添加為“otapackage”目標的依賴,而otapackage目標必定會依賴“boot.img”和“recovery.img”這些文件,這時就需要先執(zhí)行編譯對應image文件的命令之后才能使“make otapackage”命令順利執(zhí)行,最終生成升級包。
三、從makefile分析升級包編譯流程
尋找otapackage目標(我以正在進行的一個項目為例)
首先我們在makefile中找到otapackage目標,然后順藤摸瓜來分析整個編譯的過程。下面我貼出相關的makefile代碼,代碼路徑:rootdir/build/core/Makefile
$(BUILT_TARGET_FILES_PACKAGE):? ????????$(INSTALLED_BOOTIMAGE_TARGET)????-------------------------------(1)? ????????$(INSTALLED_RADIOIMAGE_TARGET)? ????????$(INSTALLED_RECOVERYIMAGE_TARGET)? ????????$(INSTALLED_SYSTEMIMAGE)? ????????$(INSTALLED_USERDATAIMAGE_TARGET)? ????????$(INSTALLED_CACHEIMAGE_TARGET)? ????????$(INSTALLED_VENDORIMAGE_TARGET)? ????????$(INSTALLED_CUSTOMIMAGE_TARGET)???? ????????$(INSTALLED_ANDROID_INFO_TXT_TARGET)? ????????$(SELINUX_FC)? ????????$(built_ota_tools)? ????????$(APKCERTS_FILE)? ????????$(HOST_OUT_EXECUTABLES)/fs_config? ????????|?$(ACP)??????????????????????????????????????-----------------(2)? ????@echo?"Package?target?files:?$@" ????$(hide)?rm?-rf?$@?$(zip_root) ????$(hide)?mkdir?-p?$(dir?$@)?$(zip_root)??????????????????--------------(3)? ????@#?Components?of?the?recovery?image ????$(hide)?mkdir?-p?$(zip_root)/RECOVERY ????$(hide)?$(call?package_files-copy-root,?????????????????-------------(4)? ????????$(TARGET_RECOVERY_ROOT_OUT),$(zip_root)/RECOVERY/RAMDISK) ????$(hide)?mkdir?-p?$(zip_root)/OTHER ????$(hide)?$(ACP)? ????????$(INSTALLED_UBOOT_TARGET)?$(zip_root)/OTHER/bootloader?????---(5)? ????$(hide)?$(ACP)? ????????$(INSTALLED_DTB_TARGET)?$(zip_root)/OTHER/dtb ????$(hide)?$(ACP)? ????????$(INSTALLED_BOOTIMAGE_TARGET)?$(zip_root)/OTHER/boot.img ????$(hide)?$(ACP)? ????????$(INSTALLED_LDFW_TARGET)?$(zip_root)/OTHER/ldfw ????$(hide)?$(ACP)? ????????$(INSTALLED_RECOVERY_TARGET)?$(zip_root)/OTHER/recovery.img ifdef?BOARD_KERNEL_BASE ????$(hide)?echo?"$(BOARD_KERNEL_BASE)"?>?$(zip_root)/RECOVERY/base endif ifdef?BOARD_KERNEL_PAGESIZE ????$(hide)?echo?"$(BOARD_KERNEL_PAGESIZE)"?>?$(zip_root)/RECOVERY/pagesize endif ????@#?Components?of?the?boot?image ????$(hide)?mkdir?-p?$(zip_root)/BOOT ????$(hide)?$(call?package_files-copy-root,? ????????$(TARGET_ROOT_OUT),$(zip_root)/BOOT/RAMDISK) ifdef?INSTALLED_KERNEL_TARGET ????$(hide)?$(ACP)?$(INSTALLED_KERNEL_TARGET)?$(zip_root)/BOOT/kernel endif ifdef?INSTALLED_2NDBOOTLOADER_TARGET ????$(hide)?$(ACP)? ????????$(INSTALLED_2NDBOOTLOADER_TARGET)?$(zip_root)/BOOT/second endif ifdef?BOARD_KERNEL_CMDLINE ????$(hide)?echo?"$(BOARD_KERNEL_CMDLINE)"?>?$(zip_root)/BOOT/cmdline endif ifdef?BOARD_KERNEL_BASE ????$(hide)?echo?"$(BOARD_KERNEL_BASE)"?>?$(zip_root)/BOOT/base endif ifdef?BOARD_KERNEL_PAGESIZE ????$(hide)?echo?"$(BOARD_KERNEL_PAGESIZE)"?>?$(zip_root)/BOOT/pagesize endif ????$(hide)?$(foreach?t,$(INSTALLED_RADIOIMAGE_TARGET), ????????????????mkdir?-p?$(zip_root)/RADIO;? ????????????????$(ACP)?$(t)?$(zip_root)/RADIO/$(notdir?$(t));) ????@#?Contents?of?the?system?image ????$(hide)?$(call?package_files-copy-root,? ????????$(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM) ????@#?Contents?of?the?data?image ????$(hide)?$(call?package_files-copy-root,? ????????$(TARGET_OUT_DATA),$(zip_root)/DATA) ifdef?BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE ????@#?Contents?of?the?vendor?image ????$(hide)?$(call?package_files-copy-root,? ????????$(TARGET_OUT_VENDOR),$(zip_root)/VENDOR) endif ????@#?Extra?contents?of?the?OTA?package ????$(hide)?mkdir?-p?$(zip_root)/OTA/bin ????$(hide)?$(ACP)?$(INSTALLED_ANDROID_INFO_TXT_TARGET)?$(zip_root)/OTA/ ????$(hide)?$(ACP)?$(PRIVATE_OTA_TOOLS)?$(zip_root)/OTA/bin/ ????@#?Files?that?do?not?end?up?in?any?images,?but?are?necessary?to ????@#?build?them. ????$(hide)?mkdir?-p?$(zip_root)/META ????@#?imei.dat?information?of?the?OTA?package ????@echo?"[imei.dat]?Adding?imei.dat?to?OTA?package" ????@echo?"[imei.dat]?path?:?bootable/recovery/etc/META-INF/imei.dat" ????$(hide)?$(ACP)?bootable/recovery/etc/META-INF/imei.dat?$(zip_root)/META/ ????@#?machine_match?information?of?the?OTA?package ????@echo?"[machine_match]?Adding?machine_match?to?OTA?package" ????$(hide)?$(ACP)?$(machine_match_binary)?$(PRODUCT_OUT)/ ????$(hide)?$(ACP)?$(APKCERTS_FILE)?$(zip_root)/META/apkcerts.txt ????$(hide)?if?test?-e?$(tool_extensions)/releasetools.py;?then?$(ACP)?$(tool_extensions)/releasetools.py?$(zip_root)/META/;?fi ????$(hide)?echo?"$(PRODUCT_OTA_PUBLIC_KEYS)"?>?$(zip_root)/META/otakeys.txt ????$(hide)?echo?"recovery_api_version=$(PRIVATE_RECOVERY_API_VERSION)"?>?$(zip_root)/META/misc_info.txt????????-------------------------------------------------------------------------------------(6) ????$(hide)?echo?"fstab_version=$(PRIVATE_RECOVERY_FSTAB_VERSION)"?>>?$(zip_root)/META/misc_info.txt?? ????$(hide)?-$(ACP)?$(PRODUCT_OUT)/firmware_type?$(zip_root)/META/ ifdef?BOARD_FLASH_BLOCK_SIZE ????$(hide)?echo?"blocksize=$(BOARD_FLASH_BLOCK_SIZE)"?>>?$(zip_root)/META/misc_info.txt endif ifdef?BOARD_BOOTIMAGE_PARTITION_SIZE ????$(hide)?echo?"boot_size=$(BOARD_BOOTIMAGE_PARTITION_SIZE)"?>>?$(zip_root)/META/misc_info.txt? endif ifdef?BOARD_RECOVERYIMAGE_PARTITION_SIZE ????$(hide)?echo?"recovery_size=$(BOARD_RECOVERYIMAGE_PARTITION_SIZE)"?>>?$(zip_root)/META/misc_info.txt endif ifdef?BOARD_HAS_EXT4_RESERVED_BLOCKS ????$(hide)?echo?"has_ext4_reserved_blocks=$(BOARD_HAS_EXT4_RESERVED_BLOCKS)"?>>?$(zip_root)/META/misc_info.txt endif ifdef?TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS ????@#?TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS?can?be?empty?to?indicate?that?nothing?but?defaults?should?be?used. ????$(hide)?echo?"recovery_mount_options=$(TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS)"?>>?$(zip_root)/META/misc_info.txt else ????$(hide)?echo?"recovery_mount_options=$(DEFAULT_TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS)"?>>?$(zip_root)/META/misc_info.txt endif ????$(hide)?echo?"tool_extensions=$(tool_extensions)"?>>?$(zip_root)/META/misc_info.txt ????$(hide)?echo?"default_system_dev_certificate=$(DEFAULT_SYSTEM_DEV_CERTIFICATE)"?>>?$(zip_root)/META/misc_info.txt ifdef?PRODUCT_EXTRA_RECOVERY_KEYS ????$(hide)?echo?"extra_recovery_keys=$(PRODUCT_EXTRA_RECOVERY_KEYS)"?>>?$(zip_root)/META/misc_info.txt endif ????$(hide)?echo?'mkbootimg_args=$(BOARD_MKBOOTIMG_ARGS)'?>>?$(zip_root)/META/misc_info.txt ????$(hide)?echo?"use_set_metadata=1"?>>?$(zip_root)/META/misc_info.txt ????$(hide)?echo?"multistage_support=1"?>>?$(zip_root)/META/misc_info.txt ????$(hide)?echo?"update_rename_support=1"?>>?$(zip_root)/META/misc_info.txt ????$(hide)?echo?"blockimgdiff_versions=1,2,3"?>>?$(zip_root)/META/misc_info.txt ifneq?($(OEM_THUMBPRINT_PROPERTIES),) ????#?OTA?scripts?are?only?interested?in?fingerprint?related?properties ????$(hide)?echo?"oem_fingerprint_properties=$(OEM_THUMBPRINT_PROPERTIES)"?>>?$(zip_root)/META/misc_info.txt endif ????$(call?generate-userimage-prop-dictionary,?$(zip_root)/META/misc_info.txt) ????$(hide)?PATH=$(foreach?p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH?MKBOOTIMG=$(MKBOOTIMG)? ????./build/tools/releasetools/make_recovery_patch?$(zip_root)?$(zip_root) @#?Zip?everything?up,?preserving?symlinks $(hide)?(cd?$(zip_root)?&&?zip?-qry?../$(notdir?$@)?.) @#?Run?fs_config?on?all?the?system,?vendor,?boot?ramdisk, @#?and?recovery?ramdisk?files?in?the?zip,?and?save?the?output $(hide)?zipinfo?-1?$@?|?awk?'BEGIN?{?FS="SYSTEM/"?}?/^SYSTEM//?{print?"system/"?$$2}'?|?$(HOST_OUT_EXECUTABLES)/fs_config?-C?-D?$(TARGET_OUT)?-S?$(SELINUX_FC)?>?$(zip_root)/META/filesystem_config.txt??????????????????????????????????????????????????????????????????????---------(7) $(hide)?zipinfo?-1?$@?|?awk?'BEGIN?{?FS="VENDOR/"?}?/^VENDOR//?{print?"vendor/"?$$2}'?|?$(HOST_OUT_EXECUTABLES)/fs_config?-C?-D?$(TARGET_OUT)?-S?$(SELINUX_FC)?>?$(zip_root)/META/vendor_filesystem_config.txt $(hide)?zipinfo?-1?$@?|?awk?'BEGIN?{?FS="BOOT/RAMDISK/"?}?/^BOOT/RAMDISK//?{print?$$2}'?|?$(HOST_OUT_EXECUTABLES)/fs_config?-C?-D?$(TARGET_OUT)?-S?$(SELINUX_FC)?>?$(zip_root)/META/boot_filesystem_config.txt $(hide)?zipinfo?-1?$@?|?awk?'BEGIN?{?FS="RECOVERY/RAMDISK/"?}?/^RECOVERY/RAMDISK//?{print?$$2}'?|?$(HOST_OUT_EXECUTABLES)/fs_config?-C?-D?$(TARGET_OUT)?-S?$(SELINUX_FC)?>?$(zip_root)/META/recovery_filesystem_config.txt $(hide)?(cd?$(zip_root)?&&?zip?-q?../$(notdir?$@)?META/*filesystem_config.txt)????????????????????????????????????--------------------------------------------------------------------------(8) $(hide)?PATH=$(foreach?p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH?MKBOOTIMG=$(MKBOOTIMG)? ????????./build/tools/releasetools/add_img_to_target_files?-p?$(HOST_OUT)?$@????????????????????????????????????????--------------------------------------------------------------------------------(9) ????$(hide)?./build/tools/releasetools/replace_img_from_target_files.py?$@?$(PRODUCT_OUT)????????????-----------------------------------------------------------------------------------------------(10) .PHONY:?target-files-package target-files-package:?$(BUILT_TARGET_FILES_PACKAGE) ifneq?($(filter?$(MAKECMDGOALS),target-files-package),) $(call?dist-for-goals,?target-files-package,?$(BUILT_TARGET_FILES_PACKAGE)) endif ifneq?($(TARGET_PRODUCT),sdk) ifeq?($(filter?generic%,$(TARGET_DEVICE)),) ifneq?($(TARGET_NO_KERNEL),true) ifneq?($(recovery_fstab),) #?----------------------------------------------------------------- #?OTA?update?package name?:=?$(TARGET_PRODUCT) ifeq?($(TARGET_BUILD_TYPE),debug) ??name?:=?$(name)_debug endif name?:=?$(name)-ota-$(FILE_NAME_TAG) INTERNAL_OTA_PACKAGE_TARGET?:=?$(PRODUCT_OUT)/$(name).zip $(INTERNAL_OTA_PACKAGE_TARGET):?KEY_CERT_PAIR?:=?$(DEFAULT_KEY_CERT_PAIR) $(INTERNAL_OTA_PACKAGE_TARGET):?$(BUILT_TARGET_FILES_PACKAGE)?$(DISTTOOLS) ????@echo?"Package?OTA:?$@" ????$(hide)?PATH=$(foreach?p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH?MKBOOTIMG=$(MKBOOTIMG)? ???????./build/tools/releasetools/ota_from_target_files?-v???????------------------(11)??????? ???????--block? ???????-p?$(HOST_OUT)? ???????-k?$(KEY_CERT_PAIR)? ???????$(if?$(OEM_OTA_CONFIG),?-o?$(OEM_OTA_CONFIG))? ???????$(BUILT_TARGET_FILES_PACKAGE)?$@ .PHONY:?otapackage otapackage:?$(INTERNAL_OTA_PACKAGE_TARGET)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
下面來分析一下makefile代碼:
首先otapackage是一個偽目標,它有個INTERNAL_OTA_PACKAGE_TARGET的依賴,INTERNAL_OTA_PACKAGE_TARGET :=
$(PRODUCT_OUT)/$(name).zip,就是最終的那個升級包。我們繼續(xù)看下面:
$(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE)
$(DISTTOOLS)
$(INTERNAL_OTA_PACKAGE_TARGET)又有一些依賴,這里我只關心 $(BUILT_TARGET_FILES_PACKAGE) ,
$(BUILT_TARGET_FILES_PACKAGE) 目標在代碼片段的最開始定義,現(xiàn)在重點分析一下 $(BUILT_TARGET_FILES_PACKAGE) 目標。
我們可以通過閱讀makefile可以知道,$(BUILT_TARGET_FILES_PACKAGE) =out/target/product//obj/PACKAGING/target_files_intermediates/*target_files-.zip,target_files-.zip(后續(xù)我們簡稱為target_file.zip)中保存著生成升級包需要的文件。下面分析代碼
(1)一些依賴目標
(2)在依賴前加“|”的意思是”|”后面的依賴要比其他依賴優(yōu)先編譯
(3)生成目錄out/target/product//obj/PACKAGING/target_files_intermediates/*target_files-(后續(xù)我們簡稱為target_file),后面會把一些中間文件拷貝到這個目錄,最終打包成out/target/product/*/obj/PACKAGING/target_files_intermediates/target_files-.zip
(4)把生成recovery的中間文件也拷貝到target_file目錄,因為升級包中的recovery.img不是跟out/target/product/*/recovery.img相同的,在執(zhí)行ota_from_target_files 腳本的過程中會重新生成recovery.img。當然,現(xiàn)在的Android都是通過打patch(recovery.img基于boot.img的patch)的方式升級recovery的。
(5)拷貝一些文件到target_file的OTHER目錄,最終的升級包一般直接把這些文件拷貝過去就ok了。
(6)把一些編譯信息放在文件中,方便后面編譯升級包時使用,比如分區(qū)信息(編譯升級包時需要檢測升級文件的大小是否大于對應的分區(qū)大小,如果大于的話當然無法升級了,只能終止編譯)。
(7)先看下面命令的執(zhí)行結果
這是在提取分區(qū)中文件的信息,包括文件權限,selinux相關的信息,這些信息將會在制作文件系統(tǒng)的時候使用。
(8)打包target_file.zip
(9)生成img文件,并將它們拷貝到target_file/IMAGE目錄,后面可能會使用。
(10)調(diào)用replace_img_from_target_files.py腳本把target_file/IMAGE目錄下面的img文件拷貝到out/target/product/目錄。調(diào)用這個腳本的目的是使out/target/product/和升級包中的升級img文件保持一致,這跟Android的一個設計缺陷有關。下面就來了解一下
我們知道out/target/product//system.img文件是由out/target/product//system編譯來的,按理說升級包中的system分區(qū)的文件來源也應該是out/target/product//system,但實際上升級包中的system分區(qū)的文件來源是target_file/SYSTEM。如果說out/target/product//system與target_file/SYSTEM兩個目錄的文件內(nèi)容一樣那也沒什么問題,問題是這兩個目錄是不一樣的,因為在執(zhí)行ota_from_target_file腳本的時候會生成一個install_recovery.sh腳本(這個腳本就是在Android啟動的時候執(zhí)行,用來升級recovery的),然后把install_recovery.sh拷貝到target_file/SYSTEM,所以造成了最終out/target/product/*/system.img和升級包中的system(升級包中沒有system.img,recovery用一種新的方法來升級system)的差異,這會引發(fā)下面的問題:
(a)如果你是用fastboot燒錄system,那么你就會用到out/target/product/*/system.img,同時你升級recovery的方式是用install_recovery.sh來升級的,那你會發(fā)現(xiàn)你的recovery其實是沒法升級的,因為在你的系統(tǒng)中壓根就沒有install_recovery.sh這個文件。
(b)如果你說,沒關系,我是在recovery中直接把recovery.img寫到recovery中升級的,(a)問題對我沒影響。那你可能會發(fā)現(xiàn)你無法進行增量升級。因為增量升級包是通過比較兩個版本的target_file.zip生成的,現(xiàn)在你的板子里面的system和增量包的基準版本不一致。
(11)執(zhí)行 ./build/tools/releasetools/ota_from_target_files腳本,最終生成升級包。下面來分析一下 ./build/tools/releasetools/ota_from_target_files。
四、ota_from_target_files腳本分析
1.使用說明(常用)
-k:指定key的路徑,如build/target/product/security/testkey
-i:編譯增量升級包, ./build/tools/releasetools/ota_from_target_files -i
def?main(argv): ??def?option_handler(o,?a):??????????????????????????????----------------------------------(1) ????if?o?==?"--board_config": ??????pass???#?deprecated ????elif?o?in?("-k",?"--package_key"): ??????OPTIONS.package_key?=?a ????elif?o?in?("-i",?"--incremental_from"): ??????OPTIONS.incremental_source?=?a ????elif?o?==?"--full_radio": ??????OPTIONS.full_radio?=?True ????elif?o?==?"--full_bootloader": ??????OPTIONS.full_bootloader?=?True ????elif?o?in?("-w",?"--wipe_user_data"): ??????OPTIONS.wipe_user_data?=?True ????elif?o?in?("-n",?"--no_prereq"): ??????OPTIONS.omit_prereq?=?True ????elif?o?in?("-o",?"--oem_settings"): ??????OPTIONS.oem_source?=?a ????elif?o?in?("-e",?"--extra_script"): ??????OPTIONS.extra_script?=?a ????elif?o?in?("-a",?"--aslr_mode"): ??????if?a?in?("on",?"On",?"true",?"True",?"yes",?"Yes"): ????????OPTIONS.aslr_mode?=?True ??????else: ????????OPTIONS.aslr_mode?=?False ????elif?o?in?("-t",?"--worker_threads"): ??????if?a.isdigit(): ????????OPTIONS.worker_threads?=?int(a) ??????else: ????????raise?ValueError("Cannot?parse?value?%r?for?option?%r?-?only?" ?????????????????????????"integers?are?allowed."?%?(a,?o)) ????elif?o?in?("-2",?"--two_step"): ??????OPTIONS.two_step?=?True ????elif?o?==?"--no_signing": ??????OPTIONS.no_signing?=?True ????elif?o?==?"--verify": ??????OPTIONS.verify?=?True ????elif?o?==?"--block": ??????OPTIONS.block_based?=?True ????elif?o?in?("-b",?"--binary"): ??????OPTIONS.updater_binary?=?a ????elif?o?in?("--no_fallback_to_full",): ??????OPTIONS.fallback_to_full?=?False ????elif?o?==?"--stash_threshold": ??????try: ????????OPTIONS.stash_threshold?=?float(a) ??????except?ValueError: ????????raise?ValueError("Cannot?parse?value?%r?for?option?%r?-?expecting?" ?????????????????????????"a?float"?%?(a,?o)) ????else: ??????return?False ????return?True ??args?=?common.ParseOptions(argv,?__doc__,?????????------------------------------------(2) ?????????????????????????????extra_opts="b:k:i:d:wne:t:a:2o:", ?????????????????????????????extra_long_opts=[ ?????????????????????????????????"board_config=", ?????????????????????????????????"package_key=", ?????????????????????????????????"incremental_from=", ?????????????????????????????????"full_radio", ?????????????????????????????????"full_bootloader", ?????????????????????????????????"wipe_user_data", ?????????????????????????????????"no_prereq", ?????????????????????????????????"extra_script=", ?????????????????????????????????"worker_threads=", ?????????????????????????????????"aslr_mode=", ?????????????????????????????????"two_step", ?????????????????????????????????"no_signing", ?????????????????????????????????"block", ?????????????????????????????????"binary=", ?????????????????????????????????"oem_settings=", ?????????????????????????????????"verify", ?????????????????????????????????"no_fallback_to_full", ?????????????????????????????????"stash_threshold=", ?????????????????????????????],?extra_option_handler=option_handler) ??if?len(args)?!=?2: ????common.Usage(__doc__) ????sys.exit(1) ??if?OPTIONS.extra_script?is?not?None:???????????????????????????????--------------------(3) ????OPTIONS.extra_script?=?open(OPTIONS.extra_script).read() ??print?"unzipping?target?target-files..." ??OPTIONS.input_tmp,?input_zip?=?common.UnzipTemp(args[0])??????????---------------------(4) ??OPTIONS.target_tmp?=?OPTIONS.input_tmp ??OPTIONS.info_dict?=?common.LoadInfoDict(input_zip)???????????????----------------------(5) ??#?If?this?image?was?originally?labelled?with?SELinux?contexts,?make?sure?we ??#?also?apply?the?labels?in?our?new?image.?During?building,?the?"file_contexts" ??#?is?in?the?out/?directory?tree,?but?for?repacking?from?target-files.zip?it's ??#?in?the?root?directory?of?the?ramdisk. ??if?"selinux_fc"?in?OPTIONS.info_dict: ????OPTIONS.info_dict["selinux_fc"]?=?os.path.join( ????????OPTIONS.input_tmp,?"BOOT",?"RAMDISK",?"file_contexts") ??if?OPTIONS.verbose: ????print?"---?target?info?---" ????common.DumpInfoDict(OPTIONS.info_dict) ??#?If?the?caller?explicitly?specified?the?device-specific?extensions ??#?path?via?-s/--device_specific,?use?that.??Otherwise,?use ??#?META/releasetools.py?if?it?is?present?in?the?target?target_files. ??#?Otherwise,?take?the?path?of?the?file?from?'tool_extensions'?in?the ??#?info?dict?and?look?for?that?in?the?local?filesystem,?relative?to ??#?the?current?directory. ??if?OPTIONS.device_specific?is?None:???????????????-------------------------(6) ????from_input?=?os.path.join(OPTIONS.input_tmp,?"META",?"releasetools.py") ????if?os.path.exists(from_input): ??????print?"(using?device-specific?extensions?from?target_files)" ??????OPTIONS.device_specific?=?from_input ????else: ??????OPTIONS.device_specific?=?OPTIONS.info_dict.get("tool_extensions",?None) ??if?OPTIONS.device_specific?is?not?None: ????OPTIONS.device_specific?=?os.path.abspath(OPTIONS.device_specific) ??while?True: ????if?OPTIONS.no_signing:???????????????????????---------------------------(7) ??????if?os.path.exists(args[1]): ????????os.unlink(args[1]) ??????output_zip?=?zipfile.ZipFile(args[1],?"w", ???????????????????????????????????compression=zipfile.ZIP_DEFLATED) ????else: ??????temp_zip_file?=?tempfile.NamedTemporaryFile() ??????output_zip?=?zipfile.ZipFile(temp_zip_file,?"w", ???????????????????????????????????compression=zipfile.ZIP_DEFLATED) ????cache_size?=?OPTIONS.info_dict.get("cache_size",?None) ????if?cache_size?is?None:?????????????????????????-------------------------------(8) ??????raise?RuntimeError("can't?determine?the?cache?partition?size") ????OPTIONS.cache_size?=?cache_size ????if?OPTIONS.incremental_source?is?None:?????????-------------------------------(9) ??????WriteFullOTAPackage(input_zip,?output_zip)???-------------------------------(10) ??????if?OPTIONS.package_key?is?None: ????????OPTIONS.package_key?=?OPTIONS.info_dict.get( ????????????"default_system_dev_certificate", ????????????"build/target/product/security/testkey") ??????common.ZipClose(output_zip) ??????break ????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) ??????if?"selinux_fc"?in?OPTIONS.source_info_dict: ????????OPTIONS.source_info_dict["selinux_fc"]?=?os.path.join( ????????????OPTIONS.source_tmp,?"BOOT",?"RAMDISK",?"file_contexts") ??????if?OPTIONS.package_key?is?None: ????????OPTIONS.package_key?=?OPTIONS.source_info_dict.get( ????????????"default_system_dev_certificate", ????????????"build/target/product/security/testkey") ??????if?OPTIONS.verbose: ????????print?"---?source?info?---" ????????common.DumpInfoDict(OPTIONS.source_info_dict) ??????try: ????????WriteIncrementalOTAPackage(input_zip,?source_zip,?output_zip) ????????common.ZipClose(output_zip) ????????break ??????except?ValueError: ????????if?not?OPTIONS.fallback_to_full: ??????????raise ????????print?"---?failed?to?build?incremental;?falling?back?to?full?---" ????????OPTIONS.incremental_source?=?None ????????common.ZipClose(output_zip) ??if?not?OPTIONS.no_signing: ????SignOutput(temp_zip_file.name,?args[1])??????????????????????---------------------(11) ????temp_zip_file.close() ??print?"done."
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
(1)首先定義一個命令參數(shù)處理的回調(diào)函數(shù)option_handler,這個回調(diào)方法把參數(shù)對應的值存儲在一個全局的OPTIONS變量中,后續(xù)的編譯通過判斷OPTIONS變量執(zhí)行不同的流程。
(2)調(diào)用common.ParseOptions方法()位于commom.py文件中,該方法的功能就是處理一些自己能處理的參數(shù)(如-h),自己不能處理的參數(shù)就交給option_handler來處理。
(3)當用戶使用-e參數(shù)指定一個文件時,最終會在升級包腳本的適當位置添加指定文件的內(nèi)容。這為一些私有的命令插入updater-script提供了方便。
(4)OPTIONS.input_tmp是target_file.zip解壓后的臨時目錄;input_zip是target_file的句柄,后面可以通過這個句柄來操作target_file.zip??梢詤⒖碿ommon.py的UnzipTemp方法。
(5)根據(jù)target_file.zip中的META/misc_info.txt文件初始化字典,這個要重點分析一下,因為這個字典里面存放著一些重要的信息。
首先我們看看misc_info.txt的內(nèi)容:
再來看看具體處理misc_info.txt的流程:
def?LoadInfoDict(input_file):????????---這里的input_file就是target_file.zip ??"""Read?and?parse?the?META/misc_info.txt?key/value?pairs?from?the ??input?target?files?and?return?a?dict.""" ??---由上面的注釋可以知道,LoadInfoDict方法的功能是解析target_file.zip中的META/misc_info.txt文件,并以key:value的形式存放在OPTIONS.info_dict字典中 ??def?read_helper(fn): ????if?isinstance(input_file,?zipfile.ZipFile):???? ??????return?input_file.read(fn)????????---input_file就是zipfile.ZipFile對象,因此走if分支 ????else: ??????path?=?os.path.join(input_file,?*fn.split("/")) ??????try: ????????with?open(path)?as?f: ??????????return?f.read() ??????except?IOError?as?e: ????????if?e.errno?==?errno.ENOENT: ??????????raise?KeyError(fn) ??d?=?{} ??try: ????d?=?LoadDictionaryFromLines(read_helper("META/misc_info.txt").split("n"))????---處理misc_info.txt文件,下面會分析LoadDictionaryFromLines方法 ??except?KeyError: ????#?ok?if?misc_info.txt?doesn't?exist ????pass ??#?backwards?compatibility:?These?values?used?to?be?in?their?own ??#?files.??Look?for?them,?in?case?we're?processing?an?old ??#?target_files?zip. ??if?"mkyaffs2_extra_flags"?not?in?d: ????try: ??????d["mkyaffs2_extra_flags"]?=?read_helper( ??????????"META/mkyaffs2-extra-flags.txt").strip() ????except?KeyError: ??????#?ok?if?flags?don't?exist ??????pass ??----下面幾個if語句就是判斷misc_info.txt文件的正確性了 ??if?"recovery_api_version"?not?in?d: ????try: ??????d["recovery_api_version"]?=?read_helper( ??????????"META/recovery-api-version.txt").strip() ????except?KeyError: ??????raise?ValueError("can't?find?recovery?API?version?in?input?target-files") ??if?"tool_extensions"?not?in?d: ????try: ??????d["tool_extensions"]?=?read_helper("META/tool-extensions.txt").strip() ????except?KeyError: ??????#?ok?if?extensions?don't?exist ??????pass ??if?"fstab_version"?not?in?d: ????d["fstab_version"]?=?"1" ??try:????---我的項目中沒有這個文件,不分析了 ????data?=?read_helper("META/imagesizes.txt") ????for?line?in?data.split("n"): ??????if?not?line: ????????continue ??????name,?value?=?line.split("?",?1) ??????if?not?value: ????????continue ??????if?name?==?"blocksize": ????????d[name]?=?value ??????else: ????????d[name?+?"_size"]?=?value ??except?KeyError: ????pass
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364651234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
最終OPTONS.info_dict={recovery_api_version:3, fstab_version:2, blocksize:4096, recovery_size:33554432, custom_size:536870912
recovery_mount_options:ext4=max_batch_time=0,commit=1,data=ordered,barrier=1,errors=panic,nodelalloc
tool_extensions:device/*/m96/../common,
default_system_dev_certificate:build/target/product/security/testkey,
…
}
至于OPTONS.info_dict的用處,后面用到了再來分析,總之,很多時候我們編譯升級包出錯都是因為OPTONS.info_dict的內(nèi)容不合法導致的。
(6)這里應該是指定一個OEM廠商自己定制的一個Python腳本(可以通過-s參數(shù)傳入),完成一些廠商自己定制的一些功能。我當前的項目沒有指定-s參數(shù),根據(jù)代碼分析會使用OPTONS.info_dict中的tool_extensions:device/*/m96/../common,這顯然不是一個Python腳本,如果后面使用到的話會報錯的,然而我當前沒有使用,這里就不去深究了。
(7)可以通過–no_signing參數(shù)指定不對升級包簽名,當然一般廠商是不會這么做的。
(8)cache_size就是misc_info.txt中的“cache_size=536870912”這個字段,如果misc_info.txt文件中沒有這個字段的話就會終止編譯。順便說一下cache_size的值是在BoardConfig.mk中設置的:
BOARD_CACHEIMAGE_PARTITION_SIZE := 536870912
(9)通過-i參數(shù)可以使OPTIONS.incremental_source=True,由于本文講述的是全量升級包的編譯,所有這里只講述if分支的流程。
(10)全量升級包的生成由這個方法完成,前面的代碼都是浮云。下面就來仔細看看WriteFullOTAPackage方法
def?WriteFullOTAPackage(input_zip,?output_zip): ??#?TODO:?how?to?determine?this???We?don't?know?what?version?it?will ??#?be?installed?on?top?of.?For?now,?we?expect?the?API?just?won't ??#?change?very?often.?Similarly?for?fstab,?it?might?have?changed ??#?in?the?target?build. ??script?=?edify_generator.EdifyGenerator(3,?OPTIONS.info_dict)???????????--------------------(a) ??oem_props?=?OPTIONS.info_dict.get("oem_fingerprint_properties")??????????????????????? ??recovery_mount_options?=?OPTIONS.info_dict.get("recovery_mount_options")--------------------(b) ??oem_dict?=?None ??if?oem_props?is?not?None?and?len(oem_props)?>?0: ????if?OPTIONS.oem_source?is?None: ??????raise?common.ExternalError("OEM?source?required?for?this?build") ????script.Mount("/oem",?recovery_mount_options) ????oem_dict?=?common.LoadDictionaryFromLines( ????????open(OPTIONS.oem_source).readlines()) ??metadata?=?{ ??????"post-build":?CalculateFingerprint(oem_props,?oem_dict, ?????????????????????????????????????????OPTIONS.info_dict), ??????"pre-device":?GetOemProperty("ro.product.device",?oem_props,?oem_dict, ???????????????????????????????????OPTIONS.info_dict), ??????"post-timestamp":?GetBuildProp("ro.build.date.utc",?OPTIONS.info_dict), ??} ??device_specific?=?common.DeviceSpecificParams(??????????????????????? ??????input_zip=input_zip, ??????input_version=OPTIONS.info_dict["recovery_api_version"], ??????output_zip=output_zip, ??????script=script, ??????input_tmp=OPTIONS.input_tmp, ??????metadata=metadata, ??????info_dict=OPTIONS.info_dict) ??has_recovery_patch?=?HasRecoveryPatch(input_zip)??????????????---------------------------(c) ??block_based?=?OPTIONS.block_based?and?has_recovery_patch??????---------------------------(d) ??if?not?OPTIONS.omit_prereq:???????????????????????????????????---------------------------(e) ????ts?=?GetBuildProp("ro.build.date.utc",?OPTIONS.info_dict) ????ts_text?=?GetBuildProp("ro.build.date",?OPTIONS.info_dict) ????script.AssertOlderBuild(ts,?ts_text) ??AppendAssertions(script,?OPTIONS.info_dict,?oem_dict) ??device_specific.FullOTA_Assertions() ??#?delete?/cache/backup ??script.AppendExtra('delete_recursive("/cache/backup");') ??kernel_img?=?common.GetOtherImage("boot.img",?"boot.img",?------------------------------(f) ??????????????????????????????????????OPTIONS.input_tmp,?"OTHER") ??ldfw_img?=?common.GetOtherImage("ldfw",?"ldfw", ??????????????????????????????????????OPTIONS.input_tmp,?"OTHER") ??if?OPTIONS.two_step:???????????????????????????????????????-----------------------------(g) ????if?not?OPTIONS.info_dict.get("multistage_support",?None): ??????assert?False,?"two-step?packages?not?supported?by?this?build" ????fs?=?OPTIONS.info_dict["fstab"]["/misc"] ????assert?fs.fs_type.upper()?==?"EMMC",? ????????"two-step?packages?only?supported?on?devices?with?EMMC?/misc?partitions" ????bcb_dev?=?{"bcb_dev":?fs.device} ????common.CheckSize(recovery_img.data,?"recovery",?OPTIONS.info_dict) ????common.ZipWriteStr(output_zip,?"recovery",?recovery_img.data) ????script.AppendExtra(""" if?get_stage("%(bcb_dev)s")?==?"2/3"?then """?%?bcb_dev) ????script.WriteRawImage("/recovery",?"recovery") ????script.WriteRawImage("/ldfw",?"ldfw") ????script.AppendExtra(""" set_stage("%(bcb_dev)s",?"3/3"); reboot_now("%(bcb_dev)s",?"recovery"); else?if?get_stage("%(bcb_dev)s")?==?"3/3"?then """?%?bcb_dev) ??#?Dump?fingerprints ??script.Print("Target:?%s"?%?CalculateFingerprint( ??????oem_props,?oem_dict,?OPTIONS.info_dict)) ??device_specific.FullOTA_InstallBegin() ??system_progress?=?0.95 ??if?OPTIONS.wipe_user_data: ????system_progress?-=?0.1 ??if?HasVendorPartition(input_zip): ????system_progress?-=?0.1 ??if?"selinux_fc"?in?OPTIONS.info_dict: ????WritePolicyConfig(OPTIONS.info_dict["selinux_fc"],?output_zip) ??recovery_mount_options?=?OPTIONS.info_dict.get("recovery_mount_options") ??system_items?=?ItemSet("system",?"META/filesystem_config.txt") ??script.ShowProgress(system_progress,?100) ??if?block_based:????????????????????????????????????????----------------------(h) ????#?Full?OTA?is?done?as?an?"incremental"?against?an?empty?source ????#?image.??This?has?the?effect?of?writing?new?data?from?the?package ????#?to?the?entire?partition,?but?lets?us?reuse?the?updater?code?that ????#?writes?incrementals?to?do?it. ????system_tgt?=?GetImage("system",?OPTIONS.input_tmp,?OPTIONS.info_dict) ????system_tgt.ResetFileMap() ????system_diff?=?common.BlockDifference("system",?system_tgt,?src=None) ????system_diff.WriteScript(script,?output_zip) ??else: ????script.FormatPartition("/system") ????script.Mount("/system",?recovery_mount_options) ????if?not?has_recovery_patch: ??????script.UnpackPackageDir("recovery",?"/system") ????script.UnpackPackageDir("system",?"/system") ????symlinks?=?CopyPartitionFiles(system_items,?input_zip,?output_zip) ????script.MakeSymlinks(symlinks) ??boot_img?=?common.GetOtherImage("boot.img",?"boot.img", ?????????????????????????????????????OPTIONS.input_tmp,?"OTHER") ??if?not?block_based: ????def?output_sink(fn,?data): ??????common.ZipWriteStr(output_zip,?"recovery/"?+?fn,?data) ??????system_items.Get("system/"?+?fn) ????common.MakeRecoveryPatch(OPTIONS.input_tmp,?output_sink, ?????????????????????????????recovery_img,?boot_img) ????system_items.GetMetadata(input_zip) ????system_items.Get("system").SetPermissions(script) ??if?HasVendorPartition(input_zip): ????vendor_items?=?ItemSet("vendor",?"META/vendor_filesystem_config.txt") ????script.ShowProgress(0.1,?0) ????if?block_based: ??????vendor_tgt?=?GetImage("vendor",?OPTIONS.input_tmp,?OPTIONS.info_dict) ??????vendor_tgt.ResetFileMap() ??????vendor_diff?=?common.BlockDifference("vendor",?vendor_tgt) ??????vendor_diff.WriteScript(script,?output_zip) ????else: ??????script.FormatPartition("/vendor") ??????script.Mount("/vendor",?recovery_mount_options) ??????script.UnpackPackageDir("vendor",?"/vendor") ??????symlinks?=?CopyPartitionFiles(vendor_items,?input_zip,?output_zip) ??????script.MakeSymlin