Restrict the verification in block-based incremental OTAs

BlockImageDiff has three versions. Only the incremental OTAs generated
with the latest version (3) can be re-applied to the system that's
already on the target build. Otherwise, operations like move will make
unconditional changes and damage the system. During the verification
phase, abort the OTA update if BlockImageDiff is less than 3 and it
doesn't match the checksum of the source build.

Change-Id: Ic630346eab2a993a84d0aeaacd7167ef62cc24f6
(cherry picked from commit daebaa6ed3)
This commit is contained in:
Tao Bao
2015-03-12 12:32:37 -07:00
parent 137b049aef
commit dd2a5892e5
2 changed files with 48 additions and 21 deletions

View File

@@ -1024,17 +1024,19 @@ def ComputeDifferences(diffs):
class BlockDifference: class BlockDifference:
def __init__(self, partition, tgt, src=None, check_first_block=False): def __init__(self, partition, tgt, src=None, check_first_block=False, version=None):
self.tgt = tgt self.tgt = tgt
self.src = src self.src = src
self.partition = partition self.partition = partition
self.check_first_block = check_first_block self.check_first_block = check_first_block
self.version = 1 if version is None:
version = 1
if OPTIONS.info_dict: if OPTIONS.info_dict:
self.version = max( version = max(
int(i) for i in int(i) for i in
OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(",")) OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
self.version = version
b = blockimgdiff.BlockImageDiff(tgt, src, threads=OPTIONS.worker_threads, b = blockimgdiff.BlockImageDiff(tgt, src, threads=OPTIONS.worker_threads,
version=self.version) version=self.version)
@@ -1069,17 +1071,25 @@ class BlockDifference:
script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' %
(self.device, self.src.care_map.to_string_raw(), (self.device, self.src.care_map.to_string_raw(),
self.src.TotalSha1())) self.src.TotalSha1()))
script.Print("Verified %s image..." % (partition,)) script.Print('Verified %s image...' % (partition,))
script.AppendExtra('else'); script.AppendExtra('else');
# When generating incrementals for the system and vendor partitions,
# explicitly check the first block (which contains the superblock) of
# the partition to see if it's what we expect. If this check fails,
# give an explicit log message about the partition having been
# remounted R/W (the most likely explanation) and the need to flash to
# get OTAs working again.
if self.check_first_block: if self.check_first_block:
self._CheckFirstBlock(script) self._CheckFirstBlock(script)
script.AppendExtra(('(range_sha1("%s", "%s") == "%s") ||\n' # Abort the OTA update. Note that the incremental OTA cannot be applied
' abort("%s partition has unexpected contents");\n' # even if it may match the checksum of the target partition.
'endif;') % # a) If version < 3, operations like move and erase will make changes
(self.device, self.tgt.care_map.to_string_raw(), # unconditionally and damage the partition.
self.tgt.TotalSha1(), self.partition)) # b) If version >= 3, it won't even reach here.
script.AppendExtra(('abort("%s partition has unexpected contents");\n'
'endif;') % (partition,))
def _WriteUpdate(self, script, output_zip): def _WriteUpdate(self, script, output_zip):
partition = self.partition partition = self.partition
@@ -1109,14 +1119,11 @@ class BlockDifference:
def _CheckFirstBlock(self, script): def _CheckFirstBlock(self, script):
r = RangeSet((0, 1)) r = RangeSet((0, 1))
srchash = self._HashBlocks(self.src, r); srchash = self._HashBlocks(self.src, r);
tgthash = self._HashBlocks(self.tgt, r);
script.AppendExtra(('(range_sha1("%s", "%s") == "%s") || ' script.AppendExtra(('(range_sha1("%s", "%s") == "%s") || '
'(range_sha1("%s", "%s") == "%s") || '
'abort("%s has been remounted R/W; ' 'abort("%s has been remounted R/W; '
'reflash device to reenable OTA updates");') 'reflash device to reenable OTA updates");')
% (self.device, r.to_string_raw(), srchash, % (self.device, r.to_string_raw(), srchash,
self.device, r.to_string_raw(), tgthash,
self.device)) self.device))
DataImage = blockimgdiff.DataImage DataImage = blockimgdiff.DataImage

View File

@@ -740,8 +740,16 @@ def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict) system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict) system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
blockimgdiff_version = 1
if OPTIONS.info_dict:
blockimgdiff_version = max(
int(i) for i in
OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
system_diff = common.BlockDifference("system", system_tgt, system_src, system_diff = common.BlockDifference("system", system_tgt, system_src,
check_first_block=True) check_first_block=True,
version=blockimgdiff_version)
if HasVendorPartition(target_zip): if HasVendorPartition(target_zip):
if not HasVendorPartition(source_zip): if not HasVendorPartition(source_zip):
@@ -749,7 +757,8 @@ def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
vendor_src = GetImage("vendor", OPTIONS.source_tmp, OPTIONS.source_info_dict) vendor_src = GetImage("vendor", OPTIONS.source_tmp, OPTIONS.source_info_dict)
vendor_tgt = GetImage("vendor", OPTIONS.target_tmp, OPTIONS.target_info_dict) vendor_tgt = GetImage("vendor", OPTIONS.target_tmp, OPTIONS.target_info_dict)
vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src, vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
check_first_block=True) check_first_block=True,
version=blockimgdiff_version)
else: else:
vendor_diff = None vendor_diff = None
@@ -810,7 +819,18 @@ else if get_stage("%(bcb_dev)s") != "3/3" then
device_specific.IncrementalOTA_VerifyBegin() device_specific.IncrementalOTA_VerifyBegin()
if oem_props is None: if oem_props is None:
# When blockimgdiff version is less than 3 (non-resumable block-based OTA),
# patching on a device that's already on the target build will damage the
# system. Because operations like move don't check the block state, they
# always apply the changes unconditionally.
if blockimgdiff_version <= 2:
script.AssertSomeFingerprint(source_fp)
else:
script.AssertSomeFingerprint(source_fp, target_fp) script.AssertSomeFingerprint(source_fp, target_fp)
else:
if blockimgdiff_version <= 2:
script.AssertSomeThumbprint(
GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
else: else:
script.AssertSomeThumbprint( script.AssertSomeThumbprint(
GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict), GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),