Doug Zongker | 021796c | 2012-08-14 13:36:09 -0700 | [diff] [blame] | 1 | import common |
| 2 | import struct |
| 3 | |
Doug Zongker | 4c179ca | 2012-08-14 16:04:34 -0700 | [diff] [blame] | 4 | def FindRadio(zipfile): |
| 5 | try: |
| 6 | return zipfile.read("RADIO/radio.img") |
| 7 | except KeyError: |
| 8 | return None |
| 9 | |
| 10 | |
Doug Zongker | 021796c | 2012-08-14 13:36:09 -0700 | [diff] [blame] | 11 | def 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 | |
Doug Zongker | 4c179ca | 2012-08-14 16:04:34 -0700 | [diff] [blame] | 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 | |
| 26 | def 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 | |
Doug Zongker | 021796c | 2012-08-14 13:36:09 -0700 | [diff] [blame] | 39 | def 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 | |
Doug Zongker | 4c179ca | 2012-08-14 16:04:34 -0700 | [diff] [blame] | 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 | |
| 90 | def 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,)) |
Doug Zongker | 021796c | 2012-08-14 13:36:09 -0700 | [diff] [blame] | 96 | |
| 97 | |
| 98 | # /* mako 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 | |
| 114 | def WriteBootloader(info, bootloader): |
Doug Zongker | 4c179ca | 2012-08-14 16:04:34 -0700 | [diff] [blame] | 115 | info.script.Print("Writing bootloader...") |
| 116 | |
Doug Zongker | 4c89a84 | 2012-08-16 16:20:10 -0700 | [diff] [blame] | 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 | |
Doug Zongker | 021796c | 2012-08-14 13:36:09 -0700 | [diff] [blame] | 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 | |
Doug Zongker | 021796c | 2012-08-14 13:36:09 -0700 | [diff] [blame] | 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 | |
Doug Zongker | 4c89a84 | 2012-08-16 16:20:10 -0700 | [diff] [blame] | 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 |
Doug Zongker | 021796c | 2012-08-14 13:36:09 -0700 | [diff] [blame] | 173 | common.ZipWriteStr(info.output_zip, "bootloader.%s.img" % (i,), |
| 174 | bootloader[imgs[i][0]:imgs[i][0]+imgs[i][1]]) |
Doug Zongker | 4c89a84 | 2012-08-16 16:20:10 -0700 | [diff] [blame] | 175 | |
Doug Zongker | 021796c | 2012-08-14 13:36:09 -0700 | [diff] [blame] | 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: |
Doug Zongker | 4c89a84 | 2012-08-16 16:20:10 -0700 | [diff] [blame] | 184 | # there is no "sbl1b" partition |
Doug Zongker | 021796c | 2012-08-14 13:36:09 -0700 | [diff] [blame] | 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 | |
Doug Zongker | 021796c | 2012-08-14 13:36:09 -0700 | [diff] [blame] | 193 | def trunc_to_null(s): |
| 194 | if '\0' in s: |
| 195 | return s[:s.index('\0')] |
| 196 | else: |
| 197 | return s |