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 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 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 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,)) 96 97 98 # /* msm8974 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 # Hammerhead's bootloader.img contains 6 separate images. 115 # Each goes to its own partition: 116 # aboot, rpm, tz, sbl1, sdi, imgdata 117 # 118 # Hammerhead also has 4 backup partitions: 119 # aboot, rpm, sbl1, tz 120 # 121 122 release_partitions = "aboot rpm tz sbl1 sdi imgdata" 123 debug_partitions = "aboot rpm tz sbl1 sdi imgdata" 124 backup_partitions = "aboot rpm sbl1 tz" 125 126 def WriteBootloader(info, bootloader): 127 info.script.Print("Writing bootloader...") 128 129 header_fmt = "<8sIII" 130 header_size = struct.calcsize(header_fmt) 131 magic, num_images, start_offset, bootloader_size = struct.unpack( 132 header_fmt, bootloader[:header_size]) 133 assert magic == "BOOTLDR!", "bootloader.img bad magic value" 134 135 img_info_fmt = "<64sI" 136 img_info_size = struct.calcsize(img_info_fmt) 137 138 imgs = [struct.unpack(img_info_fmt, 139 bootloader[header_size+i*img_info_size: 140 header_size+(i+1)*img_info_size]) 141 for i in range(num_images)] 142 143 total = 0 144 p = start_offset 145 img_dict = {} 146 for name, size in imgs: 147 img_dict[trunc_to_null(name)] = p, size 148 p += size 149 assert p - start_offset == bootloader_size, "bootloader.img corrupted" 150 imgs = img_dict 151 152 common.ZipWriteStr(info.output_zip, "bootloader-flag.txt", 153 "updating-bootloader" + "\0" * 13) 154 common.ZipWriteStr(info.output_zip, "bootloader-flag-clear.txt", "\0" * 32) 155 156 _, misc_device = common.GetTypeAndDevice("/misc", info.info_dict) 157 158 info.script.AppendExtra( 159 'package_extract_file("bootloader-flag.txt", "%s");' % 160 (misc_device,)) 161 162 # Depending on the build fingerprint, we can decide which partitions 163 # to update. 164 fp = info.info_dict["build.prop"]["ro.build.fingerprint"] 165 if "release-keys" in fp: 166 to_flash = release_partitions.split() 167 else: 168 to_flash = debug_partitions.split() 169 170 # Write the images to separate files in the OTA package 171 for i in to_flash: 172 try: 173 _, device = common.GetTypeAndDevice("/"+i, info.info_dict) 174 except KeyError: 175 print "skipping flash of %s; not in recovery.fstab" % (i,) 176 continue 177 common.ZipWriteStr(info.output_zip, "bootloader.%s.img" % (i,), 178 bootloader[imgs[i][0]:imgs[i][0]+imgs[i][1]]) 179 180 info.script.AppendExtra('package_extract_file("bootloader.%s.img", "%s");' % 181 (i, device)) 182 183 info.script.AppendExtra( 184 'package_extract_file("bootloader-flag-clear.txt", "%s");' % 185 (misc_device,)) 186 187 try: 188 for i in backup_partitions.split(): 189 _, device = common.GetTypeAndDevice("/"+i+"b", info.info_dict) 190 info.script.AppendExtra( 191 'package_extract_file("bootloader.%s.img", "%s");' % (i, device)) 192 except KeyError: 193 pass 194 195 196 def trunc_to_null(s): 197 if '\0' in s: 198 return s[:s.index('\0')] 199 else: 200 return s 201