• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  if common.OPTIONS.full_radio:
29    if not target_radio_img:
30      assert False, "full radio option specified but no radio img found"
31    else:
32      return
33  source_radio_img = FindRadio(info.source_zip)
34  if not target_radio_img or not source_radio_img: return
35  if source_radio_img != target_radio_img:
36    info.script.CacheFreeSpaceCheck(len(source_radio_img))
37    radio_type, radio_device = common.GetTypeAndDevice("/radio", info.info_dict)
38    info.script.PatchCheck("%s:%s:%d:%s:%d:%s" % (
39        radio_type, radio_device,
40        len(source_radio_img), common.sha1(source_radio_img).hexdigest(),
41        len(target_radio_img), common.sha1(target_radio_img).hexdigest()))
42
43
44def IncrementalOTA_InstallEnd(info):
45  try:
46    target_bootloader_img = info.target_zip.read("RADIO/bootloader.img")
47    try:
48      source_bootloader_img = info.source_zip.read("RADIO/bootloader.img")
49    except KeyError:
50      source_bootloader_img = None
51
52    if source_bootloader_img == target_bootloader_img:
53      print "bootloader unchanged; skipping"
54    else:
55      WriteBootloader(info, target_bootloader_img)
56  except KeyError:
57    print "no bootloader.img in target target_files; skipping install"
58
59  tf = FindRadio(info.target_zip)
60  if not tf:
61    # failed to read TARGET radio image: don't include any radio in update.
62    print "no radio.img in target target_files; skipping install"
63    # we have checked the existence of the radio image in
64    # IncrementalOTA_VerifyEnd(), so it won't reach here.
65    assert common.OPTIONS.full_radio == False
66  else:
67    tf = common.File("radio.img", tf)
68
69    sf = FindRadio(info.source_zip)
70    if not sf or common.OPTIONS.full_radio:
71      # failed to read SOURCE radio image or one has specified the option to
72      # include the whole target radio image.
73      print("no radio image in source target_files or full_radio specified; "
74            "installing complete image")
75      WriteRadio(info, tf.data)
76    else:
77      sf = common.File("radio.img", sf)
78
79      if tf.sha1 == sf.sha1:
80        print "radio image unchanged; skipping"
81      else:
82        diff = common.Difference(tf, sf, diff_program="bsdiff")
83        common.ComputeDifferences([diff])
84        _, _, d = diff.GetPatch()
85        if d is None or len(d) > tf.size * common.OPTIONS.patch_threshold:
86          # computing difference failed, or difference is nearly as
87          # big as the target:  simply send the target.
88          WriteRadio(info, tf.data)
89        else:
90          common.ZipWriteStr(info.output_zip, "radio.img.p", d)
91          info.script.Print("Patching radio...")
92          radio_type, radio_device = common.GetTypeAndDevice(
93              "/radio", info.info_dict)
94          info.script.ApplyPatch(
95              "%s:%s:%d:%s:%d:%s" % (radio_type, radio_device,
96                                     sf.size, sf.sha1, tf.size, tf.sha1),
97              "-", tf.size, tf.sha1, sf.sha1, "radio.img.p")
98
99
100def WriteRadio(info, radio_img):
101  info.script.Print("Writing radio...")
102  common.ZipWriteStr(info.output_zip, "radio.img", radio_img)
103  _, device = common.GetTypeAndDevice("/radio", info.info_dict)
104  info.script.AppendExtra(
105      'package_extract_file("radio.img", "%s");' % (device,))
106
107
108# /* msm8992 bootloader.img format */
109#
110# #define BOOTLDR_MAGIC "BOOTLDR!"
111# #define BOOTLDR_MAGIC_SIZE 8
112#
113# struct bootloader_images_header {
114#         char magic[BOOTLDR_MAGIC_SIZE];
115#         unsigned int num_images;
116#         unsigned int start_offset;
117#         unsigned int bootldr_size;
118#         struct {
119#                 char name[64];
120#                 unsigned int size;
121#         } img_info[];
122# };
123#
124# bullhead's bootloader.img contains 11 separate images.
125# Each goes to its own partition:
126#    sbl1, tz, rpm, aboot, sdi, imgdata, pmic, hyp, sec, keymaster, cmnlib
127#
128# bullhead also has 8 backup partitions:
129#    sbl1, tz, rpm, aboot, pmic, hyp, keymaster, cmnlib
130#
131release_backup_partitions = "sbl1 tz rpm aboot pmic hyp keymaster cmnlib"
132debug_backup_partitions = "sbl1 tz rpm aboot pmic hyp keymaster cmnlib"
133release_nobackup_partitions = "sdi imgdata sec"
134debug_nobackup_partitions = "sdi imgdata sec"
135
136def WriteBootloader(info, bootloader):
137  info.script.Print("Writing bootloader...")
138
139  header_fmt = "<8sIII"
140  header_size = struct.calcsize(header_fmt)
141  magic, num_images, start_offset, bootloader_size = struct.unpack(
142      header_fmt, bootloader[:header_size])
143  assert magic == "BOOTLDR!", "bootloader.img bad magic value"
144
145  img_info_fmt = "<64sI"
146  img_info_size = struct.calcsize(img_info_fmt)
147
148  imgs = [struct.unpack(img_info_fmt,
149                        bootloader[header_size+i*img_info_size:
150                                     header_size+(i+1)*img_info_size])
151          for i in range(num_images)]
152
153  total = 0
154  p = start_offset
155  img_dict = {}
156  for name, size in imgs:
157    img_dict[trunc_to_null(name)] = p, size
158    p += size
159  assert p - start_offset == bootloader_size, "bootloader.img corrupted"
160  imgs = img_dict
161
162  common.ZipWriteStr(info.output_zip, "bootloader-flag.txt",
163                     "updating-bootloader" + "\0" * 13)
164  common.ZipWriteStr(info.output_zip, "bootloader-flag-clear.txt", "\0" * 32)
165
166  _, misc_device = common.GetTypeAndDevice("/misc", info.info_dict)
167
168  info.script.AppendExtra(
169      'package_extract_file("bootloader-flag.txt", "%s");' %
170      (misc_device,))
171
172  # failed sbl updates, may render the handset unusable/unrestorable.
173  # Hence adopt below strategy for updates,enabling restore at all times.
174  # 1. Flash backup partitions
175  # 2. patch secondary pte's to swap primary/backup, and enable secondary gpt
176  # 3. Flash psuedo-backup partions, effectively flashing primary partitions
177  # 4. restore secondary pte's and restore primary gpt
178  # 5. Flash all other non backup partitions
179  #
180  # Depending on the build fingerprint, we can decide which partitions
181  # to update.
182  fp = info.info_dict["build.prop"]["ro.build.fingerprint"]
183  if "release-keys" in fp:
184    to_bkp_flash = release_backup_partitions.split()
185    to_flash = release_nobackup_partitions.split()
186  else:
187    to_bkp_flash = debug_backup_partitions.split()
188    to_flash = debug_nobackup_partitions.split()
189
190  # Write the images to separate files in the OTA package
191  # and flash backup partitions
192  for i in to_bkp_flash:
193    try:
194      _, device = common.GetTypeAndDevice("/"+i+"bak", 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  target_device = info.info_dict["build.prop"]["ro.product.device"]
205  # swap ptes in secondary and force secondary gpt
206  info.script.AppendExtra("lge_"+target_device+"_update_gpt();")
207
208  # flash again after swap, effectively flashing primary
209  # pte's are not re-read, hence primary is psuedo-secondary
210  for i in to_bkp_flash:
211    try:
212      _, device = common.GetTypeAndDevice("/"+i, info.info_dict)
213    except KeyError:
214      print "skipping flash of %s; not in recovery.fstab" % (i,)
215      continue
216    info.script.AppendExtra('package_extract_file("bootloader.%s.img", "%s");' %
217                            (i, device))
218
219  # restore secondary gpt for correct mappings and enable primary gpt
220  info.script.AppendExtra("lge_"+target_device+"_recover_gpt();")
221
222  # Write the images to separate files in the OTA package
223  for i in to_flash:
224    try:
225      _, device = common.GetTypeAndDevice("/"+i, info.info_dict)
226    except KeyError:
227      print "skipping flash of %s; not in recovery.fstab" % (i,)
228      continue
229    common.ZipWriteStr(info.output_zip, "bootloader.%s.img" % (i,),
230                       bootloader[imgs[i][0]:imgs[i][0]+imgs[i][1]])
231
232    info.script.AppendExtra('package_extract_file("bootloader.%s.img", "%s");' %
233                            (i, device))
234
235  info.script.AppendExtra(
236      'package_extract_file("bootloader-flag-clear.txt", "%s");' %
237      (misc_device,))
238
239
240def trunc_to_null(s):
241  if '\0' in s:
242    return s[:s.index('\0')]
243  else:
244    return s
245