转载

概要

此局部为全包降级次要实现过程,波及到ota_from_target_files 文件,这个也是制作全包和差分包的次要工具,接下来咱们就着重剖析怎么利用这个工具制作full_ota_package的。

次要流程

源码剖析

上节中 Makefile 中 otapackage 指标最初的 cmd 为:

$(hide) MTK_SECURITY_SW_SUPPORT=$(MTK_SECURITY_SW_SUPPORT)MKBOOTIMG=$(MKBOOTIMG) \         ./build/tools/releasetools/ota_from_target_files-v \              --block \              -p $(HOST_OUT) \              -k $(KEY_CERT_PAIR) \              $(if $(OEM_OTA_CONFIG), -o$(OEM_OTA_CONFIG)) \              $(BUILT_TARGET_FILES_PACKAGE) $@

所以跳到 ota_from_target_files python 文件中,接下来咱们先看一下这个文件的作用,usage 以及 cmd 所带的参数的意义。

"""Given a target-files zipfile, produces an OTA package that installsthat build.  An incremental OTA is produced if -i is given, otherwisea full OTA is produced.Usage:  ota_from_target_files [flags] input_target_files output_ota_package  --board_config  <file>      Deprecated.  -k (--package_key) <key> Key to use to sign the package (default isthe value of default_system_dev_certificate from the inputtarget-files's META/misc_info.txt, or      "build/target/product/security/testkey" if that value is notspecified).      For incremental OTAs, the default value is based on the sourcetarget-file, not the target build.  -i  (--incremental_from)  <file>      Generate an incremental OTA using the given target-files zip asthe starting build.  -v  (--verify)      Remount and verify the checksums of the files written to thesystem and vendor (if used) partitions.  Incremental builds only.  -o  (--oem_settings)  <file>      Use the file to specify the expected OEM-specific propertieson the OEM partition of the intended device.  -w  (--wipe_user_data)      Generate an OTA package that will wipe the user data partitionwhen installed.  -n  (--no_prereq)      Omit the timestamp prereq check normally included at the top ofthe build scripts (used for developer OTA packages whichlegitimately need to go back and forth).  -e  (--extra_script)  <file>      Insert the contents of file at the end of the update script.  -r  (--preloader)  <file>      Specify 'preloader.img' to upgrade.  -l  (--logo)  <file>      Specify 'logo.img' to upgrade.  -u  (--uboot)  <file>      Specify 'uboot.img/lk.img' to upgrade.  -a  (--aslr_mode)  <on|off>      Specify whether to turn on ASLR for the package (on by default).  -2  (--two_step)      Generate a 'two-step' OTA package, where recovery is updatedfirst, so that any changes made to the system partition are doneusing the new recovery (new kernel, etc.).  --block      Generate a block-based OTA if possible.  Will fall back to afile-based OTA if the target_files is older and doesn't supportblock-based OTAs.  -b  (--binary)  <file>      Use the given binary as the update-binary in the output package,instead of the binary in the build's target_files.  Use fordevelopment only.  -t  (--worker_threads) <int>      Specifies the number of worker-threads that will be used whengenerating patches for incremental updates (defaults to 3).  -f  (--special_factory_reset)      After upgrade, it will execute special factory reset.  -z  (--trustonic)  <file>      Specify 'mobicore.bin' to upgrade."""

文件的作用如英文形容:给出一个 target_file 的 zip 包生成一个 ota 包,如果带 –i 参数则生成差分包,否则生成 full_ota_package

Usage: ota_from_target_files [flags] input_target_filesoutput_ota_package–board_config   Deprecated.-k :指定sign package应用的key-i : 制作差分包,前面跟差分包根底包-v:verify性能-o:指定oem厂商信息-w:分明data区-n:是否查看工夫戳信息,以便确定向前或者向后降级-e:指定额定的降级脚本-r:是否降级preloader分区-l:是否降级logo分区-u:是否降级uboot分区-a:是否关上ASLR-2:生成一个two-step ota包–block:生成一个block_base的ota包-b:指定一个update-binary寄存到ota包中-t:指定线程数-f:指定是否复原出厂设置-z:指定mobicore.bin

从此处开始执行,而后跳到 main 函数中

if __name__ == '__main__':try:common.CloseInheritedPipes()main(sys.argv[1:])except common.ExternalError, e:printprint "   ERROR: %s" % (e,)printsys.exit(1)finally:common.Cleanup()

上面这一段代码次要作用是解析命令行参数,除了下面曾经剖析的参数外,另外加上了 Common.ParseOptions() 接口中的参数列表,如下:

for o, a in opts:if o in ("-h", "--help"):Usage(docstring)sys.exit()elif o in ("-v", "--verbose"):     OPTIONS.verbose = Trueelif o in ("-p", "--path"):      OPTIONS.search_path = aelif o in ("--signapk_path",):      OPTIONS.signapk_path = aelif o in ("--extra_signapk_args",):     OPTIONS.extra_signapk_args = shlex.split(a)elif o in ("--java_path",):      OPTIONS.java_path = aelif o in ("--java_args",):      OPTIONS.java_args = aelif o in ("--public_key_suffix",):      OPTIONS.public_key_suffix = aelif o in ("--private_key_suffix",):      OPTIONS.private_key_suffix = aelif o in ("-s", "--device_specific"):      OPTIONS.device_specific = aelif o in ("-x", "--extra"):key, value = a.split("=", 1)OPTIONS.extras[key] = valueelse:if extra_option_handler is None or notextra_option_handler(o, a):assert False, "unknown option \"%s\""% (o,)

由之前Makefile的cmd来看:

./build/tools/releasetools/ota_from_target_files-v \              --block \              -p $(HOST_OUT) \              -k $(KEY_CERT_PAIR) \              $(if $(OEM_OTA_CONFIG), -o$(OEM_OTA_CONFIG)) \             $(BUILT_TARGET_FILES_PACKAGE) $@      

此段代码执行完结后:

OPTIONS.block_based = TrueOPTIONS.verbose = True(此处留神:-v代表verbose;–verify代表verify)OPTIONS.search_path= $(HOST_OUT) /* xxx/out/host/linux-x86 */OPTIONS.package_key = $(KEY_CERT_PAIR)args = [‘xxx-target_files-eng.xx.zip’,’xxx-ota-eng.xx.zip’]//前者是obj下的压缩包,后者是最终的ota包。

如有纳闷,请自行参考getopt解析命令行参数模块代码

def main(argv):def option_handler(o, a):if o == "--board_config":pass   # deprecatedelif o in ("-k", "--package_key"):      OPTIONS.package_key = aelif o in ("-i", "--incremental_from"):      OPTIONS.incremental_source = aelif o in ("-w", "--wipe_user_data"):      OPTIONS.wipe_user_data = Trueelif o in ("-n", "--no_prereq"):      OPTIONS.omit_prereq = Trueelif o in ("-o", "--oem_settings"):      OPTIONS.oem_source = aelif o in ("-e", "--extra_script"):      OPTIONS.extra_script = aelif o in ("-a", "--aslr_mode"):      if a in ("on", "On", "true", "True", "yes", "Yes"):        OPTIONS.aslr_mode = Trueelse:        OPTIONS.aslr_mode = Falseelif 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 ("-f", "--special_factory_reset"):      OPTIONS.special_factory_reset = Trueelif o in ("-x", "--tee"):      OPTIONS.tee = a elif o in ("-z", "--trustonic"):      OPTIONS.trustonic = aelif o in ("-2", "--two_step"):      OPTIONS.two_step = Trueelif o in ("-r", "--preloader"):      OPTIONS.preloader = aelif o in ("-l", "--logo"):      OPTIONS.logo = aelif o in ("-u", "--uboot"):      OPTIONS.uboot = aelif o in ("-f", "--special_factory_reset"):      OPTIONS.special_factory_reset = Trueelif o in ("-g", "--ubifs"):      OPTIONS.ubifs = Trueelif o == "--no_signing":      OPTIONS.no_signing = Trueelif o in ("--verify"):      OPTIONS.verify = Trueelif o == "--block":      OPTIONS.block_based = Trueelif o in ("-b", "--binary"):      OPTIONS.updater_binary = aelif o in ("--no_fallback_to_full",):      OPTIONS.fallback_to_full = Falseelse:return Falsereturn True args = common.ParseOptions(argv, __doc__,                             extra_opts="b:k:i:d:wfgne:r:l:u:x:z:t:a:2o:",                             extra_long_opts=["board_config=",                                              "package_key=",                                              "incremental_from=",                                              "wipe_user_data",                                              "special_factory_reset",                                              "ubifs",                                              "tee=",                                              "trustonic=",                                              "no_prereq",                                              "extra_script=",                                              "preloader=",                                              "logo=",                                              "uboot=",                                              "worker_threads=",                                              "aslr_mode=",                                              "two_step",                                              "no_signing",                                              "block",                                              "binary=",                                              "oem_settings=",                                              "verify",                                              "no_fallback_to_full",                                              ],                             extra_option_handler=option_handler)if os.getenv("MTK_SECURITY_SW_SUPPORT", "no")=="no":    OPTIONS.mtk_sec_boot_sig_tail = Falseif len(args) != 2:common.Usage(__doc__)sys.exit(1)
/*此处为false*/if OPTIONS.extra_script is not None:        OPTIONS.extra_script = open(OPTIONS.extra_script).read()

解压输出压缩包到一个两头文件夹,并把目录赋给 OPTIONS.input_tem,同时创立一个输出压缩包的 ZipFile(zipfile.py 中)实例:input_zip

print "unzipping target target-files..."  OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
  1. 把输出压缩包的解压目录赋给 OPTIONS.target_tmp
  2. 通过 input_zip 读取压缩包中的 META/misc_info.txt 文件,以及 RECOVERY/RAMDISK/etc/recovery.fstabSYSTEM/build.prop 等文件,并把文件内容并转换成字典模式 OPTIONS.info_dict,建设字典代码如下:
def LoadDictionaryFromLines(lines):  d = {}for line in lines:                                                  line = line.strip()if not line or line.startswith("#"):continueif "=" in line:name, value = line.split("=", 1)d[name] = valuereturn d
OPTIONS.target_tmp = OPTIONS.input_tmp  OPTIONS.info_dict = common.LoadInfoDict(input_zip)

如果 OPTIONS.info_dict 中存在 key selinux_fc ,则 key 对应键值为:tmpxxx/BOOT/RAMDISK/file_contexts。如果冗余模式为真,则打印字典内容,此处为真。

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

如果调用者利用 -s/–device_specific 指定了 device-specific extension 门路,则应用它。否者应用META/releasetools.py如果此文件存在 target_files 压缩包中。如果以上都没有,则通过查找字典中的 key:‘tool_extension’,来作为 device_specific

#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 inthe target target_files. # Otherwise, take the path of the file from 'tool_extensions' in the  # info dict and look for that in the localfilesystem, relative to  # the current directory. ifOPTIONS.device_specific is None:    from_input =os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")ifos.path.exists(from_input):print"(using device-specific extensions from target_files)"     OPTIONS.device_specific = from_inputelse:      OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions",None) ifOPTIONS.device_specific is not None:OPTIONS.device_specific =os.path.abspath(OPTIONS.device_specific)

S1:此处 OPTIONS.mtk_sec_boot_sig_tail 为真,读取 boot.sigrecovery.sig 内容,

while True:if OPTIONS.mtk_sec_boot_sig_tail:      #After WriteIncrementalOTAPackage, input_zip seems scramble, so read *.sig at first      boot_sig = input_zip.read("META/boot.sig")      recovery_sig = input_zip.read("META/recovery.sig")

此处为 false,所以走 else 语句:创立一个 temp_zip_file 长期文件夹的 _TemporaryFileWrapper 实例。而后创立一个 zipfile 实例 output_zip,以 temp_zip_file 为入参。其实就是对1中的临时文件进行一个 zipfile 实例化,最初能够利用 zipfile 中的属性办法对这个文件进行操作,

if OPTIONS.no_signing: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)

判断是否带 -i 参数,有则进行差分包制作,无则进行全包制作. 此处没有, 所以走if语句为真,而后跳到 WriteFullOTAPackage(input_zip,output_zip) 中执行,可参考后文详细分析。

if OPTIONS.incremental_source is None:WriteFullOTAPackage(input_zip,output_zip)ifOPTIONS.package_key is None:        OPTIONS.package_key =OPTIONS.info_dict.get(            "default_system_dev_certificate",           "build/target/product/security/testkey")ifnot OPTIONS.mtk_sec_boot_sig_tail:breakelse: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")ifOPTIONS.package_key is None:       OPTIONS.package_key = OPTIONS.source_info_dict.get(           "default_system_dev_certificate",            "build/target/product/security/testkey")ifOPTIONS.verbose:print"--- source info ---"common.DumpInfoDict(OPTIONS.source_info_dict)try:WriteIncrementalOTAPackage(input_zip,source_zip, output_zip)ifnot OPTIONS.mtk_sec_boot_sig_tail:breakexceptValueError:ifnot OPTIONS.fallback_to_full: raiseprint"--- failed to build incremental; falling back to full ---"        OPTIONS.incremental_source = None        output_zip.close()

接下来调到全包降级次要接口,

WriteFullOTAPackage(input_zip, output_zip)
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.

a1:创立一个脚本实例,这个脚本未来会被写入长期升级包中:/META-INF/com/google/android/updater-script

script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
/*获取oem参数,没有这个key*/  oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")/*获取recovery_mount_options key所对应的value*/  recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")/*目前没有波及oem信息,上面几行疏忽*/  oem_dict = Noneif 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())

M1:失去metadata字典,供最初一步应用:

post-build:alps/full_(PROJECTNAME)/(PROJECT_NAME)/(PROJECTNAME)/(PROJECT_NAME):5.1/LMY47D/1501228112:eng/test-keys

post-timestamp: 1501228303

pre-device: $(PROJECT_NAME)

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)12345678910111213141516/判断是否有recovery path:target_files_zip.getinfo("SYSTEM/recovery-from-boot.p"),为真*/  has_recovery_patch = HasRecoveryPatch(input_zip)/*是否反对block,生成ota包时有带–block参数,所以此处为真*/  block_based = OPTIONS.block_based and has_recovery_patch/*不执行*/if not OPTIONS.omit_prereq:ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)    ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)script.AssertOlderBuild(ts, ts_text)

降级脚本中增加:getprop(“ro.product.device”) ==“p92s_hd” || abort(“This package is for “p92s_hd"devices; this is a “” + getprop(“ro.product.device”) +””.");

AppendAssertions(script, OPTIONS.info_dict, oem_dict)  device_specific.FullOTA_Assertions()

此处为 false,不执行

if OPTIONS.two_step: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.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)if OPTIONS.info_dict.get("mtk_header_support", None):      recovery_bthdr_img = common.GetBootableImage("recovery_bthdr.img", "recovery_bthdr.img",                                                   OPTIONS.input_tmp, "RECOVERY")common.ZipWriteStr(output_zip, "recovery_bthdr.img", recovery_bthdr_img.data)script.AppendExtra("""if get_stage("%(bcb_dev)s") == "2/3" then""" % bcb_dev)script.WriteRawImage("/recovery", "recovery.img")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)   device_specific.FullOTA_InstallBegin()
system_progress = 0.75if OPTIONS.wipe_user_data:    system_progress -= 0.1if HasVendorPartition(input_zip):    system_progress -= 0.1if HasCustomPartition(input_zip):    system_progress -= 0.1/*把file_contexts写入升级包中*/if "selinux_fc" in OPTIONS.info_dict:WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)/*失去recovery_mount_optionskey所对应的value*/  recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")/*设置system分区对应的config文件为:META/filesystem_config.txt,留着后续应用*/  system_items = ItemSet("system", "META/filesystem_config.txt")/*在降级脚本中增加语句:show_progress(0.750000, 0);*/script.ShowProgress(system_progress, 0)

此处为真,而后执行上面工作:

  1. 先从 input_tem (原始包解压后的两头文件夹)中失去 system.img
  2. system.img 进行 resetFileMap,具体不必深究
  3. 在两头文件中生成:system.transfer.list; system.new.dat ; system.patch.dat
  4. 最初再把这三个文件 system.transfer.list; system.new.dat ; system.patch.dat 写入到 OTA包中,并增加 script 语句

    ui_print(“Patching system imageunconditionally…”);block_image_update(“system”,package_extract_file(“system.transfer.list”),“system.new.dat”, “system.patch.dat”);

以上波及到另外两个python文件:common.py ; blockimgdiff.py

if block_based:    # 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:if OPTIONS.ubifs:      cust_dir1 = GetBuildProp("ro.product.device", OPTIONS.info_dict)      system_path = os.path.join("out/target/product",cust_dir1,"android.fixup.img")if os.path.exists(system_path):        system_img = open(system_path).read()common.ZipWriteStr(output_zip, "system.img", system_img)script.WriteRawImageUbifs("system", "system.img")script.Mount("/system", recovery_mount_options)if not has_recovery_patch:script.UnpackPackageDir("recovery", "/system")symlinks = CopyPartitionFiles(system_items, input_zip, 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) try:     custom_size = OPTIONS.info_dict["custom_size"]except:    custom_size = None if custom_size is not None:if (custom_size > 0) and (HasCustomPartition(input_zip) == True):      custom_items = ItemSet("custom", "META/custom_filesystem_config.txt") if block_based:        custom_tgt = GetImage("custom", OPTIONS.input_tmp, OPTIONS.info_dict)        custom_tgt.ResetFileMap()        custom_diff = common.BlockDifference("custom", custom_tgt)        custom_diff.WriteScript(script, output_zip)else:      script.FormatPartition("/custom")    script.Mount("/custom")    script.UnpackPackageDir("custom", "/custom")     symlinks = CopyPartitionFiles(custom_items, input_zip, output_zip)    script.MakeSymlinks(symlinks)     custom_items.GetMetadata(input_zip)    custom_items.Get("custom").SetPermissions(script)

B1:从输出文件中取得 boot.img (已存在),而后返回一个 FILE class 的实例,name:为镜像名;data:镜像的二进制内容,如下:

common.pyclass File(object):def **init**(self,name, data):self.name = nameself.data = datself.size = len(data)self.sha1 = sha1(data).hexdigest()@classmethoddef FromLocalFile(cls,name, diskname):    f = open(diskname, "rb")data = f.read()f.close()return File(name, data)......

这个 boot_img 实例在后续会应用。

boot_img = common.GetBootableImage("boot.img", "boot.img",                                     OPTIONS.input_tmp, "BOOT") if not block_based:def output_sink(fn, data):common.ZipWriteStr(output_zip, "recovery/" + fn, data)      system_items.Get("system/" + fn, dir=False) 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.MakeSymlinks(symlinks)       vendor_items.GetMetadata(input_zip)      vendor_items.Get("vendor").SetPermissions(script) if HasCustomPartition(input_zip):    custom_items = ItemSet("custom", "META/custom_filesystem_config.txt")script.ShowProgress(0.1, 0) if block_based:      custom_tgt = GetImage("custom", OPTIONS.input_tmp, OPTIONS.info_dict)      custom_tgt.ResetFileMap()      custom_diff = common.BlockDifference("custom", custom_tgt)      custom_diff.WriteScript(script, output_zip)else:script.FormatPartition("/custom")script.Mount("/custom")script.UnpackPackageDir("custom", "/custom") symlinks = CopyPartitionFiles(custom_items, input_zip, output_zip)script.MakeSymlinks(symlinks)       custom_items.GetMetadata(input_zip)      custom_items.Get("custom").SetPermissions(script)
  1. check boot.img 镜像的大小,是否超过 max_size ,此处用到 B1 中 boot_img class 中的 data
  2. boot_img.data 内容写入到输入压缩包中,参考 zipfile.py , tempfile.py
  3. 同时写入 script 脚本:

    show_progress(0.050000,5);assert(package_extract_file(“boot.img”,"/tmp/boot.img"),  write_raw_image("/tmp/boot.img", "bootimg"),delete("/tmp/boot.img"));
common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)common.ZipWriteStr(output_zip, "boot.img", boot_img.data)script.ShowProgress(0.05, 5)script.WriteRawImage("/boot", "boot.img")

上面几行次要是:取得 SEC_VER.txt 的门路,并把它写入输入的压缩包中。

[SEC OTA] config : vendor/mediatek/proprietary/custom/$(PROJECT_NAME)/security/recovery/SEC_VER.txt

# security versionprint "[SEC OTA] Adding security version (WriteFullOTAPackage)"  cust_dir = GetBuildProp("ro.product.model", OPTIONS.info_dict)  cust_dir_base = GetBuildProp("ro.product.device", OPTIONS.info_dict)print "[SEC OTA] cust directory : ", cust_dir_base  sec_ver_path = os.path.join("vendor/mediatek/proprietary/custom",cust_dir_base,"security/recovery/SEC_VER.txt")print "[SEC OTA] security config : ", sec_ver_pathif os.path.exists(sec_ver_path):    sec_ver = open(sec_ver_path).read()  common.ZipWriteStr(output_zip, "SEC_VER.txt", sec_ver)  

判断是否有:out/target/product/device/bror/p92s_hd/signed_bin/sig_info/boot.img.sig。如果有,写入输入压缩包中;没有则不需操作。

boot_sec_sig_ext_path = os.path.join("out/target/product",cust_dir,"signed_bin/sig_info/boot.img.sig")if not os.path.exists(boot_sec_sig_ext_path):    cust_dir = GetBuildProp("ro.product.name", OPTIONS.info_dict)    boot_sec_sig_ext_path = os.path.join("out/target/product",cust_dir,"signed_bin/sig_info/boot.img.sig")if not os.path.exists(boot_sec_sig_ext_path):    cust_dir = GetBuildProp("ro.mediatek.project.path", OPTIONS.info_dict)    boot_sec_sig_ext_path = os.path.join("out/target/product",cust_dir,"signed_bin/sig_info/boot.img.sig")print "[SEC OTA] security boot sig_ext : ", boot_sec_sig_ext_pathif os.path.exists(boot_sec_sig_ext_path):    boot_sec_sig_ext = open(boot_sec_sig_ext_path).read()  common.ZipWriteStr(output_zip, "boot.img.sig", boot_sec_sig_ext)  

output_zip 中写入 type.txt 文件,内容为1.(全包为1,差分包为0)

 #wschen startcommon.ZipWriteStr(output_zip, "type.txt", "1")

ota_scatter.txt 写入 output_zip 中,命名为 scatter.txt

cust_dir =GetBuildProp("ro.product.model", OPTIONS.info_dict)scatter_path =os.path.join("out/target/product",cust_dir,"ota_scatter.txt")if not os.path.exists(scatter_path):   cust_dir = GetBuildProp("ro.product.device",OPTIONS.info_dict)   scatter_path =os.path.join("out/target/product",cust_dir,"ota_scatter.txt")if not os.path.exists(scatter_path):   cust_dir = GetBuildProp("ro.product.name", OPTIONS.info_dict)   cust_dir = cust_dir.split('full_')[-1]   scatter_path =os.path.join("out/target/product",cust_dir,"ota_scatter.txt")if not os.path.exists(scatter_path):   cust_dir = GetBuildProp("ro.mediatek.project.path",OPTIONS.info_dict)   cust_dir = cust_dir.split('/')[-1]   scatter_path = os.path.join("out/target/product",cust_dir,"ota_scatter.txt")ota_scatter = open(scatter_path).read()common.ZipWriteStr(output_zip,"scatter.txt", ota_scatter)

上面这几步是判断是否进行preloader,logo,uboot,tee等分区进行降级,如不须要,则疏忽

#  if OPTIONS.preloader is not None or OPTIONS.uboot is not None or OPTIONS.logo is not None:#    script.AppendExtra('assert(run_program(\"/system/bin/dd\", \"if=/dev/zero\", \"of=/proc/driver/mtd_writeable\", \"bs=3\", \"count=1\"));')if OPTIONS.logo is not None:    logo_img = open(OPTIONS.logo).read()common.ZipWriteStr(output_zip, "logo.img", logo_img)script.WriteRawImage2("logo", "logo.img")if OPTIONS.preloader is not None:    preloader_img = open(OPTIONS.preloader).read()common.ZipWriteStr(output_zip, "preloader.img", preloader_img)script.WriteRawImage2("preloader", "preloader.img")if OPTIONS.uboot is not None:    uboot_img = open(OPTIONS.uboot).read()common.ZipWriteStr(output_zip, "uboot.img", uboot_img)script.WriteRawImage2("uboot", "uboot.img")  #tonykuo startif OPTIONS.tee is not None:    tee_img = open(OPTIONS.tee).read()common.ZipWriteStr(output_zip, "tee.img", tee_img)script.WriteRawImage2("tee1", "tee.img")  #tonykuo end  #koshi startif OPTIONS.trustonic is not None:    trustonic_img = open(OPTIONS.trustonic).read()common.ZipWriteStr(output_zip, "mobicore.bin", trustonic_img)script.WriteRawImage2("tee1", "mobicore.bin")  #koshi end

增加 script 语句:show_progress(0.200000, 10);并申明 WriteFull_ota 制作完结

script.ShowProgress(0.2, 10)device_specific.FullOTA_InstallEnd()

如果存在额定脚本,则把脚本内容填入降级 script 中,此处为 None

if OPTIONS.extra_script is not None:script.AppendExtra(OPTIONS.extra_script)

降级脚本中增加unmount所有mount_point语句,如下:

def UnmountAll(self):for p insorted(self.mounts):self.script.append(‘unmount("%s");’% (p,))self.mounts = set()

但因为 sef.mounts 在全包降级中为空集合,所以此处没有增加 unmount 语句到脚本中

script.UnmountAll()

制作ota包命令行中是否带有 "-f","–special_factory_reset" 参数,没有则不执行上面语句,此处为 False

#wschenif OPTIONS.special_factory_reset:script.AppendExtra('special_factory_reset();')

制作ota包命令行中是否带有"-w", "–wipe_user_data"参数,没有则不执行上面语句:革除 data 分区。此处为 False

if OPTIONS.wipe_user_data:script.ShowProgress(0.1, 10)script.FormatPartition("/data")

增加降级脚本语句:

self.script.append((‘apply_sig(package_extract_file("%(sigfile_name)s"),"%(partion_name)s");’)        % {'sigfile_name':sigfile_name,'partion_name':partion_name})==>apply_sig(package_extract_file(“sig/boot.sig”),“bootimg”);
if OPTIONS.mtk_sec_boot_sig_tail:script.ApplySig("sig/boot.sig", "bootimg")

制作ota包命令行中是否带有"-2", "–two_step"参数,没有则不执行上面语句:革除 data 分区。此处为 False

if OPTIONS.two_step:script.AppendExtra("""set_stage("%(bcb_dev)s", "");""" % bcb_dev)script.AppendExtra("else\n")script.WriteRawImage("/boot", "recovery.img")script.AppendExtra("""set_stage("%(bcb_dev)s", "2/3");reboot_now("%(bcb_dev)s", "");endif;endif;""" % bcb_dev)

此处尤为重要,次要做两件事件:

  1. 将降级脚本语句script序列写入到升级包中:"META-INF/com/google/android/updater-script"
  2. 将降级工具(可执行文件)写入升级包中:"META-INF/com/google/android/update-binary"

代码如下:请参考edify_generator.py:

defAddToZip(self, input_zip, output_zip, input_path=None):“”"Write the accumulated script to the output_zipfile. input_zipisused as the source for the ‘updater’ binary needed to runscript. If input_path is not None, it will be used asa localpathfor the binary instead of input_zip."""self.UnmountAll()common.ZipWriteStr(output_zip,“META-INF/com/google/android/updater-script”,"\n".join(self.script) + "\n")/*此处为序列之间退出‘\n’,所以最终的文件中都是一行一行的出现进去*/ifinput_path is None:data= input_zip.read(“OTA/bin/updater”)else:data= open(input_path, “rb”).read()common.ZipWriteStr(output_zip,“META-INF/com/google/android/update-binary”,data,perms=0755)
script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)

把上文 M1 处内容中的字典格局转换成 ‘%s=%s’ 格局,并写入到升级包中:“META-INF/com/android/metadata”

如下文code:调用

defWriteMetadata(metadata, output_zip):common.ZipWriteStr(output_zip,“META-INF/com/android/metadata”,                "".join(["%s=%s\n" % kv                          for kv insorted(metadata.iteritems())]))

最终文件内容如下:

post-build=alps/full_p92s_hd/p92s_hd:5.1/LMY47D/1501228112:eng/test-keyspost-timestamp=1501228303pre-device=p92s_hd
WriteMetadata(metadata, output_zip)

至此,writeFullOTAPackage函数运行结束。 接下来再持续跳到main函数残余局部接着执行,

if OPTIONS.incremental_source is None:WriteFullOTAPackage(input_zip, output_zip)if OPTIONS.package_key is None:        OPTIONS.package_key = OPTIONS.info_dict.get(            "default_system_dev_certificate",            "build/target/product/security/testkey")if not OPTIONS.mtk_sec_boot_sig_tail:breakelse: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)if not OPTIONS.mtk_sec_boot_sig_tail:breakexcept ValueError:if not OPTIONS.fallback_to_full: raiseprint "--- failed to build incremental; falling back to full ---"        OPTIONS.incremental_source = None        output_zip.close()

此处为真,接下来在长期降级文件包中写入 sig/boot.sig; sig/recovery.sig 文件。其中源 data(boot_sig,recovery_sig)为上文 S1 步骤中的内容。

if OPTIONS.mtk_sec_boot_sig_tail:common.ZipWriteStr(output_zip, "sig/boot.sig", boot_sig)common.ZipWriteStr(output_zip, "sig/recovery.sig", recovery_sig)break;  output_zip.close()

对两头降级文件包进行前签名,生成最终的升级包。

  1. running: openssl pkcs8 -inbuild/target/product/security/testkey.pk8 -inform DER -nocrypt
  2. running: java -Xmx2048m -jarout/host/linux-x86/framework/signapk.jar -wbuild/target/product/security/testkey.x509.pembuild/target/product/security/testkey.pk8 /tmp/tmpBXjz5Z out/target/product/xxxx/xxxx-ota-eng.wan.zip

最终生成升级包

第2步中会调用 `build/tools/signapk/signapk.java` 文件,生成 `META-INF/MANIFEST.MF,META-INF/CERT.RSA,META-INF/CERT.SF`,

META-INF/com/android/otacert 文件。

if not OPTIONS.no_signing:SignOutput(temp_zip_file.name, args[1])    temp_zip_file.close() print "done."

最终压缩包中的文件列表如下:

着重看下 META-INF/com/google/android 下的两个降级文件:

  • Update-binary:降级工具,可执行文件
  • Updater-script:降级脚本,由制作升级包的过程中一步一步生成的,其内容如下: