18b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert#!/usr/bin/env python
28b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert#
38b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert# Copyright (C) 2008 The Android Open Source Project
48b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert#
58b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert# Licensed under the Apache License, Version 2.0 (the "License");
68b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert# you may not use this file except in compliance with the License.
78b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert# You may obtain a copy of the License at
88b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert#
98b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert#      http://www.apache.org/licenses/LICENSE-2.0
108b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert#
118b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert# Unless required by applicable law or agreed to in writing, software
128b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert# distributed under the License is distributed on an "AS IS" BASIS,
138b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
148b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert# See the License for the specific language governing permissions and
158b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert# limitations under the License.
168b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
178b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert"""
188b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertGiven a target-files zipfile, produces an OTA package that installs
198b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertthat build.  An incremental OTA is produced if -i is given, otherwise
208b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Alberta full OTA is produced.
218b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
228b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertUsage:  ota_from_target_files [flags] input_target_files output_ota_package
238b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
248b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  --board_config  <file>
258b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      Deprecated.
268b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
278b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  -k (--package_key) <key> Key to use to sign the package (default is
288b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      the value of default_system_dev_certificate from the input
298b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      target-files's META/misc_info.txt, or
308b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      "build/target/product/security/testkey" if that value is not
318b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      specified).
328b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
338b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      For incremental OTAs, the default value is based on the source
348b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      target-file, not the target build.
358b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
368b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  -i  (--incremental_from)  <file>
378b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      Generate an incremental OTA using the given target-files zip as
388b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      the starting build.
398b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
4043078aa37aa771149bfd85d10c47cce4e818b3d4Tao Bao  --full_radio
4143078aa37aa771149bfd85d10c47cce4e818b3d4Tao Bao      When generating an incremental OTA, always include a full copy of
4243078aa37aa771149bfd85d10c47cce4e818b3d4Tao Bao      radio image. This option is only meaningful when -i is specified,
4343078aa37aa771149bfd85d10c47cce4e818b3d4Tao Bao      because a full radio is always included in a full OTA if applicable.
4443078aa37aa771149bfd85d10c47cce4e818b3d4Tao Bao
45aa6c1a144545b655837d024445020ecba202f0e0leozwang  --full_bootloader
46aa6c1a144545b655837d024445020ecba202f0e0leozwang      Similar to --full_radio. When generating an incremental OTA, always
47aa6c1a144545b655837d024445020ecba202f0e0leozwang      include a full copy of bootloader image.
48aa6c1a144545b655837d024445020ecba202f0e0leozwang
498b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  -v  (--verify)
508b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      Remount and verify the checksums of the files written to the
518b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      system and vendor (if used) partitions.  Incremental builds only.
528b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
537f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  -o  (--oem_settings)  <main_file[,additional_files...]>
547f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      Comma seperated list of files used to specify the expected OEM-specific
557f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      properties on the OEM partition of the intended device.
567f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      Multiple expected values can be used by providing multiple files.
577f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh
588608cde944d64dece63e8c770deb78c1d092c719Tao Bao  --oem_no_mount
598608cde944d64dece63e8c770deb78c1d092c719Tao Bao      For devices with OEM-specific properties but without an OEM partition,
608608cde944d64dece63e8c770deb78c1d092c719Tao Bao      do not mount the OEM partition in the updater-script. This should be
618608cde944d64dece63e8c770deb78c1d092c719Tao Bao      very rarely used, since it's expected to have a dedicated OEM partition
628608cde944d64dece63e8c770deb78c1d092c719Tao Bao      for OEM-specific properties. Only meaningful when -o is specified.
638608cde944d64dece63e8c770deb78c1d092c719Tao Bao
648b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  -w  (--wipe_user_data)
658b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      Generate an OTA package that will wipe the user data partition
668b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      when installed.
678b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
685d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao  --downgrade
695d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao      Intentionally generate an incremental OTA that updates from a newer
705d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao      build to an older one (based on timestamp comparison). "post-timestamp"
715d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao      will be replaced by "ota-downgrade=yes" in the metadata file. A data
725d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao      wipe will always be enforced, so "ota-wipe=yes" will also be included in
734996cf03d2321eef56a8163c7fc73ba9976e1021Tao Bao      the metadata file. The update-binary in the source build will be used in
743e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      the OTA package, unless --binary flag is specified. Please also check the
753e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      doc for --override_timestamp below.
763e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao
773e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao  --override_timestamp
783e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      Intentionally generate an incremental OTA that updates from a newer
793e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      build to an older one (based on timestamp comparison), by overriding the
803e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      timestamp in package metadata. This differs from --downgrade flag: we
813e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      know for sure this is NOT an actual downgrade case, but two builds are
823e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      cut in a reverse order. A legit use case is that we cut a new build C
833e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      (after having A and B), but want to enfore an update path of A -> C -> B.
843e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      Specifying --downgrade may not help since that would enforce a data wipe
853e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      for C -> B update. The value of "post-timestamp" will be set to the newer
863e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      timestamp plus one, so that the package can be pushed and applied.
875d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao
888b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  -e  (--extra_script)  <file>
898b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      Insert the contents of file at the end of the update script.
908b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
918b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  -2  (--two_step)
928b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      Generate a 'two-step' OTA package, where recovery is updated
938b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      first, so that any changes made to the system partition are done
948b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      using the new recovery (new kernel, etc.).
958b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
968b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  --block
97457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao      Generate a block-based OTA for non-A/B device. We have deprecated the
98457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao      support for file-based OTA since O. Block-based OTA will be used by
99457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao      default for all non-A/B devices. Keeping this flag here to not break
100457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao      existing callers.
1018b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1028b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  -b  (--binary)  <file>
1038b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      Use the given binary as the update-binary in the output package,
1048b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      instead of the binary in the build's target_files.  Use for
1058b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      development only.
1068b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1078b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  -t  (--worker_threads) <int>
1088b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      Specifies the number of worker-threads that will be used when
1098b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      generating patches for incremental updates (defaults to 3).
1108b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1118dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao  --stash_threshold <float>
1128dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao      Specifies the threshold that will be used to compute the maximum
1138dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao      allowed stash size (defaults to 0.8).
1149bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
1159bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  --gen_verify
1169bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      Generate an OTA package that verifies the partitions.
117d62c603573c53713164fda0430d477daa11d5e31Tao Bao
118d62c603573c53713164fda0430d477daa11d5e31Tao Bao  --log_diff <file>
119d62c603573c53713164fda0430d477daa11d5e31Tao Bao      Generate a log file that shows the differences in the source and target
120d62c603573c53713164fda0430d477daa11d5e31Tao Bao      builds for an incremental package. This option is only meaningful when
121d62c603573c53713164fda0430d477daa11d5e31Tao Bao      -i is specified.
122dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao
123dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao  --payload_signer <signer>
124dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao      Specify the signer when signing the payload and metadata for A/B OTAs.
125dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao      By default (i.e. without this flag), it calls 'openssl pkeyutl' to sign
126dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao      with the package private key. If the private key cannot be accessed
127dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao      directly, a payload signer that knows how to do that should be specified.
128dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao      The signer will be supplied with "-inkey <path_to_key>",
129dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao      "-in <input_file>" and "-out <output_file>" parameters.
1302abbbd03339947327ada0becba5bd4ef41f1bdabBaligh Uddin
1312abbbd03339947327ada0becba5bd4ef41f1bdabBaligh Uddin  --payload_signer_args <args>
1322abbbd03339947327ada0becba5bd4ef41f1bdabBaligh Uddin      Specify the arguments needed for payload signer.
1338b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert"""
1348b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
13589fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Baofrom __future__ import print_function
13689fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao
1378b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertimport sys
1388b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1398b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertif sys.hexversion < 0x02070000:
14089fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao  print("Python 2.7 or newer is required.", file=sys.stderr)
1418b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  sys.exit(1)
1428b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1432dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Baoimport copy
1448b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertimport multiprocessing
1452dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Baoimport os.path
146c098e9efd989a46d5d1aa625bc899536de15eaaaTao Baoimport subprocess
1472abbbd03339947327ada0becba5bd4ef41f1bdabBaligh Uddinimport shlex
1488b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertimport tempfile
1498b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertimport zipfile
1508b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1518b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertimport common
1528b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertimport edify_generator
1538b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertimport sparse_img
1548b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1558b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS = common.OPTIONS
1568b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.package_key = None
1578b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.incremental_source = None
1588b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.verify = False
1598b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.patch_threshold = 0.95
1608b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.wipe_user_data = False
1615d1825664a0fec256fa28d62aadcac96f59a41b2Tao BaoOPTIONS.downgrade = False
1623e6161a3b33da5a46c80c79e2d815168923e83c3Tao BaoOPTIONS.timestamp = False
1638b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.extra_script = None
1648b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.worker_threads = multiprocessing.cpu_count() // 2
1658b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertif OPTIONS.worker_threads == 0:
1668b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  OPTIONS.worker_threads = 1
1678b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.two_step = False
1688b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.no_signing = False
169457cbf6a8a3c858aff5160f02f4ee220716900efTao BaoOPTIONS.block_based = True
1708b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.updater_binary = None
1718b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.oem_source = None
1728608cde944d64dece63e8c770deb78c1d092c719Tao BaoOPTIONS.oem_no_mount = False
1738b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan AlbertOPTIONS.fallback_to_full = True
17443078aa37aa771149bfd85d10c47cce4e818b3d4Tao BaoOPTIONS.full_radio = False
175aa6c1a144545b655837d024445020ecba202f0e0leozwangOPTIONS.full_bootloader = False
176d47d8e14880132c42a75f41c8041851797c75e35Tao Bao# Stash size cannot exceed cache_size * threshold.
177d47d8e14880132c42a75f41c8041851797c75e35Tao BaoOPTIONS.cache_size = None
178d47d8e14880132c42a75f41c8041851797c75e35Tao BaoOPTIONS.stash_threshold = 0.8
1799bc6bb23b5bf64635275041fecace64635f41fbaTao BaoOPTIONS.gen_verify = False
180d62c603573c53713164fda0430d477daa11d5e31Tao BaoOPTIONS.log_diff = None
181dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao BaoOPTIONS.payload_signer = None
1822abbbd03339947327ada0becba5bd4ef41f1bdabBaligh UddinOPTIONS.payload_signer_args = []
1835f8ff9319b086c2f2b95bded2d40700037b5003fTao BaoOPTIONS.extracted_input = None
1848dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao
1852dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao BaoMETADATA_NAME = 'META-INF/com/android/metadata'
1866b0b2f9db0c7d89a678e5b0cb9dbffbec3d96f0bTao BaoUNZIP_PATTERN = ['IMAGES/*', 'META/*']
1876b0b2f9db0c7d89a678e5b0cb9dbffbec3d96f0bTao Bao
1882dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao
1898b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertdef SignOutput(temp_zip_name, output_zip_name):
1908b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
1918b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  pw = key_passwords[OPTIONS.package_key]
1928b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1938b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
1948b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                  whole_file=True)
1958b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1968b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1977f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanhdef AppendAssertions(script, info_dict, oem_dicts=None):
1988b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  oem_props = info_dict.get("oem_fingerprint_properties")
1993e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  if not oem_props:
2008b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    device = GetBuildProp("ro.product.device", info_dict)
2018b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AssertDevice(device)
2028b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  else:
2037f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh    if not oem_dicts:
2048b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      raise common.ExternalError(
2058b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert          "No OEM file provided to answer expected assertions")
2068b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    for prop in oem_props.split():
2077f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      values = []
2087f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      for oem_dict in oem_dicts:
2097f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh        if oem_dict.get(prop):
2107f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh          values.append(oem_dict[prop])
2117f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      if not values:
2128b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        raise common.ExternalError(
2138b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert            "The OEM file is missing the property %s" % prop)
2147f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      script.AssertOemProperty(prop, values)
2157f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh
2167f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh
217ebce697429c9db5ffd6ac52fc8f4bbf9cd56f9c6Tao Baodef _LoadOemDicts(script, recovery_mount_options=None):
2187f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  """Returns the list of loaded OEM properties dict."""
2197f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  oem_dicts = None
2207f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  if OPTIONS.oem_source is None:
2217f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh    raise common.ExternalError("OEM source required for this build")
222ebce697429c9db5ffd6ac52fc8f4bbf9cd56f9c6Tao Bao  if not OPTIONS.oem_no_mount and script:
2237f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh    script.Mount("/oem", recovery_mount_options)
2247f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  oem_dicts = []
2257f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  for oem_file in OPTIONS.oem_source:
2267f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh    oem_dicts.append(common.LoadDictionaryFromLines(
2277f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh        open(oem_file).readlines()))
2287f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  return oem_dicts
2298b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
2308b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
231d42e97ebb45fdc5a30799a3f37e482948d318010Tao Baodef _WriteRecoveryImageToBoot(script, output_zip):
232d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  """Find and write recovery image to /boot in two-step OTA.
233d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
234d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  In two-step OTAs, we write recovery image to /boot as the first step so that
235d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  we can reboot to there and install a new recovery image to /recovery.
236d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  A special "recovery-two-step.img" will be preferred, which encodes the correct
237d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  path of "/boot". Otherwise the device may show "device is corrupt" message
238d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  when booting into /boot.
239d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
240d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  Fall back to using the regular recovery.img if the two-step recovery image
241d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  doesn't exist. Note that rebuilding the special image at this point may be
242d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  infeasible, because we don't have the desired boot signer and keys when
243d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  calling ota_from_target_files.py.
244d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  """
245d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
246d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  recovery_two_step_img_name = "recovery-two-step.img"
247d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  recovery_two_step_img_path = os.path.join(
248d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao      OPTIONS.input_tmp, "IMAGES", recovery_two_step_img_name)
249d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  if os.path.exists(recovery_two_step_img_path):
250d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    recovery_two_step_img = common.GetBootableImage(
251d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao        recovery_two_step_img_name, recovery_two_step_img_name,
252d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao        OPTIONS.input_tmp, "RECOVERY")
253d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    common.ZipWriteStr(
254d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao        output_zip, recovery_two_step_img_name, recovery_two_step_img.data)
25589fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao    print("two-step package: using %s in stage 1/3" % (
25689fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao        recovery_two_step_img_name,))
257d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    script.WriteRawImage("/boot", recovery_two_step_img_name)
258d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao  else:
25989fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao    print("two-step package: using recovery.img in stage 1/3")
260d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    # The "recovery.img" entry has been written into package earlier.
261d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    script.WriteRawImage("/boot", "recovery.img")
262d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
263d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
2648b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertdef HasRecoveryPatch(target_files_zip):
265f2cffbddb9dccc6dd46ea2be0bbde387315f09c3Tao Bao  namelist = [name for name in target_files_zip.namelist()]
266f2cffbddb9dccc6dd46ea2be0bbde387315f09c3Tao Bao  return ("SYSTEM/recovery-from-boot.p" in namelist or
267f2cffbddb9dccc6dd46ea2be0bbde387315f09c3Tao Bao          "SYSTEM/etc/recovery.img" in namelist)
2688b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
269457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao
2708b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertdef HasVendorPartition(target_files_zip):
2718b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  try:
2728b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    target_files_zip.getinfo("VENDOR/")
2738b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    return True
2748b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  except KeyError:
2758b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    return False
2768b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
277457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao
2788b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertdef GetOemProperty(name, oem_props, oem_dict, info_dict):
2798b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if oem_props is not None and name in oem_props:
2808b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    return oem_dict[name]
2818b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  return GetBuildProp(name, info_dict)
2828b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
2838b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
2848b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertdef CalculateFingerprint(oem_props, oem_dict, info_dict):
2858b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if oem_props is None:
2868b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    return GetBuildProp("ro.build.fingerprint", info_dict)
2878b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  return "%s/%s/%s:%s" % (
2888b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
2898b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
2908b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
2918b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      GetBuildProp("ro.build.thumbprint", info_dict))
2928b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
2938b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
2947e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Baodef GetImage(which, tmpdir):
2957e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao  """Returns an image object suitable for passing to BlockImageDiff.
2967e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao
2977e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao  'which' partition must be "system" or "vendor". A prebuilt image and file
2987e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao  map must already exist in tmpdir.
2997e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao  """
3008b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
3018b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  assert which in ("system", "vendor")
3028b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
3038b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  path = os.path.join(tmpdir, "IMAGES", which + ".img")
3048b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
3058b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
3067e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao  # The image and map files must have been created prior to calling
3077e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao  # ota_from_target_files.py (since LMP).
3087e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao  assert os.path.exists(path) and os.path.exists(mappath)
3098b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
310ff7778166bd13a90c89fa333591ee2037f587a11Tao Bao  # Bug: http://b/20939131
311ff7778166bd13a90c89fa333591ee2037f587a11Tao Bao  # In ext4 filesystems, block 0 might be changed even being mounted
312ff7778166bd13a90c89fa333591ee2037f587a11Tao Bao  # R/O. We add it to clobbered_blocks so that it will be written to the
313ff7778166bd13a90c89fa333591ee2037f587a11Tao Bao  # target unconditionally. Note that they are still part of care_map.
314ff7778166bd13a90c89fa333591ee2037f587a11Tao Bao  clobbered_blocks = "0"
315ff7778166bd13a90c89fa333591ee2037f587a11Tao Bao
316ff7778166bd13a90c89fa333591ee2037f587a11Tao Bao  return sparse_img.SparseImage(path, mappath, clobbered_blocks)
3178b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
3188b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
319b63c952cc72eda821532b3bcb00a66278503287eTao Baodef AddCompatibilityArchive(target_zip, output_zip, system_included=True,
320b63c952cc72eda821532b3bcb00a66278503287eTao Bao                            vendor_included=True):
321b63c952cc72eda821532b3bcb00a66278503287eTao Bao  """Adds compatibility info from target files into the output zip.
322b63c952cc72eda821532b3bcb00a66278503287eTao Bao
323b63c952cc72eda821532b3bcb00a66278503287eTao Bao  Metadata used for on-device compatibility verification is retrieved from
324b63c952cc72eda821532b3bcb00a66278503287eTao Bao  target_zip then added to compatibility.zip which is added to the output_zip
325b63c952cc72eda821532b3bcb00a66278503287eTao Bao  archive.
326b63c952cc72eda821532b3bcb00a66278503287eTao Bao
327b63c952cc72eda821532b3bcb00a66278503287eTao Bao  Compatibility archive should only be included for devices with a vendor
328b63c952cc72eda821532b3bcb00a66278503287eTao Bao  partition as checking provides value when system and vendor are independently
329b63c952cc72eda821532b3bcb00a66278503287eTao Bao  versioned.
330b63c952cc72eda821532b3bcb00a66278503287eTao Bao
331b63c952cc72eda821532b3bcb00a66278503287eTao Bao  Args:
332b63c952cc72eda821532b3bcb00a66278503287eTao Bao    target_zip: Zip file containing the source files to be included for OTA.
333b63c952cc72eda821532b3bcb00a66278503287eTao Bao    output_zip: Zip file that will be sent for OTA.
334b63c952cc72eda821532b3bcb00a66278503287eTao Bao    system_included: If True, the system image will be updated and therefore
335b63c952cc72eda821532b3bcb00a66278503287eTao Bao        its metadata should be included.
336b63c952cc72eda821532b3bcb00a66278503287eTao Bao    vendor_included: If True, the vendor image will be updated and therefore
337b63c952cc72eda821532b3bcb00a66278503287eTao Bao        its metadata should be included.
338b63c952cc72eda821532b3bcb00a66278503287eTao Bao  """
339b63c952cc72eda821532b3bcb00a66278503287eTao Bao
340b63c952cc72eda821532b3bcb00a66278503287eTao Bao  # Determine what metadata we need. Files are names relative to META/.
341b63c952cc72eda821532b3bcb00a66278503287eTao Bao  compatibility_files = []
342b63c952cc72eda821532b3bcb00a66278503287eTao Bao  vendor_metadata = ("vendor_manifest.xml", "vendor_matrix.xml")
343b63c952cc72eda821532b3bcb00a66278503287eTao Bao  system_metadata = ("system_manifest.xml", "system_matrix.xml")
344b63c952cc72eda821532b3bcb00a66278503287eTao Bao  if vendor_included:
345b63c952cc72eda821532b3bcb00a66278503287eTao Bao    compatibility_files += vendor_metadata
346b63c952cc72eda821532b3bcb00a66278503287eTao Bao  if system_included:
347b63c952cc72eda821532b3bcb00a66278503287eTao Bao    compatibility_files += system_metadata
348b63c952cc72eda821532b3bcb00a66278503287eTao Bao
349b63c952cc72eda821532b3bcb00a66278503287eTao Bao  # Create new archive.
350b63c952cc72eda821532b3bcb00a66278503287eTao Bao  compatibility_archive = tempfile.NamedTemporaryFile()
351b63c952cc72eda821532b3bcb00a66278503287eTao Bao  compatibility_archive_zip = zipfile.ZipFile(compatibility_archive, "w",
352b63c952cc72eda821532b3bcb00a66278503287eTao Bao      compression=zipfile.ZIP_DEFLATED)
353b63c952cc72eda821532b3bcb00a66278503287eTao Bao
354b63c952cc72eda821532b3bcb00a66278503287eTao Bao  # Add metadata.
355b63c952cc72eda821532b3bcb00a66278503287eTao Bao  for file_name in compatibility_files:
356b63c952cc72eda821532b3bcb00a66278503287eTao Bao    target_file_name = "META/" + file_name
357b63c952cc72eda821532b3bcb00a66278503287eTao Bao
358b63c952cc72eda821532b3bcb00a66278503287eTao Bao    if target_file_name in target_zip.namelist():
359b63c952cc72eda821532b3bcb00a66278503287eTao Bao      data = target_zip.read(target_file_name)
360b63c952cc72eda821532b3bcb00a66278503287eTao Bao      common.ZipWriteStr(compatibility_archive_zip, file_name, data)
361b63c952cc72eda821532b3bcb00a66278503287eTao Bao
362b63c952cc72eda821532b3bcb00a66278503287eTao Bao  # Ensure files are written before we copy into output_zip.
363b63c952cc72eda821532b3bcb00a66278503287eTao Bao  compatibility_archive_zip.close()
364b63c952cc72eda821532b3bcb00a66278503287eTao Bao
365b63c952cc72eda821532b3bcb00a66278503287eTao Bao  # Only add the archive if we have any compatibility info.
366b63c952cc72eda821532b3bcb00a66278503287eTao Bao  if compatibility_archive_zip.namelist():
367b63c952cc72eda821532b3bcb00a66278503287eTao Bao    common.ZipWrite(output_zip, compatibility_archive.name,
368b63c952cc72eda821532b3bcb00a66278503287eTao Bao                    arcname="compatibility.zip",
369b63c952cc72eda821532b3bcb00a66278503287eTao Bao                    compress_type=zipfile.ZIP_STORED)
370b63c952cc72eda821532b3bcb00a66278503287eTao Bao
371b63c952cc72eda821532b3bcb00a66278503287eTao Bao
3728b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertdef WriteFullOTAPackage(input_zip, output_zip):
3738b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # TODO: how to determine this?  We don't know what version it will
37434b47bf42b4b9fad8e775a37e40922598bb7bd96Tao Bao  # be installed on top of. For now, we expect the API just won't
37534b47bf42b4b9fad8e775a37e40922598bb7bd96Tao Bao  # change very often. Similarly for fstab, it might have changed
37634b47bf42b4b9fad8e775a37e40922598bb7bd96Tao Bao  # in the target build.
3778b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
3788b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
379838c68fa1ae35a4b0fd017e92728cb5720f74782Tao Bao  recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
3803e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
3817f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  oem_dicts = None
3823e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  if oem_props:
3837f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh    oem_dicts = _LoadOemDicts(script, recovery_mount_options)
3847f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh
3857f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
3867f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh                                   OPTIONS.info_dict)
3878b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  metadata = {
38839f3eaf22135d52b87a83039355df90a56e7d85bTao Bao      "post-build": target_fp,
3897f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      "pre-device": GetOemProperty("ro.product.device", oem_props,
3907f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh                                   oem_dicts and oem_dicts[0],
3918b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                   OPTIONS.info_dict),
3928b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
3938b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  }
3948b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
3958b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  device_specific = common.DeviceSpecificParams(
3968b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      input_zip=input_zip,
3978b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      input_version=OPTIONS.info_dict["recovery_api_version"],
3988b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      output_zip=output_zip,
3998b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      script=script,
4008b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      input_tmp=OPTIONS.input_tmp,
4018b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      metadata=metadata,
4028b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      info_dict=OPTIONS.info_dict)
4038b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
404457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao  assert HasRecoveryPatch(input_zip)
4058b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
406457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao  metadata["ota-type"] = "BLOCK"
407d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao
408d8a52f97859356c65b21f8aed775f685b314ca22Elliott Hughes  ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
409d8a52f97859356c65b21f8aed775f685b314ca22Elliott Hughes  ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
410d8a52f97859356c65b21f8aed775f685b314ca22Elliott Hughes  script.AssertOlderBuild(ts, ts_text)
4118b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
4127f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  AppendAssertions(script, OPTIONS.info_dict, oem_dicts)
4138b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  device_specific.FullOTA_Assertions()
4148b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
4158b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # Two-step package strategy (in chronological order, which is *not*
4168b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # the order in which the generated script has things):
4178b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #
4188b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # if stage is not "2/3" or "3/3":
4198b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    write recovery image to boot partition
4208b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    set stage to "2/3"
4218b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    reboot to boot partition and restart recovery
4228b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # else if stage is "2/3":
4238b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    write recovery image to recovery partition
4248b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    set stage to "3/3"
4258b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    reboot to recovery partition and restart recovery
4268b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # else:
4278b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    (stage must be "3/3")
4288b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    set stage to ""
4298b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    do normal full package installation:
4308b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #       wipe and install system, boot image, etc.
4318b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #       set up system to update recovery partition on first boot
4328b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    complete script normally
4338b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    (allow recovery to mark itself finished and reboot)
4348b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
4358b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
4368b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                         OPTIONS.input_tmp, "RECOVERY")
4378b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.two_step:
4388b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    if not OPTIONS.info_dict.get("multistage_support", None):
4398b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      assert False, "two-step packages not supported by this build"
4408b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    fs = OPTIONS.info_dict["fstab"]["/misc"]
4418b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    assert fs.fs_type.upper() == "EMMC", \
4428b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        "two-step packages only supported on devices with EMMC /misc partitions"
4438b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    bcb_dev = {"bcb_dev": fs.device}
4448b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
4458b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra("""
4468b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertif get_stage("%(bcb_dev)s") == "2/3" then
4478b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert""" % bcb_dev)
448d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
449d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    # Stage 2/3: Write recovery image to /recovery (currently running /boot).
450d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    script.Comment("Stage 2/3")
4518b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.WriteRawImage("/recovery", "recovery.img")
4528b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra("""
4538b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertset_stage("%(bcb_dev)s", "3/3");
4548b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertreboot_now("%(bcb_dev)s", "recovery");
4558b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertelse if get_stage("%(bcb_dev)s") == "3/3" then
4568b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert""" % bcb_dev)
4578b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
458d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    # Stage 3/3: Make changes.
459d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    script.Comment("Stage 3/3")
460d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
4616c55a8adc81a3a2febd4e4a61f70cb464906e3b8Tao Bao  # Dump fingerprints
4623e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  script.Print("Target: %s" % target_fp)
4636c55a8adc81a3a2febd4e4a61f70cb464906e3b8Tao Bao
4648b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  device_specific.FullOTA_InstallBegin()
4658b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
4668b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  system_progress = 0.75
4678b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
4688b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.wipe_user_data:
4698b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    system_progress -= 0.1
4708b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if HasVendorPartition(input_zip):
4718b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    system_progress -= 0.1
4728b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
473d3a803e6680e86f7b4960d51ab0b620728b793caStephen Smalley  # Place a copy of file_contexts.bin into the OTA package which will be used
474d3a803e6680e86f7b4960d51ab0b620728b793caStephen Smalley  # by the recovery program.
4758b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if "selinux_fc" in OPTIONS.info_dict:
4768b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
4778b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
4788b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
4798b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
4808b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  script.ShowProgress(system_progress, 0)
4818b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
482457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao  # Full OTA is done as an "incremental" against an empty source image. This
483457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao  # has the effect of writing new data from the package to the entire
484457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao  # partition, but lets us reuse the updater code that writes incrementals to
485457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao  # do it.
486457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao  system_tgt = GetImage("system", OPTIONS.input_tmp)
487457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao  system_tgt.ResetFileMap()
488457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao  system_diff = common.BlockDifference("system", system_tgt, src=None)
489457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao  system_diff.WriteScript(script, output_zip)
4908b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
4917a5bf8a645fea21ab4f8d67f900c16692643d166Tao Bao  boot_img = common.GetBootableImage(
4927a5bf8a645fea21ab4f8d67f900c16692643d166Tao Bao      "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
4938b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
4948b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if HasVendorPartition(input_zip):
4958b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.ShowProgress(0.1, 0)
4968b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
497457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao    vendor_tgt = GetImage("vendor", OPTIONS.input_tmp)
498457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao    vendor_tgt.ResetFileMap()
499457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao    vendor_diff = common.BlockDifference("vendor", vendor_tgt)
500457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao    vendor_diff.WriteScript(script, output_zip)
5018b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5028b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
5038b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
5048b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5058b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  script.ShowProgress(0.05, 5)
5068b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  script.WriteRawImage("/boot", "boot.img")
5078b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5088b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  script.ShowProgress(0.2, 10)
5098b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  device_specific.FullOTA_InstallEnd()
5108b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5118b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.extra_script is not None:
5128b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra(OPTIONS.extra_script)
5138b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5148b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  script.UnmountAll()
5158b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5168b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.wipe_user_data:
5178b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.ShowProgress(0.1, 10)
5188b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.FormatPartition("/data")
5198b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5208b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.two_step:
5218b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra("""
5228b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertset_stage("%(bcb_dev)s", "");
5238b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert""" % bcb_dev)
5248b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra("else\n")
525d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
526d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot.
527d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    script.Comment("Stage 1/3")
528d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    _WriteRecoveryImageToBoot(script, output_zip)
529d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
5308b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra("""
5318b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertset_stage("%(bcb_dev)s", "2/3");
5328b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertreboot_now("%(bcb_dev)s", "");
5338b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertendif;
5348b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertendif;
5358b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert""" % bcb_dev)
536d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao
5375d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao  script.SetProgress(1)
5385d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao  script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
539d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao  metadata["ota-required-cache"] = str(script.required_cache)
5408b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  WriteMetadata(metadata, output_zip)
5418b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5428b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5438b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertdef WritePolicyConfig(file_name, output_zip):
5448b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
5458b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5468b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5478b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertdef WriteMetadata(metadata, output_zip):
5482dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  value = "".join(["%s=%s\n" % kv for kv in sorted(metadata.iteritems())])
5492dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  common.ZipWriteStr(output_zip, METADATA_NAME, value,
5502dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao                     compress_type=zipfile.ZIP_STORED)
5518b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5528b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5538b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertdef GetBuildProp(prop, info_dict):
5548b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  """Return the fingerprint of the build of a given target-files info_dict."""
5558b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  try:
5568b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    return info_dict.get("build.prop", {})[prop]
5578b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  except KeyError:
5588b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
5598b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5608b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
561b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Baodef HandleDowngradeMetadata(metadata):
562b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao  # Only incremental OTAs are allowed to reach here.
563b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao  assert OPTIONS.incremental_source is not None
564b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao
565b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao  post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
566b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao  pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
567b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao  is_downgrade = long(post_timestamp) < long(pre_timestamp)
568b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao
569b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao  if OPTIONS.downgrade:
570b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao    if not is_downgrade:
571b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao      raise RuntimeError("--downgrade specified but no downgrade detected: "
572b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao                         "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
5733e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao    metadata["ota-downgrade"] = "yes"
5743e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao  elif OPTIONS.timestamp:
5753e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao    if not is_downgrade:
5763e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      raise RuntimeError("--timestamp specified but no timestamp hack needed: "
5773e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao                         "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
5783e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao    metadata["post-timestamp"] = str(long(pre_timestamp) + 1)
579b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao  else:
580b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao    if is_downgrade:
5813e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      raise RuntimeError("Downgrade detected based on timestamp check: "
5823e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao                         "pre: %s, post: %s. Need to specify --timestamp OR "
5833e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao                         "--downgrade to allow building the incremental." % (
5843e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao                             pre_timestamp, post_timestamp))
585b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao    metadata["post-timestamp"] = post_timestamp
586b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao
587b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao
5888b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertdef WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
5898b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  source_version = OPTIONS.source_info_dict["recovery_api_version"]
5908b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  target_version = OPTIONS.target_info_dict["recovery_api_version"]
5918b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5928b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if source_version == 0:
5933e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao    print("WARNING: generating edify script for a source that "
5943e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao          "can't install it.")
59534b47bf42b4b9fad8e775a37e40922598bb7bd96Tao Bao  script = edify_generator.EdifyGenerator(
59634b47bf42b4b9fad8e775a37e40922598bb7bd96Tao Bao      source_version, OPTIONS.target_info_dict,
59734b47bf42b4b9fad8e775a37e40922598bb7bd96Tao Bao      fstab=OPTIONS.source_info_dict["fstab"])
5988b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
5993806c231a9a229cbb6c2bb2cfb514ba25304c913Tao Bao  recovery_mount_options = OPTIONS.source_info_dict.get(
6003806c231a9a229cbb6c2bb2cfb514ba25304c913Tao Bao      "recovery_mount_options")
6013e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  source_oem_props = OPTIONS.source_info_dict.get("oem_fingerprint_properties")
6023e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  target_oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
6037f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  oem_dicts = None
6047f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  if source_oem_props and target_oem_props:
6057f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh    oem_dicts = _LoadOemDicts(script, recovery_mount_options)
6063806c231a9a229cbb6c2bb2cfb514ba25304c913Tao Bao
6078b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  metadata = {
6083e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao      "pre-device": GetOemProperty("ro.product.device", source_oem_props,
6097f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh                                   oem_dicts and oem_dicts[0],
6107f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh                                   OPTIONS.source_info_dict),
611d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao      "ota-type": "BLOCK",
6128b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  }
6138b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
614b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao  HandleDowngradeMetadata(metadata)
6155d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao
6168b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  device_specific = common.DeviceSpecificParams(
6178b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      source_zip=source_zip,
6188b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      source_version=source_version,
6198b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      target_zip=target_zip,
6208b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      target_version=target_version,
6218b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      output_zip=output_zip,
6228b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      script=script,
6238b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      metadata=metadata,
6246f0b219ac551710c724e3f344023943178cdc217Tao Bao      info_dict=OPTIONS.source_info_dict)
6258b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
6267f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  source_fp = CalculateFingerprint(source_oem_props, oem_dicts and oem_dicts[0],
6273806c231a9a229cbb6c2bb2cfb514ba25304c913Tao Bao                                   OPTIONS.source_info_dict)
6287f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  target_fp = CalculateFingerprint(target_oem_props, oem_dicts and oem_dicts[0],
6293806c231a9a229cbb6c2bb2cfb514ba25304c913Tao Bao                                   OPTIONS.target_info_dict)
6308b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  metadata["pre-build"] = source_fp
6318b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  metadata["post-build"] = target_fp
632d06f07eef48005a3fa99fdd0ca5380d60c5ae459Tianjie Xu  metadata["pre-build-incremental"] = GetBuildProp(
633d06f07eef48005a3fa99fdd0ca5380d60c5ae459Tianjie Xu      "ro.build.version.incremental", OPTIONS.source_info_dict)
634d06f07eef48005a3fa99fdd0ca5380d60c5ae459Tianjie Xu  metadata["post-build-incremental"] = GetBuildProp(
635d06f07eef48005a3fa99fdd0ca5380d60c5ae459Tianjie Xu      "ro.build.version.incremental", OPTIONS.target_info_dict)
6368b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
6378b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  source_boot = common.GetBootableImage(
6388b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
6398b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.source_info_dict)
6408b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  target_boot = common.GetBootableImage(
6418b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
6428b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  updating_boot = (not OPTIONS.two_step and
6438b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                   (source_boot.data != target_boot.data))
6448b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
6458b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  target_recovery = common.GetBootableImage(
6468b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
6478b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
6487e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao  system_src = GetImage("system", OPTIONS.source_tmp)
6497e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao  system_tgt = GetImage("system", OPTIONS.target_tmp)
6508b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
6518b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  blockimgdiff_version = 1
6528b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.info_dict:
6538b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    blockimgdiff_version = max(
6548b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        int(i) for i in
6558b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
6568b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
657f8acad1480a3b4479c7ddfa89df8be946d83d3edTao Bao  # Check the first block of the source system partition for remount R/W only
658f8acad1480a3b4479c7ddfa89df8be946d83d3edTao Bao  # if the filesystem is ext4.
659f8acad1480a3b4479c7ddfa89df8be946d83d3edTao Bao  system_src_partition = OPTIONS.source_info_dict["fstab"]["/system"]
660f8acad1480a3b4479c7ddfa89df8be946d83d3edTao Bao  check_first_block = system_src_partition.fs_type == "ext4"
661293fd135c7bc0c21b41f1782d21c26de64e8854aTao Bao  # Disable using imgdiff for squashfs. 'imgdiff -z' expects input files to be
662293fd135c7bc0c21b41f1782d21c26de64e8854aTao Bao  # in zip formats. However with squashfs, a) all files are compressed in LZ4;
663293fd135c7bc0c21b41f1782d21c26de64e8854aTao Bao  # b) the blocks listed in block map may not contain all the bytes for a given
664293fd135c7bc0c21b41f1782d21c26de64e8854aTao Bao  # file (because they're rounded to be 4K-aligned).
665f8acad1480a3b4479c7ddfa89df8be946d83d3edTao Bao  system_tgt_partition = OPTIONS.target_info_dict["fstab"]["/system"]
666f8acad1480a3b4479c7ddfa89df8be946d83d3edTao Bao  disable_imgdiff = (system_src_partition.fs_type == "squashfs" or
667f8acad1480a3b4479c7ddfa89df8be946d83d3edTao Bao                     system_tgt_partition.fs_type == "squashfs")
6688b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  system_diff = common.BlockDifference("system", system_tgt, system_src,
669fc3422ad3697b5d83adfb69133f66e1623416b18Tianjie Xu                                       check_first_block,
670293fd135c7bc0c21b41f1782d21c26de64e8854aTao Bao                                       version=blockimgdiff_version,
671293fd135c7bc0c21b41f1782d21c26de64e8854aTao Bao                                       disable_imgdiff=disable_imgdiff)
6728b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
6738b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if HasVendorPartition(target_zip):
6748b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    if not HasVendorPartition(source_zip):
6758b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      raise RuntimeError("can't generate incremental that adds /vendor")
6767e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao    vendor_src = GetImage("vendor", OPTIONS.source_tmp)
6777e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao    vendor_tgt = GetImage("vendor", OPTIONS.target_tmp)
678fc3422ad3697b5d83adfb69133f66e1623416b18Tianjie Xu
679fc3422ad3697b5d83adfb69133f66e1623416b18Tianjie Xu    # Check first block of vendor partition for remount R/W only if
680fc3422ad3697b5d83adfb69133f66e1623416b18Tianjie Xu    # disk type is ext4
681fc3422ad3697b5d83adfb69133f66e1623416b18Tianjie Xu    vendor_partition = OPTIONS.source_info_dict["fstab"]["/vendor"]
682d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao    check_first_block = vendor_partition.fs_type == "ext4"
683293fd135c7bc0c21b41f1782d21c26de64e8854aTao Bao    disable_imgdiff = vendor_partition.fs_type == "squashfs"
6848b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
685fc3422ad3697b5d83adfb69133f66e1623416b18Tianjie Xu                                         check_first_block,
686293fd135c7bc0c21b41f1782d21c26de64e8854aTao Bao                                         version=blockimgdiff_version,
687293fd135c7bc0c21b41f1782d21c26de64e8854aTao Bao                                         disable_imgdiff=disable_imgdiff)
6888b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  else:
6898b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    vendor_diff = None
6908b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
6917f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  AppendAssertions(script, OPTIONS.target_info_dict, oem_dicts)
6928b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  device_specific.IncrementalOTA_Assertions()
6938b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
6948b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # Two-step incremental package strategy (in chronological order,
6958b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # which is *not* the order in which the generated script has
6968b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # things):
6978b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #
6988b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # if stage is not "2/3" or "3/3":
6998b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    do verification on current system
7008b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    write recovery image to boot partition
7018b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    set stage to "2/3"
7028b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    reboot to boot partition and restart recovery
7038b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # else if stage is "2/3":
7048b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    write recovery image to recovery partition
7058b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    set stage to "3/3"
7068b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    reboot to recovery partition and restart recovery
7078b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # else:
7088b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    (stage must be "3/3")
7098b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    perform update:
7108b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #       patch system files, etc.
7118b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #       force full install of new boot image
7128b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #       set up system to update recovery partition on first boot
7138b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    complete script normally
7148b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  #    (allow recovery to mark itself finished and reboot)
7158b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
7168b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.two_step:
717dd24da9ec91b74b7e3c8d1af9f1f9f792d41ac4dTao Bao    if not OPTIONS.source_info_dict.get("multistage_support", None):
7188b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      assert False, "two-step packages not supported by this build"
719dd24da9ec91b74b7e3c8d1af9f1f9f792d41ac4dTao Bao    fs = OPTIONS.source_info_dict["fstab"]["/misc"]
7208b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    assert fs.fs_type.upper() == "EMMC", \
7218b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        "two-step packages only supported on devices with EMMC /misc partitions"
7228b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    bcb_dev = {"bcb_dev": fs.device}
7238b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
7248b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra("""
7258b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertif get_stage("%(bcb_dev)s") == "2/3" then
7268b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert""" % bcb_dev)
727d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
728d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    # Stage 2/3: Write recovery image to /recovery (currently running /boot).
729d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    script.Comment("Stage 2/3")
7308b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra("sleep(20);\n")
7318b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.WriteRawImage("/recovery", "recovery.img")
7328b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra("""
7338b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertset_stage("%(bcb_dev)s", "3/3");
7348b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertreboot_now("%(bcb_dev)s", "recovery");
7358b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertelse if get_stage("%(bcb_dev)s") != "3/3" then
7368b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert""" % bcb_dev)
7378b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
738d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    # Stage 1/3: (a) Verify the current system.
739d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    script.Comment("Stage 1/3")
740d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
7416c55a8adc81a3a2febd4e4a61f70cb464906e3b8Tao Bao  # Dump fingerprints
742f9023856ad04cbe866939bbdd9efcd3cecc286a3Tao Bao  script.Print("Source: %s" % (source_fp,))
743f9023856ad04cbe866939bbdd9efcd3cecc286a3Tao Bao  script.Print("Target: %s" % (target_fp,))
7446c55a8adc81a3a2febd4e4a61f70cb464906e3b8Tao Bao
7458b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  script.Print("Verifying current system...")
7468b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
7478b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  device_specific.IncrementalOTA_VerifyBegin()
7488b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
7493e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
7503e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  # patching on a device that's already on the target build will damage the
7513e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  # system. Because operations like move don't check the block state, they
7523e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  # always apply the changes unconditionally.
7533e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  if blockimgdiff_version <= 2:
7543e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao    if source_oem_props is None:
7558b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      script.AssertSomeFingerprint(source_fp)
7568b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    else:
7578b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      script.AssertSomeThumbprint(
7588b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert          GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
7593e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao
7603e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  else: # blockimgdiff_version > 2
7613e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao    if source_oem_props is None and target_oem_props is None:
7623e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao      script.AssertSomeFingerprint(source_fp, target_fp)
7633e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao    elif source_oem_props is not None and target_oem_props is not None:
764838c68fa1ae35a4b0fd017e92728cb5720f74782Tao Bao      script.AssertSomeThumbprint(
765838c68fa1ae35a4b0fd017e92728cb5720f74782Tao Bao          GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
766c086370440bb32501da427718a7313f12ec2c841Tao Bao          GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
7673e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao    elif source_oem_props is None and target_oem_props is not None:
7683e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao      script.AssertFingerprintOrThumbprint(
7693e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao          source_fp,
7703e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao          GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict))
7713e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao    else:
7723e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao      script.AssertFingerprintOrThumbprint(
7733e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao          target_fp,
7743e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao          GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
7758b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
776d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao  # Check the required cache size (i.e. stashed blocks).
777d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao  size = []
778d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao  if system_diff:
779d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao    size.append(system_diff.required_cache)
780d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao  if vendor_diff:
781d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao    size.append(vendor_diff.required_cache)
782d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao
7838b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if updating_boot:
784dd24da9ec91b74b7e3c8d1af9f1f9f792d41ac4dTao Bao    boot_type, boot_device = common.GetTypeAndDevice(
785dd24da9ec91b74b7e3c8d1af9f1f9f792d41ac4dTao Bao        "/boot", OPTIONS.source_info_dict)
7868b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    d = common.Difference(target_boot, source_boot)
7878b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    _, _, d = d.ComputePatch()
7888b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    if d is None:
7898b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      include_full_boot = True
7908b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
7918b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    else:
7928b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      include_full_boot = False
7938b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
79489fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao      print("boot      target: %d  source: %d  diff: %d" % (
79589fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao          target_boot.size, source_boot.size, len(d)))
7968b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
7978b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
7988b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
7998b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      script.PatchCheck("%s:%s:%d:%s:%d:%s" %
8008b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                        (boot_type, boot_device,
8018b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                         source_boot.size, source_boot.sha1,
8028b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                         target_boot.size, target_boot.sha1))
803d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao      size.append(target_boot.size)
804d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao
805d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao  if size:
806d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao    script.CacheFreeSpaceCheck(max(size))
8078b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8088b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  device_specific.IncrementalOTA_VerifyEnd()
8098b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8108b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.two_step:
811d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    # Stage 1/3: (b) Write recovery image to /boot.
812d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    _WriteRecoveryImageToBoot(script, output_zip)
813d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
8148b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra("""
8158b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertset_stage("%(bcb_dev)s", "2/3");
8168b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertreboot_now("%(bcb_dev)s", "");
8178b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertelse
8188b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert""" % bcb_dev)
8198b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
820d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    # Stage 3/3: Make changes.
821d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao    script.Comment("Stage 3/3")
822d42e97ebb45fdc5a30799a3f37e482948d318010Tao Bao
8238b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # Verify the existing partitions.
824d522bdc9edbf64d15a59c6924853b2e2c8c39e90Tao Bao  system_diff.WriteVerifyScript(script, touched_blocks_only=True)
8258b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if vendor_diff:
826d522bdc9edbf64d15a59c6924853b2e2c8c39e90Tao Bao    vendor_diff.WriteVerifyScript(script, touched_blocks_only=True)
8278b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8288b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  script.Comment("---- start making changes here ----")
8298b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8308b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  device_specific.IncrementalOTA_InstallBegin()
8318b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8328b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  system_diff.WriteScript(script, output_zip,
8338b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                          progress=0.8 if vendor_diff else 0.9)
83468658c0f4fe5420226df5849b642f98fb7f5d984Tao Bao
8358b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if vendor_diff:
8368b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    vendor_diff.WriteScript(script, output_zip, progress=0.1)
8378b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8388b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.two_step:
8398b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
8408b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.WriteRawImage("/boot", "boot.img")
84189fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao    print("writing full boot image (forced by two-step mode)")
8428b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8438b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if not OPTIONS.two_step:
8448b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    if updating_boot:
8458b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      if include_full_boot:
84689fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao        print("boot image changed; including full.")
8478b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        script.Print("Installing boot image...")
8488b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        script.WriteRawImage("/boot", "boot.img")
8498b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      else:
8508b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        # Produce the boot image by applying a patch to the current
8518b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        # contents of the boot partition, and write it back to the
8528b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        # partition.
85389fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao        print("boot image changed; including patch.")
8548b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        script.Print("Patching boot image...")
8558b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        script.ShowProgress(0.1, 10)
8568b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        script.ApplyPatch("%s:%s:%d:%s:%d:%s"
8578b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                          % (boot_type, boot_device,
8588b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                             source_boot.size, source_boot.sha1,
8598b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                             target_boot.size, target_boot.sha1),
8608b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                          "-",
8618b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                          target_boot.size, target_boot.sha1,
8628b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                          source_boot.sha1, "patch/boot.img.p")
8638b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    else:
86489fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao      print("boot image unchanged; skipping.")
8658b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8668b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # Do device-specific installation (eg, write radio image).
8678b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  device_specific.IncrementalOTA_InstallEnd()
8688b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8698b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.extra_script is not None:
8708b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra(OPTIONS.extra_script)
8718b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8728b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.wipe_user_data:
8738b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.Print("Erasing user data...")
8748b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.FormatPartition("/data")
8755d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao    metadata["ota-wipe"] = "yes"
8768b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8778b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.two_step:
8788b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    script.AppendExtra("""
8798b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertset_stage("%(bcb_dev)s", "");
8808b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertendif;
8818b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertendif;
8828b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert""" % bcb_dev)
8838b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8848b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  script.SetProgress(1)
8854996cf03d2321eef56a8163c7fc73ba9976e1021Tao Bao  # For downgrade OTAs, we prefer to use the update-binary in the source
8864996cf03d2321eef56a8163c7fc73ba9976e1021Tao Bao  # build that is actually newer than the one in the target build.
8874996cf03d2321eef56a8163c7fc73ba9976e1021Tao Bao  if OPTIONS.downgrade:
8884996cf03d2321eef56a8163c7fc73ba9976e1021Tao Bao    script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
8894996cf03d2321eef56a8163c7fc73ba9976e1021Tao Bao  else:
8904996cf03d2321eef56a8163c7fc73ba9976e1021Tao Bao    script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
891d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao  metadata["ota-required-cache"] = str(script.required_cache)
8928b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  WriteMetadata(metadata, output_zip)
8938b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8948b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
8959bc6bb23b5bf64635275041fecace64635f41fbaTao Baodef WriteVerifyPackage(input_zip, output_zip):
8969bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
8979bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
8989bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
8999bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  recovery_mount_options = OPTIONS.info_dict.get(
9009bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      "recovery_mount_options")
9017f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  oem_dicts = None
9023e30d97dde42416a1762c161ed7217d4e7ebf2c6Tao Bao  if oem_props:
903ebce697429c9db5ffd6ac52fc8f4bbf9cd56f9c6Tao Bao    oem_dicts = _LoadOemDicts(script, recovery_mount_options)
9047f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh
9057f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
9067f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh                                   OPTIONS.info_dict)
9079bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  metadata = {
9089bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      "post-build": target_fp,
9097f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      "pre-device": GetOemProperty("ro.product.device", oem_props,
9107f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh                                   oem_dicts and oem_dicts[0],
9119bc6bb23b5bf64635275041fecace64635f41fbaTao Bao                                   OPTIONS.info_dict),
9129bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
9139bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  }
9149bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
9159bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  device_specific = common.DeviceSpecificParams(
9169bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      input_zip=input_zip,
9179bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      input_version=OPTIONS.info_dict["recovery_api_version"],
9189bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      output_zip=output_zip,
9199bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      script=script,
9209bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      input_tmp=OPTIONS.input_tmp,
9219bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      metadata=metadata,
9229bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      info_dict=OPTIONS.info_dict)
9239bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
9247f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  AppendAssertions(script, OPTIONS.info_dict, oem_dicts)
9259bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
9269bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  script.Print("Verifying device images against %s..." % target_fp)
9279bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  script.AppendExtra("")
9289bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
9299bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  script.Print("Verifying boot...")
9309bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  boot_img = common.GetBootableImage(
9319bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
9329bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  boot_type, boot_device = common.GetTypeAndDevice(
9339bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      "/boot", OPTIONS.info_dict)
9349bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  script.Verify("%s:%s:%d:%s" % (
9359bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      boot_type, boot_device, boot_img.size, boot_img.sha1))
9369bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  script.AppendExtra("")
9379bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
9389bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  script.Print("Verifying recovery...")
9399bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  recovery_img = common.GetBootableImage(
9409bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
9419bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  recovery_type, recovery_device = common.GetTypeAndDevice(
9429bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      "/recovery", OPTIONS.info_dict)
9439bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  script.Verify("%s:%s:%d:%s" % (
9449bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      recovery_type, recovery_device, recovery_img.size, recovery_img.sha1))
9459bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  script.AppendExtra("")
9469bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
9477e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao  system_tgt = GetImage("system", OPTIONS.input_tmp)
9489bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  system_tgt.ResetFileMap()
9499bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  system_diff = common.BlockDifference("system", system_tgt, src=None)
9509bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  system_diff.WriteStrictVerifyScript(script)
9519bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
9529bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  if HasVendorPartition(input_zip):
9537e0f160f30247ce234dfc563fc4f1e3a008fed20Tao Bao    vendor_tgt = GetImage("vendor", OPTIONS.input_tmp)
9549bc6bb23b5bf64635275041fecace64635f41fbaTao Bao    vendor_tgt.ResetFileMap()
9559bc6bb23b5bf64635275041fecace64635f41fbaTao Bao    vendor_diff = common.BlockDifference("vendor", vendor_tgt, src=None)
9569bc6bb23b5bf64635275041fecace64635f41fbaTao Bao    vendor_diff.WriteStrictVerifyScript(script)
9579bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
9589bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  # Device specific partitions, such as radio, bootloader and etc.
9599bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  device_specific.VerifyOTA_Assertions()
9609bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
9619bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  script.SetProgress(1.0)
9629bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
963d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao  metadata["ota-required-cache"] = str(script.required_cache)
9649bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  WriteMetadata(metadata, output_zip)
9659bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
9669bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
967c098e9efd989a46d5d1aa625bc899536de15eaaaTao Baodef WriteABOTAPackageWithBrilloScript(target_file, output_file,
968c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao                                      source_file=None):
969c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  """Generate an Android OTA package that has A/B update payload."""
970c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
9712dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  def ComputeStreamingMetadata(zip_file, reserve_space=False,
9722dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao                               expected_length=None):
9732dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    """Compute the streaming metadata for a given zip.
9742dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao
9752dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    When 'reserve_space' is True, we reserve extra space for the offset and
9762dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    length of the metadata entry itself, although we don't know the final
9772dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    values until the package gets signed. This function will be called again
9782dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    after signing. We then write the actual values and pad the string to the
9792dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    length we set earlier. Note that we can't use the actual length of the
9802dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    metadata entry in the second run. Otherwise the offsets for other entries
9812dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    will be changing again.
9822dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    """
983c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao
984c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao    def ComputeEntryOffsetSize(name):
985c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao      """Compute the zip entry offset and size."""
986c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao      info = zip_file.getinfo(name)
987c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao      offset = info.header_offset + len(info.FileHeader())
988c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao      size = info.file_size
9892dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao      return '%s:%d:%d' % (os.path.basename(name), offset, size)
990c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao
991c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao    # payload.bin and payload_properties.txt must exist.
992c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao    offsets = [ComputeEntryOffsetSize('payload.bin'),
993c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao               ComputeEntryOffsetSize('payload_properties.txt')]
994c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao
995c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao    # care_map.txt is available only if dm-verity is enabled.
996c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao    if 'care_map.txt' in zip_file.namelist():
997c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao      offsets.append(ComputeEntryOffsetSize('care_map.txt'))
9982dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao
999b63c952cc72eda821532b3bcb00a66278503287eTao Bao    if 'compatibility.zip' in zip_file.namelist():
1000b63c952cc72eda821532b3bcb00a66278503287eTao Bao      offsets.append(ComputeEntryOffsetSize('compatibility.zip'))
1001b63c952cc72eda821532b3bcb00a66278503287eTao Bao
10022dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    # 'META-INF/com/android/metadata' is required. We don't know its actual
10032dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    # offset and length (as well as the values for other entries). So we
10042dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    # reserve 10-byte as a placeholder, which is to cover the space for metadata
10052dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    # entry ('xx:xxx', since it's ZIP_STORED which should appear at the
10062dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    # beginning of the zip), as well as the possible value changes in other
10072dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    # entries.
10082dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    if reserve_space:
10092dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao      offsets.append('metadata:' + ' ' * 10)
10102dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    else:
10112dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao      offsets.append(ComputeEntryOffsetSize(METADATA_NAME))
10122dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao
10132dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    value = ','.join(offsets)
10142dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    if expected_length is not None:
10152dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao      assert len(value) <= expected_length, \
10162dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao          'Insufficient reserved space: reserved=%d, actual=%d' % (
10172dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao              expected_length, len(value))
10182dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao      value += ' ' * (expected_length - len(value))
10192dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    return value
1020c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao
1021d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  # The place where the output from the subprocess should go.
1022d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  log_file = sys.stdout if OPTIONS.verbose else subprocess.PIPE
1023d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo
1024c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  # Setup signing keys.
1025c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  if OPTIONS.package_key is None:
1026c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao    OPTIONS.package_key = OPTIONS.info_dict.get(
1027c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao        "default_system_dev_certificate",
1028c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao        "build/target/product/security/testkey")
1029c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1030dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao  # A/B updater expects a signing key in RSA format. Gets the key ready for
1031dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao  # later use in step 3, unless a payload_signer has been specified.
1032dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao  if OPTIONS.payload_signer is None:
1033dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao    cmd = ["openssl", "pkcs8",
1034dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao           "-in", OPTIONS.package_key + OPTIONS.private_key_suffix,
1035dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao           "-inform", "DER", "-nocrypt"]
1036dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao    rsa_key = common.MakeTempFile(prefix="key-", suffix=".key")
1037dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao    cmd.extend(["-out", rsa_key])
10386047c24faea772eabe2eaad96087290f47720c75Tao Bao    p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
10396047c24faea772eabe2eaad96087290f47720c75Tao Bao    p1.communicate()
1040dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao    assert p1.returncode == 0, "openssl pkcs8 failed"
1041dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao
1042dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao  # Stage the output zip package for package signing.
1043c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  temp_zip_file = tempfile.NamedTemporaryFile()
1044c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  output_zip = zipfile.ZipFile(temp_zip_file, "w",
1045c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao                               compression=zipfile.ZIP_DEFLATED)
1046c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1047c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  # Metadata to comply with Android OTA package format.
1048c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties", None)
10497f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh  oem_dicts = None
1050c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  if oem_props:
1051ebce697429c9db5ffd6ac52fc8f4bbf9cd56f9c6Tao Bao    oem_dicts = _LoadOemDicts(None)
1052c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1053c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  metadata = {
10547f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      "post-build": CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
1055c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao                                         OPTIONS.info_dict),
1056d06f07eef48005a3fa99fdd0ca5380d60c5ae459Tianjie Xu      "post-build-incremental" : GetBuildProp("ro.build.version.incremental",
1057d06f07eef48005a3fa99fdd0ca5380d60c5ae459Tianjie Xu                                              OPTIONS.info_dict),
10587f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      "pre-device": GetOemProperty("ro.product.device", oem_props,
10597f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh                                   oem_dicts and oem_dicts[0],
1060c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao                                   OPTIONS.info_dict),
1061d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao      "ota-required-cache": "0",
1062d8d14bec0d9fb604060634729b4a09c7898d0c9aTao Bao      "ota-type": "AB",
1063c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  }
1064c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1065c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  if source_file is not None:
10667f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh    metadata["pre-build"] = CalculateFingerprint(oem_props,
10677f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh                                                 oem_dicts and oem_dicts[0],
1068c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao                                                 OPTIONS.source_info_dict)
1069d06f07eef48005a3fa99fdd0ca5380d60c5ae459Tianjie Xu    metadata["pre-build-incremental"] = GetBuildProp(
1070d06f07eef48005a3fa99fdd0ca5380d60c5ae459Tianjie Xu        "ro.build.version.incremental", OPTIONS.source_info_dict)
1071c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1072b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao    HandleDowngradeMetadata(metadata)
1073b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao  else:
1074b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao    metadata["post-timestamp"] = GetBuildProp(
1075b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao        "ro.build.date.utc", OPTIONS.info_dict)
1076b31892e5de3259e5bcce3b43399f9fa7f723f81dTao Bao
1077c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  # 1. Generate payload.
1078c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  payload_file = common.MakeTempFile(prefix="payload-", suffix=".bin")
1079c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  cmd = ["brillo_update_payload", "generate",
1080c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao         "--payload", payload_file,
1081c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao         "--target_image", target_file]
1082c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  if source_file is not None:
1083c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao    cmd.extend(["--source_image", source_file])
1084d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1085d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1.communicate()
1086c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  assert p1.returncode == 0, "brillo_update_payload generate failed"
1087c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1088c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  # 2. Generate hashes of the payload and metadata files.
1089c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1090c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1091c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  cmd = ["brillo_update_payload", "hash",
1092c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao         "--unsigned_payload", payload_file,
1093c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao         "--signature_size", "256",
1094c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao         "--metadata_hash_file", metadata_sig_file,
1095c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao         "--payload_hash_file", payload_sig_file]
1096d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1097d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1.communicate()
1098c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  assert p1.returncode == 0, "brillo_update_payload hash failed"
1099c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1100c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  # 3. Sign the hashes and insert them back into the payload file.
1101c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  signed_payload_sig_file = common.MakeTempFile(prefix="signed-sig-",
1102c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao                                                suffix=".bin")
1103c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  signed_metadata_sig_file = common.MakeTempFile(prefix="signed-sig-",
1104c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao                                                 suffix=".bin")
1105c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  # 3a. Sign the payload hash.
1106dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao  if OPTIONS.payload_signer is not None:
11072abbbd03339947327ada0becba5bd4ef41f1bdabBaligh Uddin    cmd = [OPTIONS.payload_signer]
11082abbbd03339947327ada0becba5bd4ef41f1bdabBaligh Uddin    cmd.extend(OPTIONS.payload_signer_args)
1109dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao  else:
1110dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao    cmd = ["openssl", "pkeyutl", "-sign",
1111dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao           "-inkey", rsa_key,
1112dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao           "-pkeyopt", "digest:sha256"]
1113dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao  cmd.extend(["-in", payload_sig_file,
1114dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao              "-out", signed_payload_sig_file])
1115d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1116d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1.communicate()
1117c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  assert p1.returncode == 0, "openssl sign payload failed"
1118c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1119c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  # 3b. Sign the metadata hash.
1120dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao  if OPTIONS.payload_signer is not None:
11212abbbd03339947327ada0becba5bd4ef41f1bdabBaligh Uddin    cmd = [OPTIONS.payload_signer]
11222abbbd03339947327ada0becba5bd4ef41f1bdabBaligh Uddin    cmd.extend(OPTIONS.payload_signer_args)
1123dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao  else:
1124dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao    cmd = ["openssl", "pkeyutl", "-sign",
1125dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao           "-inkey", rsa_key,
1126dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao           "-pkeyopt", "digest:sha256"]
1127dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao  cmd.extend(["-in", metadata_sig_file,
1128dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao              "-out", signed_metadata_sig_file])
1129d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1130d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1.communicate()
1131c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  assert p1.returncode == 0, "openssl sign metadata failed"
1132c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1133c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  # 3c. Insert the signatures back into the payload file.
1134c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  signed_payload_file = common.MakeTempFile(prefix="signed-payload-",
1135c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao                                            suffix=".bin")
1136c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  cmd = ["brillo_update_payload", "sign",
1137c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao         "--unsigned_payload", payload_file,
1138c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao         "--payload", signed_payload_file,
1139c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao         "--signature_size", "256",
1140c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao         "--metadata_signature_file", signed_metadata_sig_file,
1141c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao         "--payload_signature_file", signed_payload_sig_file]
1142d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1143d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1.communicate()
1144c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  assert p1.returncode == 0, "brillo_update_payload sign failed"
1145c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
114619241c11bd1cf039bcd74859426ad22282849912Alex Deymo  # 4. Dump the signed payload properties.
114719241c11bd1cf039bcd74859426ad22282849912Alex Deymo  properties_file = common.MakeTempFile(prefix="payload-properties-",
114819241c11bd1cf039bcd74859426ad22282849912Alex Deymo                                        suffix=".txt")
114919241c11bd1cf039bcd74859426ad22282849912Alex Deymo  cmd = ["brillo_update_payload", "properties",
115019241c11bd1cf039bcd74859426ad22282849912Alex Deymo         "--payload", signed_payload_file,
115119241c11bd1cf039bcd74859426ad22282849912Alex Deymo         "--properties_file", properties_file]
1152d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1153d8d96ecdaebbccc003a5de6a7b90661d4de016abAlex Deymo  p1.communicate()
115419241c11bd1cf039bcd74859426ad22282849912Alex Deymo  assert p1.returncode == 0, "brillo_update_payload properties failed"
115519241c11bd1cf039bcd74859426ad22282849912Alex Deymo
11567c5dc578b3b683c3fc02c32b76562f7f2fcb6dbdTao Bao  if OPTIONS.wipe_user_data:
11577c5dc578b3b683c3fc02c32b76562f7f2fcb6dbdTao Bao    with open(properties_file, "a") as f:
11587c5dc578b3b683c3fc02c32b76562f7f2fcb6dbdTao Bao      f.write("POWERWASH=1\n")
11597c5dc578b3b683c3fc02c32b76562f7f2fcb6dbdTao Bao    metadata["ota-wipe"] = "yes"
11607c5dc578b3b683c3fc02c32b76562f7f2fcb6dbdTao Bao
1161c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao  # Add the signed payload file and properties into the zip. In order to
1162c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao  # support streaming, we pack payload.bin, payload_properties.txt and
1163c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao  # care_map.txt as ZIP_STORED. So these entries can be read directly with
1164c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao  # the offset and length pairs.
1165c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  common.ZipWrite(output_zip, signed_payload_file, arcname="payload.bin",
1166c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao                  compress_type=zipfile.ZIP_STORED)
1167c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao  common.ZipWrite(output_zip, properties_file,
1168c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao                  arcname="payload_properties.txt",
1169c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao                  compress_type=zipfile.ZIP_STORED)
1170c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1171cfa86223d62a6afa0eb8f5a1a215e985bb0a8c89Tianjie Xu  # If dm-verity is supported for the device, copy contents of care_map
1172cfa86223d62a6afa0eb8f5a1a215e985bb0a8c89Tianjie Xu  # into A/B OTA package.
1173b63c952cc72eda821532b3bcb00a66278503287eTao Bao  target_zip = zipfile.ZipFile(target_file, "r")
1174cfa86223d62a6afa0eb8f5a1a215e985bb0a8c89Tianjie Xu  if OPTIONS.info_dict.get("verity") == "true":
1175cfa86223d62a6afa0eb8f5a1a215e985bb0a8c89Tianjie Xu    care_map_path = "META/care_map.txt"
1176cfa86223d62a6afa0eb8f5a1a215e985bb0a8c89Tianjie Xu    namelist = target_zip.namelist()
1177cfa86223d62a6afa0eb8f5a1a215e985bb0a8c89Tianjie Xu    if care_map_path in namelist:
1178cfa86223d62a6afa0eb8f5a1a215e985bb0a8c89Tianjie Xu      care_map_data = target_zip.read(care_map_path)
1179c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao      common.ZipWriteStr(output_zip, "care_map.txt", care_map_data,
1180c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao          compress_type=zipfile.ZIP_STORED)
1181cfa86223d62a6afa0eb8f5a1a215e985bb0a8c89Tianjie Xu    else:
118289fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao      print("Warning: cannot find care map file in target_file package")
1183b63c952cc72eda821532b3bcb00a66278503287eTao Bao
1184b63c952cc72eda821532b3bcb00a66278503287eTao Bao  if HasVendorPartition(target_zip):
1185b63c952cc72eda821532b3bcb00a66278503287eTao Bao    update_vendor = True
1186b63c952cc72eda821532b3bcb00a66278503287eTao Bao    update_system = True
1187b63c952cc72eda821532b3bcb00a66278503287eTao Bao
1188b63c952cc72eda821532b3bcb00a66278503287eTao Bao    # If incremental then figure out what is being updated so metadata only for
1189b63c952cc72eda821532b3bcb00a66278503287eTao Bao    # the updated image is included.
1190b63c952cc72eda821532b3bcb00a66278503287eTao Bao    if source_file is not None:
1191b63c952cc72eda821532b3bcb00a66278503287eTao Bao      input_tmp, input_zip = common.UnzipTemp(
1192b63c952cc72eda821532b3bcb00a66278503287eTao Bao          target_file, UNZIP_PATTERN)
1193b63c952cc72eda821532b3bcb00a66278503287eTao Bao      source_tmp, source_zip = common.UnzipTemp(
1194b63c952cc72eda821532b3bcb00a66278503287eTao Bao          source_file, UNZIP_PATTERN)
1195b63c952cc72eda821532b3bcb00a66278503287eTao Bao
1196b63c952cc72eda821532b3bcb00a66278503287eTao Bao      vendor_src = GetImage("vendor", source_tmp)
1197b63c952cc72eda821532b3bcb00a66278503287eTao Bao      vendor_tgt = GetImage("vendor", input_tmp)
1198b63c952cc72eda821532b3bcb00a66278503287eTao Bao      system_src = GetImage("system", source_tmp)
1199b63c952cc72eda821532b3bcb00a66278503287eTao Bao      system_tgt = GetImage("system", input_tmp)
1200b63c952cc72eda821532b3bcb00a66278503287eTao Bao
1201b63c952cc72eda821532b3bcb00a66278503287eTao Bao      update_system = system_src.TotalSha1() != system_tgt.TotalSha1()
1202b63c952cc72eda821532b3bcb00a66278503287eTao Bao      update_vendor = vendor_src.TotalSha1() != vendor_tgt.TotalSha1()
1203b63c952cc72eda821532b3bcb00a66278503287eTao Bao
1204b63c952cc72eda821532b3bcb00a66278503287eTao Bao      input_zip.close()
1205b63c952cc72eda821532b3bcb00a66278503287eTao Bao      source_zip.close()
1206b63c952cc72eda821532b3bcb00a66278503287eTao Bao
1207b63c952cc72eda821532b3bcb00a66278503287eTao Bao    target_zip = zipfile.ZipFile(target_file, "r")
1208b63c952cc72eda821532b3bcb00a66278503287eTao Bao    AddCompatibilityArchive(target_zip, output_zip, update_system,
1209b63c952cc72eda821532b3bcb00a66278503287eTao Bao                            update_vendor)
1210b63c952cc72eda821532b3bcb00a66278503287eTao Bao  common.ZipClose(target_zip)
1211cfa86223d62a6afa0eb8f5a1a215e985bb0a8c89Tianjie Xu
12122dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  # Write the current metadata entry with placeholders.
12132dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
12142dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao      output_zip, reserve_space=True)
12152dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  WriteMetadata(metadata, output_zip)
1216c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  common.ZipClose(output_zip)
1217c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
12182dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  # SignOutput(), which in turn calls signapk.jar, will possibly reorder the
12192dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  # zip entries, as well as padding the entry headers. We do a preliminary
12202dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  # signing (with an incomplete metadata entry) to allow that to happen. Then
12212dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  # compute the zip entry offsets, write back the final metadata and do the
12222dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  # final signing.
12232dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  prelim_signing = tempfile.NamedTemporaryFile()
12242dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  SignOutput(temp_zip_file.name, prelim_signing.name)
12252dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  common.ZipClose(temp_zip_file)
12262dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao
12272dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  # Open the signed zip. Compute the final metadata that's needed for streaming.
12282dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  prelim_zip = zipfile.ZipFile(prelim_signing, "r",
1229c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao                               compression=zipfile.ZIP_DEFLATED)
12302dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  expected_length = len(metadata['ota-streaming-property-files'])
1231bfdcb1257cbb1acd91fe546b7c91a3277154211aTao Bao  metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
12322dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao      prelim_zip, reserve_space=False, expected_length=expected_length)
12332dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao
12342dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  # Copy the zip entries, as we cannot update / delete entries with zipfile.
12352dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  final_signing = tempfile.NamedTemporaryFile()
12362dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  output_zip = zipfile.ZipFile(final_signing, "w",
12372dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao                               compression=zipfile.ZIP_DEFLATED)
12382dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  for item in prelim_zip.infolist():
12392dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    if item.filename == METADATA_NAME:
12402dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao      continue
12412dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao
12422dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    data = prelim_zip.read(item.filename)
12432dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    out_info = copy.copy(item)
12442dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao    common.ZipWriteStr(output_zip, out_info, data)
1245c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao
12462dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  # Now write the final metadata entry.
1247c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao  WriteMetadata(metadata, output_zip)
12482dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  common.ZipClose(prelim_zip)
1249c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao  common.ZipClose(output_zip)
1250c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao
12512dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  # Re-sign the package after updating the metadata entry.
12522dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  SignOutput(final_signing.name, output_file)
12532dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  final_signing.close()
1254c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao
12552dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  # Reopen the final signed zip to double check the streaming metadata.
1256c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao  output_zip = zipfile.ZipFile(output_file, "r")
12572dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  actual = metadata['ota-streaming-property-files'].strip()
12582dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  expected = ComputeStreamingMetadata(output_zip)
12592dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao  assert actual == expected, \
12602dd1c4837712a1ec3f5c9dc7d861247894a1eb4fTao Bao      "Mismatching streaming metadata: %s vs %s." % (actual, expected)
1261c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao  common.ZipClose(output_zip)
1262c96316c89b6b4fdcccdb46c8a39c79eb62468fffTao Bao
1263c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
12648b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertdef main(argv):
12658b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
12668b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  def option_handler(o, a):
12678b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    if o == "--board_config":
12688b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      pass   # deprecated
12698b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o in ("-k", "--package_key"):
12708b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.package_key = a
12718b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o in ("-i", "--incremental_from"):
12728b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.incremental_source = a
127343078aa37aa771149bfd85d10c47cce4e818b3d4Tao Bao    elif o == "--full_radio":
127443078aa37aa771149bfd85d10c47cce4e818b3d4Tao Bao      OPTIONS.full_radio = True
1275aa6c1a144545b655837d024445020ecba202f0e0leozwang    elif o == "--full_bootloader":
1276aa6c1a144545b655837d024445020ecba202f0e0leozwang      OPTIONS.full_bootloader = True
12778b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o in ("-w", "--wipe_user_data"):
12788b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.wipe_user_data = True
12795d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao    elif o == "--downgrade":
12805d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao      OPTIONS.downgrade = True
12815d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao      OPTIONS.wipe_user_data = True
12823e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao    elif o == "--override_timestamp":
12833e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      OPTIONS.timestamp = True
12848b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o in ("-o", "--oem_settings"):
12857f804ba71fd5fa32e6d9735ec2544075a63b9684Alain Vongsouvanh      OPTIONS.oem_source = a.split(',')
12868608cde944d64dece63e8c770deb78c1d092c719Tao Bao    elif o == "--oem_no_mount":
12878608cde944d64dece63e8c770deb78c1d092c719Tao Bao      OPTIONS.oem_no_mount = True
12888b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o in ("-e", "--extra_script"):
12898b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.extra_script = a
12908b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o in ("-t", "--worker_threads"):
12918b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      if a.isdigit():
12928b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        OPTIONS.worker_threads = int(a)
12938b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      else:
12948b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert        raise ValueError("Cannot parse value %r for option %r - only "
12958b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                         "integers are allowed." % (a, o))
12968b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o in ("-2", "--two_step"):
12978b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.two_step = True
12988b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o == "--no_signing":
12998b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.no_signing = True
13008b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o == "--verify":
13018b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.verify = True
13028b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o == "--block":
13038b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.block_based = True
13048b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o in ("-b", "--binary"):
13058b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.updater_binary = a
13068b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    elif o in ("--no_fallback_to_full",):
13078b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.fallback_to_full = False
13088dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao    elif o == "--stash_threshold":
13098dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao      try:
13108dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao        OPTIONS.stash_threshold = float(a)
13118dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao      except ValueError:
13128dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao        raise ValueError("Cannot parse value %r for option %r - expecting "
13138dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao                         "a float" % (a, o))
13149bc6bb23b5bf64635275041fecace64635f41fbaTao Bao    elif o == "--gen_verify":
13159bc6bb23b5bf64635275041fecace64635f41fbaTao Bao      OPTIONS.gen_verify = True
1316d62c603573c53713164fda0430d477daa11d5e31Tao Bao    elif o == "--log_diff":
1317d62c603573c53713164fda0430d477daa11d5e31Tao Bao      OPTIONS.log_diff = a
1318dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao    elif o == "--payload_signer":
1319dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao      OPTIONS.payload_signer = a
13202abbbd03339947327ada0becba5bd4ef41f1bdabBaligh Uddin    elif o == "--payload_signer_args":
13212abbbd03339947327ada0becba5bd4ef41f1bdabBaligh Uddin      OPTIONS.payload_signer_args = shlex.split(a)
1322cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    elif o == "--extracted_input_target_files":
1323cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen      OPTIONS.extracted_input = a
13248b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    else:
13258b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      return False
13268b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    return True
13278b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
13288b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  args = common.ParseOptions(argv, __doc__,
13292a0d1da4d9c064e8cefd581aea9031aa9e79a3beTao Bao                             extra_opts="b:k:i:d:we:t:2o:",
13308b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                             extra_long_opts=[
13318b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "board_config=",
13328b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "package_key=",
13338b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "incremental_from=",
133443078aa37aa771149bfd85d10c47cce4e818b3d4Tao Bao                                 "full_radio",
1335aa6c1a144545b655837d024445020ecba202f0e0leozwang                                 "full_bootloader",
13368b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "wipe_user_data",
13375d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao                                 "downgrade",
13383e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao                                 "override_timestamp",
13398b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "extra_script=",
13408b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "worker_threads=",
13418b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "two_step",
13428b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "no_signing",
13438b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "block",
13448b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "binary=",
13458b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "oem_settings=",
13468608cde944d64dece63e8c770deb78c1d092c719Tao Bao                                 "oem_no_mount",
13478b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "verify",
13488b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                                 "no_fallback_to_full",
13498dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao                                 "stash_threshold=",
1350d62c603573c53713164fda0430d477daa11d5e31Tao Bao                                 "gen_verify",
1351d62c603573c53713164fda0430d477daa11d5e31Tao Bao                                 "log_diff=",
1352dea0f8bfed01fa620d23d7dd8ff533246f26e8a0Tao Bao                                 "payload_signer=",
13532abbbd03339947327ada0becba5bd4ef41f1bdabBaligh Uddin                                 "payload_signer_args=",
1354cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen                                 "extracted_input_target_files=",
13558b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert                             ], extra_option_handler=option_handler)
13568b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
13578b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if len(args) != 2:
13588b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    common.Usage(__doc__)
13598b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    sys.exit(1)
13608b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
13615d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao  if OPTIONS.downgrade:
13625d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao    # Sanity check to enforce a data wipe.
13635d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao    if not OPTIONS.wipe_user_data:
13645d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao      raise ValueError("Cannot downgrade without a data wipe")
13655d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao
13665d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao    # We should only allow downgrading incrementals (as opposed to full).
13675d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao    # Otherwise the device may go back from arbitrary build with this full
13685d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao    # OTA package.
13695d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao    if OPTIONS.incremental_source is None:
1370d8a52f97859356c65b21f8aed775f685b314ca22Elliott Hughes      raise ValueError("Cannot generate downgradable full OTAs")
13715d1825664a0fec256fa28d62aadcac96f59a41b2Tao Bao
13723e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao  assert not (OPTIONS.downgrade and OPTIONS.timestamp), \
13733e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao      "Cannot have --downgrade AND --override_timestamp both"
13743e6161a3b33da5a46c80c79e2d815168923e83c3Tao Bao
1375c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  # Load the dict file from the zip directly to have a peek at the OTA type.
1376c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  # For packages using A/B update, unzipping is not needed.
1377cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen  if OPTIONS.extracted_input is not None:
1378cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.extracted_input, OPTIONS.extracted_input)
1379cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen  else:
1380cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    input_zip = zipfile.ZipFile(args[0], "r")
1381cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    OPTIONS.info_dict = common.LoadInfoDict(input_zip)
1382cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    common.ZipClose(input_zip)
1383c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1384c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  ab_update = OPTIONS.info_dict.get("ab_update") == "true"
1385c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1386c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  if ab_update:
1387c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao    if OPTIONS.incremental_source is not None:
1388c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao      OPTIONS.target_info_dict = OPTIONS.info_dict
1389c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao      source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r")
1390c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao      OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1391c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao      common.ZipClose(source_zip)
1392c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1393c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao    if OPTIONS.verbose:
139489fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao      print("--- target info ---")
1395c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao      common.DumpInfoDict(OPTIONS.info_dict)
1396c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1397c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao      if OPTIONS.incremental_source is not None:
139889fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao        print("--- source info ---")
1399c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao        common.DumpInfoDict(OPTIONS.source_info_dict)
1400c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
1401c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao    WriteABOTAPackageWithBrilloScript(
1402c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao        target_file=args[0],
1403c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao        output_file=args[1],
1404c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao        source_file=OPTIONS.incremental_source)
1405c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
140689fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao    print("done.")
1407c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao    return
1408c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao
14098b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.extra_script is not None:
14108b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    OPTIONS.extra_script = open(OPTIONS.extra_script).read()
14118b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1412cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen  if OPTIONS.extracted_input is not None:
1413cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    OPTIONS.input_tmp = OPTIONS.extracted_input
1414cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    OPTIONS.target_tmp = OPTIONS.input_tmp
1415cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.input_tmp, OPTIONS.input_tmp)
1416cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    input_zip = zipfile.ZipFile(args[0], "r")
1417cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen  else:
1418cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    print("unzipping target target-files...")
1419cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    OPTIONS.input_tmp, input_zip = common.UnzipTemp(
1420cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen        args[0], UNZIP_PATTERN)
14218b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1422cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    OPTIONS.target_tmp = OPTIONS.input_tmp
1423cea5cd210e5c0251025e5125215fa1fab1d18dfbDan Willemsen    OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
14248b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
14258b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.verbose:
142689fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao    print("--- target info ---")
14278b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    common.DumpInfoDict(OPTIONS.info_dict)
14288b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
14298b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # If the caller explicitly specified the device-specific extensions
14308b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # path via -s/--device_specific, use that.  Otherwise, use
14318b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # META/releasetools.py if it is present in the target target_files.
14328b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # Otherwise, take the path of the file from 'tool_extensions' in the
14338b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # info dict and look for that in the local filesystem, relative to
14348b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  # the current directory.
14358b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
14368b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.device_specific is None:
14378b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
14388b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    if os.path.exists(from_input):
143989fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao      print("(using device-specific extensions from target_files)")
14408b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.device_specific = from_input
14418b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    else:
14428b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
14438b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
14448b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if OPTIONS.device_specific is not None:
14458b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
14468b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1447c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  if OPTIONS.info_dict.get("no_recovery") == "true":
1448db45efa64764c1de5c007384ab172ad817e1d295Tao Bao    raise common.ExternalError(
1449db45efa64764c1de5c007384ab172ad817e1d295Tao Bao        "--- target build has specified no recovery ---")
1450db45efa64764c1de5c007384ab172ad817e1d295Tao Bao
1451767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  # Use the default key to sign the package if not specified with package_key.
1452767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  if not OPTIONS.no_signing:
1453767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao    if OPTIONS.package_key is None:
1454767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao      OPTIONS.package_key = OPTIONS.info_dict.get(
1455767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao          "default_system_dev_certificate",
1456767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao          "build/target/product/security/testkey")
1457767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao
1458767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  # Set up the output zip. Create a temporary zip file if signing is needed.
1459767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  if OPTIONS.no_signing:
1460767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao    if os.path.exists(args[1]):
1461767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao      os.unlink(args[1])
1462767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao    output_zip = zipfile.ZipFile(args[1], "w",
1463767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao                                 compression=zipfile.ZIP_DEFLATED)
1464767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  else:
1465767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao    temp_zip_file = tempfile.NamedTemporaryFile()
1466767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao    output_zip = zipfile.ZipFile(temp_zip_file, "w",
1467767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao                                 compression=zipfile.ZIP_DEFLATED)
14688b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
146940ef35b9e916163bc408d6d9945f92f012885d33Daniel Rosenberg  # Non A/B OTAs rely on /cache partition to store temporary files.
1470767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  cache_size = OPTIONS.info_dict.get("cache_size", None)
1471c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao  if cache_size is None:
147289fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao    print("--- can't determine the cache partition size ---")
1473767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  OPTIONS.cache_size = cache_size
14748b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
14759bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  # Generate a verify package.
14769bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  if OPTIONS.gen_verify:
14779bc6bb23b5bf64635275041fecace64635f41fbaTao Bao    WriteVerifyPackage(input_zip, output_zip)
14789bc6bb23b5bf64635275041fecace64635f41fbaTao Bao
1479767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  # Generate a full OTA.
14809bc6bb23b5bf64635275041fecace64635f41fbaTao Bao  elif OPTIONS.incremental_source is None:
1481c098e9efd989a46d5d1aa625bc899536de15eaaaTao Bao    WriteFullOTAPackage(input_zip, output_zip)
14828dcf738234d2701ad907fc14cfe0ce8fb760b8b0Tao Bao
1483767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  # Generate an incremental OTA. It will fall back to generate a full OTA on
1484767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  # failure unless no_fallback_to_full is specified.
1485767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  else:
148689fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao    print("unzipping source target-files...")
1487767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao    OPTIONS.source_tmp, source_zip = common.UnzipTemp(
14886b0b2f9db0c7d89a678e5b0cb9dbffbec3d96f0bTao Bao        OPTIONS.incremental_source,
1489457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao        UNZIP_PATTERN)
1490767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao    OPTIONS.target_info_dict = OPTIONS.info_dict
1491767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao    OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
1492767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao                                                   OPTIONS.source_tmp)
1493767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao    if OPTIONS.verbose:
149489fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao      print("--- source info ---")
1495767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao      common.DumpInfoDict(OPTIONS.source_info_dict)
1496767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao    try:
1497457cbf6a8a3c858aff5160f02f4ee220716900efTao Bao      WriteBlockIncrementalOTAPackage(input_zip, source_zip, output_zip)
1498d62c603573c53713164fda0430d477daa11d5e31Tao Bao      if OPTIONS.log_diff:
1499d62c603573c53713164fda0430d477daa11d5e31Tao Bao        out_file = open(OPTIONS.log_diff, 'w')
1500d62c603573c53713164fda0430d477daa11d5e31Tao Bao        import target_files_diff
1501d62c603573c53713164fda0430d477daa11d5e31Tao Bao        target_files_diff.recursiveDiff('',
1502d62c603573c53713164fda0430d477daa11d5e31Tao Bao                                        OPTIONS.source_tmp,
1503d62c603573c53713164fda0430d477daa11d5e31Tao Bao                                        OPTIONS.input_tmp,
1504d62c603573c53713164fda0430d477daa11d5e31Tao Bao                                        out_file)
1505d62c603573c53713164fda0430d477daa11d5e31Tao Bao        out_file.close()
1506767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao    except ValueError:
1507767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao      if not OPTIONS.fallback_to_full:
1508767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao        raise
150989fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao      print("--- failed to build incremental; falling back to full ---")
1510767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao      OPTIONS.incremental_source = None
15118b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert      WriteFullOTAPackage(input_zip, output_zip)
15128b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1513767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  common.ZipClose(output_zip)
15148b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
1515767e3ac246c03a72834f80413ebcd7dceea4fc0bTao Bao  # Sign the generated zip package unless no_signing is specified.
15168b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  if not OPTIONS.no_signing:
15178b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    SignOutput(temp_zip_file.name, args[1])
15188b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    temp_zip_file.close()
15198b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
152089fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao  print("done.")
15218b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
15228b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert
15238b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albertif __name__ == '__main__':
15248b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  try:
15258b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    common.CloseInheritedPipes()
15268b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    main(sys.argv[1:])
15278b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  except common.ExternalError as e:
152889fbb0f6d586b4111b9207438d5d047ba0ad6d5fTao Bao    print("\n   ERROR: %s\n" % (e,))
15298b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    sys.exit(1)
15308b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert  finally:
15318b72aefb5a8ed4da28c6f83854e8babf53b9cb53Dan Albert    common.Cleanup()
1532