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