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