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