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=3
fstab_version=2
tool_extensions=out/target/product/wt98360/obj/CUSTGEN/config/../common
default_system_dev_certificate=build/target/product/security/testkey
mkbootimg_args=
use_set_metadata=1
update_rename_support=1
fs_type=ext4
system_size=1363148800
userdata_size=1152385024
cache_size=132120576
extfs_sparse_flag=-s
mkyaffs2_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 exist
    pass

  # 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 exist
      pass

  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 exist
      pass

  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: continue
      name, value = line.split(" ", 1)
      if not value: continue
      if name == "blocksize":
        d[name] = value
      else:
        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 * 1024
      else:
        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,因此

def LoadRecoveryFSTab(zip, fstab_version):

class Partition(object):

pass

try:

data = zip.read("RECOVERY/RAMDISK/etc/recovery.fstab")#当前target.zip中并没有这文件,因此这里暂不作详解

except KeyError:

print "Warning: could not find RECOVERY/RAMDISK/etc/recovery.fstab in %s." % zip

data = ""

if fstab_version == 1:

d = {}

for line in data.split("\n"):

line = line.strip()

if not line or line.startswith("#"): continue

pieces = line.split()

if not (3 <= len(pieces) <= 4):

raise ValueError("malformed recovery.fstab line: \"%s\"" % (line,))

p = Partition()

p.mount_point = pieces[0]

p.fs_type = pieces[1]

p.device = pieces[2]

p.length = 0

options = None

if len(pieces) >= 4:

if pieces[3].startswith("/"):

p.device2 = pieces[3]

if len(pieces) >= 5:

options = pieces[4]

else:

p.device2 = None

options = pieces[3]

else:

p.device2 = None

if options:

options = options.split(",")

for i in options:

if i.startswith("length="):

p.length = int(i[7:])

else:

print "%s: unknown option \"%s\"" % (p.mount_point, i)

d[p.mount_point] = p

elif fstab_version == 2:

d = {}

for line in data.split("\n"):

line = line.strip()

if not line or line.startswith("#"): continue

pieces = line.split()

if len(pieces) != 5:

raise ValueError("malformed recovery.fstab line: \"%s\"" % (line,))

# Ignore entries that are managed by vold

options = pieces[4]

if "voldmanaged=" in options: continue

# It‘s a good line, parse it

p = Partition()

p.device = pieces[0]

p.mount_point = pieces[1]

p.fs_type = pieces[2]

p.device2 = None

p.length = 0

options = options.split(",")

for i in options:

if i.startswith("length="):

p.length = int(i[7:])

else:

# Ignore all unknown options in the unified fstab

continue

d[p.mount_point] = p

else:

raise ValueError("Unknown fstab_version: \"%d\"" % (fstab_version,))

return d

第四步,解析SYSTEM/build.prop属性信息,将解析的属性信息保存为一个数据字典,并返回

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
时间: 2024-10-25 18:39:11

Android OTA升级包制作脚本详解(二,解压缩)的相关文章

Android OTA升级包制作脚本详解(四,生成升级脚本updater-script)

updater-script简介: updater-script是我们升级时所具体使用到的脚本文件,它主要用以控制升级流程的主要逻辑.具体位置位于更新包中/META-INFO/com/google/android/目录下,在我们制作升级包的时候产生. updater-script生成: 那么升级脚本updater-script是如何产生的呢,我们来看ota_from_target_file中的一条语句,这个之前有过介绍. #在/build/tools/releasetools/目录下的模块edi

Android OTA升级包制作脚本详解(五,升级脚本updater-script的执行&lt;1&gt;)

写在前面: 首先当我们执行升级脚本updater-script的时候,就表示我们已经进入了升级安装状态.那么在我们就从实际的安装作为入口开始分析.也就是说我们从install.cpp中的install_package函数开始一步步来分析. 这里主要分析与脚本相关的部分,其他的请参考这位朋友的博文http://blog.chinaunix.net/uid-22028566-id-3533856.html,我也很受启发.这里也借用一张图来帮助流程上的分析. 下面是调用的流程:install_pack

Android OTA升级包制作脚本详解(三,打包)

这是在ota_from_target_files中mian函数中打包的主要流程语句: #抽象一个新的临时文件 temp_zip_file = tempfile.NamedTemporaryFile() #创建一个zip包用来进行打包 output_zip = zipfile.ZipFile(temp_zip_file, "w", compression=zipfile.ZIP_DEFLATED) #判断是差分还是整包 if OPTIONS.incremental_source is N

Android OTA升级包制作脚本详解(一,参数解析)

写在前面: "build/tools/releasetools/ota_from_target_files  -u lk.bin  -n target.zip update.zip"这是制作整包的命令,很显然这里支持lk升级.本系列博文主要对该命令的执行流程及原理进行一个系统的分析,涉及到/build/tools/releasetools/目录下多个模块如ota_from_target_files.common等.由于本人对python了解粗浅,文中所涉及到的python语法大都做了注

android OTA升级包制作

0.签名 java -Xmx2048m -jar out/host/linux-x86/framework/signapk.jar -w build/target/product/security/testkey.x509.pem build/target/product/security/testkey.pk8 这个key是debug模式下自动生成的key 你也可以通过openssl创建自己私有的key OTA打包过程中会自动使用生成的key进行签名,OTA升级包里签名的位置如下 │ [OTA

android OTA升级包制作【转】

本文转载自:http://www.thinksaas.cn/topics/0/445/445670.html 0.签名 java -Xmx2048m -jar out/host/linux-x86/framework/signapk.jar -w build/target/product/security/testkey.x509.pem build/target/product/security/testkey.pk8 这个key是debug模式下自动生成的key 你也可以通过openssl创

Android活动条(actionbar)使用详解(二)

  1.使用ActionBar实现Tab导航 使用ActionBar实现Tab导航的思路是:AcitonBar通常与Fragment结合使用实现Tab导航.ActionBar在顶端生成多个Tab标签,当用户点击某个Tab标签时,系统根据用户点击事件导航指定Tab页面.实现步骤如下: (1)调用ActionBar的setNavigationMode(ActionBar.NAVIGATION_MODE_TABS)方法设置使用Tab导航方式; (2)调用ActionBar的addTab()方法添加多个

Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)

[Android布局学习系列]   1.Android 布局学习之——Layout(布局)详解一   2.Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)   3.Android 布局学习之——LinearLayout的layout_weight属性   4.Android 布局学习之——LinearLayout属性baselineAligned的作用及baseline    Layout Parameters(布局参数): 在XML文件中,我们经常看到类似与lay

Android自定义控件系列八:详解onMeasure()(二)--利用onMeasure测量来实现图片拉伸永不变形,解决屏幕适配问题

上一篇文章详细讲解了一下onMeasure/measure方法在Android自定义控件时的原理和作用,参看博文:Android自定义控件系列七:详解onMeasure()方法中如何测量一个控件尺寸(一),今天就来真正实践一下,让这两个方法大显神威来帮我们搞定图片的屏幕适配问题. 请尊重原创劳动成果,转载请注明出处:http://blog.csdn.net/cyp331203/article/details/45038329,非允许请勿用于商业或盈利用途,违者必究. 使用ImageView会遇到