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