def ComputeAllPropertyFiles(input_file, needed_property_files): # Write the current metadata entry with placeholders. with zipfile.ZipFile(input_file, allowZip64=True) as input_zip: for property_files in needed_property_files: metadata.property_files[ property_files.name] = property_files.Compute(input_zip) namelist = input_zip.namelist() if METADATA_NAME in namelist or METADATA_PROTO_NAME in namelist: ZipDelete(input_file, [METADATA_NAME, METADATA_PROTO_NAME]) output_zip = zipfile.ZipFile(input_file, 'a', allowZip64=True) WriteMetadata(metadata, output_zip) ZipClose(output_zip) if OPTIONS.no_signing: return input_file prelim_signing = MakeTempFile(suffix='.zip') SignOutput(input_file, prelim_signing) return prelim_signing
def FinalizeMetadata(metadata, input_file, output_file, needed_property_files): """Finalizes the metadata and signs an A/B OTA package. In order to stream an A/B OTA package, we need 'ota-streaming-property-files' that contains the offsets and sizes for the ZIP entries. An example property-files string is as follows. "payload.bin:679:343,payload_properties.txt:378:45,metadata:69:379" OTA server can pass down this string, in addition to the package URL, to the system update client. System update client can then fetch individual ZIP entries (ZIP_STORED) directly at the given offset of the URL. Args: metadata: The metadata dict for the package. input_file: The input ZIP filename that doesn't contain the package METADATA entry yet. output_file: The final output ZIP filename. needed_property_files: The list of PropertyFiles' to be generated. """ def ComputeAllPropertyFiles(input_file, needed_property_files): # Write the current metadata entry with placeholders. with zipfile.ZipFile(input_file, allowZip64=True) as input_zip: for property_files in needed_property_files: metadata.property_files[ property_files.name] = property_files.Compute(input_zip) namelist = input_zip.namelist() if METADATA_NAME in namelist or METADATA_PROTO_NAME in namelist: ZipDelete(input_file, [METADATA_NAME, METADATA_PROTO_NAME]) output_zip = zipfile.ZipFile(input_file, 'a', allowZip64=True) WriteMetadata(metadata, output_zip) ZipClose(output_zip) if OPTIONS.no_signing: return input_file prelim_signing = MakeTempFile(suffix='.zip') SignOutput(input_file, prelim_signing) return prelim_signing def FinalizeAllPropertyFiles(prelim_signing, needed_property_files): with zipfile.ZipFile(prelim_signing, allowZip64=True) as prelim_signing_zip: for property_files in needed_property_files: metadata.property_files[ property_files.name] = property_files.Finalize( prelim_signing_zip, len(metadata.property_files[property_files.name])) # SignOutput(), which in turn calls signapk.jar, will possibly reorder the ZIP # entries, as well as padding the entry headers. We do a preliminary signing # (with an incomplete metadata entry) to allow that to happen. Then compute # the ZIP entry offsets, write back the final metadata and do the final # signing. prelim_signing = ComputeAllPropertyFiles(input_file, needed_property_files) try: FinalizeAllPropertyFiles(prelim_signing, needed_property_files) except PropertyFiles.InsufficientSpaceException: # Even with the preliminary signing, the entry orders may change # dramatically, which leads to insufficiently reserved space during the # first call to ComputeAllPropertyFiles(). In that case, we redo all the # preliminary signing works, based on the already ordered ZIP entries, to # address the issue. prelim_signing = ComputeAllPropertyFiles(prelim_signing, needed_property_files) FinalizeAllPropertyFiles(prelim_signing, needed_property_files) # Replace the METADATA entry. ZipDelete(prelim_signing, [METADATA_NAME, METADATA_PROTO_NAME]) output_zip = zipfile.ZipFile(prelim_signing, 'a', allowZip64=True) WriteMetadata(metadata, output_zip) ZipClose(output_zip) # Re-sign the package after updating the metadata entry. if OPTIONS.no_signing: output_file = prelim_signing else: SignOutput(prelim_signing, output_file) # Reopen the final signed zip to double check the streaming metadata. with zipfile.ZipFile(output_file, allowZip64=True) as output_zip: for property_files in needed_property_files: property_files.Verify( output_zip, metadata.property_files[property_files.name].strip()) # If requested, dump the metadata to a separate file. output_metadata_path = OPTIONS.output_metadata_path if output_metadata_path: WriteMetadata(metadata, output_metadata_path)