Iliyan Malchev | 4ffa22b | 2013-02-27 18:45:49 -0800 | [diff] [blame] | 1 | import common |
| 2 | import struct |
| 3 | |
| 4 | def FindRadio(zipfile): |
| 5 | try: |
| 6 | return zipfile.read("RADIO/radio.img") |
| 7 | except KeyError: |
| 8 | return None |
| 9 | |
| 10 | |
| 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 | |
| 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 | |
johnny1_lin | ee060bd | 2013-07-18 17:07:26 +0800 | [diff] [blame] | 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 | |
Iliyan Malchev | 4ffa22b | 2013-02-27 18:45:49 -0800 | [diff] [blame] | 31 | |
| 32 | def 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 | |
| 45 | def 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 | |
johnny1_lin | ee060bd | 2013-07-18 17:07:26 +0800 | [diff] [blame] | 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 | |
Iliyan Malchev | 4ffa22b | 2013-02-27 18:45:49 -0800 | [diff] [blame] | 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 | |
| 103 | def 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 | |
johnny1_lin | ee060bd | 2013-07-18 17:07:26 +0800 | [diff] [blame] | 110 | def FindDDR(zipfile): |
| 111 | try: |
| 112 | return zipfile.read("RADIO/DDR.bin") |
| 113 | except KeyError: |
| 114 | return None |
| 115 | |
| 116 | |
| 117 | def 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");' ) |
Iliyan Malchev | 4ffa22b | 2013-02-27 18:45:49 -0800 | [diff] [blame] | 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 | |
| 139 | def 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 | |
| 218 | def trunc_to_null(s): |
| 219 | if '\0' in s: |
| 220 | return s[:s.index('\0')] |
| 221 | else: |
| 222 | return s |