Android OTA升级包制作脚本详解(二,解压缩)

第一步:解压缩(ota_from_target_files)

print "unzipping target target-files…" OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])上面的代码是开始进行解压缩的入口def UnzipTemp(filename, pattern=None): """Unzip the given archive into a temporary directory and return the name. If filename is of the form "foo.zip+bar.zip", unzip foo.zip into a temp dir, then unzip bar.zip into that_dir/BOOTABLE_IMAGES. Returns (tempdir, zipobj) where zipobj is a zipfile.ZipFile (of the main file), open for reading. """ # 该函数用于创建一个临时文件夹,参数指的是临时文件夹的前缀,返回值tmp是临时文件夹的绝对路径,并赋给OPTIONS的tempfiles属性 tmp = tempfile.mkdtemp(prefix="targetfiles-") OPTIONS.tempfiles.append(tmp) def unzip_to_dir(filename, dirname):#这里设置了一个变量名cmd的数组,里面存放的是需要执行的命令和参数,这个命令也就是“unzip -o -q filename -d dirname”cmd = ["unzip", "-o", "-q", filename, "-d", dirname]if pattern is not None:cmd.append(pattern)#这里调用了Run方法p = Run(cmd, stdout=subprocess.PIPE)"""Popen.communicate(input=None)与子进程进行交互。向stdin发送数据,或从stdout和stderr中读取数据。可选参数input指定发送到子进程的参数。Communicate()返回一个元组:(stdoutdata,stderrdata)。注意:如果希望通过进程的stdin向其发送数据,,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。"""p.communicate()if p.returncode != 0:raise ExternalError("failed to unzip input target-files \&;%s\&;" %(filename,)) #match :只从字符串的开始与正则表达式匹配,匹配成功返回所匹配的项,否则返回none; m = re.match(r"^(.*[.]zip)\+(.*[.]zip)$", filename, re.IGNORECASE) #如果这里加上并执行"""print m"""语句的话,结果为"""[target.zip]""" if m:unzip_to_dir(m.group(1), tmp)unzip_to_dir(m.group(2), os.path.join(tmp, "BOOTABLE_IMAGES"))filename = m.group(1) else:#这里执行解压操作,文件名的值为"target.zip",tem的值为"/tmp/targetfiles-fEX9aH",并且调用upzip_to_dir方法来执行解压缩命令unzip_to_dir(filename, tmp) #这里返回临时路径和存储了zipfile内容的变量 # 这里的第二个参数用r表示是读取zip文件,w是创建一个zip文件 return tmp, zipfile.ZipFile(filename, "r")#这里开启新的进程来执行解压缩的命令def Run(args, **kwargs): """Create and return a subprocess.Popen object, printing the command line on the terminal if -v was specified.""" if OPTIONS.verbose:print " running: ", " ".join(args) """这里调用Popen模块开启新的进程用来执行系统命令,这种方式可运用对进程的控制,将返回结果复制给变量,更方便去处理。args的值实际上是一个list,用于指定进程的可执行文件及其参数。""" return subprocess.Popen(args, **kwargs)接着回到main函数中对解压缩返回的结果进行处理

OPTIONS.target_tmp = OPTIONS.input_tmp OPTIONS.info_dict = common.LoadInfoDict(input_zip)第二步,解析target.zip中META/misc_info.txt、imagesizes.txt中的信息,如下图:

这是misc_info.txt中的内容:

recovery_api_version=3fstab_version=2tool_extensions=out/target/product/wt98360/obj/CUSTGEN/config/../commondefault_system_dev_certificate=build/target/product/security/testkeymkbootimg_args=use_set_metadata=1update_rename_support=1fs_type=ext4system_size=1363148800userdata_size=1152385024cache_size=132120576extfs_sparse_flag=-smkyaffs2_extra_flags=-c 2048 -s 64 selinux_fc=out/target/product/wt98360/root/file_contexts

具体代码如下:def LoadInfoDict(zip): """Read and parse the META/misc_info.txt key/value pairs from the input target files and return a dict.""" #定义一个字典变量用于存储处理后的信息 d = {} try:#这里zip.read()方法打开update.zip中的META/misc_info.txt,并按"\n"进行切片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:# ok if misc_info.txt doesn't existpass # backwards compatibility: These values used to be in their own # files. Look for them, in case we're processing an old # target_files zip. if "mkyaffs2_extra_flags" not in d:try:d["mkyaffs2_extra_flags"] = zip.read("META/mkyaffs2-extra-flags.txt").strip()except KeyError:# ok if flags don't existpass if "recovery_api_version" not in d:try:d["recovery_api_version"] = zip.read("META/recovery-api-version.txt").strip()except KeyError:raise ValueError("can't find recovery API version in input target-files") if "tool_extensions" not in d:try:d["tool_extensions"] = zip.read("META/tool-extensions.txt").strip()except KeyError:# ok if extensions don't existpass if "fstab_version" not in d:d["fstab_version"] = "1" try:data = zip.read("META/imagesizes.txt")for line in data.split("\n"):if not line: continuename, value = line.split(" ", 1)if not value: continueif name == "blocksize":d[name] = valueelse:d[name + "_size"] = value except KeyError:pass def makeint(key):if key in d:if d[key].endswith('M'):d[key] = d[key].split("M")[0]d[key] = int(d[key], 0) * 1024 * 1024else:d[key] = int(d[key], 0) makeint("recovery_api_version") makeint("blocksize") makeint("system_size") makeint("userdata_size") makeint("cache_size") makeint("recovery_size") makeint("boot_size") makeint("fstab_version") #wschen 2012-11-07 makeint("custom_size")d["fstab"] = LoadRecoveryFSTab(zip, d["fstab_version"]) d["build.prop"] = LoadBuildProp(zip) return d

上面的代码中,在方法的末尾有分别去解析了分区表和Build属性,那么具体的操作流程,我们下面进行详细的分析

第三步,解析recovery分区信息这里fastab_version的版本是2,因此你在潮湿的风中感受到了平稳的呼吸,多好听啊,

Android OTA升级包制作脚本详解(二,解压缩)

相关文章:

你感兴趣的文章:

标签云: