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

目录

  • 目录
  • 概述
  • make otapackage
  • BUILT_TARGET_FILES_PACKAGE
  • ota_from_target_files
    • WriteFullOTAPackage
    • SignOutput
  • 总结

概述

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: [email protected]"
    $(hide) ./build/tools/releasetools/ota_from_target_files -v     -p $(HOST_OUT)     -k $(KEY_CERT_PAIR)     $(BUILT_TARGET_FILES_PACKAGE) [email protected]

可以看到,$(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: [email protected]"
    # 删除之前的zip文件
    $(hide) rm -rf [email protected] $(zip_root)
    $(hide) mkdir -p $(dir [email protected]) $(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 [email protected]) .)
    $(hide) zipinfo -1 [email protected] | 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 [email protected] | 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 [email protected] | 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 [email protected]) 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("\n"):
            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("\n"):
        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",
                        "\n".join(self.script) + "\n")
    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包的名称

所以,我们很容易想到通过签名之后才形成的正式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 += "\n"
    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包,执行升级流程。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-08 17:43:36

Android Recovery OTA升级(一)—— make otapackage的相关文章

Android OTA升级

1,Build otapackage后system.img没有打包进去? Ota包里面缺失system img,原因是客户修改了prop里面的"ro.product.device" value值. 尝试以下两种方式,ota_from_target_files中不需要设定 cust_dir1 这个值了: a. 修改ota_from_target_files 中的system_path:system_path = os.path.join("out/target/product/

android 更新APN列表OTA升级后开机即生效

更新APN列表OTA升级后需要恢复出厂设置APN更新才有效, 客户需要做升级后开机即生效. 因为,OTA升级更新的是三个区域,boot , recovery, system, APN属于DATA域,OTA升级不会涉及到, 所以,必须reset之后才会更新有效. 所以, 需要修改alps\build\tools\releasetools\ota_from_target_files这个脚本, 在 script.DeleteFiles([i[1] for i in to_create]) script

Android recovery分析(一)---全量升级包的编译流程

一.前言 recovery的最主要功能就是升级,而升级文件就是升级包了,那么升级包时如何编译出来的呢?文就这个问题做个简要的分析. 注:本文中的叙述纯属个人理解,欢迎批评指正. 二.升级包编译命令 1.source build/envsetup.sh 2.lunch (选择合适的配置) 3.make otapackage 注:有些平台可能没有将"recoveryimage"."bootimage"等目标添加为"otapackage"目标的依赖,而

Android recovery分析

Recovery的作用 Android利用Recovery模式,进行恢复出厂设置,全量包OTA升级,增量包升级. 升级一般通过运行升级包中的META-INF/com/google/android/update-script脚本来执行自定义升级,脚本中是一组recovery系统能识别的UI控制,文件系统操作命令,例如write_raw_image(写FLASH分区),copy_dir(复制目录).该包一般被下载至SDCARD和CACHE分区下. 升级中还涉及到包的数字签名,签名方式和普通JAR文件

【转】Android Recovery模式

原文网址:http://leox.iteye.com/blog/975303 (muddogxp 原创,转载请注明) Recovery简介 Android利用Recovery模式,进行恢复出厂设置,OTA升级,patch升级及firmware升级. 升级一般通过运行升级包中的META-INF/com/google/android/update-script脚本来执行自定义升级,脚本中是一组recovery系统能识别的UI控制,文件系统操作命令,例如write_raw_image(写FLASH分区

OTA Updates官方文档(一,OTA 升级)

写在前面: Android设备可以接受和安装基于系统和应用的更新.在设备中有一个特殊recovery分区,在这个分区中有一套特殊的恢复系统可以将下载的更新包进行解压并应用到系统中去. 本节主要描述了更新包的组织架构,并且概述了如何使用更新包打包工具制作系统升级的更新包.OTA 的存在是用来对潜在系统的升级,或者在系统分区安装只读(不可卸载)的应用程序,因此在升级过程中不会影响到用于已经安装到系统中的 应用程序. 本节的内容主要基于Android5.x版本. 一.Android设备布局的设计 通常

关于OTA升级从高版本到低版本升级后,数据库无法降级引起的异常分析

1.问题描述: OTA升级从高版本升级到低版本成功,开机后桌面闹钟图标不见了,且桌面闹钟报错,无法打开应用. 参考log如下: 01-14 20:29:22.290: E/AndroidRuntime(2722): FATAL EXCEPTION: AsyncHandler 01-14 20:29:22.290: E/AndroidRuntime(2722): Process: com.android.deskclock, PID: 2722 01-14 20:29:22.290: E/Andr

OTA升级详解(一)

不积跬步,无以至千里: 不积小流,无以成江海. 出自荀子<劝学篇> 1.概念解释 OTA是何物? 英文解释为 Over The Air,既空中下载的意思,具体指远程无线方式,OTA 技术可以理解为一种远程无线升级技术: FOTA:Firmware OverThe Air/固件空中升级,通过云端为具有连网功能的设备:例如手机.平板电脑.移动互联网设备等提供固件升级服务,手机中的固件升级即可称为 FOTA: 在3G.4G网络普遍的今天,很多时候还是要考虑流量限制,如果步入5G时代,虽然流量已不在是

Android Recovery Ui 分析

Android  recovery和android本质上是两个独立的rootfs, 只是recovery这个rootfs存在的意义就是为android这个rootfs服务,因此被解释为Android系统的一部分. recovery作为一个简单的rootfs, 提供了非常有限的几个功能,只包含了几个简单的库,UI的显示采用的是直接刷framebuffer的形式,作为android framework及app层的码农,对这种形式相对陌生,特抽点时间梳理了一番. 首先,浏览一下reocvery的mai