validate_target_files.py revision dd24c971a36d73d1e4224aa3bb8b08b956eecd5f
1dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin#!/usr/bin/env python 2dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 3dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# Copyright (C) 2017 The Android Open Source Project 4dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# 5dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# Licensed under the Apache License, Version 2.0 (the "License"); 6dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# you may not use this file except in compliance with the License. 7dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# You may obtain a copy of the License at 8dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# 9dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# http://www.apache.org/licenses/LICENSE-2.0 10dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# 11dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# Unless required by applicable law or agreed to in writing, software 12dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# distributed under the License is distributed on an "AS IS" BASIS, 13dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# See the License for the specific language governing permissions and 15dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin# limitations under the License. 16dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 17dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin""" 18dd018df8a00e841fe38fabe38520b7d297a885c1Igor MurashkinValidate a given (signed) target_files.zip. 19dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 20dd018df8a00e841fe38fabe38520b7d297a885c1Igor MurashkinIt performs checks to ensure the integrity of the input zip. 21dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin - It verifies the file consistency between the ones in IMAGES/system.img (read 22dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin via IMAGES/system.map) and the ones under unpacked folder of SYSTEM/. The 23dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin same check also applies to the vendor image if present. 24dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin""" 25dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 26dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkinimport logging 27dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkinimport os.path 28dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkinimport re 29dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkinimport sys 30dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkinimport zipfile 31dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 32dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkinimport common 33dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 34dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 35dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkindef _ReadFile(file_name, unpacked_name, round_up=False): 36dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin """Constructs and returns a File object. Rounds up its size if needed.""" 37dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 38dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin assert os.path.exists(unpacked_name) 39dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin with open(unpacked_name, 'r') as f: 40dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin file_data = f.read() 41dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin file_size = len(file_data) 42dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin if round_up: 43dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin file_size_rounded_up = common.RoundUpTo4K(file_size) 44dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin file_data += '\0' * (file_size_rounded_up - file_size) 45dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin return common.File(file_name, file_data) 46dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 47dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 48dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkindef ValidateFileAgainstSha1(input_tmp, file_name, file_path, expected_sha1): 49dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin """Check if the file has the expected SHA-1.""" 50dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 51dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.info('Validating the SHA-1 of %s', file_name) 52dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin unpacked_name = os.path.join(input_tmp, file_path) 53dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin assert os.path.exists(unpacked_name) 54dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin actual_sha1 = _ReadFile(file_name, unpacked_name, False).sha1 55dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin assert actual_sha1 == expected_sha1, \ 56dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 'SHA-1 mismatches for {}. actual {}, expected {}'.format( 57dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin file_name, actual_sha1, expected_sha1) 58dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 59dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 60dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkindef ValidateFileConsistency(input_zip, input_tmp, info_dict): 61dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin """Compare the files from image files and unpacked folders.""" 62dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 63dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin def CheckAllFiles(which): 64dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.info('Checking %s image.', which) 65dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # Allow having shared blocks when loading the sparse image, because allowing 66dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # that doesn't affect the checks below (we will have all the blocks on file, 67dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # unless it's skipped due to the holes). 68dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin image = common.GetSparseImage(which, input_tmp, input_zip, True) 69dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin prefix = '/' + which 70dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin for entry in image.file_map: 71dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # Skip entries like '__NONZERO-0'. 72dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin if not entry.startswith(prefix): 73dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin continue 74dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 75dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # Read the blocks that the file resides. Note that it will contain the 76dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # bytes past the file length, which is expected to be padded with '\0's. 77dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin ranges = image.file_map[entry] 78dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 79dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin incomplete = ranges.extra.get('incomplete', False) 80dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin if incomplete: 81dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.warning('Skipping %s that has incomplete block list', entry) 82dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin continue 83dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 84dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # TODO(b/79951650): Handle files with non-monotonic ranges. 85dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin if not ranges.monotonic: 86dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.warning( 87dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 'Skipping %s that has non-monotonic ranges: %s', entry, ranges) 88dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin continue 89dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 90dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin blocks_sha1 = image.RangeSha1(ranges) 91dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 92dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # The filename under unpacked directory, such as SYSTEM/bin/sh. 93dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin unpacked_name = os.path.join( 94dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin input_tmp, which.upper(), entry[(len(prefix) + 1):]) 95dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin unpacked_file = _ReadFile(entry, unpacked_name, True) 96dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin file_sha1 = unpacked_file.sha1 97dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin assert blocks_sha1 == file_sha1, \ 98dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 'file: %s, range: %s, blocks_sha1: %s, file_sha1: %s' % ( 99dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin entry, ranges, blocks_sha1, file_sha1) 100dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 101dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.info('Validating file consistency.') 102dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 103dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # TODO(b/79617342): Validate non-sparse images. 104dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin if info_dict.get('extfs_sparse_flag') != '-s': 105dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.warning('Skipped due to target using non-sparse images') 106dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin return 107dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 108dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # Verify IMAGES/system.img. 109dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin CheckAllFiles('system') 110dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 111dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # Verify IMAGES/vendor.img if applicable. 112dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin if 'VENDOR/' in input_zip.namelist(): 113dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin CheckAllFiles('vendor') 114dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 115dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # Not checking IMAGES/system_other.img since it doesn't have the map file. 116dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 117dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 118dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkindef ValidateInstallRecoveryScript(input_tmp, info_dict): 119dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin """Validate the SHA-1 embedded in install-recovery.sh. 120dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 121dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin install-recovery.sh is written in common.py and has the following format: 122dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 123dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 1. full recovery: 124dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin ... 125dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin if ! applypatch -c type:device:size:SHA-1; then 126dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin applypatch /system/etc/recovery.img type:device sha1 size && ... 127dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin ... 128dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 129dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 2. recovery from boot: 130dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin ... 131dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin applypatch [-b bonus_args] boot_info recovery_info recovery_sha1 \ 132dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin recovery_size patch_info && ... 133dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin ... 134dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 135dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin For full recovery, we want to calculate the SHA-1 of /system/etc/recovery.img 136dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin and compare it against the one embedded in the script. While for recovery 137dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin from boot, we want to check the SHA-1 for both recovery.img and boot.img 138dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin under IMAGES/. 139dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin """ 140dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 141dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin script_path = 'SYSTEM/bin/install-recovery.sh' 142dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin if not os.path.exists(os.path.join(input_tmp, script_path)): 143dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.info('%s does not exist in input_tmp', script_path) 144dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin return 145dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 146dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.info('Checking %s', script_path) 147dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin with open(os.path.join(input_tmp, script_path), 'r') as script: 148dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin lines = script.read().strip().split('\n') 149dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin assert len(lines) >= 6 150dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin check_cmd = re.search(r'if ! applypatch -c \w+:.+:\w+:(\w+);', 151dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin lines[1].strip()) 152dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin expected_recovery_check_sha1 = check_cmd.group(1) 153dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin patch_cmd = re.search(r'(applypatch.+)&&', lines[2].strip()) 154dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin applypatch_argv = patch_cmd.group(1).strip().split() 155dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 156dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin full_recovery_image = info_dict.get("full_recovery_image") == "true" 157dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin if full_recovery_image: 158dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin assert len(applypatch_argv) == 5 159dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # Check we have the same expected SHA-1 of recovery.img in both check mode 160dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # and patch mode. 161dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin expected_recovery_sha1 = applypatch_argv[3].strip() 162dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin assert expected_recovery_check_sha1 == expected_recovery_sha1 163dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin ValidateFileAgainstSha1(input_tmp, 'recovery.img', 164dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 'SYSTEM/etc/recovery.img', expected_recovery_sha1) 165dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin else: 166dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # We're patching boot.img to get recovery.img where bonus_args is optional 167dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin if applypatch_argv[1] == "-b": 168dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin assert len(applypatch_argv) == 8 169dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin boot_info_index = 3 170dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin else: 171dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin assert len(applypatch_argv) == 6 172dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin boot_info_index = 1 173dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 174dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # boot_info: boot_type:boot_device:boot_size:boot_sha1 175dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin boot_info = applypatch_argv[boot_info_index].strip().split(':') 176dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin assert len(boot_info) == 4 177dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin ValidateFileAgainstSha1(input_tmp, file_name='boot.img', 178dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin file_path='IMAGES/boot.img', 179dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin expected_sha1=boot_info[3]) 180dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 181dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin recovery_sha1_index = boot_info_index + 2 182dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin expected_recovery_sha1 = applypatch_argv[recovery_sha1_index] 183dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin assert expected_recovery_check_sha1 == expected_recovery_sha1 184dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin ValidateFileAgainstSha1(input_tmp, file_name='recovery.img', 185dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin file_path='IMAGES/recovery.img', 186dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin expected_sha1=expected_recovery_sha1) 187dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 188dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.info('Done checking %s', script_path) 189dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 190dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 191dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkindef main(argv): 192dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin def option_handler(): 193dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin return True 194dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 195dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin args = common.ParseOptions( 196dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin argv, __doc__, extra_opts="", 197dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin extra_long_opts=[], 198dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin extra_option_handler=option_handler) 199dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 200dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin if len(args) != 1: 201dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin common.Usage(__doc__) 202dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin sys.exit(1) 203dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 204dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging_format = '%(asctime)s - %(filename)s - %(levelname)-8s: %(message)s' 205dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin date_format = '%Y/%m/%d %H:%M:%S' 206dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.basicConfig(level=logging.INFO, format=logging_format, 207dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin datefmt=date_format) 208dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 209dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.info("Unzipping the input target_files.zip: %s", args[0]) 210dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin input_tmp = common.UnzipTemp(args[0]) 211dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 212dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin info_dict = common.LoadInfoDict(input_tmp) 213dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin with zipfile.ZipFile(args[0], 'r') as input_zip: 214dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin ValidateFileConsistency(input_zip, input_tmp, info_dict) 215dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 216dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin ValidateInstallRecoveryScript(input_tmp, info_dict) 217dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 218dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # TODO: Check if the OTA keys have been properly updated (the ones on /system, 219dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin # in recovery image). 220dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 221dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin logging.info("Done.") 222dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 223dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin 224dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkinif __name__ == '__main__': 225dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin try: 226dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin main(sys.argv[1:]) 227dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin finally: 228dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin common.Cleanup() 229dd018df8a00e841fe38fabe38520b7d297a885c1Igor Murashkin