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

updater-script简介:

updater-script是我们升级时所具体使用到的脚本文件,它主要用以控制升级流程的主要逻辑。具体位置位于更新包中/META-INFO/com/google/android/目录下,在我们制作升级包的时候产生。

updater-script生成:

那么升级脚本updater-script是如何产生的呢,我们来看ota_from_target_file中的一条语句,这个之前有过介绍。

#在/build/tools/releasetools/目录下的模块edify_generator作为一个抽象的脚本生成器,用来生成edify脚本。这里的edify脚本指的就是updater-script-升级安装脚本,它是一个文本文件。而edify是用于从.zip文件中安装CyanogenMod和其它软件的简单脚本语言。edify脚本不一定是用于更新固件。它可以用来替换/添加/删除特定的文件,甚至格式分区。通常情况下,edify脚本运行于用户在恢复模式中选择“刷写zip”时。

script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)

那么updater-script中如何自动一步一步生成每一个脚本指令或者脚本语句呢,这里我们简单举几个例子给大家作为一个参考:

①对比更新包时间戳,只允许升级旧版本

下面这段代码是在ota_from_target_files中的语句

  #下面这段代码我们可以理解为不允许降级,也就是说在脚本中的这段Assert语句,使得update zip包只能用于升级旧版本。
  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)

下面是对应edify_generator模块的中的相关方法:

  def AssertOlderBuild(self, timestamp, timestamp_text):
    """Assert that the build on the device is older (or the same as)
    the given timestamp."""
    self.script.append(
        ('(!less_than_int(%s, getprop("ro.build.date.utc"))) || '
         'abort("Can\'t install this package (%s) over newer '
         'build (" + getprop("ro.build.date") + ").");'
         ) % (timestamp, timestamp_text))

那么我们从上面的代码中可以看到,这里呢在updater-script中追加了这样的一段语句:

'(!less_than_int(%s, getprop("ro.build.date.utc"))) || '
         'abort("Can\'t install this package (%s) over newer '
         'build (" + getprop("ro.build.date") + ").");'
         ) % (timestamp, timestamp_text)

那么实际在脚本中是这样子的,如:

(!less_than_int(1413536309, getprop("ro.build.date.utc"))) || abort("Can't install this package (Fri Oct 17 16:58:29 CST 2014) over newer build (" + getprop("ro.build.date") + ").");

那么这段话我们在执行updater-script脚本的时候具体逻辑是指当更新包中版本低于当前手机中的版本时终止安装更新。那么在安装的时候具体如何操作的呢,我们随后再详细描述。

②显示进度

  #在升级脚本中生成显示进度的语句,这里实际上是在脚本中增加了这样一条语句(show_progress) 参数一表示将暂用的时间在总体时间的比例。参数二用于控制显示速度。如show_progress(0.1, 10);show_progress下面的操作可能进行10s,完成后进度条前进0.1(也就是10%)
  script.ShowProgress(0.5, 0)

那么这里调用了edify_generator模块中的ShowProgress(0.05,0):

 def SetProgress(self, frac):
    """Set the position of the progress bar within the chunk defined
    by the most recent ShowProgress call.  'frac' should be in
    [0,1]."""
    self.script.append("set_progress(%f);" % (frac,))

而实际在updater-script中的逻辑如下:

show_progress(0.500000, 0);

③格式化分区

  #如果命令中有参数要求擦除data分区数据,那么在升级脚本中生成格式化分区的语句,分区用挂载点来描述,格式如下:(/data)
  if OPTIONS.wipe_user_data:
    script.FormatPartition("/data")

那么这里调用了edify_generator模块中的FormatPartition()函数:

  def FormatPartition(self, partition):
    """Format the given partition, specified by its mount point (eg,
    "/system")."""

    reserve_size = 0
    fstab = self.info.get("fstab", None)

    #wschen 2012-11-12
    if partition == "/custom":
      self.script.append('format("ext4", "EMMC", "/dev/block/mmcblk", "0", "/custom");')

    elif fstab:
      p = fstab[partition]
      self.script.append('format("%s", "%s", "%s", "%s", "%s");' %
                         (p.fs_type, common.PARTITION_TYPES[p.fs_type],
                          p.device, p.length, p.mount_point))

④挂载分区

script.Mount("/system")

那么这里调用了edify_generator模块中的Mount()函数:

  def Mount(self, mount_point):
    """Mount the partition with the given mount_point."""
	#根据指定的挂载点挂载分区
    fstab = self.info.get("fstab", None)

    #wschen 2012-11-12
	#这里挂载定制分区custom,暂不作详细描述,随后会针对升级定制分区进行一个详细的介绍
    if mount_point == "/custom":
      self.script.append('mount("ext4", "EMMC", "/dev/block/mmcblk", "/custom");')
      self.mounts.add(mount_point)

    elif fstab:
      p = fstab[mount_point]
      self.script.append('mount("%s", "%s", "%s", "%s");' %
                         (p.fs_type, common.PARTITION_TYPES[p.fs_type],
                          p.device, p.mount_point))
      self.mounts.add(p.mount_point)

⑤释放文件夹内容到指定文件夹下,注意这里被释放的文件夹是指在OTA package中也就是更新包中的对应的文件夹,也就是下面函数中的第一个参数

    script.UnpackPackageDir("recovery", "/system")
    script.UnpackPackageDir("system", "/system")

那么这里调用了edify_generator模块中的UnpackPackageDir()函数

  def UnpackPackageDir(self, src, dst):
    """Unpack a given directory from the OTA package into the given
    destination directory."""
    self.script.append('package_extract_dir("%s", "%s");' % (src, dst))

⑥建立符号链接

symlinks = CopySystemFiles(input_zip, output_zip)
    script.MakeSymlinks(symlinks)

edify_generator模块中相对应的MakeSymlinks()函数

  def MakeSymlinks(self, symlink_list):
    """Create symlinks, given a list of (dest, link) pairs."""
    by_dest = {}
    for d, l in symlink_list:
      by_dest.setdefault(d, []).append(l)

    for dest, links in sorted(by_dest.iteritems()):
      cmd = ('symlink("%s", ' % (dest,) +
             ",\0".join(['"' + i + '"' for i in sorted(links)]) + ");")
      self.script.append(self._WordWrap(cmd))

⑦权限设置

          script.SetPermissions("/"+item.name, item.uid, item.gid,
                                item.mode, item.selabel, item.capabilities)

具体函数如:

  def SetPermissions(self, fn, uid, gid, mode, selabel, capabilities):
    """Set file ownership and permissions."""
    if not self.info.get("use_set_metadata", False):
      self.script.append('set_perm(%d, %d, 0%o, "%s");' % (uid, gid, mode, fn))
    else:
      if capabilities is None: capabilities = "0x0"
      cmd = 'set_metadata("%s", "uid", %d, "gid", %d, "mode", 0%o, '           '"capabilities", %s' % (fn, uid, gid, mode, capabilities)
      if selabel is not None:
        cmd += ', "selabel", "%s"' % ( selabel )
      cmd += ');'
      self.script.append(cmd)

⑧写入分区

  script.WriteRawImage("/boot", "boot.img")

具体相对应函数如下:

  def WriteRawImage(self, mount_point, fn):
    """Write the given package file into the partition for the given
    mount point."""

    fstab = self.info["fstab"]
    if fstab:
      p = fstab[mount_point]
      partition_type = common.PARTITION_TYPES[p.fs_type]
      args = {'device': p.device, 'fn': fn}
      if fn == "boot.img" and p.device == "boot":
        self.script.append(
          ('assert(package_extract_file("%(fn)s", "/tmp/%(fn)s"),\n'
           '       write_raw_image("/tmp/%(fn)s", "bootimg"),\n'
           '       delete("/tmp/%(fn)s"));') % args)

      elif partition_type == "MTD":
        self.script.append(
            'write_raw_image(package_extract_file("%(fn)s"), "%(device)s");'
            % args)
      elif partition_type == "EMMC":
        self.script.append(
            'package_extract_file("%(fn)s", "%(device)s");' % args)
      else:
        raise ValueError("don't know how to write \"%s\" partitions" % (p.fs_type,))

下面贴出updater-script简单语法供大家参考:

1、mount

语法:

mount(type, location, mount_point);这里表示挂载,其中type="MTD" location="<partition>" 挂载yaffs2文件系统分区;

type="vfat" location="/dev/block/<whatever>" 挂载设备。如:mount("MTD", "system", "/system");挂载system分区,设置返回指针"/system”

mount("vfat", "/dev/block/mmcblk1p2", "/system");

挂载/dev/block/mmcblk1p2,返回指针"/system”

2、Unmount

语法:

unmount(mount_point);指mount_point是mount所设置产生的指针。其作用与挂载相对应,卸载分区或设备。此函数与mount配套使用。如;unmount("/system");

卸载/system分区

3、Format

语法:

format(type, location);这里的type="MTD" location=partition(分区),格式化location参数所代表的分区。如:format("MTD", "system");格式化system分区

4、Delete

语法:

delete(<path>);删除path路径下文件,如delete("/data/zipalign.log");删除文件/data/zipalign.log

5、delete_recursive

语法:

delete_recursive(<path>);删除path路径下文件夹;如:delete_recursive("/data/dalvik-cache");删除文件夹/data/dalvik-cache

6、show_progress

语法:

show_progress(<fraction>,<duration>);这个之前介绍过,用于显示进度条,进度条会根据<duration>进行前进<fraction>,如show_progress(0.1, 10);show_progress下面的操作可能进行10s,完成后进度条前进0.1(也就是10%)

7、package_extract_dir

语法:

package_extract_dir(package_path, destination_path);释放文件夹package_path至destination_path如:package_extract_dir("system", "/system");释放ROM包里system文件夹下所有文件和子文件夹至/system

8、package_extract_file

语法:

package_extract_file(package_path, destination_path);这里表示解压package_path文件至destination_path,如package_extract_dir("my.zip", "/system");解压ROM包里的my.zip文件至/system

9、Symlink

语法:

symlink(<target>, <src1>, <src2>,...);表示建立指向target符号链接src1,src2,……;如symlink("toolbox", "/system/bin/ps");建立指向toolbox的符号链接/system/bin/ps

10、set_perm

语法:

set_perm(<uid>, <gid>,<mode>, <path>);表示设置权限,设置<path>文件的用户为uid,用户组为gid,权限为mode;如:set_perm(1002, 1002, 0440, "/system/etc/dbus.conf");设置文件/system/etc/dbus.conf的所有者为1002,所属用户组为1002,权限为:所有者有读权限,所属用户组有读权限,其他无任何权限。

11、set_perm_recursive

语法:

set_perm_recursive(<uid>,<gid>,<dir-mode>,<file-mode>,<path>);表示设置文件夹和文件夹内文件的权限;如:set_perm_recursive(1000, 1000, 0771, 0644, "/data/app");设置/data/app的所有者和所属用户组为1000,app文件夹的权限是:所有者和所属组拥有全部权限,其他有执行权限;app文件夹下的文件权限是:所有者有读写权限,所属组有读权限,其他有读权限。

12、ui_print

语法:

ui_print("str");这里指屏幕打印输出"str";如:ui_print("It‘s ready!");屏幕打印It’s ready!

13、run_program

语法:

run_program(<path>);指运行<path>脚本。如:run_program("/sbin/busybox","mount","/system");

14、write_raw_image

语法:

write_raw_image(<path>, partition);写入<path>至partition分区;如:write_raw_image("/tmp/boot.img", "boot")将yaffs2格式的boot包直接写入boot分区

15、assert

语法:

assert(<sub1>,<sub2>,<sub3>);这里如果执行sub1不返回错误则执行sub2,如果sub2不返回错误则执行sub3以此类推;如:assert(package_extract_file("boot.img", "/tmp/boot.img"),

write_raw_image("/tmp/boot.img", "boot"),

delete("/tmp/boot.img"));执行package_extract_file,如果不返回错误则执行write_raw_image,如果write_raw_image不出错则执行delete[1]

时间: 2024-08-11 05:33:53

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

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 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升级包制作脚本详解(二,解压缩)

第一步:解压缩(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 d

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语法大都做了注

FLASH动作脚本详解

FLASH动作脚本详解 一.FLASH脚本基础入门讲解 二.按钮AS的编写 三.影片剪辑的AS编写 四.动态文本框 五.影片剪辑的拖拽 六.流程控制与循环语句 七.绘图及颜色的AS的编写 八.声音 AS 的编写与控制 九.时间日期的 AS编写 十.点语法以及路径 十一.深入了解时间控制 十二.无条件转移 十三.变量 十四.运算符(一) 十五.变量(二) 十六.影片剪辑的属性 十七.再讲循环语句 十八.影片剪辑处理函数 十九.复制影片剪辑 二十.深入 startDrag()与 stopDrag()

Android基础入门教程——8.3.7 Paint API之—— Xfermode与PorterDuff详解(四)

Android基础入门教程--8.3.7 Paint API之-- Xfermode与PorterDuff详解(四) 标签(空格分隔): Android基础入门教程 本节引言: 上节我们写了关于Xfermode与PorterDuff使用的第一个例子:圆角&圆形图片ImageView的实现, 我们体会到了PorterDuff.Mode.DST_IN给我们带来的好处,本节我们继续来写例子练练手, 还记得Android基础入门教程--8.3.2 绘图类实战示例给大家带来的拔掉美女衣服的实现吗? 当时我

OTA升级包制作工具处理过程分析

http://blog.csdn.net/ly890700/article/details/56048815 Android Recovery(30) 1.概述 OTA升级包制作工具是一个用python实现的命令行工具.工具位于source_root/ \build\tools\releasetools目录下,入口文件是ota_from_target_files.此工具可对编译生成的源或目标软件版本包进行处理,生成最终的OAT完整升级包(默认),或通过参数-i控制,生成OTA增量升级包(差分包)