Advertisement
ruberval

ota

Jul 9th, 2013
120
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 31.04 KB | None | 0 0
  1. #!/usr/bin/env python
  2. #
  3. # Copyright (C) 2008 The Android Open Source Project
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. #      http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16.  
  17. """
  18. Given a target-files zipfile, produces an OTA package that installs
  19. that build.  An incremental OTA is produced if -i is given, otherwise
  20. a full OTA is produced.
  21.  
  22. Usage:  ota_from_target_files [flags] input_target_files output_ota_package
  23.  
  24.  -b  (--board_config)  <file>
  25.      Deprecated.
  26.  
  27.  -k (--package_key) <key> Key to use to sign the package (default is
  28.      the value of default_system_dev_certificate from the input
  29.      target-files's META/misc_info.txt, or
  30.      "build/target/product/security/testkey" if that value is not
  31.      specified).
  32.  
  33.      For incremental OTAs, the default value is based on the source
  34.      target-file, not the target build.
  35.  
  36.  -i  (--incremental_from)  <file>
  37.      Generate an incremental OTA using the given target-files zip as
  38.      the starting build.
  39.  
  40.  -w  (--wipe_user_data)
  41.      Generate an OTA package that will wipe the user data partition
  42.      when installed.
  43.  
  44.  -n  (--no_prereq)
  45.      Omit the timestamp prereq check normally included at the top of
  46.      the build scripts (used for developer OTA packages which
  47.      legitimately need to go back and forth).
  48.  
  49.  -e  (--extra_script)  <file>
  50.      Insert the contents of file at the end of the update script.
  51.  
  52.  -a  (--aslr_mode)  <on|off>
  53.      Specify whether to turn on ASLR for the package (on by default).
  54.  
  55.  --override_device <device>
  56.      Override device-specific asserts. Can be a comma-separated list.
  57.  
  58.  --no_assert <true|false>
  59.      Including this will turn device asserts off.
  60.  
  61.  --backup <boolean>
  62.      Enable or disable the execution of backuptool.sh.
  63.      Disabled by default.
  64.  
  65.  
  66. """
  67.  
  68. import sys
  69.  
  70. if sys.hexversion < 0x02040000:
  71.   print >> sys.stderr, "Python 2.4 or newer is required."
  72.   sys.exit(1)
  73.  
  74. import copy
  75. import errno
  76. import os
  77. import re
  78. import subprocess
  79. import tempfile
  80. import time
  81. import zipfile
  82.  
  83. try:
  84.   from hashlib import sha1 as sha1
  85. except ImportError:
  86.   from sha import sha as sha1
  87.  
  88. import common
  89. import edify_generator
  90.  
  91. OPTIONS = common.OPTIONS
  92. OPTIONS.package_key = None
  93. OPTIONS.incremental_source = None
  94. OPTIONS.require_verbatim = set()
  95. OPTIONS.prohibit_verbatim = set(("system/build.prop",))
  96. OPTIONS.patch_threshold = 0.95
  97. OPTIONS.wipe_user_data = False
  98. OPTIONS.omit_prereq = False
  99. OPTIONS.extra_script = None
  100. OPTIONS.aslr_mode = True
  101. OPTIONS.worker_threads = 3
  102. OPTIONS.override_device = 'auto'
  103. OPTIONS.no_assert = False
  104. OPTIONS.backuptool = False
  105.  
  106. def MostPopularKey(d, default):
  107.   """Given a dict, return the key corresponding to the largest
  108.  value.  Returns 'default' if the dict is empty."""
  109.   x = [(v, k) for (k, v) in d.iteritems()]
  110.   if not x: return default
  111.   x.sort()
  112.   return x[-1][1]
  113.  
  114.  
  115. def IsSymlink(info):
  116.   """Return true if the zipfile.ZipInfo object passed in represents a
  117.  symlink."""
  118.   return (info.external_attr >> 16) & 0770000 == 0120000
  119.  
  120. def IsRegular(info):
  121.   """Return true if the zipfile.ZipInfo object passed in represents a
  122.  symlink."""
  123.   return (info.external_attr >> 28) == 010
  124.  
  125. class Item:
  126.   """Items represent the metadata (user, group, mode) of files and
  127.  directories in the system image."""
  128.   ITEMS = {}
  129.   def __init__(self, name, dir=False):
  130.     self.name = name
  131.     self.uid = None
  132.     self.gid = None
  133.     self.mode = None
  134.     self.dir = dir
  135.  
  136.     if name:
  137.       self.parent = Item.Get(os.path.dirname(name), dir=True)
  138.       self.parent.children.append(self)
  139.     else:
  140.       self.parent = None
  141.     if dir:
  142.       self.children = []
  143.  
  144.   def Dump(self, indent=0):
  145.     if self.uid is not None:
  146.       print "%s%s %d %d %o" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
  147.     else:
  148.       print "%s%s %s %s %s" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
  149.     if self.dir:
  150.       print "%s%s" % ("  "*indent, self.descendants)
  151.       print "%s%s" % ("  "*indent, self.best_subtree)
  152.       for i in self.children:
  153.         i.Dump(indent=indent+1)
  154.  
  155.   @classmethod
  156.   def Get(cls, name, dir=False):
  157.     if name not in cls.ITEMS:
  158.       cls.ITEMS[name] = Item(name, dir=dir)
  159.     return cls.ITEMS[name]
  160.  
  161.   @classmethod
  162.   def GetMetadata(cls, input_zip):
  163.  
  164.     try:
  165.       # See if the target_files contains a record of what the uid,
  166.       # gid, and mode is supposed to be.
  167.       output = input_zip.read("META/filesystem_config.txt")
  168.     except KeyError:
  169.       # Run the external 'fs_config' program to determine the desired
  170.       # uid, gid, and mode for every Item object.  Note this uses the
  171.       # one in the client now, which might not be the same as the one
  172.       # used when this target_files was built.
  173.       p = common.Run(["fs_config"], stdin=subprocess.PIPE,
  174.                      stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  175.       suffix = { False: "", True: "/" }
  176.       input = "".join(["%s%s\n" % (i.name, suffix[i.dir])
  177.                        for i in cls.ITEMS.itervalues() if i.name])
  178.       output, error = p.communicate(input)
  179.       assert not error
  180.  
  181.     for line in output.split("\n"):
  182.       if not line: continue
  183.       name, uid, gid, mode = line.split()
  184.       i = cls.ITEMS.get(name, None)
  185.       if i is not None:
  186.         i.uid = int(uid)
  187.         i.gid = int(gid)
  188.         i.mode = int(mode, 8)
  189.         if i.dir:
  190.           i.children.sort(key=lambda i: i.name)
  191.  
  192.     # set metadata for the files generated by this script.
  193.     i = cls.ITEMS.get("system/recovery-from-boot.p", None)
  194.     if i: i.uid, i.gid, i.mode = 0, 0, 0644
  195.     i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
  196.     if i: i.uid, i.gid, i.mode = 0, 0, 0544
  197.  
  198.   def CountChildMetadata(self):
  199.     """Count up the (uid, gid, mode) tuples for all children and
  200.    determine the best strategy for using set_perm_recursive and
  201.    set_perm to correctly chown/chmod all the files to their desired
  202.    values.  Recursively calls itself for all descendants.
  203.  
  204.    Returns a dict of {(uid, gid, dmode, fmode): count} counting up
  205.    all descendants of this node.  (dmode or fmode may be None.)  Also
  206.    sets the best_subtree of each directory Item to the (uid, gid,
  207.    dmode, fmode) tuple that will match the most descendants of that
  208.    Item.
  209.    """
  210.  
  211.     assert self.dir
  212.     d = self.descendants = {(self.uid, self.gid, self.mode, None): 1}
  213.     for i in self.children:
  214.       if i.dir:
  215.         for k, v in i.CountChildMetadata().iteritems():
  216.           d[k] = d.get(k, 0) + v
  217.       else:
  218.         k = (i.uid, i.gid, None, i.mode)
  219.         d[k] = d.get(k, 0) + 1
  220.  
  221.     # Find the (uid, gid, dmode, fmode) tuple that matches the most
  222.     # descendants.
  223.  
  224.     # First, find the (uid, gid) pair that matches the most
  225.     # descendants.
  226.     ug = {}
  227.     for (uid, gid, _, _), count in d.iteritems():
  228.       ug[(uid, gid)] = ug.get((uid, gid), 0) + count
  229.     ug = MostPopularKey(ug, (0, 0))
  230.  
  231.     # Now find the dmode and fmode that match the most descendants
  232.     # with that (uid, gid), and choose those.
  233.     best_dmode = (0, 0755)
  234.     best_fmode = (0, 0644)
  235.     for k, count in d.iteritems():
  236.       if k[:2] != ug: continue
  237.       if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
  238.       if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
  239.     self.best_subtree = ug + (best_dmode[1], best_fmode[1])
  240.  
  241.     return d
  242.  
  243.   def SetPermissions(self, script):
  244.     """Append set_perm/set_perm_recursive commands to 'script' to
  245.    set all permissions, users, and groups for the tree of files
  246.    rooted at 'self'."""
  247.  
  248.     self.CountChildMetadata()
  249.  
  250.     def recurse(item, current):
  251.       # current is the (uid, gid, dmode, fmode) tuple that the current
  252.       # item (and all its children) have already been set to.  We only
  253.       # need to issue set_perm/set_perm_recursive commands if we're
  254.       # supposed to be something different.
  255.       if item.dir:
  256.         if current != item.best_subtree:
  257.           script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
  258.           current = item.best_subtree
  259.  
  260.         if item.uid != current[0] or item.gid != current[1] or \
  261.            item.mode != current[2]:
  262.           script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
  263.  
  264.         for i in item.children:
  265.           recurse(i, current)
  266.       else:
  267.         if item.uid != current[0] or item.gid != current[1] or \
  268.                item.mode != current[3]:
  269.           script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
  270.  
  271.     recurse(self, (-1, -1, -1, -1))
  272.  
  273.  
  274. def CopySystemFiles(input_zip, output_zip=None,
  275.                     substitute=None):
  276.   """Copies files underneath system/ in the input zip to the output
  277.  zip.  Populates the Item class with their metadata, and returns a
  278.  list of symlinks.  output_zip may be None, in which case the copy is
  279.  skipped (but the other side effects still happen).  substitute is an
  280.  optional dict of {output filename: contents} to be output instead of
  281.  certain input files.
  282.  """
  283.  
  284.   symlinks = []
  285.  
  286.   for info in input_zip.infolist():
  287.     if info.filename.startswith("SYSTEM/"):
  288.       basefilename = info.filename[7:]
  289.       if IsSymlink(info):
  290.         symlinks.append((input_zip.read(info.filename),
  291.                          "/system/" + basefilename))
  292.       else:
  293.         info2 = copy.copy(info)
  294.         fn = info2.filename = "system/" + basefilename
  295.         if substitute and fn in substitute and substitute[fn] is None:
  296.           continue
  297.         if output_zip is not None:
  298.           if substitute and fn in substitute:
  299.             data = substitute[fn]
  300.           else:
  301.             data = input_zip.read(info.filename)
  302.           output_zip.writestr(info2, data)
  303.         if fn.endswith("/"):
  304.           Item.Get(fn[:-1], dir=True)
  305.         else:
  306.           Item.Get(fn, dir=False)
  307.  
  308.   symlinks.sort()
  309.   return symlinks
  310.  
  311.  
  312. def SignOutput(temp_zip_name, output_zip_name):
  313.   key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
  314.   pw = key_passwords[OPTIONS.package_key]
  315.  
  316.   common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
  317.                   whole_file=True)
  318.  
  319.  
  320. def AppendAssertions(script, info_dict):
  321.   if OPTIONS.override_device == "auto":
  322.     device = GetBuildProp("ro.product.device", info_dict)
  323.   else:
  324.     device = OPTIONS.override_device
  325.   script.AssertDevice(device)
  326.  
  327.  
  328. def MakeRecoveryPatch(input_tmp, output_zip, recovery_img, boot_img):
  329.   """Generate a binary patch that creates the recovery image starting
  330.  with the boot image.  (Most of the space in these images is just the
  331.  kernel, which is identical for the two, so the resulting patch
  332.  should be efficient.)  Add it to the output zip, along with a shell
  333.  script that is run from init.rc on first boot to actually do the
  334.  patching and install the new recovery image.
  335.  
  336.  recovery_img and boot_img should be File objects for the
  337.  corresponding images.  info should be the dictionary returned by
  338.  common.LoadInfoDict() on the input target_files.
  339.  
  340.  Returns an Item for the shell script, which must be made
  341.  executable.
  342.  """
  343.  
  344.   diff_program = ["imgdiff"]
  345.   path = os.path.join(input_tmp, "SYSTEM", "etc", "recovery-resource.dat")
  346.   if os.path.exists(path):
  347.     diff_program.append("-b")
  348.     diff_program.append(path)
  349.     bonus_args = "-b /system/etc/recovery-resource.dat"
  350.   else:
  351.     bonus_args = ""
  352.  
  353.   d = common.Difference(recovery_img, boot_img, diff_program=diff_program)
  354.   _, _, patch = d.ComputePatch()
  355.   common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
  356.   Item.Get("system/recovery-from-boot.p", dir=False)
  357.  
  358.   boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
  359.   recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)
  360.  
  361.   sh = """#!/system/bin/sh
  362. if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
  363.  log -t recovery "Installing new recovery image"
  364.  applypatch %(bonus_args)s %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p
  365. else
  366.  log -t recovery "Recovery image already installed"
  367. fi
  368. """ % { 'boot_size': boot_img.size,
  369.         'boot_sha1': boot_img.sha1,
  370.         'recovery_size': recovery_img.size,
  371.         'recovery_sha1': recovery_img.sha1,
  372.         'boot_type': boot_type,
  373.         'boot_device': boot_device,
  374.         'recovery_type': recovery_type,
  375.         'recovery_device': recovery_device,
  376.         'bonus_args': bonus_args,
  377.         }
  378.   common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
  379.   return Item.Get("system/etc/install-recovery.sh", dir=False)
  380.  
  381.  
  382. def WriteFullOTAPackage(input_zip, output_zip):
  383.   # TODO: how to determine this?  We don't know what version it will
  384.   # be installed on top of.  For now, we expect the API just won't
  385.   # change very often.
  386.   script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
  387.  
  388.   metadata = {"post-build": GetBuildProp("ro.build.fingerprint",
  389.                                          OPTIONS.info_dict),
  390.               "pre-device": GetBuildProp("ro.product.device",
  391.                                          OPTIONS.info_dict),
  392.               "post-timestamp": GetBuildProp("ro.build.date.utc",
  393.                                              OPTIONS.info_dict),
  394.               }
  395.  
  396.   device_specific = common.DeviceSpecificParams(
  397.       input_zip=input_zip,
  398.       input_version=OPTIONS.info_dict["recovery_api_version"],
  399.       output_zip=output_zip,
  400.       script=script,
  401.       input_tmp=OPTIONS.input_tmp,
  402.       metadata=metadata,
  403.       info_dict=OPTIONS.info_dict)
  404.  
  405.   if not OPTIONS.no_assert:
  406.     #AppendAssertions(script, OPTIONS.info_dict)
  407.     device_specific.FullOTA_Assertions()
  408.  
  409.   device_specific.FullOTA_InstallBegin()
  410.  
  411.   if OPTIONS.backuptool:
  412.     script.Mount("/system")
  413.     script.RunBackup("backup")
  414.     script.Unmount("/system")
  415.  
  416.   script.ShowProgress(0.5, 0)
  417.  
  418.   if OPTIONS.wipe_user_data:
  419.     script.FormatPartition("/data")
  420.  
  421.   script.Print("              Bem Vindos                     ");
  422.   script.Print("              Bienvenido                     ");
  423.   script.Print("                WelCome                      ");
  424.   script.Print("              Sky Night                      ");
  425.   script.Print("          www.luandroid.com.br               ");
  426.   script.Print("            Team Lu4ndr01d                   ");
  427.  
  428.   script.Print("Deletando sistema...")
  429.  
  430.   if "selinux_fc" in OPTIONS.info_dict:
  431.     WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
  432.  
  433.   script.FormatPartition("/system")
  434.   script.Print("Montando sistema...")
  435.   script.Mount("/system")
  436.   script.ShowProgress(0.5, 40)
  437.   script.Print("Instalando Sistema...")
  438.   script.UnpackPackageDir("system", "/system")
  439.   script.Print("Criando Symlinks...")
  440.  
  441.  
  442.   symlinks = CopySystemFiles(input_zip, output_zip)
  443.   script.MakeSymlinks(symlinks)
  444.  
  445.   boot_img = common.GetBootableImage("boot.img", "boot.img",
  446.                                      OPTIONS.input_tmp, "BOOT")
  447.  
  448.   Item.GetMetadata(input_zip)
  449.   Item.Get("system").SetPermissions(script)
  450.  
  451.   common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
  452.   common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
  453.   script.ShowProgress(0.2, 0)
  454.  
  455.   if OPTIONS.backuptool:
  456.     script.ShowProgress(0.2, 10)
  457.     script.RunBackup("restore")
  458.  
  459.   script.ShowProgress(0.2, 10)
  460.   script.WriteRawImage("/boot", "boot.img")
  461.  
  462.   script.ShowProgress(0.1, 0)
  463.   script.Print("Instalacao Completada com sucesso!")
  464.   device_specific.FullOTA_InstallEnd()
  465.  
  466.   if OPTIONS.extra_script is not None:
  467.     script.AppendExtra(OPTIONS.extra_script)
  468.  
  469.   script.UnmountAll()
  470.   script.AddToZip(input_zip, output_zip)
  471.   WriteMetadata(metadata, output_zip)
  472.  
  473. def WritePolicyConfig(file_context, output_zip):
  474.   f = open(file_context, 'r');
  475.   basename = os.path.basename(file_context)
  476.   common.ZipWriteStr(output_zip, basename, f.read())
  477.  
  478.  
  479. def WriteMetadata(metadata, output_zip):
  480.   common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
  481.                      "".join(["%s=%s\n" % kv
  482.                               for kv in sorted(metadata.iteritems())]))
  483.  
  484. def LoadSystemFiles(z):
  485.   """Load all the files from SYSTEM/... in a given target-files
  486.  ZipFile, and return a dict of {filename: File object}."""
  487.   out = {}
  488.   for info in z.infolist():
  489.     if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
  490.       basefilename = info.filename[7:]
  491.       fn = "system/" + basefilename
  492.       data = z.read(info.filename)
  493.       out[fn] = common.File(fn, data)
  494.   return out
  495.  
  496.  
  497. def GetBuildProp(prop, info_dict):
  498.   """Return the fingerprint of the build of a given target-files info_dict."""
  499.   try:
  500.     return info_dict.get("build.prop", {})[prop]
  501.   except KeyError:
  502.     raise common.ExternalError("couldn't find %s in build.prop" % (property,))
  503.  
  504.  
  505. def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
  506.   source_version = OPTIONS.source_info_dict["recovery_api_version"]
  507.   target_version = OPTIONS.target_info_dict["recovery_api_version"]
  508.  
  509.   if source_version == 0:
  510.     print ("WARNING: generating edify script for a source that "
  511.            "can't install it.")
  512.   script = edify_generator.EdifyGenerator(source_version,
  513.                                           OPTIONS.target_info_dict)
  514.  
  515.   metadata = {"pre-device": GetBuildProp("ro.product.device",
  516.                                          OPTIONS.source_info_dict),
  517.               "post-timestamp": GetBuildProp("ro.build.date.utc",
  518.                                              OPTIONS.target_info_dict),
  519.               }
  520.  
  521.   device_specific = common.DeviceSpecificParams(
  522.       source_zip=source_zip,
  523.       source_version=source_version,
  524.       target_zip=target_zip,
  525.       target_version=target_version,
  526.       output_zip=output_zip,
  527.       script=script,
  528.       metadata=metadata,
  529.       info_dict=OPTIONS.info_dict)
  530.  
  531.   print "Loading target..."
  532.   target_data = LoadSystemFiles(target_zip)
  533.   print "Loading source..."
  534.   source_data = LoadSystemFiles(source_zip)
  535.  
  536.   verbatim_targets = []
  537.   patch_list = []
  538.   diffs = []
  539.   largest_source_size = 0
  540.   for fn in sorted(target_data.keys()):
  541.     tf = target_data[fn]
  542.     assert fn == tf.name
  543.     sf = source_data.get(fn, None)
  544.  
  545.     if sf is None or fn in OPTIONS.require_verbatim:
  546.       # This file should be included verbatim
  547.       if fn in OPTIONS.prohibit_verbatim:
  548.         raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
  549.       print "send", fn, "verbatim"
  550.       tf.AddToZip(output_zip)
  551.       verbatim_targets.append((fn, tf.size))
  552.     elif tf.sha1 != sf.sha1:
  553.       # File is different; consider sending as a patch
  554.       diffs.append(common.Difference(tf, sf))
  555.     else:
  556.       # Target file identical to source.
  557.       pass
  558.  
  559.   common.ComputeDifferences(diffs)
  560.  
  561.   for diff in diffs:
  562.     tf, sf, d = diff.GetPatch()
  563.     if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
  564.       # patch is almost as big as the file; don't bother patching
  565.       tf.AddToZip(output_zip)
  566.       verbatim_targets.append((tf.name, tf.size))
  567.     else:
  568.       common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d)
  569.       patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))
  570.       largest_source_size = max(largest_source_size, sf.size)
  571.  
  572.   source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
  573.   target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
  574.   metadata["pre-build"] = source_fp
  575.   metadata["post-build"] = target_fp
  576.  
  577.   script.Mount("/system")
  578.   script.AssertSomeFingerprint(source_fp, target_fp)
  579.  
  580.   source_boot = common.GetBootableImage(
  581.       "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
  582.       OPTIONS.source_info_dict)
  583.   target_boot = common.GetBootableImage(
  584.       "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
  585.   updating_boot = (source_boot.data != target_boot.data)
  586.  
  587.   updating_recovery = False
  588.  
  589.   # Here's how we divide up the progress bar:
  590.   #  0.1 for verifying the start state (PatchCheck calls)
  591.   #  0.8 for applying patches (ApplyPatch calls)
  592.   #  0.1 for unpacking verbatim files, symlinking, and doing the
  593.   #      device-specific commands.
  594.  
  595.   if OPTIONS.no_assert:
  596.     AppendAssertions(script, OPTIONS.target_info_dict)
  597.   device_specific.IncrementalOTA_Assertions()
  598.  
  599.   script.Print("Verifying current system...")
  600.  
  601.   device_specific.IncrementalOTA_VerifyBegin()
  602.  
  603.   script.ShowProgress(0.1, 0)
  604.   total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
  605.   if updating_boot:
  606.     total_verify_size += source_boot.size
  607.   so_far = 0
  608.  
  609.   for fn, tf, sf, size, patch_sha in patch_list:
  610.     script.PatchCheck("/"+fn, tf.sha1, sf.sha1)
  611.     so_far += sf.size
  612.     script.SetProgress(so_far / total_verify_size)
  613.  
  614.   if updating_boot:
  615.     d = common.Difference(target_boot, source_boot)
  616.     _, _, d = d.ComputePatch()
  617.     print "boot      target: %d  source: %d  diff: %d" % (
  618.         target_boot.size, source_boot.size, len(d))
  619.  
  620.     common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
  621.  
  622.     boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
  623.  
  624.     script.PatchCheck("%s:%s:%d:%s:%d:%s" %
  625.                       (boot_type, boot_device,
  626.                        source_boot.size, source_boot.sha1,
  627.                        target_boot.size, target_boot.sha1))
  628.     so_far += source_boot.size
  629.     script.SetProgress(so_far / total_verify_size)
  630.  
  631.   if patch_list or updating_recovery or updating_boot:
  632.     script.CacheFreeSpaceCheck(largest_source_size)
  633.  
  634.   device_specific.IncrementalOTA_VerifyEnd()
  635.  
  636.   script.Comment("---- start making changes here ----")
  637.  
  638.   device_specific.IncrementalOTA_InstallBegin()
  639.  
  640.   if OPTIONS.wipe_user_data:
  641.     script.Print("Erasing user data...")
  642.     script.FormatPartition("/data")
  643.  
  644.   script.Print("Removing unneeded files...")
  645.   script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
  646.                      ["/"+i for i in sorted(source_data)
  647.                             if i not in target_data] +
  648.                      ["/system/recovery.img"])
  649.  
  650.   script.ShowProgress(0.8, 0)
  651.   total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
  652.   if updating_boot:
  653.     total_patch_size += target_boot.size
  654.   so_far = 0
  655.  
  656.   script.Print("Patching system files...")
  657.   deferred_patch_list = []
  658.   for item in patch_list:
  659.     fn, tf, sf, size, _ = item
  660.     if tf.name == "system/build.prop":
  661.       deferred_patch_list.append(item)
  662.       continue
  663.     script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
  664.     so_far += tf.size
  665.     script.SetProgress(so_far / total_patch_size)
  666.  
  667.   if updating_boot:
  668.     # Produce the boot image by applying a patch to the current
  669.     # contents of the boot partition, and write it back to the
  670.     # partition.
  671.     script.Print("Patching boot image...")
  672.     script.ApplyPatch("%s:%s:%d:%s:%d:%s"
  673.                       % (boot_type, boot_device,
  674.                          source_boot.size, source_boot.sha1,
  675.                          target_boot.size, target_boot.sha1),
  676.                       "-",
  677.                       target_boot.size, target_boot.sha1,
  678.                       source_boot.sha1, "patch/boot.img.p")
  679.     so_far += target_boot.size
  680.     script.SetProgress(so_far / total_patch_size)
  681.     print "boot image changed; including."
  682.   else:
  683.     print "boot image unchanged; skipping."
  684.  
  685.   if updating_recovery:
  686.     # Recovery is generated as a patch using both the boot image
  687.     # (which contains the same linux kernel as recovery) and the file
  688.     # /system/etc/recovery-resource.dat (which contains all the images
  689.     # used in the recovery UI) as sources.  This lets us minimize the
  690.     # size of the patch, which must be included in every OTA package.
  691.     #
  692.     # For older builds where recovery-resource.dat is not present, we
  693.     # use only the boot image as the source.
  694.  
  695.     MakeRecoveryPatch(OPTIONS.target_tmp, output_zip,
  696.                       target_recovery, target_boot)
  697.     script.DeleteFiles(["/system/recovery-from-boot.p",
  698.                         "/system/etc/install-recovery.sh"])
  699.     print "recovery image changed; including as patch from boot."
  700.   else:
  701.     print "recovery image unchanged; skipping."
  702.  
  703.   script.ShowProgress(0.1, 10)
  704.  
  705.   target_symlinks = CopySystemFiles(target_zip, None)
  706.  
  707.   target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
  708.   temp_script = script.MakeTemporary()
  709.   Item.GetMetadata(target_zip)
  710.   Item.Get("system").SetPermissions(temp_script)
  711.  
  712.   # Note that this call will mess up the tree of Items, so make sure
  713.   # we're done with it.
  714.   source_symlinks = CopySystemFiles(source_zip, None)
  715.   source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
  716.  
  717.   # Delete all the symlinks in source that aren't in target.  This
  718.   # needs to happen before verbatim files are unpacked, in case a
  719.   # symlink in the source is replaced by a real file in the target.
  720.   to_delete = []
  721.   for dest, link in source_symlinks:
  722.     if link not in target_symlinks_d:
  723.       to_delete.append(link)
  724.   script.DeleteFiles(to_delete)
  725.  
  726.   if verbatim_targets:
  727.     script.Print("Unpacking new files...")
  728.     script.UnpackPackageDir("system", "/system")
  729.  
  730.   script.Print("Symlinks and permissions...")
  731.  
  732.   # Create all the symlinks that don't already exist, or point to
  733.   # somewhere different than what we want.  Delete each symlink before
  734.   # creating it, since the 'symlink' command won't overwrite.
  735.   to_create = []
  736.   for dest, link in target_symlinks:
  737.     if link in source_symlinks_d:
  738.       if dest != source_symlinks_d[link]:
  739.         to_create.append((dest, link))
  740.     else:
  741.       to_create.append((dest, link))
  742.   script.DeleteFiles([i[1] for i in to_create])
  743.   script.MakeSymlinks(to_create)
  744.  
  745.   # Now that the symlinks are created, we can set all the
  746.   # permissions.
  747.   script.AppendScript(temp_script)
  748.  
  749.   # Do device-specific installation (eg, write radio image).
  750.   device_specific.IncrementalOTA_InstallEnd()
  751.  
  752.   if OPTIONS.extra_script is not None:
  753.     script.AppendExtra(OPTIONS.extra_script)
  754.  
  755.   # Patch the build.prop file last, so if something fails but the
  756.   # device can still come up, it appears to be the old build and will
  757.   # get set the OTA package again to retry.
  758.   script.Print("Patching remaining system files...")
  759.   for item in deferred_patch_list:
  760.     fn, tf, sf, size, _ = item
  761.     script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
  762.   script.SetPermissions("/system/build.prop", 0, 0, 0644)
  763.  
  764.   script.AddToZip(target_zip, output_zip)
  765.   WriteMetadata(metadata, output_zip)
  766.  
  767.  
  768. def main(argv):
  769.  
  770.   def option_handler(o, a):
  771.     if o in ("-b", "--board_config"):
  772.       pass   # deprecated
  773.     elif o in ("-k", "--package_key"):
  774.       OPTIONS.package_key = a
  775.     elif o in ("-i", "--incremental_from"):
  776.       OPTIONS.incremental_source = a
  777.     elif o in ("-w", "--wipe_user_data"):
  778.       OPTIONS.wipe_user_data = True
  779.     elif o in ("-n", "--no_prereq"):
  780.       OPTIONS.omit_prereq = True
  781.     elif o in ("-e", "--extra_script"):
  782.       OPTIONS.extra_script = a
  783.     elif o in ("--no_assert"):
  784.       if a in ("on", "On", "true", "True", "yes", "Yes"):
  785.         OPTIONS.no_assert = True
  786.       else:
  787.         OPTIONS.no_assert = False
  788.     elif o in ("-a", "--aslr_mode"):
  789.       if a in ("on", "On", "true", "True", "yes", "Yes"):
  790.         OPTIONS.aslr_mode = True
  791.       else:
  792.         OPTIONS.aslr_mode = False
  793.     elif o in ("--override_device"):
  794.       OPTIONS.override_device = a
  795.     elif o in ("--worker_threads"):
  796.       OPTIONS.worker_threads = int(a)
  797.     elif o in ("--backup"):
  798.       OPTIONS.backuptool = bool(a.lower() == 'true')
  799.     else:
  800.       return False
  801.     return True
  802.  
  803.   args = common.ParseOptions(argv, __doc__,
  804.                              extra_opts="b:k:i:d:wne:a:",
  805.                              extra_long_opts=["board_config=",
  806.                                               "package_key=",
  807.                                               "no_assert=",
  808.                                               "incremental_from=",
  809.                                               "wipe_user_data",
  810.                                               "no_prereq",
  811.                                               "extra_script=",
  812.                                               "worker_threads=",
  813.                                               "aslr_mode=",
  814.                                               "override_device=",
  815.                                               "backup=",
  816.                                               ],
  817.                              extra_option_handler=option_handler)
  818.  
  819.   if len(args) != 2:
  820.     common.Usage(__doc__)
  821.     sys.exit(1)
  822.  
  823.   if OPTIONS.extra_script is not None:
  824.     OPTIONS.extra_script = open(OPTIONS.extra_script).read()
  825.  
  826.   print "unzipping target target-files..."
  827.   OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
  828.  
  829.   OPTIONS.target_tmp = OPTIONS.input_tmp
  830.   OPTIONS.info_dict = common.LoadInfoDict(input_zip)
  831.   if OPTIONS.verbose:
  832.     print "--- target info ---"
  833.     common.DumpInfoDict(OPTIONS.info_dict)
  834.  
  835.   if OPTIONS.device_specific is None:
  836.     OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
  837.   if OPTIONS.device_specific is not None:
  838.     OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
  839.     print "using device-specific extensions in", OPTIONS.device_specific
  840.  
  841.   temp_zip_file = tempfile.NamedTemporaryFile()
  842.   output_zip = zipfile.ZipFile(temp_zip_file, "w",
  843.                                compression=zipfile.ZIP_DEFLATED)
  844.  
  845.   if OPTIONS.incremental_source is None:
  846.     WriteFullOTAPackage(input_zip, output_zip)
  847.     if OPTIONS.package_key is None:
  848.       OPTIONS.package_key = OPTIONS.info_dict.get(
  849.           "default_system_dev_certificate",
  850.           "build/target/product/security/testkey")
  851.   else:
  852.     print "unzipping source target-files..."
  853.     OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
  854.     OPTIONS.target_info_dict = OPTIONS.info_dict
  855.     OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
  856.     if OPTIONS.package_key is None:
  857.       OPTIONS.package_key = OPTIONS.source_info_dict.get(
  858.           "default_system_dev_certificate",
  859.           "build/target/product/security/testkey")
  860.     if OPTIONS.verbose:
  861.       print "--- source info ---"
  862.       common.DumpInfoDict(OPTIONS.source_info_dict)
  863.     WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
  864.  
  865.   output_zip.close()
  866.  
  867.   SignOutput(temp_zip_file.name, args[1])
  868.   temp_zip_file.close()
  869.  
  870.   common.Cleanup()
  871.  
  872.   print "done."
  873.  
  874.  
  875. if __name__ == '__main__':
  876.   try:
  877.     common.CloseInheritedPipes()
  878.     main(sys.argv[1:])
  879.   except common.ExternalError, e:
  880.     print
  881.     print "   ERROR: %s" % (e,)
  882.     print
  883.     sys.exit(1)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement