reprint

summary

This part is the main implementation process of the full-package upgrade, involving the ota_from_target_files file, which is also the main tool for making full-package and differential packages. Next, we will focus on analyzing how to use this tool to create full_ota_package.

Main process

Source code analysis

The last cmd of the otapackage target in the Makefile in the previous section is:

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

So jump to the ota_from_target_files python file, then let's take a look at the function of this file, usage and the meaning of the parameters of cmd.

 """
Given a target-files zipfile, produces an OTA package that installs
that build.  An incremental OTA is produced if -i is given, otherwise
a 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 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.
  -v  (--verify)
      Remount and verify the checksums of the files written to the
system and vendor (if used) partitions.  Incremental builds only.
  -o  (--oem_settings)  <file>
      Use the file to specify the expected OEM-specific properties
on the OEM partition of the intended device.
  -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.
  -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 updated
first, so that any changes made to the system partition are done
using the new recovery (new kernel, etc.).
  --block
      Generate a block-based OTA if possible.  Will fall back to a
file-based OTA if the target_files is older and doesn't support
block-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 for
development only.
  -t  (--worker_threads) <int>
      Specifies the number of worker-threads that will be used when
generating 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.
"""

The function of the file is as described in English: a zip package of target_file is given to generate an ota package, if the –i parameter is included, a differential package is generated, otherwise 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

Execute from here, then jump to the main function

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

The main function of the following code is to parse the command line parameters. In addition to the parameters already analyzed above, the list of parameters in the Common.ParseOptions() interface is added, as follows:

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

Judging from the cmd of the previous Makefile:

 ./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) $@

After this code is executed:

 OPTIONS.block_based = True
OPTIONS.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包。

If you have any doubts, please refer to the getopt parsing command line parameter module code by yourself.

 def main(argv):
def option_handler(o, a):
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 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 ("-f", "--special_factory_reset"):
      OPTIONS.special_factory_reset = True
elif o in ("-x", "--tee"):
      OPTIONS.tee = a 
elif o in ("-z", "--trustonic"):
      OPTIONS.trustonic = a
elif o in ("-2", "--two_step"):
      OPTIONS.two_step = True
elif o in ("-r", "--preloader"):
      OPTIONS.preloader = a
elif o in ("-l", "--logo"):
      OPTIONS.logo = a
elif o in ("-u", "--uboot"):
      OPTIONS.uboot = a
elif o in ("-f", "--special_factory_reset"):
      OPTIONS.special_factory_reset = True
elif o in ("-g", "--ubifs"):
      OPTIONS.ubifs = True
elif o == "--no_signing":
      OPTIONS.no_signing = True
elif o in ("--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
else:
return False
return 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 = False
if 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()

Unzip the input archive to an intermediate folder, and assign the directory to OPTIONS.input_tem , and create a ZipFile of the input archive ( zipfile.py ) Example: input_zip

 print "unzipping target target-files..."
  OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
  1. Assign the decompression directory of the input archive to OPTIONS.target_tmp .
  2. Through input_zip read the META/misc_info.txt file in the compressed package, and RECOVERY/RAMDISK/etc/recovery.fstab , SYSTEM/build.prop and other files, and convert the content of the file into a dictionary The form OPTIONS.info_dict , the code for creating the dictionary is as follows:
 def LoadDictionaryFromLines(lines):
  d = {}
for line in lines:                                                  
line = line.strip()
if not line or line.startswith("#"):continue
if "=" in line:
name, value = line.split("=", 1)
d[name] = value
return d
 OPTIONS.target_tmp = OPTIONS.input_tmp
  OPTIONS.info_dict = common.LoadInfoDict(input_zip)

If OPTIONS.info_dict exists in key selinux_fc , the corresponding key value of key is: tmpxxx/BOOT/RAMDISK/file_contexts . If redundant mode is true, print the dictionary content, true here.

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

It is used if the caller specified the -s/–device_specific device-specific extension path with ---bf632b0030ed896e08896814ce56dc1b---. Otherwise, use META/releasetools.py if this file exists in the target_files archive. If none of the above, look up the dictionary key:‘tool_extension’ as 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_input
else:
      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: Here OPTIONS.mtk_sec_boot_sig_tail is true, read boot.sig , recovery.sig content,

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

Here is false , so go else statement: Create a temp_zip_file temp folder of _TemporaryFileWrapper instance. Then create an instance of zipfile output_zip with temp_zip_file as the input parameter. In fact, it is to instantiate the temporary file in 1 zipfile , and finally use the attribute method in zipfile to operate on this file,

 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)

Determine whether to bring the -i parameter, if there is, then make the differential package, if not, make the full package. There is no here, so take the if statement to be true, and then jump to WriteFullOTAPackage(input_zip,output_zip) to execute, Refer to the following detailed analysis.

 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:
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")
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:
break
exceptValueError:
ifnot OPTIONS.fallback_to_full: raise
print"--- failed to build incremental; falling back to full ---"
        OPTIONS.incremental_source = None
        output_zip.close()

Next, transfer to the main interface of the all-inclusive upgrade,

 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: Create a script instance, this script will be written into the temporary upgrade package in the future: /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 = 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())

M1: Get the metadata dictionary for the last step:

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)

Add in upgrade script: 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()

Here is false , do not execute

 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.75
if OPTIONS.wipe_user_data:
    system_progress -= 0.1
if HasVendorPartition(input_zip):
    system_progress -= 0.1
if 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)

true here, then perform the following tasks:

  1. First get it from input_tem (the intermediate folder after decompressing the original package) system.img
  2. For system.img resetFileMap , no need to go into details
  3. Generated in intermediate file: system.transfer.list; system.new.dat ; system.patch.dat
  4. Finally, write these three files system.transfer.list; system.new.dat ; system.patch.dat into the OTA package, and add the script statement

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

The above involves two other python files: 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: Obtain boot.img (existing) from the input file, and then return an instance of FILE class , name: the image name; data: the binary content of the image, as follows:

 common.py

class File(object):
def **init**(self,name, data):
self.name = name
self.data = dat
self.size = len(data)
self.sha1 = sha1(data).hexdigest()
@classmethod
def FromLocalFile(cls,name, diskname):
    f = open(diskname, "rb")
data = f.read()
f.close()
return File(name, data)
......

This boot_img instance will be used later.

 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 The size of the image, whether it exceeds max_size , used here in B1 boot_img class in B1 data
  2. Write the content of boot_img.data into the output compressed package, refer to zipfile.py , tempfile.py
  3. Also write script 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")

The following lines are mainly: get the path of SEC_VER.txt and write it into the output compressed package.

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

 # security version
print "[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_path
if os.path.exists(sec_ver_path):
    sec_ver = open(sec_ver_path).read()  
common.ZipWriteStr(output_zip, "SEC_VER.txt", sec_ver)

Determine if there is: out/target/product/device/bror/p92s_hd/signed_bin/sig_info/boot.img.sig . If there is, write it into the output compressed package; if not, no operation is required.

 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_path
if 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)

Write type.txt file in output_zip 126e2564b5e8d52fd75bfcd841d8fe41---, the content is 1. (1 for all packets, 0 for differential packets)

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

Write --- ota_scatter.txt into output_zip and name it 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)

The following steps are to determine whether to upgrade partitions such as preloader, logo, uboot, tee, etc. If not, ignore it

 #  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 start
if 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 start
if 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

Add script statement: show_progress(0.200000, 10); and declare WriteFull_ota end of production

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

If there is an additional script, fill in the script content in the upgrade script , here is None

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

Add unmount all mount_point statements to the upgrade script, as follows:

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

However, since sef.mounts is an empty set in the all-inclusive upgrade, the unmount statement is not added to the script here.

 script.UnmountAll()

Whether there is a "-f","–special_factory_reset" parameter in the command line for making the ota package, if not, do not execute the following statement, here is False

 #wschen
if OPTIONS.special_factory_reset:
script.AppendExtra('special_factory_reset();')

Whether the command line for making the ota package contains the "-w", "–wipe_user_data" parameter, if not, do not execute the following statement: clear the data partition. Here is False

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

Add the upgrade script statement:

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

Whether there is "-2", "–two_step" parameter in the command line for making the ota package, if not, do not execute the following statement: clear the data partition. Here is 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)

This is particularly important here, mainly to do two things:

  1. Write the upgrade script statement script sequence into the upgrade package: "META-INF/com/google/android/updater-script"
  2. Write the upgrade tool (executable file) into the upgrade package: "META-INF/com/google/android/update-binary"

The code is as follows: please refer to edify_generator.py:

 defAddToZip(self, input_zip, output_zip, input_path=None):
“”"Write the accumulated script to the output_zipfile. input_zip
isused as the source for the ‘updater’ binary needed to run
script. If input_path is not None, it will be used asa local
pathfor 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)

Convert the dictionary format in the content at M1 above to ‘%s=%s’ and write it into the upgrade package: “META-INF/com/android/metadata”

As the following code: call

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

The final file content is as follows:

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

At this point, the writeFullOTAPackage function has finished running. Next, continue to jump to the rest of the main function and execute it,

 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:
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)
if not OPTIONS.mtk_sec_boot_sig_tail:
break
except ValueError:
if not OPTIONS.fallback_to_full: raise
print "--- failed to build incremental; falling back to full ---"
        OPTIONS.incremental_source = None
        output_zip.close()

This is true, then write the sig/boot.sig; sig/recovery.sig file in the temporary upgrade file package. The source data(boot_sig,recovery_sig) is the content in step S1 above.

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

Pre-sign the intermediate upgrade package to generate the final upgrade package.

  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

Finally generate the upgrade package

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

META-INF/com/android/otacert file.

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

The list of files in the final archive is as follows:

Focus on the two upgrade files under META-INF/com/google/android :

  • Update-binary : upgrade tool, executable file
  • Updater-script : The upgrade script is generated step by step during the process of making the upgrade package. The content is as follows:


戈壁老王
143 声望60 粉丝

做为一个不称职的老年码农,一直疏忽整理笔记,开博记录一下,用来丰富老年生活,