Merge "releasetools: Allow generating BBOTA for images with shared blocks."
am: 9452d84b97
Change-Id: Iab1c1e4f25f67fbf9eebb9ec8a4ff0ad7e05fd13
This commit is contained in:
commit
6c453193a1
4 changed files with 63 additions and 11 deletions
|
@ -272,6 +272,7 @@ class ImgdiffStats(object):
|
|||
# Reasons for not applying imgdiff on APKs.
|
||||
SKIPPED_TRIMMED = "Not used imgdiff due to trimmed RangeSet"
|
||||
SKIPPED_NONMONOTONIC = "Not used imgdiff due to having non-monotonic ranges"
|
||||
SKIPPED_SHARED_BLOCKS = "Not used imgdiff due to using shared blocks"
|
||||
SKIPPED_INCOMPLETE = "Not used imgdiff due to incomplete RangeSet"
|
||||
|
||||
# The list of valid reasons, which will also be the dumped order in a report.
|
||||
|
@ -280,6 +281,7 @@ class ImgdiffStats(object):
|
|||
USED_IMGDIFF_LARGE_APK,
|
||||
SKIPPED_TRIMMED,
|
||||
SKIPPED_NONMONOTONIC,
|
||||
SKIPPED_SHARED_BLOCKS,
|
||||
SKIPPED_INCOMPLETE,
|
||||
)
|
||||
|
||||
|
@ -414,6 +416,7 @@ class BlockImageDiff(object):
|
|||
- The file type is supported by imgdiff;
|
||||
- The source and target blocks are monotonic (i.e. the data is stored with
|
||||
blocks in increasing order);
|
||||
- Both files don't contain shared blocks;
|
||||
- Both files have complete lists of blocks;
|
||||
- We haven't removed any blocks from the source set.
|
||||
|
||||
|
@ -437,6 +440,11 @@ class BlockImageDiff(object):
|
|||
self.imgdiff_stats.Log(name, ImgdiffStats.SKIPPED_NONMONOTONIC)
|
||||
return False
|
||||
|
||||
if (tgt_ranges.extra.get('uses_shared_blocks') or
|
||||
src_ranges.extra.get('uses_shared_blocks')):
|
||||
self.imgdiff_stats.Log(name, ImgdiffStats.SKIPPED_SHARED_BLOCKS)
|
||||
return False
|
||||
|
||||
if tgt_ranges.extra.get('incomplete') or src_ranges.extra.get('incomplete'):
|
||||
self.imgdiff_stats.Log(name, ImgdiffStats.SKIPPED_INCOMPLETE)
|
||||
return False
|
||||
|
|
|
@ -625,7 +625,7 @@ def UnzipTemp(filename, pattern=None):
|
|||
return tmp, zipfile.ZipFile(filename, "r")
|
||||
|
||||
|
||||
def GetSparseImage(which, tmpdir, input_zip):
|
||||
def GetSparseImage(which, tmpdir, input_zip, allow_shared_blocks):
|
||||
"""Returns a SparseImage object suitable for passing to BlockImageDiff.
|
||||
|
||||
This function loads the specified sparse image from the given path, and
|
||||
|
@ -637,6 +637,7 @@ def GetSparseImage(which, tmpdir, input_zip):
|
|||
which: The partition name, which must be "system" or "vendor".
|
||||
tmpdir: The directory that contains the prebuilt image and block map file.
|
||||
input_zip: The target-files ZIP archive.
|
||||
allow_shared_blocks: Whether having shared blocks is allowed.
|
||||
|
||||
Returns:
|
||||
A SparseImage object, with file_map info loaded.
|
||||
|
@ -655,7 +656,8 @@ def GetSparseImage(which, tmpdir, input_zip):
|
|||
# unconditionally. Note that they are still part of care_map. (Bug: 20939131)
|
||||
clobbered_blocks = "0"
|
||||
|
||||
image = sparse_img.SparseImage(path, mappath, clobbered_blocks)
|
||||
image = sparse_img.SparseImage(path, mappath, clobbered_blocks,
|
||||
allow_shared_blocks=allow_shared_blocks)
|
||||
|
||||
# block.map may contain less blocks, because mke2fs may skip allocating blocks
|
||||
# if they contain all zeros. We can't reconstruct such a file from its block
|
||||
|
@ -669,6 +671,13 @@ def GetSparseImage(which, tmpdir, input_zip):
|
|||
|
||||
info = input_zip.getinfo(arcname)
|
||||
ranges = image.file_map[entry]
|
||||
|
||||
# If a RangeSet has been tagged as using shared blocks while loading the
|
||||
# image, its block list must be already incomplete due to that reason. Don't
|
||||
# give it 'incomplete' tag to avoid messing up the imgdiff stats.
|
||||
if ranges.extra.get('uses_shared_blocks'):
|
||||
continue
|
||||
|
||||
if RoundUpTo4K(info.file_size) > ranges.size() * 4096:
|
||||
ranges.extra['incomplete'] = True
|
||||
|
||||
|
|
|
@ -786,11 +786,15 @@ else if get_stage("%(bcb_dev)s") == "3/3" then
|
|||
|
||||
script.ShowProgress(system_progress, 0)
|
||||
|
||||
# See the notes in WriteBlockIncrementalOTAPackage().
|
||||
allow_shared_blocks = target_info.get('ext4_share_dup_blocks') == "true"
|
||||
|
||||
# Full OTA is done as an "incremental" against an empty source image. This
|
||||
# has the effect of writing new data from the package to the entire
|
||||
# partition, but lets us reuse the updater code that writes incrementals to
|
||||
# do it.
|
||||
system_tgt = common.GetSparseImage("system", OPTIONS.input_tmp, input_zip)
|
||||
system_tgt = common.GetSparseImage("system", OPTIONS.input_tmp, input_zip,
|
||||
allow_shared_blocks)
|
||||
system_tgt.ResetFileMap()
|
||||
system_diff = common.BlockDifference("system", system_tgt, src=None)
|
||||
system_diff.WriteScript(script, output_zip)
|
||||
|
@ -801,7 +805,8 @@ else if get_stage("%(bcb_dev)s") == "3/3" then
|
|||
if HasVendorPartition(input_zip):
|
||||
script.ShowProgress(0.1, 0)
|
||||
|
||||
vendor_tgt = common.GetSparseImage("vendor", OPTIONS.input_tmp, input_zip)
|
||||
vendor_tgt = common.GetSparseImage("vendor", OPTIONS.input_tmp, input_zip,
|
||||
allow_shared_blocks)
|
||||
vendor_tgt.ResetFileMap()
|
||||
vendor_diff = common.BlockDifference("vendor", vendor_tgt)
|
||||
vendor_diff.WriteScript(script, output_zip)
|
||||
|
@ -978,8 +983,16 @@ def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
|
|||
target_recovery = common.GetBootableImage(
|
||||
"/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
|
||||
|
||||
system_src = common.GetSparseImage("system", OPTIONS.source_tmp, source_zip)
|
||||
system_tgt = common.GetSparseImage("system", OPTIONS.target_tmp, target_zip)
|
||||
# When target uses 'BOARD_EXT4_SHARE_DUP_BLOCKS := true', images may contain
|
||||
# shared blocks (i.e. some blocks will show up in multiple files' block
|
||||
# list). We can only allocate such shared blocks to the first "owner", and
|
||||
# disable imgdiff for all later occurrences.
|
||||
allow_shared_blocks = (source_info.get('ext4_share_dup_blocks') == "true" or
|
||||
target_info.get('ext4_share_dup_blocks') == "true")
|
||||
system_src = common.GetSparseImage("system", OPTIONS.source_tmp, source_zip,
|
||||
allow_shared_blocks)
|
||||
system_tgt = common.GetSparseImage("system", OPTIONS.target_tmp, target_zip,
|
||||
allow_shared_blocks)
|
||||
|
||||
blockimgdiff_version = max(
|
||||
int(i) for i in target_info.get("blockimgdiff_versions", "1").split(","))
|
||||
|
@ -1004,8 +1017,10 @@ def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
|
|||
if HasVendorPartition(target_zip):
|
||||
if not HasVendorPartition(source_zip):
|
||||
raise RuntimeError("can't generate incremental that adds /vendor")
|
||||
vendor_src = common.GetSparseImage("vendor", OPTIONS.source_tmp, source_zip)
|
||||
vendor_tgt = common.GetSparseImage("vendor", OPTIONS.target_tmp, target_zip)
|
||||
vendor_src = common.GetSparseImage("vendor", OPTIONS.source_tmp, source_zip,
|
||||
allow_shared_blocks)
|
||||
vendor_tgt = common.GetSparseImage("vendor", OPTIONS.target_tmp, target_zip,
|
||||
allow_shared_blocks)
|
||||
|
||||
# Check first block of vendor partition for remount R/W only if
|
||||
# disk type is ext4
|
||||
|
|
|
@ -33,7 +33,7 @@ class SparseImage(object):
|
|||
"""
|
||||
|
||||
def __init__(self, simg_fn, file_map_fn=None, clobbered_blocks=None,
|
||||
mode="rb", build_map=True):
|
||||
mode="rb", build_map=True, allow_shared_blocks=False):
|
||||
self.simg_f = f = open(simg_fn, mode)
|
||||
|
||||
header_bin = f.read(28)
|
||||
|
@ -129,7 +129,8 @@ class SparseImage(object):
|
|||
self.extended = extended
|
||||
|
||||
if file_map_fn:
|
||||
self.LoadFileBlockMap(file_map_fn, self.clobbered_blocks)
|
||||
self.LoadFileBlockMap(file_map_fn, self.clobbered_blocks,
|
||||
allow_shared_blocks)
|
||||
else:
|
||||
self.file_map = {"__DATA": self.care_map}
|
||||
|
||||
|
@ -209,7 +210,14 @@ class SparseImage(object):
|
|||
yield fill_data * (this_read * (self.blocksize >> 2))
|
||||
to_read -= this_read
|
||||
|
||||
def LoadFileBlockMap(self, fn, clobbered_blocks):
|
||||
def LoadFileBlockMap(self, fn, clobbered_blocks, allow_shared_blocks):
|
||||
"""Loads the given block map file.
|
||||
|
||||
Args:
|
||||
fn: The filename of the block map file.
|
||||
clobbered_blocks: A RangeSet instance for the clobbered blocks.
|
||||
allow_shared_blocks: Whether having shared blocks is allowed.
|
||||
"""
|
||||
remaining = self.care_map
|
||||
self.file_map = out = {}
|
||||
|
||||
|
@ -217,6 +225,18 @@ class SparseImage(object):
|
|||
for line in f:
|
||||
fn, ranges = line.split(None, 1)
|
||||
ranges = rangelib.RangeSet.parse(ranges)
|
||||
|
||||
if allow_shared_blocks:
|
||||
# Find the shared blocks that have been claimed by others.
|
||||
shared_blocks = ranges.subtract(remaining)
|
||||
if shared_blocks:
|
||||
ranges = ranges.subtract(shared_blocks)
|
||||
if not ranges:
|
||||
continue
|
||||
|
||||
# Tag the entry so that we can skip applying imgdiff on this file.
|
||||
ranges.extra['uses_shared_blocks'] = True
|
||||
|
||||
out[fn] = ranges
|
||||
assert ranges.size() == ranges.intersect(remaining).size()
|
||||
|
||||
|
|
Loading…
Reference in a new issue