1import common
2import struct
3
4def FindRadio(zipfile):
5  try:
6    return zipfile.read("RADIO/radio.img")
7  except KeyError:
8    return None
9
10
11def 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
26def 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
39def 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
90def 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
114def 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
193def trunc_to_null(s):
194  if '\0' in s:
195    return s[:s.index('\0')]
196  else:
197    return s
198