aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Garnes <matt@cyngn.com>2015-05-04 23:32:08 (GMT)
committerMatt Garnes <matt@cyngn.com>2015-05-04 23:32:08 (GMT)
commit945e2a569fbcc4ba1c0cfd193c795a80663be721 (patch)
tree4cfde827b1f0391d8e5e4cd6b1e8a1e5659ca84c
parent8b19c9ec46213ca382c18cef868fdae97f83b234 (diff)
parent745623e65d938d8bf8df8d1bffb2c08540eea3e4 (diff)
downloadandroid_build-caf/cm-12.1.zip
android_build-caf/cm-12.1.tar.gz
android_build-caf/cm-12.1.tar.bz2
Merge remote-tracking branch 'caf/LA.BR.1.2.3' into caf/cm-12.1caf/cm-12.1
-rw-r--r--core/Makefile76
-rw-r--r--core/build_id.mk2
-rw-r--r--target/product/verity.mk2
-rwxr-xr-xtools/releasetools/add_img_to_target_files.py18
-rw-r--r--tools/releasetools/blockimgdiff.py59
-rwxr-xr-xtools/releasetools/build_image.py17
-rwxr-xr-xtools/releasetools/common.py106
-rwxr-xr-xtools/releasetools/img_from_target_files.py18
-rwxr-xr-xtools/releasetools/ota_from_target_files6
-rw-r--r--tools/releasetools/test_common.py108
10 files changed, 350 insertions, 62 deletions
diff --git a/core/Makefile b/core/Makefile
index 67206d3..fae0457 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -796,6 +796,7 @@ recovery_fstab := $(strip $(wildcard $(TARGET_DEVICE_DIR)/recovery.fstab))
endif
# Named '.dat' so we don't attempt to use imgdiff for patching it.
RECOVERY_RESOURCE_ZIP := $(TARGET_OUT)/etc/recovery-resource.dat
+RECOVERY_PATCH_INSTALL := $(TARGET_OUT)/bin/install-recovery.sh
ifeq ($(recovery_resources_private),)
$(info No private recovery resources for TARGET_DEVICE $(TARGET_DEVICE))
@@ -885,15 +886,75 @@ endif
$(hide) $(call assert-max-image-size,$@,$(BOARD_RECOVERYIMAGE_PARTITION_SIZE))
@echo ----- Made recovery image: $@ --------
+recovery_patch_path := $(call intermediates-dir-for,PACKAGING,recovery_patch)
+ota_temp_root := $(PRODUCT_OUT)/ota_temp
+$(RECOVERY_PATCH_INSTALL): PRIVATE_RECOVERY_API_VERSION := $(RECOVERY_API_VERSION)
+$(RECOVERY_PATCH_INSTALL): PRIVATE_RECOVERY_FSTAB_VERSION := $(RECOVERY_FSTAB_VERSION)
+$(RECOVERY_PATCH_INSTALL): $(INSTALLED_RECOVERYIMAGE_TARGET) \
+ $(RECOVERY_FROM_BOOT_PATCH) \
+ $(ALL_PREBUILT) \
+ $(ALL_COPIED_HEADERS) \
+ $(ALL_GENERATED_SOURCES) \
+ $(ALL_DEFAULT_INSTALLED_MODULES) \
+ $(PDK_FUSION_SYSIMG_FILES)
+ @echo "Installing recovery patch to system partition"
+ $(hide) mkdir -p $(ota_temp_root)
+ $(hide) mkdir -p $(ota_temp_root)/BOOT
+ $(hide) mkdir -p $(ota_temp_root)/RECOVERY
+ $(hide) mkdir -p $(ota_temp_root)/BOOTABLE_IMAGES
+ $(hide) mkdir -p $(ota_temp_root)/SYSTEM
+ $(hide) mkdir -p $(ota_temp_root)/SYSTEM/bin
+ $(hide) mkdir -p $(ota_temp_root)/SYSTEM/etc
+ $(hide) mkdir -p $(ota_temp_root)/META
+ $(hide) $(call package_files-copy-root, \
+ $(TARGET_RECOVERY_ROOT_OUT),$(ota_temp_root)/RECOVERY/RAMDISK)
+ $(hide) $(call package_files-copy-root, \
+ $(TARGET_ROOT_OUT),$(ota_temp_root)/BOOT/RAMDISK)
+ $(hide) $(call package_files-copy-root, \
+ $(TARGET_OUT)/etc,$(ota_temp_root)/SYSTEM/etc)
+ @echo "recovery_api_version=$(PRIVATE_RECOVERY_API_VERSION)" > $(ota_temp_root)/META/misc_info.txt
+ @echo "fstab_version=$(PRIVATE_RECOVERY_FSTAB_VERSION)" >> $(ota_temp_root)/META/misc_info.txt
+ifdef BOARD_FLASH_BLOCK_SIZE
+ @echo "blocksize=$(BOARD_FLASH_BLOCK_SIZE)" >> $(ota_temp_root)/META/misc_info.txt
+endif
+ifdef BOARD_BOOTIMAGE_PARTITION_SIZE
+ @echo "boot_size=$(BOARD_BOOTIMAGE_PARTITION_SIZE)" >> $(ota_temp_root)/META/misc_info.txt
+endif
+ifdef BOARD_RECOVERYIMAGE_PARTITION_SIZE
+ @echo "recovery_size=$(BOARD_RECOVERYIMAGE_PARTITION_SIZE)" >> $(ota_temp_root)/META/misc_info.txt
+endif
+ifdef TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS
+ @# TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS can be empty to indicate that nothing but defaults should be used.
+ @echo "recovery_mount_options=$(TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS)" >> $(ota_temp_root)/META/misc_info.txt
+else
+ @echo "recovery_mount_options=$(DEFAULT_TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS)" >> $(ota_temp_root)/META/misc_info.txt
+endif
+ @echo "tool_extensions=$(tool_extensions)" >> $(ota_temp_root)/META/misc_info.txt
+ @echo "default_system_dev_certificate=$(DEFAULT_SYSTEM_DEV_CERTIFICATE)" >> $(ota_temp_root)/META/misc_info.txt
+ifdef PRODUCT_EXTRA_RECOVERY_KEYS
+ @echo "extra_recovery_keys=$(PRODUCT_EXTRA_RECOVERY_KEYS)" >> $(ota_temp_root)/META/misc_info.txt
+endif
+ @echo 'mkbootimg_args=$(BOARD_MKBOOTIMG_ARGS)' >> $(ota_temp_root)/META/misc_info.txt
+ @echo "use_set_metadata=1" >> $(ota_temp_root)/META/misc_info.txt
+ @echo "multistage_support=1" >> $(ota_temp_root)/META/misc_info.txt
+ @echo "update_rename_support=1" >> $(ota_temp_root)/META/misc_info.txt
+ifneq ($(OEM_THUMBPRINT_PROPERTIES),)
+ # OTA scripts are only interested in fingerprint related properties
+ @echo "oem_fingerprint_properties=$(OEM_THUMBPRINT_PROPERTIES)" >> $(ota_temp_root)/META/misc_info.txt
+endif
+ $(call generate-userimage-prop-dictionary, $(ota_temp_root)/META/misc_info.txt)
+ $(hide) cp -r $(PRODUCT_OUT)/boot.img $(ota_temp_root)/BOOTABLE_IMAGES/
+ $(hide) cp -r $(PRODUCT_OUT)/recovery.img $(ota_temp_root)/BOOTABLE_IMAGES/
+ $(hide) ./build/tools/releasetools/make_recovery_patch $(ota_temp_root) $(ota_temp_root)
+ $(hide) cp --remove-destination $(ota_temp_root)/SYSTEM/bin/install-recovery.sh $(TARGET_OUT)/bin/install-recovery.sh
+ $(hide) cp --remove-destination $(ota_temp_root)/SYSTEM/recovery-from-boot.p $(TARGET_OUT)/recovery-from-boot.p
$(RECOVERY_RESOURCE_ZIP): $(INSTALLED_RECOVERYIMAGE_TARGET)
$(hide) mkdir -p $(dir $@)
$(hide) find $(TARGET_RECOVERY_ROOT_OUT)/res -type f | sort | zip -0qrj $@ -@
-
else
INSTALLED_RECOVERYIMAGE_TARGET :=
RECOVERY_RESOURCE_ZIP :=
endif
-
.PHONY: recoveryimage
recoveryimage: $(INSTALLED_RECOVERYIMAGE_TARGET) $(RECOVERY_RESOURCE_ZIP)
@@ -924,7 +985,8 @@ INTERNAL_SYSTEMIMAGE_FILES := $(filter $(TARGET_OUT)/%, \
$(ALL_GENERATED_SOURCES) \
$(ALL_DEFAULT_INSTALLED_MODULES) \
$(PDK_FUSION_SYSIMG_FILES) \
- $(RECOVERY_RESOURCE_ZIP))
+ $(RECOVERY_RESOURCE_ZIP) \
+ $(RECOVERY_PATCH_INSTALL))
FULL_SYSTEMIMAGE_DEPS := $(INTERNAL_SYSTEMIMAGE_FILES) $(INTERNAL_USERIMAGES_DEPS)
# -----------------------------------------------------------------
@@ -1358,6 +1420,12 @@ $(BUILT_TARGET_FILES_PACKAGE): \
$(hide) mkdir -p $(zip_root)/RECOVERY
$(hide) $(call package_files-copy-root, \
$(TARGET_RECOVERY_ROOT_OUT),$(zip_root)/RECOVERY/RAMDISK)
+# Just copy the already built boot/recovery images into the target-files dir
+# in order to avoid mismatched images between the out dir and what the ota
+# build system tries to rebuild.
+ $(hide) mkdir -p $(zip_root)/BOOTABLE_IMAGES
+ $(hide) $(ACP) $(INSTALLED_BOOTIMAGE_TARGET) $(zip_root)/BOOTABLE_IMAGES/
+ $(hide) $(ACP) $(INSTALLED_RECOVERYIMAGE_TARGET) $(zip_root)/BOOTABLE_IMAGES/
ifdef INSTALLED_KERNEL_TARGET
$(hide) $(ACP) $(INSTALLED_KERNEL_TARGET) $(zip_root)/RECOVERY/kernel
endif
@@ -1463,7 +1531,7 @@ endif
$(hide) echo "use_set_metadata=1" >> $(zip_root)/META/misc_info.txt
$(hide) echo "multistage_support=1" >> $(zip_root)/META/misc_info.txt
$(hide) echo "update_rename_support=1" >> $(zip_root)/META/misc_info.txt
- $(hide) echo "blockimgdiff_versions=1,2" >> $(zip_root)/META/misc_info.txt
+ $(hide) echo "blockimgdiff_versions=1,2,3" >> $(zip_root)/META/misc_info.txt
ifneq ($(OEM_THUMBPRINT_PROPERTIES),)
# OTA scripts are only interested in fingerprint related properties
$(hide) echo "oem_fingerprint_properties=$(OEM_THUMBPRINT_PROPERTIES)" >> $(zip_root)/META/misc_info.txt
diff --git a/core/build_id.mk b/core/build_id.mk
index e59357b..29b44b7 100644
--- a/core/build_id.mk
+++ b/core/build_id.mk
@@ -18,4 +18,4 @@
# (like "CRB01"). It must be a single word, and is
# capitalized by convention.
-export BUILD_ID=LMY47D
+export BUILD_ID=LMY47O
diff --git a/target/product/verity.mk b/target/product/verity.mk
index dd566e2..0361b64 100644
--- a/target/product/verity.mk
+++ b/target/product/verity.mk
@@ -16,7 +16,7 @@
# Provides dependencies necessary for verified boot
-PRODUCT_SUPPORTS_VERITY := false
+PRODUCT_SUPPORTS_VERITY := true
# The dev key is used to sign boot and recovery images, and the verity
# metadata table. Actual product deliverables will be re-signed by hand.
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index e98e4b6..0e38909 100755
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -30,9 +30,6 @@ if sys.hexversion < 0x02070000:
import errno
import os
-import re
-import shutil
-import subprocess
import tempfile
import zipfile
@@ -70,10 +67,8 @@ def AddSystem(output_zip, prefix="IMAGES/", recovery_img=None, boot_img=None):
block_list = common.MakeTempFile(prefix="system-blocklist-", suffix=".map")
imgname = BuildSystem(OPTIONS.input_tmp, OPTIONS.info_dict,
block_list=block_list)
- with open(imgname, "rb") as f:
- common.ZipWriteStr(output_zip, prefix + "system.img", f.read())
- with open(block_list, "rb") as f:
- common.ZipWriteStr(output_zip, prefix + "system.map", f.read())
+ common.ZipWrite(output_zip, imgname, prefix + "system.img")
+ common.ZipWrite(output_zip, block_list, prefix + "system.map")
def BuildSystem(input_dir, info_dict, block_list=None):
@@ -94,10 +89,8 @@ def AddVendor(output_zip, prefix="IMAGES/"):
block_list = common.MakeTempFile(prefix="vendor-blocklist-", suffix=".map")
imgname = BuildVendor(OPTIONS.input_tmp, OPTIONS.info_dict,
block_list=block_list)
- with open(imgname, "rb") as f:
- common.ZipWriteStr(output_zip, prefix + "vendor.img", f.read())
- with open(block_list, "rb") as f:
- common.ZipWriteStr(output_zip, prefix + "vendor.map", f.read())
+ common.ZipWrite(output_zip, imgname, prefix + "vendor.img")
+ common.ZipWrite(output_zip, block_list, prefix + "vendor.map")
def BuildVendor(input_dir, info_dict, block_list=None):
@@ -296,7 +289,6 @@ def AddImagesToTargetFiles(filename):
output_zip.close()
def main(argv):
-
def option_handler(o, a):
if o in ("-a", "--add_missing"):
OPTIONS.add_missing = True
@@ -312,8 +304,6 @@ def main(argv):
"rebuild_recovery",
],
extra_option_handler=option_handler)
-
-
if len(args) != 1:
common.Usage(__doc__)
sys.exit(1)
diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py
index 8b179d5..0646c5f 100644
--- a/tools/releasetools/blockimgdiff.py
+++ b/tools/releasetools/blockimgdiff.py
@@ -190,14 +190,14 @@ class Transfer(object):
# original image.
class BlockImageDiff(object):
- def __init__(self, tgt, src=None, threads=None, version=2):
+ def __init__(self, tgt, src=None, threads=None, version=3):
if threads is None:
threads = multiprocessing.cpu_count() // 2
if threads == 0: threads = 1
self.threads = threads
self.version = version
- assert version in (1, 2)
+ assert version in (1, 2, 3)
self.tgt = tgt
if src is None:
@@ -244,6 +244,15 @@ class BlockImageDiff(object):
self.ComputePatches(prefix)
self.WriteTransfers(prefix)
+ def HashBlocks(self, source, ranges):
+ data = source.ReadRangeSet(ranges)
+ ctx = sha1()
+
+ for p in data:
+ ctx.update(p)
+
+ return ctx.hexdigest()
+
def WriteTransfers(self, prefix):
out = []
@@ -272,14 +281,22 @@ class BlockImageDiff(object):
next_stash_id += 1
stashes[s] = sid
stashed_blocks += sr.size()
- out.append("stash %d %s\n" % (sid, sr.to_string_raw()))
+ if self.version == 2:
+ out.append("stash %d %s\n" % (sid, sr.to_string_raw()))
+ else:
+ sh = self.HashBlocks(self.src, sr)
+ if sh in stashes:
+ stashes[sh] += 1
+ else:
+ stashes[sh] = 1
+ out.append("stash %s %s\n" % (sh, sr.to_string_raw()))
if stashed_blocks > max_stashed_blocks:
max_stashed_blocks = stashed_blocks
if self.version == 1:
src_string = xf.src_ranges.to_string_raw()
- elif self.version == 2:
+ elif self.version >= 2:
# <# blocks> <src ranges>
# OR
@@ -289,6 +306,7 @@ class BlockImageDiff(object):
size = xf.src_ranges.size()
src_string = [str(size)]
+ free_string = []
unstashed_src_ranges = xf.src_ranges
mapped_stashes = []
@@ -296,9 +314,18 @@ class BlockImageDiff(object):
sid = stashes.pop(s)
stashed_blocks -= sr.size()
unstashed_src_ranges = unstashed_src_ranges.subtract(sr)
+ sh = self.HashBlocks(self.src, sr)
sr = xf.src_ranges.map_within(sr)
mapped_stashes.append(sr)
- src_string.append("%d:%s" % (sid, sr.to_string_raw()))
+ if self.version == 2:
+ src_string.append("%d:%s" % (sid, sr.to_string_raw()))
+ else:
+ assert sh in stashes
+ src_string.append("%s:%s" % (sh, sr.to_string_raw()))
+ stashes[sh] -= 1
+ if stashes[sh] == 0:
+ free_string.append("free %s\n" % (sh))
+ stashes.pop(sh)
heapq.heappush(free_stash_ids, sid)
if unstashed_src_ranges:
@@ -314,7 +341,7 @@ class BlockImageDiff(object):
src_string = " ".join(src_string)
- # both versions:
+ # all versions:
# zero <rangeset>
# new <rangeset>
# erase <rangeset>
@@ -328,6 +355,11 @@ class BlockImageDiff(object):
# bsdiff patchstart patchlen <tgt rangeset> <src_string>
# imgdiff patchstart patchlen <tgt rangeset> <src_string>
# move <tgt rangeset> <src_string>
+ #
+ # version 3:
+ # bsdiff patchstart patchlen srchash tgthash <tgt rangeset> <src_string>
+ # imgdiff patchstart patchlen srchash tgthash <tgt rangeset> <src_string>
+ # move hash <tgt rangeset> <src_string>
tgt_size = xf.tgt_ranges.size()
@@ -348,6 +380,11 @@ class BlockImageDiff(object):
out.append("%s %s %s\n" % (
xf.style,
xf.tgt_ranges.to_string_raw(), src_string))
+ elif self.version >= 3:
+ out.append("%s %s %s %s\n" % (
+ xf.style,
+ self.HashBlocks(self.tgt, xf.tgt_ranges),
+ xf.tgt_ranges.to_string_raw(), src_string))
total += tgt_size
elif xf.style in ("bsdiff", "imgdiff"):
performs_read = True
@@ -361,6 +398,13 @@ class BlockImageDiff(object):
out.append("%s %d %d %s %s\n" % (
xf.style, xf.patch_start, xf.patch_len,
xf.tgt_ranges.to_string_raw(), src_string))
+ elif self.version >= 3:
+ out.append("%s %d %d %s %s %s %s\n" % (
+ xf.style,
+ xf.patch_start, xf.patch_len,
+ self.HashBlocks(self.src, xf.src_ranges),
+ self.HashBlocks(self.tgt, xf.tgt_ranges),
+ xf.tgt_ranges.to_string_raw(), src_string))
total += tgt_size
elif xf.style == "zero":
assert xf.tgt_ranges
@@ -371,6 +415,9 @@ class BlockImageDiff(object):
else:
raise ValueError, "unknown transfer style '%s'\n" % (xf.style,)
+ if free_string:
+ out.append("".join(free_string))
+
# sanity check: abort if we're going to need more than 512 MB if
# stash space
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index 302aa0c..1f1b5e4 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -220,7 +220,6 @@ def BuildImage(in_dir, prop_dict, out_file,
build_command = []
fs_type = prop_dict.get("fs_type", "")
run_fsck = False
-
is_verity_partition = "verity_block_device" in prop_dict
verity_supported = prop_dict.get("verity") == "true"
# adjust the partition size to make room for the hashes if this is to be verified
@@ -244,6 +243,22 @@ def BuildImage(in_dir, prop_dict, out_file,
build_command.extend(["-j", prop_dict["journal_size"]])
if "timestamp" in prop_dict:
build_command.extend(["-T", str(prop_dict["timestamp"])])
+ else:
+ #Timestamp not provided in property_dict.
+ #Lets try to find the build.prop file and get the timestamp from there
+ #instead
+ path = in_dir + "/build.prop"
+ if os.path.exists(path):
+ with open(path) as f:
+ lines = f.readlines()
+ for line in lines:
+ line = line.strip()
+ if line.startswith("ro.build.date.utc"):
+ name, value = line.split("=", 1)
+ print "read ro.build.date.utc from build.prop as ", value
+ build_command.extend(["-T", value])
+ else:
+ print "unable to open build.prop file..Image will be built using system time"
if fs_config is not None:
build_command.extend(["-C", fs_config])
if block_list is not None:
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index df3423d..d16ab11 100755
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -795,6 +795,46 @@ class PasswordManager(object):
return result
+def ZipWrite(zip_file, filename, arcname=None, perms=0o644,
+ compress_type=None):
+ import datetime
+
+ # http://b/18015246
+ # Python 2.7's zipfile implementation wrongly thinks that zip64 is required
+ # for files larger than 2GiB. We can work around this by adjusting their
+ # limit. Note that `zipfile.writestr()` will not work for strings larger than
+ # 2GiB. The Python interpreter sometimes rejects strings that large (though
+ # it isn't clear to me exactly what circumstances cause this).
+ # `zipfile.write()` must be used directly to work around this.
+ #
+ # This mess can be avoided if we port to python3.
+ saved_zip64_limit = zipfile.ZIP64_LIMIT
+ zipfile.ZIP64_LIMIT = (1 << 32) - 1
+
+ if compress_type is None:
+ compress_type = zip_file.compression
+ if arcname is None:
+ arcname = filename
+
+ saved_stat = os.stat(filename)
+
+ try:
+ # `zipfile.write()` doesn't allow us to pass ZipInfo, so just modify the
+ # file to be zipped and reset it when we're done.
+ os.chmod(filename, perms)
+
+ # Use a fixed timestamp so the output is repeatable.
+ epoch = datetime.datetime.fromtimestamp(0)
+ timestamp = (datetime.datetime(2009, 1, 1) - epoch).total_seconds()
+ os.utime(filename, (timestamp, timestamp))
+
+ zip_file.write(filename, arcname=arcname, compress_type=compress_type)
+ finally:
+ os.chmod(filename, saved_stat.st_mode)
+ os.utime(filename, (saved_stat.st_atime, saved_stat.st_mtime))
+ zipfile.ZIP64_LIMIT = saved_zip64_limit
+
+
def ZipWriteStr(zip, filename, data, perms=0644, compression=None):
# use a fixed timestamp so the output is repeatable.
zinfo = zipfile.ZipInfo(filename=filename,
@@ -1070,51 +1110,65 @@ class BlockDifference:
self._WriteUpdate(script, output_zip)
def WriteVerifyScript(self, script):
+ partition = self.partition
if not self.src:
- script.Print("Image %s will be patched unconditionally." % (self.partition,))
+ script.Print("Image %s will be patched unconditionally." % (partition,))
else:
+ script.AppendExtra(('if block_image_verify("%s", '
+ 'package_extract_file("%s.transfer.list"), '
+ '"%s.new.dat", "%s.patch.dat") then') %
+ (self.device, partition, partition, partition))
+ script.Print("Verified %s image..." % (partition,))
+ script.AppendExtra('else');
+
if self.check_first_block:
self._CheckFirstBlock(script)
- script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' %
- (self.device, self.src.care_map.to_string_raw(),
- self.src.TotalSha1()))
- script.Print("Verified %s image..." % (self.partition,))
- script.AppendExtra(('else\n'
- ' (range_sha1("%s", "%s") == "%s") ||\n'
+ script.AppendExtra(('(range_sha1("%s", "%s") == "%s") ||\n'
' abort("%s partition has unexpected contents");\n'
'endif;') %
(self.device, self.tgt.care_map.to_string_raw(),
self.tgt.TotalSha1(), self.partition))
def _WriteUpdate(self, script, output_zip):
- partition = self.partition
- with open(self.path + ".transfer.list", "rb") as f:
- ZipWriteStr(output_zip, partition + ".transfer.list", f.read())
- with open(self.path + ".new.dat", "rb") as f:
- ZipWriteStr(output_zip, partition + ".new.dat", f.read())
- with open(self.path + ".patch.dat", "rb") as f:
- ZipWriteStr(output_zip, partition + ".patch.dat", f.read(),
- compression=zipfile.ZIP_STORED)
-
- call = (('block_image_update("%s", '
- 'package_extract_file("%s.transfer.list"), '
- '"%s.new.dat", "%s.patch.dat");\n') %
- (self.device, partition, partition, partition))
+ ZipWrite(output_zip,
+ '{}.transfer.list'.format(self.path),
+ '{}.transfer.list'.format(self.partition))
+ ZipWrite(output_zip,
+ '{}.new.dat'.format(self.path),
+ '{}.new.dat'.format(self.partition))
+ ZipWrite(output_zip,
+ '{}.patch.dat'.format(self.path),
+ '{}.patch.dat'.format(self.partition),
+ compress_type=zipfile.ZIP_STORED)
+
+ call = ('block_image_update("{device}", '
+ 'package_extract_file("{partition}.transfer.list"), '
+ '"{partition}.new.dat", "{partition}.patch.dat");\n'.format(
+ device=self.device, partition=self.partition))
script.AppendExtra(script._WordWrap(call))
+ def _HashBlocks(self, source, ranges):
+ data = source.ReadRangeSet(ranges)
+ ctx = sha1()
+
+ for p in data:
+ ctx.update(p)
+
+ return ctx.hexdigest()
+
def _CheckFirstBlock(self, script):
r = RangeSet((0, 1))
- h = sha1()
- for data in self.src.ReadRangeSet(r):
- h.update(data)
- h = h.hexdigest()
+ srchash = self._HashBlocks(self.src, r);
+ tgthash = self._HashBlocks(self.tgt, r);
script.AppendExtra(('(range_sha1("%s", "%s") == "%s") || '
+ '(range_sha1("%s", "%s") == "%s") || '
'abort("%s has been remounted R/W; '
'reflash device to reenable OTA updates");')
- % (self.device, r.to_string_raw(), h, self.device))
-
+ % (self.device, r.to_string_raw(), srchash,
+ self.device, r.to_string_raw(), tgthash,
+ self.device))
DataImage = blockimgdiff.DataImage
diff --git a/tools/releasetools/img_from_target_files.py b/tools/releasetools/img_from_target_files.py
index 4b88e73..4dda0b7 100755
--- a/tools/releasetools/img_from_target_files.py
+++ b/tools/releasetools/img_from_target_files.py
@@ -88,11 +88,13 @@ def main(argv):
# and all we have to do is copy them to the output zip.
images = os.listdir(images_path)
if images:
- for i in images:
- if bootable_only and i not in ("boot.img", "recovery.img"): continue
- if not i.endswith(".img"): continue
- with open(os.path.join(images_path, i), "r") as f:
- common.ZipWriteStr(output_zip, i, f.read())
+ for image in images:
+ if bootable_only and image not in ("boot.img", "recovery.img"):
+ continue
+ if not image.endswith(".img"):
+ continue
+ common.ZipWrite(
+ output_zip, os.path.join(images_path, image), image)
done = True
if not done:
@@ -139,7 +141,13 @@ def main(argv):
finally:
print "cleaning up..."
+ # http://b/18015246
+ # See common.py for context. zipfile also refers to ZIP64_LIMIT during
+ # close() when it writes out the central directory.
+ saved_zip64_limit = zipfile.ZIP64_LIMIT
+ zipfile.ZIP64_LIMIT = (1 << 32) - 1
output_zip.close()
+ zipfile.ZIP64_LIMIT = saved_zip64_limit
shutil.rmtree(OPTIONS.input_tmp)
print "done."
diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files
index 945f11a..6517bf3 100755
--- a/tools/releasetools/ota_from_target_files
+++ b/tools/releasetools/ota_from_target_files
@@ -646,10 +646,8 @@ endif;
WriteMetadata(metadata, output_zip)
-def WritePolicyConfig(file_context, output_zip):
- f = open(file_context, 'r');
- basename = os.path.basename(file_context)
- common.ZipWriteStr(output_zip, basename, f.read())
+def WritePolicyConfig(file_name, output_zip):
+ common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
def WriteMetadata(metadata, output_zip):
diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py
new file mode 100644
index 0000000..f163f92
--- /dev/null
+++ b/tools/releasetools/test_common.py
@@ -0,0 +1,108 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import os
+import tempfile
+import time
+import unittest
+import zipfile
+
+import common
+
+
+def random_string_with_holes(size, block_size, step_size):
+ data = ["\0"] * size
+ for begin in range(0, size, step_size):
+ end = begin + block_size
+ data[begin:end] = os.urandom(block_size)
+ return "".join(data)
+
+
+class CommonZipTest(unittest.TestCase):
+ def _test_ZipWrite(self, contents, extra_zipwrite_args=None):
+ extra_zipwrite_args = dict(extra_zipwrite_args or {})
+
+ test_file = tempfile.NamedTemporaryFile(delete=False)
+ zip_file = tempfile.NamedTemporaryFile(delete=False)
+
+ test_file_name = test_file.name
+ zip_file_name = zip_file.name
+
+ # File names within an archive strip the leading slash.
+ arcname = extra_zipwrite_args.get("arcname", test_file_name)
+ if arcname[0] == "/":
+ arcname = arcname[1:]
+
+ zip_file.close()
+ zip_file = zipfile.ZipFile(zip_file_name, "w")
+
+ try:
+ test_file.write(contents)
+ test_file.close()
+
+ old_stat = os.stat(test_file_name)
+ expected_mode = extra_zipwrite_args.get("perms", 0o644)
+
+ time.sleep(5) # Make sure the atime/mtime will change measurably.
+
+ common.ZipWrite(zip_file, test_file_name, **extra_zipwrite_args)
+
+ new_stat = os.stat(test_file_name)
+ self.assertEqual(int(old_stat.st_mode), int(new_stat.st_mode))
+ self.assertEqual(int(old_stat.st_mtime), int(new_stat.st_mtime))
+
+ zip_file.close()
+ zip_file = zipfile.ZipFile(zip_file_name, "r")
+ info = zip_file.getinfo(arcname)
+
+ self.assertEqual(info.date_time, (2009, 1, 1, 0, 0, 0))
+ mode = (info.external_attr >> 16) & 0o777
+ self.assertEqual(mode, expected_mode)
+ self.assertEqual(zip_file.read(arcname), contents)
+ finally:
+ os.remove(test_file_name)
+ os.remove(zip_file_name)
+
+ def test_ZipWrite(self):
+ file_contents = os.urandom(1024)
+ self._test_ZipWrite(file_contents)
+
+ def test_ZipWrite_with_opts(self):
+ file_contents = os.urandom(1024)
+ self._test_ZipWrite(file_contents, {
+ "arcname": "foobar",
+ "perms": 0o777,
+ "compress_type": zipfile.ZIP_DEFLATED,
+ })
+
+ def test_ZipWrite_large_file(self):
+ kilobytes = 1024
+ megabytes = 1024 * kilobytes
+ gigabytes = 1024 * megabytes
+
+ size = int(2 * gigabytes + 1)
+ block_size = 4 * kilobytes
+ step_size = 4 * megabytes
+ file_contents = random_string_with_holes(
+ size, block_size, step_size)
+ self._test_ZipWrite(file_contents, {
+ "compress_type": zipfile.ZIP_DEFLATED,
+ })
+
+ def test_ZipWrite_resets_ZIP64_LIMIT(self):
+ default_limit = (1 << 31) - 1
+ self.assertEqual(default_limit, zipfile.ZIP64_LIMIT)
+ self._test_ZipWrite('')
+ self.assertEqual(default_limit, zipfile.ZIP64_LIMIT)