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