Merge "Add libc_malloc_hook to list of libraries."
diff --git a/core/Makefile b/core/Makefile
index 656d52d..a67a411 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -2059,17 +2059,6 @@
endif
-# Convert to lower case without requiring a shell, which isn't cacheable.
-to-lower = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,\
-$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,\
-$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,\
-$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
-# Convert to upper case without requiring a shell, which isn't cacheable.
-to-upper=$(subst a,A,$(subst b,B,$(subst c,C,$(subst d,D,$(subst e,E,$(subst f,F,$(subst g,G,\
-$(subst h,H,$(subst i,I,$(subst j,J,$(subst k,K,$(subst l,L,$(subst m,M,$(subst n,N,$(subst o,O,\
-$(subst p,P,$(subst q,Q,$(subst r,R,$(subst s,S,$(subst t,T,$(subst u,U,$(subst v,V,$(subst w,W,\
-$(subst x,X,$(subst y,Y,$(subst z,Z,$1))))))))))))))))))))))))))
-
# -----------------------------------------------------------------
# vbmeta image
ifeq ($(BOARD_AVB_ENABLE),true)
@@ -2378,18 +2367,18 @@
system/extras/verity/build_verity_metadata.py \
system/extras/ext4_utils/mke2fs.conf \
external/avb/test/data/testkey_rsa4096.pem \
- $(sort $(shell find system/update_engine/scripts -name \*.pyc -prune -o -type f -print)) \
- $(sort $(shell find build/target/product/security -type f -name \*.x509.pem -o -name \*.pk8 -o \
- -name verity_key)) \
- $(sort $(shell find device $(wildcard vendor) -type f -name \*.pk8 -o -name verifiedboot\* -o \
- -name \*.x509.pem -o -name oem\*.prop))
+ $(shell find system/update_engine/scripts -name \*.pyc -prune -o -type f -print | sort) \
+ $(shell find build/target/product/security -type f -name \*.x509.pem -o -name \*.pk8 -o \
+ -name verity_key | sort) \
+ $(shell find device $(wildcard vendor) -type f -name \*.pk8 -o -name verifiedboot\* -o \
+ -name \*.x509.pem -o -name oem\*.prop | sort)
OTATOOLS_RELEASETOOLS := \
- $(sort $(shell find build/make/tools/releasetools -name \*.pyc -prune -o -type f))
+ $(shell find build/make/tools/releasetools -name \*.pyc -prune -o -type f | sort)
ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT))
OTATOOLS_DEPS += \
- $(sort $(shell find external/vboot_reference/tests/devkeys -type f))
+ $(shell find external/vboot_reference/tests/devkeys -type f | sort)
endif
$(BUILT_OTATOOLS_PACKAGE): $(OTATOOLS) $(OTATOOLS_DEPS) $(OTATOOLS_RELEASETOOLS) | $(ACP)
diff --git a/core/aux_config.mk b/core/aux_config.mk
index 6a5cd63..bdae86a 100644
--- a/core/aux_config.mk
+++ b/core/aux_config.mk
@@ -154,7 +154,7 @@
config_roots := $(wildcard device vendor)
all_configs :=
ifdef config_roots
-all_configs := $(sort $(shell find $(config_roots) -maxdepth 4 -name '*$(variant_sfx)' -o -name '*$(os_sfx)'))
+all_configs := $(shell find $(config_roots) -maxdepth 4 -name '*$(variant_sfx)' -o -name '*$(os_sfx)' | sort)
endif
all_os_configs := $(filter %$(os_sfx),$(all_configs))
all_variant_configs := $(filter %$(variant_sfx),$(all_configs))
diff --git a/core/definitions.mk b/core/definitions.mk
index ed8eb42..ed5f41f 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -2601,11 +2601,12 @@
#
define uncompress-dexs
$(hide) if (zipinfo $@ '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then \
- rm -rf $(dir $@)uncompresseddexs && mkdir $(dir $@)uncompresseddexs; \
- unzip -q $@ '*.dex' -d $(dir $@)uncompresseddexs && \
+ tmpdir=$@.tmpdir; \
+ rm -rf $$tmpdir && mkdir $$tmpdir; \
+ unzip -q $@ '*.dex' -d $$tmpdir && \
zip -qd $@ '*.dex' && \
- ( cd $(dir $@)uncompresseddexs && find . -type f | sort | zip -qD -X -0 ../$(notdir $@) -@ ) && \
- rm -rf $(dir $@)uncompresseddexs; \
+ ( cd $$tmpdir && find . -type f | sort | zip -qD -X -0 ../$(notdir $@) -@ ) && \
+ rm -rf $$tmpdir; \
fi
endef
@@ -3473,3 +3474,24 @@
$(filter-out current,\
$(if $(call has-system-sdk-version,$(1)),$(patsubst system_%,%,$(1)),$(1)))
endef
+
+# Convert to lower case without requiring a shell, which isn't cacheable.
+to-lower=$(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
+
+# Convert to upper case without requiring a shell, which isn't cacheable.
+to-upper=$(subst a,A,$(subst b,B,$(subst c,C,$(subst d,D,$(subst e,E,$(subst f,F,$(subst g,G,$(subst h,H,$(subst i,I,$(subst j,J,$(subst k,K,$(subst l,L,$(subst m,M,$(subst n,N,$(subst o,O,$(subst p,P,$(subst q,Q,$(subst r,R,$(subst s,S,$(subst t,T,$(subst u,U,$(subst v,V,$(subst w,W,$(subst x,X,$(subst y,Y,$(subst z,Z,$1))))))))))))))))))))))))))
+
+# Sanity-check to-lower and to-upper
+lower := abcdefghijklmnopqrstuvwxyz-_
+upper := ABCDEFGHIJKLMNOPQRSTUVWXYZ-_
+
+ifneq ($(lower),$(call to-lower,$(upper)))
+ $(error to-lower sanity check failure)
+endif
+
+ifneq ($(upper),$(call to-upper,$(lower)))
+ $(error to-upper sanity check failure)
+endif
+
+lower :=
+upper :=
diff --git a/core/pdk_config.mk b/core/pdk_config.mk
index fed05f0..0ff091e 100644
--- a/core/pdk_config.mk
+++ b/core/pdk_config.mk
@@ -43,7 +43,7 @@
$(PDK_PLATFORM_JAVA_ZIP_JAVA_HOST_LIB_DIR)
PDK_PLATFORM_JAVA_ZIP_CONTENTS += $(foreach lib_dir,$(PDK_PLATFORM_JAVA_ZIP_JAVA_LIB_DIR),\
- $(lib_dir)/classes.jar $(lib_dir)/classes.jar.toc \
+ $(lib_dir)/classes.jar $(lib_dir)/classes-header.jar \
$(lib_dir)/javalib.jar $(lib_dir)/classes*.dex \
$(lib_dir)/classes.dex.toc )
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 42a910c..153b741 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -134,6 +134,8 @@
$(call add_json_list, NamespacesToExport, $(PRODUCT_SOONG_NAMESPACES))
+$(call add_json_list, PgoAdditionalProfileDirs, $(PGO_ADDITIONAL_PROFILE_DIRS))
+
_contents := $(subst $(comma)$(newline)__SV_END,$(newline)}$(newline),$(_contents)__SV_END)
$(file >$(SOONG_VARIABLES).tmp,$(_contents))
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index d0023bd..25acbf7 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -235,7 +235,7 @@
# It must be of the form "YYYY-MM-DD" on production devices.
# It must match one of the Android Security Patch Level strings of the Public Security Bulletins.
# If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
- PLATFORM_SECURITY_PATCH := 2018-03-05
+ PLATFORM_SECURITY_PATCH := 2018-04-05
endif
ifndef PLATFORM_BASE_OS
diff --git a/target/product/base.mk b/target/product/base.mk
index 14e315d..a7f2d5c 100644
--- a/target/product/base.mk
+++ b/target/product/base.mk
@@ -32,6 +32,7 @@
bit \
blkid \
bmgr \
+ bpfloader \
bugreport \
bugreportz \
cameraserver \
diff --git a/tools/fs_config/Android.mk b/tools/fs_config/Android.mk
index 3773d38..1247896 100644
--- a/tools/fs_config/Android.mk
+++ b/tools/fs_config/Android.mk
@@ -261,6 +261,7 @@
LOCAL_MODULE := passwd
LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
include $(BUILD_SYSTEM)/base_rules.mk
@@ -279,6 +280,7 @@
LOCAL_MODULE := group
LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
include $(BUILD_SYSTEM)/base_rules.mk
diff --git a/tools/fs_config/fs_config_generator.py b/tools/fs_config/fs_config_generator.py
index c8d1dd3..d51d075 100755
--- a/tools/fs_config/fs_config_generator.py
+++ b/tools/fs_config/fs_config_generator.py
@@ -146,18 +146,27 @@
found (str): The file found in, not required to be specified.
Raises:
+ ValueError: if the friendly name is longer than 31 characters as
+ that is bionic's internal buffer size for name.
ValueError: if value is not a valid string number as processed by
int(x, 0)
"""
self.identifier = identifier
self.value = value
self.found = found
- self.normalized_value = str(int(value, 0))
+ try:
+ self.normalized_value = str(int(value, 0))
+ except ValueException:
+ raise ValueError('Invalid "value", not aid number, got: \"%s\"' % value)
# Where we calculate the friendly name
friendly = identifier[len(AID.PREFIX):].lower()
self.friendly = AID._fixup_friendly(friendly)
+ if len(self.friendly) > 31:
+ raise ValueError('AID names must be under 32 characters "%s"' % self.friendly)
+
+
def __eq__(self, other):
return self.identifier == other.identifier \
@@ -639,10 +648,8 @@
try:
aid = AID(section_name, value, file_name)
- except ValueError:
- sys.exit(
- error_message('Invalid "value", not aid number, got: \"%s\"' %
- value))
+ except ValueError as exception:
+ sys.exit(error_message(exception))
# Values must be within OEM range
if not Utils.in_any_range(int(aid.value, 0), self._oem_ranges):
diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py
index 931026b..d6ff6a6 100644
--- a/tools/releasetools/blockimgdiff.py
+++ b/tools/releasetools/blockimgdiff.py
@@ -15,7 +15,6 @@
from __future__ import print_function
import array
-import common
import copy
import functools
import heapq
@@ -27,9 +26,10 @@
import subprocess
import sys
import threading
-
from collections import deque, OrderedDict
from hashlib import sha1
+
+import common
from rangelib import RangeSet
@@ -191,7 +191,6 @@
self.tgt_sha1 = tgt_sha1
self.src_sha1 = src_sha1
self.style = style
- self.intact = tgt_ranges.monotonic and src_ranges.monotonic
# We use OrderedDict rather than dict so that the output is repeatable;
# otherwise it would depend on the hash values of the Transfer objects.
@@ -257,6 +256,71 @@
return self.score <= other.score
+class ImgdiffStats(object):
+ """A class that collects imgdiff stats.
+
+ It keeps track of the files that will be applied imgdiff while generating
+ BlockImageDiff. It also logs the ones that cannot use imgdiff, with specific
+ reasons. The stats is only meaningful when imgdiff not being disabled by the
+ caller of BlockImageDiff. In addition, only files with supported types
+ (BlockImageDiff.FileTypeSupportedByImgdiff()) are allowed to be logged.
+
+ TODO: The info could be inaccurate due to the unconditional fallback from
+ imgdiff to bsdiff on errors. The fallbacks will be removed.
+ """
+
+ USED_IMGDIFF = "APK files diff'd with imgdiff"
+ USED_IMGDIFF_LARGE_APK = "Large APK files split and diff'd with imgdiff"
+
+ # 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"
+
+ # The list of valid reasons, which will also be the dumped order in a report.
+ REASONS = (
+ USED_IMGDIFF,
+ USED_IMGDIFF_LARGE_APK,
+ SKIPPED_TRIMMED,
+ SKIPPED_NONMONOTONIC,
+ )
+
+ def __init__(self):
+ self.stats = {}
+
+ def Log(self, filename, reason):
+ """Logs why imgdiff can or cannot be applied to the given filename.
+
+ Args:
+ filename: The filename string.
+ reason: One of the reason constants listed in REASONS.
+
+ Raises:
+ AssertionError: On unsupported filetypes or invalid reason.
+ """
+ assert BlockImageDiff.FileTypeSupportedByImgdiff(filename)
+ assert reason in self.REASONS
+
+ if reason not in self.stats:
+ self.stats[reason] = set()
+ self.stats[reason].add(filename)
+
+ def Report(self):
+ """Prints a report of the collected imgdiff stats."""
+
+ def print_header(header, separator):
+ print(header)
+ print(separator * len(header) + '\n')
+
+ print_header(' Imgdiff Stats Report ', '=')
+ for key in self.REASONS:
+ if key not in self.stats:
+ continue
+ values = self.stats[key]
+ section_header = ' {} (count: {}) '.format(key, len(values))
+ print_header(section_header, '-')
+ print(''.join([' {}\n'.format(name) for name in values]))
+
+
# BlockImageDiff works on two image objects. An image object is
# anything that provides the following attributes:
#
@@ -312,6 +376,7 @@
self.touched_src_ranges = RangeSet()
self.touched_src_sha1 = None
self.disable_imgdiff = disable_imgdiff
+ self.imgdiff_stats = ImgdiffStats() if not disable_imgdiff else None
assert version in (3, 4)
@@ -333,6 +398,54 @@
def max_stashed_size(self):
return self._max_stashed_size
+ @staticmethod
+ def FileTypeSupportedByImgdiff(filename):
+ """Returns whether the file type is supported by imgdiff."""
+ return filename.lower().endswith(('.apk', '.jar', '.zip'))
+
+ def CanUseImgdiff(self, name, tgt_ranges, src_ranges, large_apk=False):
+ """Checks whether we can apply imgdiff for the given RangeSets.
+
+ For files in ZIP format (e.g., APKs, JARs, etc.) we would like to use
+ 'imgdiff -z' if possible. Because it usually produces significantly smaller
+ patches than bsdiff.
+
+ This is permissible if all of the following conditions hold.
+ - The imgdiff hasn't been disabled by the caller (e.g. squashfs);
+ - 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);
+ - We haven't removed any blocks from the source set.
+
+ If all these conditions are satisfied, concatenating all the blocks in the
+ RangeSet in order will produce a valid ZIP file (plus possibly extra zeros
+ in the last block). imgdiff is fine with extra zeros at the end of the file.
+
+ Args:
+ name: The filename to be diff'd.
+ tgt_ranges: The target RangeSet.
+ src_ranges: The source RangeSet.
+ large_apk: Whether this is to split a large APK.
+
+ Returns:
+ A boolean result.
+ """
+ if self.disable_imgdiff or not self.FileTypeSupportedByImgdiff(name):
+ return False
+
+ if not tgt_ranges.monotonic or not src_ranges.monotonic:
+ self.imgdiff_stats.Log(name, ImgdiffStats.SKIPPED_NONMONOTONIC)
+ return False
+
+ if tgt_ranges.extra.get('trimmed') or src_ranges.extra.get('trimmed'):
+ self.imgdiff_stats.Log(name, ImgdiffStats.SKIPPED_TRIMMED)
+ return False
+
+ reason = (ImgdiffStats.USED_IMGDIFF_LARGE_APK if large_apk
+ else ImgdiffStats.USED_IMGDIFF)
+ self.imgdiff_stats.Log(name, reason)
+ return True
+
def Compute(self, prefix):
# When looking for a source file to use as the diff input for a
# target file, we try:
@@ -366,6 +479,10 @@
self.ComputePatches(prefix)
self.WriteTransfers(prefix)
+ # Report the imgdiff stats.
+ if common.OPTIONS.verbose and not self.disable_imgdiff:
+ self.imgdiff_stats.Report()
+
def WriteTransfers(self, prefix):
def WriteSplitTransfers(out, style, target_blocks):
"""Limit the size of operand in command 'new' and 'zero' to 1024 blocks.
@@ -418,7 +535,7 @@
# <# blocks> - <stash refs...>
size = xf.src_ranges.size()
- src_str = [str(size)]
+ src_str_buffer = [str(size)]
unstashed_src_ranges = xf.src_ranges
mapped_stashes = []
@@ -428,7 +545,7 @@
sr = xf.src_ranges.map_within(sr)
mapped_stashes.append(sr)
assert sh in stashes
- src_str.append("%s:%s" % (sh, sr.to_string_raw()))
+ src_str_buffer.append("%s:%s" % (sh, sr.to_string_raw()))
stashes[sh] -= 1
if stashes[sh] == 0:
free_string.append("free %s\n" % (sh,))
@@ -436,17 +553,17 @@
stashes.pop(sh)
if unstashed_src_ranges:
- src_str.insert(1, unstashed_src_ranges.to_string_raw())
+ src_str_buffer.insert(1, unstashed_src_ranges.to_string_raw())
if xf.use_stash:
mapped_unstashed = xf.src_ranges.map_within(unstashed_src_ranges)
- src_str.insert(2, mapped_unstashed.to_string_raw())
+ src_str_buffer.insert(2, mapped_unstashed.to_string_raw())
mapped_stashes.append(mapped_unstashed)
self.AssertPartition(RangeSet(data=(0, size)), mapped_stashes)
else:
- src_str.insert(1, "-")
+ src_str_buffer.insert(1, "-")
self.AssertPartition(RangeSet(data=(0, size)), mapped_stashes)
- src_str = " ".join(src_str)
+ src_str = " ".join(src_str_buffer)
# version 3+:
# zero <rangeset>
@@ -567,11 +684,11 @@
max_allowed = OPTIONS.cache_size * OPTIONS.stash_threshold
print("max stashed blocks: %d (%d bytes), "
"limit: %d bytes (%.2f%%)\n" % (
- max_stashed_blocks, self._max_stashed_size, max_allowed,
- self._max_stashed_size * 100.0 / max_allowed))
+ max_stashed_blocks, self._max_stashed_size, max_allowed,
+ self._max_stashed_size * 100.0 / max_allowed))
else:
print("max stashed blocks: %d (%d bytes), limit: <unknown>\n" % (
- max_stashed_blocks, self._max_stashed_size))
+ max_stashed_blocks, self._max_stashed_size))
def ReviseStashSize(self):
print("Revising stash size...")
@@ -711,28 +828,13 @@
# transfer is intact.
assert not self.disable_imgdiff
imgdiff = True
- if not xf.intact:
+ if (xf.src_ranges.extra.get('trimmed') or
+ xf.tgt_ranges.extra.get('trimmed')):
imgdiff = False
xf.patch = None
else:
- # For files in zip format (eg, APKs, JARs, etc.) we would
- # like to use imgdiff -z if possible (because it usually
- # produces significantly smaller patches than bsdiff).
- # This is permissible if:
- #
- # - imgdiff is not disabled, and
- # - the source and target files are monotonic (ie, the
- # data is stored with blocks in increasing order), and
- # - we haven't removed any blocks from the source set.
- #
- # If these conditions are satisfied then appending all the
- # blocks in the set together in order will produce a valid
- # zip file (plus possibly extra zeros in the last block),
- # which is what imgdiff needs to operate. (imgdiff is
- # fine with extra zeros at the end of the file.)
- imgdiff = (not self.disable_imgdiff and xf.intact and
- xf.tgt_name.split(".")[-1].lower()
- in ("apk", "jar", "zip"))
+ imgdiff = self.CanUseImgdiff(
+ xf.tgt_name, xf.tgt_ranges, xf.src_ranges)
xf.style = "imgdiff" if imgdiff else "bsdiff"
diff_queue.append((index, imgdiff, patch_num))
patch_num += 1
@@ -750,9 +852,6 @@
patches = [None] * diff_total
error_messages = []
warning_messages = []
- if sys.stdout.isatty():
- global diff_done
- diff_done = 0
# Using multiprocessing doesn't give additional benefits, due to the
# pattern of the code. The diffing work is done by subprocess.call, which
@@ -768,8 +867,15 @@
if not diff_queue:
return
xf_index, imgdiff, patch_index = diff_queue.pop()
+ xf = self.transfers[xf_index]
- xf = self.transfers[xf_index]
+ if sys.stdout.isatty():
+ diff_left = len(diff_queue)
+ progress = (diff_total - diff_left) * 100 / diff_total
+ # '\033[K' is to clear to EOL.
+ print(' [%3d%%] %s\033[K' % (progress, xf.tgt_name), end='\r')
+ sys.stdout.flush()
+
patch = xf.patch
if not patch:
src_ranges = xf.src_ranges
@@ -789,10 +895,10 @@
except ValueError as e:
message.append(
"Failed to generate %s for %s: tgt=%s, src=%s:\n%s" % (
- "imgdiff" if imgdiff else "bsdiff",
- xf.tgt_name if xf.tgt_name == xf.src_name else
+ "imgdiff" if imgdiff else "bsdiff",
+ xf.tgt_name if xf.tgt_name == xf.src_name else
xf.tgt_name + " (from " + xf.src_name + ")",
- xf.tgt_ranges, xf.src_ranges, e.message))
+ xf.tgt_ranges, xf.src_ranges, e.message))
# TODO(b/68016761): Better handle the holes in mke2fs created
# images.
if imgdiff:
@@ -800,7 +906,7 @@
patch = compute_patch(src_file, tgt_file, imgdiff=False)
message.append(
"Fell back and generated with bsdiff instead for %s" % (
- xf.tgt_name,))
+ xf.tgt_name,))
xf.style = "bsdiff"
with lock:
warning_messages.extend(message)
@@ -808,7 +914,7 @@
except ValueError as e:
message.append(
"Also failed to generate with bsdiff for %s:\n%s" % (
- xf.tgt_name, e.message))
+ xf.tgt_name, e.message))
if message:
with lock:
@@ -816,13 +922,6 @@
with lock:
patches[patch_index] = (xf_index, patch)
- if sys.stdout.isatty():
- global diff_done
- diff_done += 1
- progress = diff_done * 100 / diff_total
- # '\033[K' is to clear to EOL.
- print(' [%d%%] %s\033[K' % (progress, xf.tgt_name), end='\r')
- sys.stdout.flush()
threads = [threading.Thread(target=diff_worker)
for _ in range(self.threads)]
@@ -859,11 +958,11 @@
if common.OPTIONS.verbose:
tgt_size = xf.tgt_ranges.size() * self.tgt.blocksize
print("%10d %10d (%6.2f%%) %7s %s %s %s" % (
- xf.patch_len, tgt_size, xf.patch_len * 100.0 / tgt_size,
- xf.style,
- xf.tgt_name if xf.tgt_name == xf.src_name else (
- xf.tgt_name + " (from " + xf.src_name + ")"),
- xf.tgt_ranges, xf.src_ranges))
+ xf.patch_len, tgt_size, xf.patch_len * 100.0 / tgt_size,
+ xf.style,
+ xf.tgt_name if xf.tgt_name == xf.src_name else (
+ xf.tgt_name + " (from " + xf.src_name + ")"),
+ xf.tgt_ranges, xf.src_ranges))
def AssertSha1Good(self):
"""Check the SHA-1 of the src & tgt blocks in the transfer list.
@@ -977,7 +1076,7 @@
out_of_order += 1
assert xf.src_ranges.overlaps(u.tgt_ranges)
xf.src_ranges = xf.src_ranges.subtract(u.tgt_ranges)
- xf.intact = False
+ xf.src_ranges.extra['trimmed'] = True
if xf.style == "diff" and not xf.src_ranges:
# nothing left to diff from; treat as new data
@@ -1096,7 +1195,8 @@
while sinks:
new_sinks = OrderedDict()
for u in sinks:
- if u not in G: continue
+ if u not in G:
+ continue
s2.appendleft(u)
del G[u]
for iu in u.incoming:
@@ -1109,7 +1209,8 @@
while sources:
new_sources = OrderedDict()
for u in sources:
- if u not in G: continue
+ if u not in G:
+ continue
s1.append(u)
del G[u]
for iu in u.outgoing:
@@ -1118,7 +1219,8 @@
new_sources[iu] = None
sources = new_sources
- if not G: break
+ if not G:
+ break
# Find the "best" vertex to put next. "Best" is the one that
# maximizes the net difference in source blocks saved we get by
@@ -1175,14 +1277,16 @@
intersections = OrderedDict()
for s, e in a.tgt_ranges:
for i in range(s, e):
- if i >= len(source_ranges): break
+ if i >= len(source_ranges):
+ break
# Add all the Transfers in source_ranges[i] to the (ordered) set.
if source_ranges[i] is not None:
for j in source_ranges[i]:
intersections[j] = None
for b in intersections:
- if a is b: continue
+ if a is b:
+ continue
# If the blocks written by A are read by B, then B needs to go before A.
i = a.tgt_ranges.intersect(b.src_ranges)
@@ -1261,11 +1365,12 @@
style, by_id)
return
- if tgt_name.split(".")[-1].lower() in ("apk", "jar", "zip"):
- split_enable = (not self.disable_imgdiff and src_ranges.monotonic and
- tgt_ranges.monotonic)
- if split_enable and (self.tgt.RangeSha1(tgt_ranges) !=
- self.src.RangeSha1(src_ranges)):
+ # Split large APKs with imgdiff, if possible. We're intentionally checking
+ # file types one more time (CanUseImgdiff() checks that as well), before
+ # calling the costly RangeSha1()s.
+ if (self.FileTypeSupportedByImgdiff(tgt_name) and
+ self.tgt.RangeSha1(tgt_ranges) != self.src.RangeSha1(src_ranges)):
+ if self.CanUseImgdiff(tgt_name, tgt_ranges, src_ranges, True):
large_apks.append((tgt_name, src_name, tgt_ranges, src_ranges))
return
@@ -1318,8 +1423,9 @@
if tgt_changed < tgt_size * crop_threshold:
assert tgt_changed + tgt_skipped.size() == tgt_size
- print('%10d %10d (%6.2f%%) %s' % (tgt_skipped.size(), tgt_size,
- tgt_skipped.size() * 100.0 / tgt_size, tgt_name))
+ print('%10d %10d (%6.2f%%) %s' % (
+ tgt_skipped.size(), tgt_size,
+ tgt_skipped.size() * 100.0 / tgt_size, tgt_name))
AddSplitTransfers(
"%s-skipped" % (tgt_name,),
"%s-skipped" % (src_name,),
@@ -1457,7 +1563,7 @@
tgt_ranges, src_ranges,
lines)
for index, (patch_start, patch_length, split_tgt_ranges,
- split_src_ranges) in enumerate(split_info_list):
+ split_src_ranges) in enumerate(split_info_list):
with open(patch_file) as f:
f.seek(patch_start)
patch_content = f.read(patch_length)
diff --git a/tools/releasetools/test_blockimgdiff.py b/tools/releasetools/test_blockimgdiff.py
index 7084e21..a2552d6 100644
--- a/tools/releasetools/test_blockimgdiff.py
+++ b/tools/releasetools/test_blockimgdiff.py
@@ -19,7 +19,8 @@
import unittest
import common
-from blockimgdiff import BlockImageDiff, EmptyImage, HeapItem, Transfer
+from blockimgdiff import (BlockImageDiff, EmptyImage, HeapItem, ImgdiffStats,
+ Transfer)
from rangelib import RangeSet
@@ -172,3 +173,94 @@
# Insufficient cache to stash 15 blocks (size * 0.8 < 15).
common.OPTIONS.cache_size = 15 * 4096
self.assertEqual(15, block_image_diff.ReviseStashSize())
+
+ def test_FileTypeSupportedByImgdiff(self):
+ self.assertTrue(
+ BlockImageDiff.FileTypeSupportedByImgdiff(
+ "/system/priv-app/Settings/Settings.apk"))
+ self.assertTrue(
+ BlockImageDiff.FileTypeSupportedByImgdiff(
+ "/system/framework/am.jar"))
+ self.assertTrue(
+ BlockImageDiff.FileTypeSupportedByImgdiff(
+ "/system/etc/security/otacerts.zip"))
+
+ self.assertFalse(
+ BlockImageDiff.FileTypeSupportedByImgdiff(
+ "/system/framework/arm/boot.oat"))
+ self.assertFalse(
+ BlockImageDiff.FileTypeSupportedByImgdiff(
+ "/system/priv-app/notanapk"))
+
+ def test_CanUseImgdiff(self):
+ block_image_diff = BlockImageDiff(EmptyImage(), EmptyImage())
+ self.assertTrue(
+ block_image_diff.CanUseImgdiff(
+ "/system/app/app1.apk", RangeSet("10-15"), RangeSet("0-5")))
+ self.assertTrue(
+ block_image_diff.CanUseImgdiff(
+ "/vendor/app/app2.apk", RangeSet("20 25"), RangeSet("30-31"), True))
+
+ self.assertDictEqual(
+ {
+ ImgdiffStats.USED_IMGDIFF : {"/system/app/app1.apk"},
+ ImgdiffStats.USED_IMGDIFF_LARGE_APK : {"/vendor/app/app2.apk"},
+ },
+ block_image_diff.imgdiff_stats.stats)
+
+
+ def test_CanUseImgdiff_ineligible(self):
+ # Disabled by caller.
+ block_image_diff = BlockImageDiff(EmptyImage(), EmptyImage(),
+ disable_imgdiff=True)
+ self.assertFalse(
+ block_image_diff.CanUseImgdiff(
+ "/system/app/app1.apk", RangeSet("10-15"), RangeSet("0-5")))
+
+ # Unsupported file type.
+ block_image_diff = BlockImageDiff(EmptyImage(), EmptyImage())
+ self.assertFalse(
+ block_image_diff.CanUseImgdiff(
+ "/system/bin/gzip", RangeSet("10-15"), RangeSet("0-5")))
+
+ # At least one of the ranges is in non-monotonic order.
+ self.assertFalse(
+ block_image_diff.CanUseImgdiff(
+ "/system/app/app2.apk", RangeSet("10-15"),
+ RangeSet("15-20 30 10-14")))
+
+ # At least one of the ranges has been modified.
+ src_ranges = RangeSet("0-5")
+ src_ranges.extra['trimmed'] = True
+ self.assertFalse(
+ block_image_diff.CanUseImgdiff(
+ "/vendor/app/app3.apk", RangeSet("10-15"), src_ranges))
+
+ # The stats are correctly logged.
+ self.assertDictEqual(
+ {
+ ImgdiffStats.SKIPPED_NONMONOTONIC : {'/system/app/app2.apk'},
+ ImgdiffStats.SKIPPED_TRIMMED : {'/vendor/app/app3.apk'},
+ },
+ block_image_diff.imgdiff_stats.stats)
+
+
+class ImgdiffStatsTest(unittest.TestCase):
+
+ def test_Log(self):
+ imgdiff_stats = ImgdiffStats()
+ imgdiff_stats.Log("/system/app/app2.apk", ImgdiffStats.USED_IMGDIFF)
+ self.assertDictEqual(
+ {
+ ImgdiffStats.USED_IMGDIFF: {'/system/app/app2.apk'},
+ },
+ imgdiff_stats.stats)
+
+ def test_Log_invalidInputs(self):
+ imgdiff_stats = ImgdiffStats()
+
+ self.assertRaises(AssertionError, imgdiff_stats.Log, "/system/bin/gzip",
+ ImgdiffStats.USED_IMGDIFF)
+
+ self.assertRaises(AssertionError, imgdiff_stats.Log, "/system/app/app1.apk",
+ "invalid reason")