• Android Recovery OTA升级(一)—— make otapackage


    文件夹


    概述

    make otapackage是Android Build系统支持的命令。用来生成Recovery系统能够进行升级的zip包。

    因此。想要了解Android的OTA升级机制。我们首先须要学习make otapackage命令的运行过程。

    为了防止泄密,下面源代码内容都是基于Android4.4.2_r1分支进行分析。


    make otapackage

    make otapackage是一个.PHONY伪目标。make系统中,伪目标并非一个文件。仅仅是一个标签,因为伪目标不是文件,所以make无法生成它的依赖关系和决定它是否要运行。

    我们仅仅能通过显示的指明这个“目标”才干让其生效。

    须要注意的是,伪目标的取名不能和文件名称重名。不然就失去伪目标的意义了。


    了解了.PHONY之后。我们来看一下make otapackage的make源代码:

    .PHONY: otapackage
    otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)

    通过make代码。我们看到otapackage这个伪目标是依赖于$(INTERNAL_OTA_PACKAGE_TARGET)的,接下来,我会分析一下依赖文件的生成源代码:

    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) ./build/tools/releasetools/ota_from_target_files -v 
        -p $(HOST_OUT) 
        -k $(KEY_CERT_PAIR) 
        $(BUILT_TARGET_FILES_PACKAGE) $@

    能够看到,$(INTERNAL_OTA_PACKAGE_TARGET)依赖于$(KEY_CERT_PAIR),$(HOST_OUT),$(BUILT_TARGET_FILES_PACKAGE)这三个文件和$(DISTTOOLS)所代表的jar包。
    而这些所依赖的文件,最后都会作为參数传递给ota_from_target_files这个python脚本。这个python脚本会进一步生成终于的recovery升级包。

    演示样例參数例如以下:

    ['-v', '-p', 'out/host/linux-x86', '-k', 'build/target/product/security/testkey', 'out/target/product/xxx/obj/PACKAGING/target_files_intermediates/product-target_files-wangzhengyi.zip', 'out/target/product/xxx/product_20150724.1246-ota.zip']

    从參数中能够看出,out/target/product/xxx/product_20150724.1246-ota.zip是终于的recovery升级包,而out/target/product/xxx/obj/PACKAGING/target_files_intermediates/product-target_files-wangzhengyi.zip是中间的暂时zip包。它事实上就是$(BUILT_TARGET_FILES_PACKAGE),接下来我们看一下$(BUILT_TARGET_FILES_PACKAGE)的生成代码。


    BUILT_TARGET_FILES_PACKAGE

    BUILT_TARGET_FILES_PACKAGE的make源代码例如以下:

    BUILT_TARGET_FILES_PACKAGE:= $(intermediates)/$(name).zip
    $(BUILT_TARGET_FILES_PACKAGE): intermediates := $(intermediates)
    $(BUILT_TARGET_FILES_PACKAGE): zip_root := $(intermediates)/$(name)
    
    # $(1): Directory to copy
    # $(2): Location to copy it to
    # The "ls -A" is to prevent "acp s/* d" from failing if s is empty.
    define package_files-copy-root
        if [ -d "$(strip $(1))" -a "$$(ls -A $(1))" ]; then 
            mkdir -p $(2) && 
            $(ACP) -rd $(strip $(1))/* $(2); 
        fi
    endif
    
    built_ota_tools := 
        $(call intermediates-dir-for,EXECUTABLES,applypatch)/applypatch 
        $(call intermediates-dir-for,EXECUTABLES,applypatch_static)/applypatch_static 
        $(call intermediates-dir-for,EXECUTABLES,check_prereq)/check_prereq 
        $(call intermediates-dir-for,EXECUTABLES,sqlite3)/sqlite3 
        $(call intermediates-dir-for,EXECUTABLES,updater)/updater
    
    $(BUILT_TARGET_FILES_PACKAGE): PRIVATE_OTA_TOOLS := $(built_ota_tools)
    $(BUILT_TARGET_FILES_PACKAGE): PRIVATE_RECOVERY_API_VERSION := $(RECOVERY_API_VERSION)
    $(BUILT_TARGET_FILES_PACKAGE): PRIVATE_RECOVERY_FSTAB_VERSION := $(RECOVERY_FSTAB_VERSION)
    
    # 開始构建中间zip包
    $(BUILT_TARGET_FILES_PACKAGE): 
            $(INSTALLED_BOOTIMAGE_TARGET) 
            $(INSTALLED_RADIOIMAGE_TARGET) 
            $(INSTALLED_RECOVERYIMAGE_TARGET) 
            $(INSTALLED_SYSTEMIMAGE) 
            $(INSTALLED_USERDATAIMAGE_TARGET) 
            $(INSTALLED_CACHEIMAGE_TARGET) 
            $(INSTALLED_VENDORIMAGE_TARGET) 
            $(INSTALLED_ANDROID_INFO_TXT_TARGET) 
            $(SELINUX_FC) 
            $(built_ota_tools) 
            $(APKCERTS_FILE) 
            $(HOST_OUT_EXECUTABLES)/fs_config 
            | $(ACP)
        @echo "Package target files: $@"
        # 删除之前的zip文件
        $(hide) rm -rf $@ $(zip_root)
        $(hide) mkdir -p $(dir $@) $(zip_root)
        @# Components of the recovery image
        $(hide) mkdir -p $(zip_root)/RECOVERY
        $(hide) $(call package_files-copy-root, 
            $(TARGET_RECOVERY_ROOT_OUT),$(zip_root)/RECOVERY/RAMDISK)
    ifdef INSTALLED_KERNEL_TARGET
        $(hide) $(INSTALLED_KERNEL_TARGET) $(zip_root)/RECOVERY/kernel
    endif
    ifdef INSTALLED_2NDBOOTLOADER_TARGET
        $(hide) $(ACP) 
            $(INSTALLED_2NDBOOTLOADER_TARGET) $(zip_root)/RECOVERY/second
    endif
    ifdef BOARD_KERNEL_CMDLINE
        $(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/RECOVERY/cmdline
    endif
    ifdef BOARD_KERNEL_PAGESIZE
        $(hide) echo "$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/RECOVERY/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
       $(hide) $(ACP) $(APKCERTS_FILE) $(zip_root)/META/apkcerts.txt
       # 向otakeys.txt文件里写入各种信息
       $(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
       $(hide) echo "fstab_version=$(PRIVATE_RECOVERY_FSTAB_VERSION)" >> $(zip_root)/META/misc_info.txt
    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
        $(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 "update_rename_support=1" >> $(zip_root)/META/misc_info.txt
        $(call generate-userimage-prop-dictionary, $(zip_root)/META/misc_info.txt)
    
        # 打包zip包
        $(hide) (cd $(zip_root) && zip -qry ../$(notdir $@) .)
        $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="SYSTEM/" } /^SYSTEM// {print "system/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/filesystem_config.txt
        $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT/RAMDISK// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -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 -S $(SELINUX_FC) > $(zip_root)/META/recovery_filesystem_config.txt
        $(hide) (cd $(zip_root) && zip -q ../$(notdir $@) META/*filesystem_config.txt)
    
    .PHONY: target-files-package
    target-files-package: $(BUILT_TARGET_FILES_PACKAGE)

    不知道大家第一次看到这段代码,第一感觉怎样。会不会认为非常难理解?
    反正,我学习Android Build系统的makefile源代码时候,都感觉非常晕、非常绕、非常难入手。毕竟我之前是写解释型语言的。这里给大家介绍两个经验:

    • 坚持的去看,坚持总是没错的。
    • 用warning和error去打log。去跟踪。

    接下来,我进一步解释一下上面这块目标(target-files-package)主要实现了哪些功能:

    1. 创建$(zip_root)根文件夹,接下来都是基于zip_root文件夹进行其他文件夹的创建。
    2. 创建并填充RECOVERY文件夹。包含:kernel镜像文件、RAMDISK文件夹。此文件夹终于用来生成recovery.img。

    3. 创建并填充BOOT文件夹,包含:kernel镜像文件、RAMDISK文件夹、ramdisk镜像。此文件夹终于用来生成boot.img。
    4. 填充SYSTEM文件夹。
    5. 创建并填充OTA/bin文件夹。
    6. 创建META文件夹并向该文件夹下加入一些文本文件。
    7. 最后将文件夹打包成zip包。

    ota_from_target_files

    上面的make系统仅仅是生成了target-files-package这个暂时目标文件。而终于Recovery系统能使用的zip包还须要经过ota_from_target_files脚本处理。
    ota_from_target_files脚本还是非常强大的。能够生成:

    1. OTA全量包。
    2. OTA增量包。

    这里我们仅仅介绍OTA全量包的生成过程。

    在最初的otapackage的make源代码中,我们已经看到。终于是会调用ota_from_target_files脚本的。而且还有必要的參数传递,这里给出演示样例的參数例如以下:

    ['-v', '-p', 'out/host/linux-x86', '-k', 'build/target/product/security/testkey', 'out/target/product/xxx/obj/PACKAGING/target_files_intermediates/product-target_files-wangzhengyi.zip', 'out/target/product/xxx/product_20150724.1246-ota.zip']

    參数作用:

    • -v : verbose标识,有这个标识在ota生成过程中会打印出很多其他的运行信息。

    • -p : 定义脚本中用到的可运行文件的路径。
    • -k : 签名时所用的密钥。防止ota升级包的内容被篡改。

    跟OTA增量升级相关的源代码例如以下(为了理清逻辑关系。我的代码顺序和声明顺序正好是反过来的):

    if __name__ == '__main__':
        try:
            main(sys.argv[1:])
        except common.ExternalError, e:
            print
            print "    ERROR: %s" % (e,)
            print
            sys.exit(1)
    
    def main(argv):
        # 调用getprop.getprop处理我们传入的參数,这里省略处理參数代码
        # 处理參数主要是为了给OPTIONS对象赋值
        # 以上面的传入參数为例,处理之后,OPTIONS对象的成员属性赋值例如以下:
        # OPTIONS.package_key = build/target/product/security/testkey
        # OPTIONS.verbose = True
        # OPTIONS.search_path = out/host/linux-x86
    
        if len(args) != 2:
            # args是getprop.getprop无法处理的參数
            # 这里的args是['target-files-package', 'final ota zip name']组成的list
            sys.exit(1)
    
        print "unzipping target target-files..."
        # OPTIONS.input_tmp保存解压文件夹名称
        # input_zip为依据target-files-package生成的zipfile对象
        OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
        OPTIONS.target_tmp = OPTIONS.input_tmp
    
        # 主要是解析例如以下三个文件,并将文件内容以(k,v)键值对形式保存到OPTIONS.info_dict中
        # 三个文件各自是:
        # 1. META/misc_info.txt
        # 2. SYSTEM/build.prop
        # 3. RECOVERY/RAMDISK/etc/recovery.fstab
        OPTIONS.info_dict = common.LoadInfoDict(input_zip)
    
        if "selinux_fc" in OPTIONS.info_dict:
            OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
        if OPTIONS.device_specific is None:
            OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
        if OPTIONS.device_specific is not None:
            OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
            print "using device-specific extensions in", OPTIONS.device_specific
    
        temp_zip_file = tempfile.NamedTemporaryFile()
        output_zip = zipfile.ZipFile(temp_zip_file, "w", compression=zipfile.ZIP_DEFLATED)
    
        # 构造全量包时OPTIONS.incremental_source的值为None
        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")
    
        output_zip.close()
        # 对全量包进行防篡改签名,并进行重命名。略微重点分析
        SignOutput(temp_zip_file.name, args[1])
        temp_zip_file.close()
    
        print "done."
    
    
    # common类的UnzipTemp函数源代码
    def UnzipTemp(filename, pattern=None):
        # 创建/tmp文件夹下暂时文件,用于存储target-files-package解压的内容
        tmp = tempfile.mkdtemp(prefix="targetfiles-")
        OPTIONS.tempfiles.append(tmp)
    
        def unzip_to_dir(filename, dirname):
            cmd = ["unzip", "-o", "-q", filename, "-d", dirname]
            p = subprocess.Popen(cmd, stdout = subprocess.PIPE)
            p.communicate()
            if p.returncode != 0:
                raise ExternalError("failed to unzip input target-files")
    
        unzip_to_dir(filename, tmp)
        return tmp, zipfile.ZipFile(filename, "r")
    
    
    # common类的LoadInfoDict函数
    def LoadInfoDict(zip):
        d = {}
        try:
            for line in zip.read("META/misc_info.txt").split("
    "):
                line = line.strip()
                if not line or line.startswith("#"): continue
                k, v = line.split("=", 1)
                d[k] = v
        except KeyError:
            pass
    
        # 解析挂载信息,不上源代码了
        d["fstab"] = LoadRecoveryFSTab(zip, d["fstab_version"])
        d["build.prop"] = LoadBuildProp(zip)
        return d
    
    
    def LoadBuildProp(zip):
        try:
            data = zip.read("SYSTEM/build.prop")
        except KeyError:
            print "Warning: could not find SYSTEM/build.prop in %s" % zip
            data = ""
    
        d = {}
        for line in data.split("
    "):
            line = line.strip()
            if not line or line.startswith("#"): continue
            name, value = line.split("=", 1)
            d[name] = value
        return d
    

    ota_from_target_files生成全量包的代码如上所看到的。一些不必要看的代码我已经省略了。可是还有两处生成全量包的关键函数我这边须要重点分析。


    WriteFullOTAPackage

    这是依据target-files-package生成全量包的关键函数,我们来看一下它的详细实现。有一点须要解释一下,依据我们的演示样例參数,input_zip和output_zip各自是:

    • input_zip:out/target/product/xxx/obj/PACKAGING/target_files_intermediates/product-target_files-wangzhengyi.zip的zipfile对象
    • output_zip:/tmp文件夹下暂时文件的zipfile对象
    def WriteFullOTAPackage(input_zip, output_zip):
        script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
    
        # 从build.prop文件内容中获取属性构建metadata字典
        metadata = {"post-build": GetBuildProp("ro.build.fingerprint", 
                                                OPTIONS.info_dict),
                    "pre-device": GetBuildProp("ro.product.device",
                                                OPTIONS.info_dict),
                    "post-timestamp": GetBuildProp("ro.build.data.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)
    
        # 在updater-script脚本添加时间推断,假设须要升级的版本号晚于当前系统的时间,
        # 则不进行更新
        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)
    
        # 在updater-script脚本中添加产品类型推断
        AppendAssertions(script, OPTIONS.info_dict)
    
        # 在updater-script添加进度显示
        script.ShowProgress(0.5, 0)
    
        # 安全相关。将BOOT/RAMDISK/file_contexts写入到output_zip中 
        if "selinux_fc" in OPTIONS.info_dict:
            WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
    
        # 在updater-script脚本中:
        # 1. 添加system分区格式化代码
        # 2. 添加system分区挂载代码
        # 3. 将recovery文件夹解压到system分区
        # 4. 将system文件夹解压到system分区
        script.FormatPartition("/system")
        script.Mount("/system")
        script.UnpackPackageDir("recovery", "/system")
        script.UnpackPackageDir("system", "/system")
    
        # 将input_zip的system文件夹文件复制到output_zip中,并返回链接文件名称称
        symlinks = CopySystemFiles(input_zip, output_zip)
        script.MakeSymlinks(symlinks)
    
        # 调用mkbootfs、minigzip、mkbootimg构造boot.img和recovery.img
        boot_img = common.GetBootableImage("boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
        recovery_img = common.GetBootableImage("recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
        MakeRecoveryPath(OPTIONS.input_tmp, output_zip, recovery_img, boot_img)
    
        # 在updater-script中设置system文件权限
        Item.Get("system").SetPermissions(script)
    
        # 将boot.img放入output_zip中。并在updater-script中添加写入信息
        common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
        common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
        script.ShowProgress(0.2, 0)
    
        script.ShowProgress(0.2, 10)
        script.WriteRawImage("/boot", "boot.img")
        # updater-script中添加分区卸载信息
        script.UmountAll()
        # 将updater-script和update-binary写入到output_zip
        script.AddToZip(input_zip, output_zip)
        #将metadata信息写入到output_zip的META-INF/com/android/metadata文件里
        WriteMetadata(metadata, output_zip)
    
    
    def CopySystemFiles(input_zip, output_zip=None, substitute=None):
        symlinks = []
    
        for info in input_zip.infolist():
            if info.filename.startswith("SYSTEM/"):
                basefilename = info.filename[7:]
                if IsSymlink(info):
                    #链接文件
                    symlinks.append((input_zip.read(info.filename), "/system/" + basefilename))
                else:
                    info2 = copy.copy(info)
                    fn = info2.filename = "system/" + basefilename
                    if output_zip is not None:
                        data = input_zip.read(info.filename)
                    output_zip.writestr(info2, data)
                    if fn.endswith("/"):
                        Item.Get(fn[:-1], dir=True)
                    else:
                        Item.Get(fn, dir=False)i
    
        symlinks.sort()
        return symlinks
    
    
    def AddToZip(self, input_zip, output_zip, input_path=None):
        common.ZipWriteStr(output_zip, "META-INF/com/google/android/updater-script",
                            "
    ".join(self.script) + "
    ")
        if input_path is None:
            data = input_zip.read("OTA/bin/updater")
        else:
            data = open(os.path.join(input_path, "updater")).read()
        common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary",
                            data, perms=0755)

    代码里凝视写的非常清楚了,大家有一点python基础,应该非常好理解。
    须要注意的是:这里的output_zip是tmp文件夹下的暂时zip文件,那么真正的OTA包是在哪里生成的呢?
    这就须要去看一下SignOutput的源代码了。


    SignOutput

    首先,我们先看一下main函数中对SignOutput的调用:

    SignOutput(temp_zip_file.name, args[1])

    当中:

    • temp_zip_file.name : 就是output_zip对象相应的文件名称称
    • args[1] : 就是终于的OTA zip包的名称

    所以,我们非常easy想到通过签名之后才形成的正式OTA zip包。
    源代码例如以下:

    def SignOutput(temp_zip_name, output_zip_name):
        key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
        pw = key_passwords[OPTIONS.package_key]
    
        common.SignFile(temp_zip_file, output_zip_name, OPTIONS.package_key, pw, whole_file=True)
    
    
    def SignFile(input_name, output_name, key, password, align=None, whole_file=False):
        sign_name = output_name
    
        cmd = [OPTIONS.java_path, "-Xmx2048m", "-jar",
                os.path.join(OPTIONS.search_path, OPTIONS.signapk_path)]
        cmd.extend(OPTIONS.extra_signapk_args)
        if whole_file:
            cmd.append("-w")
        cmd.extend([key + OPTIONS.public_key_suffix,
                    key + OPTIONS.private_key_suffix,
                    input_name, sign_name])
        p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        if password is not None:
            password += "
    "
        p.communicate(password)

    真正的签名运行命令例如以下:

    java -Xmx2048m -jar out/host/linux-x86/framework/signapk.jar -w build/target/product/security/testkey.xxx.pem build/target/product/security/testkey.xxx /tmp/tmpXZiMiN out/target/product/xxx/product_20150724.1246-ota.zip

    总结

    这篇博客主要是总结了运行make otapackage所须要了解的依赖关系和python生成OTA包的脚本原理。


    接下来。我还会总结一篇文章。是从Recovery源代码角度出发,看Recovery是怎样解析OTA zip包。运行升级流程。

  • 相关阅读:
    Wix Burn:如何将32位和64位的安装包制作成一个安装包
    禁止32位安装包运行在64位操作系统上
    图片校验码
    Oracle建表命令
    npm系列
    git使用
    syslog
    hibernate配置enum枚举属性
    httpClient发送post请求
    修改ubuntu系统语言
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7020315.html
Copyright © 2020-2023  润新知