Merge "Adding vendor_boot-test-harness.img"
diff --git a/core/Makefile b/core/Makefile
index 3d1fdaa..24302d4 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -206,7 +206,7 @@
@mkdir -p $(dir $@)
$(hide) grep -v "$(subst $(space),\|,$(strip \
$(sdk_build_prop_remove)))" $< > $@.tmp
- $(hide) for x in $(sdk_build_prop_remove); do \
+ $(hide) for x in $(strip $(sdk_build_prop_remove)); do \
echo "$$x"generic >> $@.tmp; done
$(hide) mv $@.tmp $@
@@ -320,11 +320,11 @@
define build-image-kernel-modules-depmod
$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: .KATI_IMPLICIT_OUTPUTS := $(3)/$(DEPMOD_STAGING_SUBDIR)/modules.alias $(3)/$(DEPMOD_STAGING_SUBDIR)/modules.softdep $(3)/$(DEPMOD_STAGING_SUBDIR)/$(5)
$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: $(DEPMOD)
-$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_MODULES := $(1)
+$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_MODULES := $(strip $(1))
$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_MOUNT_POINT := $(2)
$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_MODULE_DIR := $(3)/$(DEPMOD_STAGING_SUBDIR)/$(2)/lib/modules/$(8)
$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_STAGING_DIR := $(3)
-$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_LOAD_MODULES := $(4)
+$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_LOAD_MODULES := $(strip $(4))
$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_LOAD_FILE := $(3)/$(DEPMOD_STAGING_SUBDIR)/$(5)
$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_MODULE_ARCHIVE := $(6)
$(3)/$(DEPMOD_STAGING_SUBDIR)/modules.dep: PRIVATE_OUTPUT_DIR := $(7)
@@ -5190,10 +5190,10 @@
ifeq ($(AB_OTA_UPDATER),true)
@# When using the A/B updater, include the updater config files in the zip.
$(hide) cp $(TOPDIR)system/update_engine/update_engine.conf $(zip_root)/META/update_engine_config.txt
- $(hide) for part in $(AB_OTA_PARTITIONS); do \
+ $(hide) for part in $(strip $(AB_OTA_PARTITIONS)); do \
echo "$${part}" >> $(zip_root)/META/ab_partitions.txt; \
done
- $(hide) for conf in $(AB_OTA_POSTINSTALL_CONFIG); do \
+ $(hide) for conf in $(strip $(AB_OTA_POSTINSTALL_CONFIG)); do \
echo "$${conf}" >> $(zip_root)/META/postinstall_config.txt; \
done
ifdef OSRELEASED_DIRECTORY
@@ -5990,7 +5990,7 @@
$(INTERNAL_SDK_TARGET): $(deps)
@echo "Package SDK: $@"
$(hide) rm -rf $(PRIVATE_DIR) $@
- $(hide) for f in $(target_gnu_MODULES); do \
+ $(hide) for f in $(strip $(target_gnu_MODULES)); do \
if [ -f $$f ]; then \
echo SDK: $(if $(SDK_GNU_ERROR),ERROR:,warning:) \
including GNU target $$f >&2; \
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 8c702b3..fe97047 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -54,6 +54,7 @@
else ifneq (,$(SANITIZE_TARGET)$(SANITIZE_HOST))
# Prebuilts aren't built with sanitizers either.
SOONG_CONFIG_art_module_source_build := true
+ MODULE_BUILD_FROM_SOURCE := true
else ifeq (,$(filter x86 x86_64,$(HOST_CROSS_ARCH)))
# We currently only provide prebuilts for x86 on host. This skips prebuilts in
# cuttlefish builds for ARM servers.
diff --git a/core/dex_preopt_config.mk b/core/dex_preopt_config.mk
index 63b32e7..0c806c1 100644
--- a/core/dex_preopt_config.mk
+++ b/core/dex_preopt_config.mk
@@ -108,7 +108,7 @@
$(call add_json_list, ArtApexJars, $(filter $(PRODUCT_BOOT_JARS),$(ART_APEX_JARS)))
$(call add_json_list, SystemServerJars, $(PRODUCT_SYSTEM_SERVER_JARS))
$(call add_json_list, SystemServerApps, $(PRODUCT_SYSTEM_SERVER_APPS))
- $(call add_json_list, UpdatableSystemServerJars, $(PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS))
+ $(call add_json_list, ApexSystemServerJars, $(PRODUCT_APEX_SYSTEM_SERVER_JARS))
$(call add_json_bool, BrokenSuboptimalOrderOfSystemServerJars, $(PRODUCT_BROKEN_SUBOPTIMAL_ORDER_OF_SYSTEM_SERVER_JARS))
$(call add_json_list, SpeedApps, $(PRODUCT_DEXPREOPT_SPEED_APPS))
$(call add_json_list, PreoptFlags, $(PRODUCT_DEX_PREOPT_DEFAULT_FLAGS))
diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk
index fcdfa82..1d16eab 100644
--- a/core/dex_preopt_odex_install.mk
+++ b/core/dex_preopt_odex_install.mk
@@ -61,7 +61,7 @@
endif
# Don't preopt system server jars that are updatable.
-ifneq (,$(filter %:$(LOCAL_MODULE), $(PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS)))
+ifneq (,$(filter %:$(LOCAL_MODULE), $(PRODUCT_APEX_SYSTEM_SERVER_JARS)))
LOCAL_DEX_PREOPT :=
endif
diff --git a/core/main.mk b/core/main.mk
index e2b8c34..d65bd2f 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -120,6 +120,9 @@
ifndef SKIP_BOOT_JARS_CHECK
SKIP_BOOT_JARS_CHECK := true
endif
+# Mainline modules prebuilts do support coverage. Build them from source.
+# See b/159241638
+MODULE_BUILD_FROM_SOURCE := true
endif
ifdef TARGET_ARCH_SUITE
@@ -355,7 +358,7 @@
ADDITIONAL_PRODUCT_PROPERTIES += ro.build.characteristics=$(TARGET_AAPT_CHARACTERISTICS)
ifeq ($(AB_OTA_UPDATER),true)
-ADDITIONAL_PRODUCT_PROPERTIES += ro.product.ab_ota_partitions=$(subst $(space),$(comma),$(AB_OTA_PARTITIONS))
+ADDITIONAL_PRODUCT_PROPERTIES += ro.product.ab_ota_partitions=$(subst $(space),$(comma),$(strip $(AB_OTA_PARTITIONS)))
endif
# -----------------------------------------------------------------
diff --git a/core/product.mk b/core/product.mk
index a87e287..f6347e8 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -234,7 +234,7 @@
_product_list_vars += PRODUCT_SYSTEM_SERVER_APPS
_product_list_vars += PRODUCT_SYSTEM_SERVER_JARS
# List of system_server jars delivered via apex. Format = <apex name>:<jar name>.
-_product_list_vars += PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS
+_product_list_vars += PRODUCT_APEX_SYSTEM_SERVER_JARS
# If true, then suboptimal order of system server jars does not cause an error.
_product_single_value_vars += PRODUCT_BROKEN_SUBOPTIMAL_ORDER_OF_SYSTEM_SERVER_JARS
diff --git a/core/product_config.mk b/core/product_config.mk
index a9f3d34..99ff8aa 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -77,6 +77,16 @@
$(sort $(shell find $(2) -name "$(1)" -type f | $(SED_EXTENDED) "s:($(2)/?(.*)):\\1\\:$(3)/\\2:" | sed "s://:/:g"))
endef
+#
+# Convert file file to the PRODUCT_COPY_FILES/PRODUCT_SDK_ADDON_COPY_FILES
+# format: for each file F return $(F):$(PREFIX)/$(notdir $(F))
+# $(1): files list
+# $(2): prefix
+
+define copy-files
+$(foreach f,$(1),$(f):$(2)/$(notdir $(f)))
+endef
+
# ---------------------------------------------------------------
# Check for obsolete PRODUCT- and APP- goals
ifeq ($(CALLED_FROM_SETUP),true)
diff --git a/core/product_config.rbc b/core/product_config.rbc
index 8e85c4b..d9a2a72 100644
--- a/core/product_config.rbc
+++ b/core/product_config.rbc
@@ -16,6 +16,7 @@
"""Runtime functions."""
+_soong_config_namespaces_key = "$SOONG_CONFIG_NAMESPACES"
def _global_init():
"""Returns dict created from the runtime environment."""
globals = dict()
@@ -29,6 +30,7 @@
globals[k] = getattr(rblf_cli, k)
globals.setdefault("PRODUCT_SOONG_NAMESPACES", [])
+ globals.setdefault(_soong_config_namespaces_key, {})
_envsetup_init(globals)
# Variables that should be defined.
@@ -74,7 +76,12 @@
if _options.print_globals:
print()
for attr, val in sorted(globals.items()):
- if attr not in _globals_base:
+ if attr == _soong_config_namespaces_key:
+ __print_attr("SOONG_CONFIG_NAMESPACES", val.keys())
+ for nsname, nsvars in sorted(val.items()):
+ for var, val in sorted(nsvars.items()):
+ __print_attr("SOONG_CONFIG_%s_%s" % (nsname, var), val)
+ elif attr not in _globals_base:
__print_attr(attr, val)
def __printvars_rearrange_list(value_list):
@@ -268,6 +275,20 @@
"""Returns configuration item for the inherited module."""
return (pcm_name,)
+def _add_soong_config_namespace(g, nsname):
+ """Adds given namespace."""
+
+ # A value cannot be updated, so we need to create a new dictionary
+ old = g[_soong_config_namespaces_key]
+ g[_soong_config_namespaces_key] = dict([(k,v) for k,v in old.items()] + [(nsname, {})])
+
+def _add_soong_config_var_value(g, nsname, var, value):
+ """Defines a variable and adds it to the given namespace."""
+ ns = g[_soong_config_namespaces_key].get(nsname)
+ if ns == None:
+ fail("no such namespace: " + nsname)
+ ns[var] = value
+
def _addprefix(prefix, string_or_list):
"""Adds prefix and returns a list.
@@ -348,6 +369,10 @@
if type(val) == "list":
val.append(_indirect(pcm_name))
+def _copy_files(l, outdir):
+ """Generate <item>:<outdir>/item for each item."""
+ return ["%s:%s/%s" % (item, outdir, item) for item in __words(l)]
+
def _copy_if_exists(path_pair):
"""If from file exists, returns [from:to] pair."""
value = path_pair.split(":", 2)
@@ -523,8 +548,11 @@
# Settings used during debugging.
_options = __get_options()
rblf = struct(
+ add_soong_config_namespace = _add_soong_config_namespace,
+ add_soong_config_var_value = _add_soong_config_var_value,
addprefix = _addprefix,
addsuffix = _addsuffix,
+ copy_files = _copy_files,
copy_if_exists = _copy_if_exists,
cfg = __h_cfg,
enforce_product_packages_exist = _enforce_product_packages_exist,
diff --git a/core/sysprop.mk b/core/sysprop.mk
index be9b1f8..1d38f8c 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -430,7 +430,7 @@
$(eval $(call build-properties,\
odm,\
$(INSTALLED_ODM_BUILD_PROP_TARGET),\
- $(_prop_files),\
+ $(_prop_files_),\
$(_prop_vars_),\
$(empty),\
$(empty),\
diff --git a/core/tasks/OWNERS b/core/tasks/OWNERS
new file mode 100644
index 0000000..594930d
--- /dev/null
+++ b/core/tasks/OWNERS
@@ -0,0 +1 @@
+per-file art-host-tests.mk = dshi@google.com,dsrbecky@google.com,jdesprez@google.com,rpl@google.com
diff --git a/core/tasks/art-host-tests.mk b/core/tasks/art-host-tests.mk
index d771b06..b9a349d 100644
--- a/core/tasks/art-host-tests.mk
+++ b/core/tasks/art-host-tests.mk
@@ -29,6 +29,7 @@
$(art_host_tests_zip) : $(COMPATIBILITY.art-host-tests.FILES) $(my_host_shared_lib_for_art_host_tests) $(SOONG_ZIP)
echo $(sort $(COMPATIBILITY.art-host-tests.FILES)) | tr " " "\n" > $@.list
grep $(HOST_OUT_TESTCASES) $@.list > $@-host.list || true
+ $(hide) touch $@-host-libs.list
$(hide) for shared_lib in $(PRIVATE_HOST_SHARED_LIBS); do \
echo $$shared_lib >> $@-host-libs.list; \
done
diff --git a/target/product/default_art_config.mk b/target/product/default_art_config.mk
index a5e7bf3..82f86fc 100644
--- a/target/product/default_art_config.mk
+++ b/target/product/default_art_config.mk
@@ -59,7 +59,7 @@
com.android.wifi:framework-wifi
# APEX system server jars. Keep the list sorted by module names and then library names.
-PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS := \
+PRODUCT_APEX_SYSTEM_SERVER_JARS := \
com.android.art:service-art \
com.android.permission:service-permission \
diff --git a/target/product/gsi/Android.mk b/target/product/gsi/Android.mk
index cb4fdcb..39848e5 100644
--- a/target/product/gsi/Android.mk
+++ b/target/product/gsi/Android.mk
@@ -237,6 +237,6 @@
LOCAL_SRC_FILES := $(LOCAL_MODULE)
LOCAL_MODULE_CLASS := ETC
LOCAL_SYSTEM_EXT_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := init
+LOCAL_MODULE_RELATIVE_PATH := gsi
include $(BUILD_PREBUILT)
diff --git a/target/product/gsi/init.gsi.rc b/target/product/gsi/init.gsi.rc
index f482843..69c8e46 100644
--- a/target/product/gsi/init.gsi.rc
+++ b/target/product/gsi/init.gsi.rc
@@ -2,4 +2,4 @@
# Android init script for GSI required initialization
#
-import /system/system_ext/etc/init/init.vndk-${ro.vndk.version:-nodef}.rc
+import /system/system_ext/etc/gsi/init.vndk-${ro.vndk.version:-nodef}.rc
diff --git a/target/product/gsi/init.vndk-nodef.rc b/target/product/gsi/init.vndk-nodef.rc
index efeef11..1b141a0 100644
--- a/target/product/gsi/init.vndk-nodef.rc
+++ b/target/product/gsi/init.vndk-nodef.rc
@@ -1,3 +1,3 @@
on early-init
- # Must define BOARD_VNDK_VERSION
+ # Reboot if BOARD_VNDK_VERSION is not defined
exec - root -- /system/bin/reboot bootloader
diff --git a/tests/device.rbc b/tests/device.rbc
index 5d4e70c..b57dbf9 100644
--- a/tests/device.rbc
+++ b/tests/device.rbc
@@ -21,7 +21,14 @@
### PRODUCT_COPY_FILES += device_from:device_to
### include $(LOCAL_PATH)/include1.mk
### PRODUCT_PACKAGES += dev_after
-### PRODUCT_COPY_FILES += $(call find-copy-subdir-files,audio_platform_info*.xml,device/google/redfin/audio,$(TARGET_COPY_OUT_VENDOR)/etc) xyz
+### PRODUCT_COPY_FILES += $(call find-copy-subdir-files,audio_platform_info*.xml,device/google/redfin/audio,$(TARGET_COPY_OUT_VENDOR)/etc) xyz:/etc/xyz
+### PRODUCT_COPY_FILES += $(call copy-files,x.xml y.xml,/etc)
+### $(call add_soong_namespace,NS1)
+### $(call add_soong_config_var_value,NS1,v1,abc)
+### $(call add_soong_config_var_value,NS1,v2,def)
+### $(call add_soong_namespace,NS2)
+### $(call add_soong_config_var_value,NS2,v3,abc)
+### $(call add_soong_config_var_value,NS2,v3,xyz)
load("//build/make/core:product_config.rbc", "rblf")
load(":part1.rbc", _part1_init = "init")
@@ -39,4 +46,12 @@
_include1_init(g, handle)
cfg["PRODUCT_PACKAGES"] += ["dev_after"]
cfg["PRODUCT_COPY_FILES"] += (rblf.find_and_copy("audio_platform_info*.xml", "device/google/redfin/audio", "||VENDOR-PATH-PH||/etc") +
- ["xyz"])
+ ["xyz:/etc/xyz"])
+ cfg["PRODUCT_COPY_FILES"] += rblf.copy_files("x.xml y.xml", "/etc")
+ rblf.add_soong_config_namespace(g, "NS1")
+ rblf.add_soong_config_var_value(g, "NS1", "v1", "abc")
+ rblf.add_soong_config_var_value(g, "NS1", "v2", "def")
+ rblf.add_soong_config_namespace(g, "NS2")
+ rblf.add_soong_config_var_value(g, "NS2", "v3", "abc")
+ rblf.add_soong_config_var_value(g, "NS2", "v3", "xyz")
+
diff --git a/tests/run.rbc b/tests/run.rbc
index 4cda180..15f6212 100644
--- a/tests/run.rbc
+++ b/tests/run.rbc
@@ -51,7 +51,9 @@
"part_from:part_to",
"device_from:device_to",
"device/google/redfin/audio/audio_platform_info_noextcodec_snd.xml:||VENDOR-PATH-PH||/etc/audio_platform_info_noextcodec_snd.xml",
- "xyz"
+ "xyz:/etc/xyz",
+ "x.xml:/etc/x.xml",
+ "y.xml:/etc/y.xml",
],
"PRODUCT_HOST_PACKAGES": ["host"],
"PRODUCT_PACKAGES": [
@@ -63,3 +65,17 @@
},
{ k:v for k, v in sorted(config.items()) }
)
+
+ns = globals["$SOONG_CONFIG_NAMESPACES"]
+assert_eq(
+ {
+ "NS1": {
+ "v1": "abc",
+ "v2": "def"
+ },
+ "NS2": {
+ "v3": "xyz"
+ }
+ },
+ {k:v for k, v in sorted(ns.items()) }
+)
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index b8c812d..f3b58f8 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -1030,8 +1030,5 @@
try:
common.CloseInheritedPipes()
main(sys.argv[1:])
- except common.ExternalError:
- logger.exception("\n ERROR:\n")
- sys.exit(1)
finally:
common.Cleanup()
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index bcc10bd..1f3022b 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -241,7 +241,7 @@
import common
import ota_utils
from ota_utils import (UNZIP_PATTERN, FinalizeMetadata, GetPackageMetadata,
- PropertyFiles, SECURITY_PATCH_LEVEL_PROP_NAME)
+ PropertyFiles, SECURITY_PATCH_LEVEL_PROP_NAME, GetZipEntryOffset)
import target_files_diff
from check_target_files_vintf import CheckVintfIfTrebleEnabled
from non_ab_ota import GenerateNonAbOtaPackage
@@ -603,20 +603,20 @@
payload, till the end of 'medatada_signature_message'.
"""
payload_info = input_zip.getinfo('payload.bin')
- payload_offset = payload_info.header_offset
- payload_offset += zipfile.sizeFileHeader
- payload_offset += len(payload_info.extra) + len(payload_info.filename)
- payload_size = payload_info.file_size
+ (payload_offset, payload_size) = GetZipEntryOffset(input_zip, payload_info)
- with input_zip.open('payload.bin') as payload_fp:
- header_bin = payload_fp.read(24)
+ # Read the underlying raw zipfile at specified offset
+ payload_fp = input_zip.fp
+ payload_fp.seek(payload_offset)
+ header_bin = payload_fp.read(24)
# network byte order (big-endian)
header = struct.unpack("!IQQL", header_bin)
# 'CrAU'
magic = header[0]
- assert magic == 0x43724155, "Invalid magic: {:x}".format(magic)
+ assert magic == 0x43724155, "Invalid magic: {:x}, computed offset {}" \
+ .format(magic, payload_offset)
manifest_size = header[2]
metadata_signature_size = header[3]
diff --git a/tools/releasetools/ota_utils.py b/tools/releasetools/ota_utils.py
index 28c246b..5737009 100644
--- a/tools/releasetools/ota_utils.py
+++ b/tools/releasetools/ota_utils.py
@@ -16,6 +16,7 @@
import itertools
import logging
import os
+import struct
import zipfile
import ota_metadata_pb2
@@ -399,6 +400,35 @@
return device_names, fingerprints
+def GetZipEntryOffset(zfp, entry_info):
+ """Get offset to a beginning of a particular zip entry
+ Args:
+ fp: zipfile.ZipFile
+ entry_info: zipfile.ZipInfo
+
+ Returns:
+ (offset, size) tuple
+ """
+ # Don't use len(entry_info.extra). Because that returns size of extra
+ # fields in central directory. We need to look at local file directory,
+ # as these two might have different sizes.
+
+ # We cannot work with zipfile.ZipFile instances, we need a |fp| for the underlying file.
+ zfp = zfp.fp
+ zfp.seek(entry_info.header_offset)
+ data = zfp.read(zipfile.sizeFileHeader)
+ fheader = struct.unpack(zipfile.structFileHeader, data)
+ # Last two fields of local file header are filename length and
+ # extra length
+ filename_len = fheader[-2]
+ extra_len = fheader[-1]
+ offset = entry_info.header_offset
+ offset += zipfile.sizeFileHeader
+ offset += filename_len + extra_len
+ size = entry_info.file_size
+ return (offset, size)
+
+
class PropertyFiles(object):
"""A class that computes the property-files string for an OTA package.
@@ -517,10 +547,7 @@
def ComputeEntryOffsetSize(name):
"""Computes the zip entry offset and size."""
info = zip_file.getinfo(name)
- offset = info.header_offset
- offset += zipfile.sizeFileHeader
- offset += len(info.extra) + len(info.filename)
- size = info.file_size
+ (offset, size) = GetZipEntryOffset(zip_file, info)
return '%s:%d:%d' % (os.path.basename(name), offset, size)
tokens = []
diff --git a/tools/releasetools/test_ota_utils.py b/tools/releasetools/test_ota_utils.py
new file mode 100644
index 0000000..9a82e6f
--- /dev/null
+++ b/tools/releasetools/test_ota_utils.py
@@ -0,0 +1,56 @@
+# Copyright (C) 2021 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 unittest
+import io
+import ota_utils
+import zipfile
+
+
+class TestZipEntryOffset(unittest.TestCase):
+ def test_extra_length_differ(self):
+ # This is a magic zip file such that:
+ # 1. It has 1 entry, `file.txt'`
+ # 2. The central directory entry for the entry contains an extra field of#
+ # length 24, while the local file header for the entry contains an extra#
+ # field of length 28.
+ # It is key that the entry contains extra field of different length.
+ # The sole purpose of this test case is make sure our offset computing
+ # logic works in this scenario.
+
+ # This is created by:
+ # touch file.txt
+ # zip -0 test.zip file.txt
+ # Above command may or may not work on all platforms.
+ # Some zip implementation will keep the extra field size consistent.
+ # Some don't
+ magic_zip = b'PK\x03\x04\n\x00\x00\x00\x00\x00nY\xfcR\x00\x00\x00\x00\x00\x00\x00' +\
+ b'\x00\x00\x00\x00\x00\x08\x00\x1c\x00file.txtUT\t\x00\x03' +\
+ b'\xa0s\x01a\xa0s\x01aux\x0b\x00\x01\x04\x88\xc4\t\x00\x04S_\x01\x00' +\
+ b'PK\x01\x02\x1e\x03\n\x00\x00\x00\x00\x00nY\xfcR\x00\x00\x00\x00' +\
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x18\x00\x00\x00\x00\x00' +\
+ b'\x00\x00\x00\x00\x80\x81\x00\x00\x00\x00file.txt' +\
+ b'UT\x05\x00\x03\xa0s\x01aux\x0b\x00\x01\x04\x88\xc4\t\x00\x04' +\
+ b'S_\x01\x00PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00N\x00\x00' +\
+ b'\x00B\x00\x00\x00\x00\x00'
+ # Just making sure we concatenated the bytes correctly
+ self.assertEqual(len(magic_zip), 166)
+ fp = io.BytesIO(magic_zip)
+ with zipfile.ZipFile(fp, 'r') as zfp:
+ self.assertGreater(len(zfp.infolist()), 0)
+ zinfo = zfp.getinfo("file.txt")
+ (offset, size) = ota_utils.GetZipEntryOffset(zfp, zinfo)
+ self.assertEqual(size, zinfo.file_size)
+ self.assertEqual(offset, zipfile.sizeFileHeader+len(zinfo.filename) + 28)