Home | History | Annotate | Download | only in deb
      1 import common
      2 import struct
      3 
      4 def FindRadio(zipfile):
      5   try:
      6     return zipfile.read("RADIO/radio.img")
      7   except KeyError:
      8     return None
      9 
     10 
     11 def FullOTA_InstallEnd(info):
     12   try:
     13     bootloader_img = info.input_zip.read("RADIO/bootloader.img")
     14   except KeyError:
     15     print "no bootloader.img in target_files; skipping install"
     16   else:
     17     WriteBootloader(info, bootloader_img)
     18 
     19   radio_img = FindRadio(info.input_zip)
     20   if radio_img:
     21     WriteRadio(info, radio_img)
     22   else:
     23     print "no radio.img in target_files; skipping install"
     24 
     25 
     26 def IncrementalOTA_VerifyEnd(info):
     27   target_radio_img = FindRadio(info.target_zip)
     28   source_radio_img = FindRadio(info.source_zip)
     29   if not target_radio_img or not source_radio_img: return
     30   if source_radio_img != target_radio_img:
     31     info.script.CacheFreeSpaceCheck(len(source_radio_img))
     32     radio_type, radio_device = common.GetTypeAndDevice("/radio", info.info_dict)
     33     info.script.PatchCheck("%s:%s:%d:%s:%d:%s" % (
     34         radio_type, radio_device,
     35         len(source_radio_img), common.sha1(source_radio_img).hexdigest(),
     36         len(target_radio_img), common.sha1(target_radio_img).hexdigest()))
     37 
     38 
     39 def IncrementalOTA_InstallEnd(info):
     40   try:
     41     target_bootloader_img = info.target_zip.read("RADIO/bootloader.img")
     42     try:
     43       source_bootloader_img = info.source_zip.read("RADIO/bootloader.img")
     44     except KeyError:
     45       source_bootloader_img = None
     46 
     47     if source_bootloader_img == target_bootloader_img:
     48       print "bootloader unchanged; skipping"
     49     else:
     50       WriteBootloader(info, target_bootloader_img)
     51   except KeyError:
     52     print "no bootloader.img in target target_files; skipping install"
     53 
     54   tf = FindRadio(info.target_zip)
     55   if not tf:
     56     # failed to read TARGET radio image: don't include any radio in update.
     57     print "no radio.img in target target_files; skipping install"
     58   else:
     59     tf = common.File("radio.img", tf)
     60 
     61     sf = FindRadio(info.source_zip)
     62     if not sf:
     63       # failed to read SOURCE radio image: include the whole target
     64       # radio image.
     65       WriteRadio(info, tf.data)
     66     else:
     67       sf = common.File("radio.img", sf)
     68 
     69       if tf.sha1 == sf.sha1:
     70         print "radio image unchanged; skipping"
     71       else:
     72         diff = common.Difference(tf, sf, diff_program="bsdiff")
     73         common.ComputeDifferences([diff])
     74         _, _, d = diff.GetPatch()
     75         if d is None or len(d) > tf.size * common.OPTIONS.patch_threshold:
     76           # computing difference failed, or difference is nearly as
     77           # big as the target:  simply send the target.
     78           WriteRadio(info, tf.data)
     79         else:
     80           common.ZipWriteStr(info.output_zip, "radio.img.p", d)
     81           info.script.Print("Patching radio...")
     82           radio_type, radio_device = common.GetTypeAndDevice(
     83               "/radio", info.info_dict)
     84           info.script.ApplyPatch(
     85               "%s:%s:%d:%s:%d:%s" % (radio_type, radio_device,
     86                                      sf.size, sf.sha1, tf.size, tf.sha1),
     87               "-", tf.size, tf.sha1, sf.sha1, "radio.img.p")
     88 
     89 
     90 def WriteRadio(info, radio_img):
     91   info.script.Print("Writing radio...")
     92   common.ZipWriteStr(info.output_zip, "radio.img", radio_img)
     93   _, device = common.GetTypeAndDevice("/radio", info.info_dict)
     94   info.script.AppendExtra(
     95       'package_extract_file("radio.img", "%s");' % (device,))
     96 
     97 
     98 # /* msm8960 bootloader.img format */
     99 #
    100 # #define BOOTLDR_MAGIC "BOOTLDR!"
    101 # #define BOOTLDR_MAGIC_SIZE 8
    102 #
    103 # struct bootloader_images_header {
    104 #         char magic[BOOTLDR_MAGIC_SIZE];
    105 #         unsigned int num_images;
    106 #         unsigned int start_offset;
    107 #         unsigned int bootldr_size;
    108 #         struct {
    109 #                 char name[64];
    110 #                 unsigned int size;
    111 #         } img_info[];
    112 # };
    113 
    114 def WriteBootloader(info, bootloader):
    115   info.script.Print("Writing bootloader...")
    116 
    117   # bootloader.img contains 6 separate images.  Each goes to its own
    118   # partition; we write all 6 for development devices but skip one for
    119   # release devices..  There are backup partitions of all but the
    120   # special one that we also write.  The special one is "sbl1", which
    121   # does not have a backup, so we don't update it on release devices..
    122 
    123 
    124   header_fmt = "<8sIII"
    125   header_size = struct.calcsize(header_fmt)
    126   magic, num_images, start_offset, bootloader_size = struct.unpack(
    127       header_fmt, bootloader[:header_size])
    128   assert magic == "BOOTLDR!", "bootloader.img bad magic value"
    129 
    130   img_info_fmt = "<64sI"
    131   img_info_size = struct.calcsize(img_info_fmt)
    132 
    133   imgs = [struct.unpack(img_info_fmt,
    134                         bootloader[header_size+i*img_info_size:
    135                                      header_size+(i+1)*img_info_size])
    136           for i in range(num_images)]
    137 
    138   total = 0
    139   p = start_offset
    140   img_dict = {}
    141   for name, size in imgs:
    142     img_dict[trunc_to_null(name)] = p, size
    143     p += size
    144   assert p - start_offset == bootloader_size, "bootloader.img corrupted"
    145   imgs = img_dict
    146 
    147   common.ZipWriteStr(info.output_zip, "bootloader-flag.txt",
    148                      "updating-bootloader" + "\0" * 13)
    149   common.ZipWriteStr(info.output_zip, "bootloader-flag-clear.txt", "\0" * 32)
    150 
    151   _, misc_device = common.GetTypeAndDevice("/misc", info.info_dict)
    152 
    153   info.script.AppendExtra(
    154       'package_extract_file("bootloader-flag.txt", "%s");' %
    155       (misc_device,))
    156 
    157   # flashing sbl1 is somewhat dangerous because if we die while doing
    158   # it the device can't boot.  Do it for development devices but not
    159   # release devices.
    160   fp = info.info_dict["build.prop"]["ro.build.fingerprint"]
    161   if "release-keys" in fp:
    162     to_flash = "sbl2 sbl3 tz rpm aboot".split()
    163   else:
    164     to_flash = "sbl1 sbl2 sbl3 tz rpm aboot".split()
    165 
    166   # Write the images to separate files in the OTA package
    167   for i in to_flash:
    168     try:
    169       _, device = common.GetTypeAndDevice("/"+i, info.info_dict)
    170     except KeyError:
    171       print "skipping flash of %s; not in recovery.fstab" % (i,)
    172       continue
    173     common.ZipWriteStr(info.output_zip, "bootloader.%s.img" % (i,),
    174                        bootloader[imgs[i][0]:imgs[i][0]+imgs[i][1]])
    175 
    176     info.script.AppendExtra('package_extract_file("bootloader.%s.img", "%s");' %
    177                             (i, device))
    178 
    179   info.script.AppendExtra(
    180       'package_extract_file("bootloader-flag-clear.txt", "%s");' %
    181       (misc_device,))
    182 
    183   try:
    184     # there is no "sbl1b" partition
    185     for i in "sbl2 sbl3 tz rpm aboot".split():
    186       _, device = common.GetTypeAndDevice("/"+i+"b", info.info_dict)
    187       info.script.AppendExtra(
    188           'package_extract_file("bootloader.%s.img", "%s");' % (i, device))
    189   except KeyError:
    190     pass
    191 
    192 
    193 def trunc_to_null(s):
    194   if '\0' in s:
    195     return s[:s.index('\0')]
    196   else:
    197     return s
    198