diff options
| -rw-r--r-- | core/Makefile | 7 | ||||
| -rw-r--r-- | core/base_rules.mk | 5 | ||||
| -rw-r--r-- | core/build_rro_package.mk | 25 | ||||
| -rw-r--r-- | core/clang/HOST_x86_common.mk | 3 | ||||
| -rw-r--r-- | core/clear_vars.mk | 2 | ||||
| -rw-r--r-- | core/config.mk | 1 | ||||
| -rw-r--r-- | core/product.mk | 1 | ||||
| -rw-r--r-- | core/product_config.mk | 3 | ||||
| -rw-r--r-- | target/product/emulator.mk | 1 | ||||
| -rwxr-xr-x | tools/fileslist.py | 29 | ||||
| -rwxr-xr-x | tools/fileslist_util.py | 68 | ||||
| -rwxr-xr-x | tools/releasetools/add_img_to_target_files.py | 39 | ||||
| -rwxr-xr-x | tools/releasetools/build_image.py | 65 | ||||
| -rw-r--r-- | tools/releasetools/edify_generator.py | 43 | ||||
| -rwxr-xr-x | tools/releasetools/ota_from_target_files.py | 184 | ||||
| -rwxr-xr-x | tools/releasetools/sign_target_files_apks.py | 4 |
16 files changed, 345 insertions, 135 deletions
diff --git a/core/Makefile b/core/Makefile index 6a70b49c59..60f9837644 100644 --- a/core/Makefile +++ b/core/Makefile @@ -799,6 +799,7 @@ $(if $(BOARD_SYSTEMIMAGE_SQUASHFS_COMPRESSOR_OPT),$(hide) echo "system_squashfs_ $(if $(BOARD_SYSTEMIMAGE_SQUASHFS_BLOCK_SIZE),$(hide) echo "system_squashfs_block_size=$(BOARD_SYSTEMIMAGE_SQUASHFS_BLOCK_SIZE)" >> $(1)) $(if $(BOARD_SYSTEMIMAGE_SQUASHFS_DISABLE_4K_ALIGN),$(hide) echo "system_squashfs_disable_4k_align=$(BOARD_SYSTEMIMAGE_SQUASHFS_DISABLE_4K_ALIGN)" >> $(1)) $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_BASE_FS_PATH),$(hide) echo "system_base_fs_file=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_BASE_FS_PATH)" >> $(1)) +$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_HEADROOM),$(hide) echo "system_headroom=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_HEADROOM)" >> $(1)) $(if $(BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE),$(hide) echo "userdata_fs_type=$(BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE)" >> $(1)) $(if $(BOARD_USERDATAIMAGE_PARTITION_SIZE),$(hide) echo "userdata_size=$(BOARD_USERDATAIMAGE_PARTITION_SIZE)" >> $(1)) $(if $(BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE),$(hide) echo "cache_fs_type=$(BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE)" >> $(1)) @@ -1092,7 +1093,8 @@ $(INSTALLED_FILES_FILE): $(FULL_SYSTEMIMAGE_DEPS) @echo Installed file list: $@ @mkdir -p $(dir $@) @rm -f $@ - $(hide) build/tools/fileslist.py $(TARGET_OUT) > $@ + $(hide) build/tools/fileslist.py $(TARGET_OUT) > $(@:.txt=.json) + $(hide) build/tools/fileslist_util.py -c $(@:.txt=.json) > $@ .PHONY: installed-file-list installed-file-list: $(INSTALLED_FILES_FILE) @@ -1495,7 +1497,8 @@ $(INSTALLED_FILES_FILE_VENDOR) : $(INTERNAL_VENDORIMAGE_FILES) @echo Installed file list: $@ @mkdir -p $(dir $@) @rm -f $@ - $(hide) build/tools/fileslist.py $(TARGET_OUT_VENDOR) > $@ + $(hide) build/tools/fileslist.py $(TARGET_OUT_VENDOR) > $(@:.txt=.json) + $(hide) build/tools/fileslist_util.py -c $(@:.txt=.json) > $@ vendorimage_intermediates := \ $(call intermediates-dir-for,PACKAGING,vendor) diff --git a/core/base_rules.mk b/core/base_rules.mk index 0e3bd6893a..1dda2fab7e 100644 --- a/core/base_rules.mk +++ b/core/base_rules.mk @@ -210,7 +210,10 @@ ifneq (true,$(LOCAL_UNINSTALLABLE_MODULE)) # Apk and its attachments reside in its own subdir. ifeq ($(LOCAL_MODULE_CLASS),APPS) # framework-res.apk doesn't like the additional layer. - ifneq ($(LOCAL_NO_STANDARD_LIBRARIES),true) + ifeq ($(LOCAL_NO_STANDARD_LIBRARIES),true) + # Neither do Runtime Resource Overlay apks, which contain just the overlaid resources. + else ifeq ($(LOCAL_IS_RUNTIME_RESOURCE_OVERLAY),true) + else my_module_path := $(my_module_path)/$(LOCAL_MODULE) endif endif diff --git a/core/build_rro_package.mk b/core/build_rro_package.mk new file mode 100644 index 0000000000..9865b33fec --- /dev/null +++ b/core/build_rro_package.mk @@ -0,0 +1,25 @@ +############################################################################# +## Standard rules for installing runtime resouce overlay APKs. +## +## Set LOCAL_RRO_THEME to the theme name if the package should apply only to +## a particular theme as set by ro.boot.vendor.overlay.theme system property. +## +## If LOCAL_RRO_THEME is not set, the package will apply always, independent +## of themes. +## +############################################################################# + +LOCAL_IS_RUNTIME_RESOURCE_OVERLAY := true + +ifneq ($(LOCAL_SRC_FILES),) + $(error runtime resource overlay package should not contain sources) +endif + +ifeq (S(LOCAL_RRO_THEME),) + LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/overlay +else + LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/overlay/$(LOCAL_RRO_THEME) +endif + +include $(BUILD_SYSTEM)/package.mk + diff --git a/core/clang/HOST_x86_common.mk b/core/clang/HOST_x86_common.mk index 9e71750c14..690c0f6b38 100644 --- a/core/clang/HOST_x86_common.mk +++ b/core/clang/HOST_x86_common.mk @@ -13,7 +13,8 @@ endif ifeq ($(HOST_OS),linux) CLANG_CONFIG_x86_LINUX_HOST_EXTRA_ASFLAGS := \ --gcc-toolchain=$($(clang_2nd_arch_prefix)HOST_TOOLCHAIN_FOR_CLANG) \ - --sysroot $($(clang_2nd_arch_prefix)HOST_TOOLCHAIN_FOR_CLANG)/sysroot + --sysroot $($(clang_2nd_arch_prefix)HOST_TOOLCHAIN_FOR_CLANG)/sysroot \ + -B$($(clang_2nd_arch_prefix)HOST_TOOLCHAIN_FOR_CLANG)/x86_64-linux/bin CLANG_CONFIG_x86_LINUX_HOST_EXTRA_CFLAGS := \ --gcc-toolchain=$($(clang_2nd_arch_prefix)HOST_TOOLCHAIN_FOR_CLANG) diff --git a/core/clear_vars.mk b/core/clear_vars.mk index 5886610588..f7567b4b66 100644 --- a/core/clear_vars.mk +++ b/core/clear_vars.mk @@ -363,6 +363,8 @@ LOCAL_CLANG_64:= LOCAL_INIT_RC_32:= LOCAL_INIT_RC_64:= LOCAL_JAVA_LANGUAGE_VERSION:= +LOCAL_IS_RUNTIME_RESOURCE_OVERLAY:= +LOCAL_RRO_THEME:= # Trim MAKEFILE_LIST so that $(call my-dir) doesn't need to # iterate over thousands of entries every time. diff --git a/core/config.mk b/core/config.mk index 5b9f1f8b67..2847d349eb 100644 --- a/core/config.mk +++ b/core/config.mk @@ -85,6 +85,7 @@ BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk BUILD_PHONY_PACKAGE:= $(BUILD_SYSTEM)/phony_package.mk +BUILD_RRO_PACKAGE:= $(BUILD_SYSTEM)/build_rro_package.mk BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk diff --git a/core/product.mk b/core/product.mk index 332b015fd8..c69e96343f 100644 --- a/core/product.mk +++ b/core/product.mk @@ -124,6 +124,7 @@ _product_var_list := \ PRODUCT_SYSTEM_BASE_FS_PATH \ PRODUCT_VENDOR_BASE_FS_PATH \ PRODUCT_SHIPPING_API_LEVEL \ + PRODUCT_SYSTEM_HEADROOM \ diff --git a/core/product_config.mk b/core/product_config.mk index 6438d51bee..4117332467 100644 --- a/core/product_config.mk +++ b/core/product_config.mk @@ -319,6 +319,9 @@ ifndef PRODUCT_MANUFACTURER PRODUCT_MANUFACTURER := unknown endif +# Add reserved headroom to a system image. +PRODUCT_SYSTEM_HEADROOM := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_HEADROOM)) + ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_CHARACTERISTICS),) TARGET_AAPT_CHARACTERISTICS := default else diff --git a/target/product/emulator.mk b/target/product/emulator.mk index b08a28a2a9..afa8389ce9 100644 --- a/target/product/emulator.mk +++ b/target/product/emulator.mk @@ -61,6 +61,7 @@ PRODUCT_COPY_FILES += \ device/generic/goldfish/init.ranchu.rc:root/init.ranchu.rc \ device/generic/goldfish/fstab.ranchu:root/fstab.ranchu \ device/generic/goldfish/ueventd.ranchu.rc:root/ueventd.ranchu.rc \ + device/generic/goldfish/input/goldfish_rotary.idc:system/usr/idc/goldfish_rotary.idc \ frameworks/native/data/etc/android.hardware.usb.accessory.xml:system/etc/permissions/android.hardware.usb.accessory.xml PRODUCT_PACKAGE_OVERLAYS := device/generic/goldfish/overlay diff --git a/tools/fileslist.py b/tools/fileslist.py index a11efaa8fe..b9e73503e2 100755 --- a/tools/fileslist.py +++ b/tools/fileslist.py @@ -15,12 +15,24 @@ # limitations under the License. # -import operator, os, sys +import json, hashlib, operator, os, sys def get_file_size(path): st = os.lstat(path) return st.st_size; +def get_file_digest(path): + if os.path.isfile(path) == False: + return "----------------------------------------------------------------" + digest = hashlib.sha256() + with open(path, 'rb') as f: + while True: + buf = f.read(1024*1024) + if not buf: + break + digest.update(buf) + return digest.hexdigest(); + def main(argv): output = [] roots = argv[1:] @@ -30,16 +42,17 @@ def main(argv): relative = dir[base:] for f in files: try: - row = ( - get_file_size(os.path.sep.join((dir, f))), - os.path.sep.join((relative, f)), - ) + path = os.path.sep.join((dir, f)) + row = { + "Size": get_file_size(path), + "Name": os.path.sep.join((relative, f)), + "SHA256": get_file_digest(path), + } output.append(row) except os.error: pass - output.sort(key=operator.itemgetter(0), reverse=True) - for row in output: - print "%12d %s" % row + output.sort(key=operator.itemgetter("Size", "Name"), reverse=True) + print json.dumps(output, indent=2, separators=(',',': ')) if __name__ == '__main__': main(sys.argv) diff --git a/tools/fileslist_util.py b/tools/fileslist_util.py new file mode 100755 index 0000000000..ff40d51a02 --- /dev/null +++ b/tools/fileslist_util.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# +# Copyright (C) 2016 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 getopt, json, sys + +def PrintFileNames(path): + with open(path) as jf: + data = json.load(jf) + for line in data: + print(line["Name"]) + +def PrintCanonicalList(path): + with open(path) as jf: + data = json.load(jf) + for line in data: + print "{0:12d} {1}".format(line["Size"], line["Name"]) + +def PrintUsage(name): + print(""" +Usage: %s -[nc] json_files_list + -n produces list of files only + -c produces classic installed-files.txt +""" % (name)) + +def main(argv): + try: + opts, args = getopt.getopt(argv[1:], "nc", "") + except getopt.GetoptError, err: + print(err) + PrintUsage(argv[0]) + sys.exit(2) + + if len(opts) == 0: + print("No conversion option specified") + PrintUsage(argv[0]) + sys.exit(2) + + if len(args) == 0: + print("No input file specified") + PrintUsage(argv[0]) + sys.exit(2) + + for o, a in opts: + if o == ("-n"): + PrintFileNames(args[0]) + sys.exit() + elif o == ("-c"): + PrintCanonicalList(args[0]) + sys.exit() + else: + assert False, "Unsupported option" + +if __name__ == '__main__': + main(sys.argv) diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py index 0bbd8f6d9b..5a0a4116fd 100755 --- a/tools/releasetools/add_img_to_target_files.py +++ b/tools/releasetools/add_img_to_target_files.py @@ -19,7 +19,31 @@ Given a target-files zipfile that does not contain images (ie, does not have an IMAGES/ top-level subdirectory), produce the images and add them to the zipfile. -Usage: add_img_to_target_files target_files +Usage: add_img_to_target_files [flag] target_files + + -a (--add_missing) + Build and add missing images to "IMAGES/". If this option is + not specified, this script will simply exit when "IMAGES/" + directory exists in the target file. + + -r (--rebuild_recovery) + Rebuild the recovery patch and write it to the system image. Only + meaningful when system image needs to be rebuilt. + + --replace_verity_private_key + Replace the private key used for verity signing. (same as the option + in sign_target_files_apks) + + --replace_verity_public_key + Replace the certificate (public key) used for verity verification. (same + as the option in sign_target_files_apks) + + --is_signing + Skip building & adding the images for "userdata" and "cache" if we + are signing the target files. + + --verity_signer_path + Specify the signer path to build verity metadata. """ import sys @@ -45,6 +69,7 @@ OPTIONS.add_missing = False OPTIONS.rebuild_recovery = False OPTIONS.replace_verity_public_key = False OPTIONS.replace_verity_private_key = False +OPTIONS.is_signing = False OPTIONS.verity_signer_path = None def GetCareMap(which, imgname): @@ -364,10 +389,11 @@ def AddImagesToTargetFiles(filename): if has_system_other: banner("system_other") AddSystemOther(output_zip) - banner("userdata") - AddUserdata(output_zip) - banner("cache") - AddCache(output_zip) + if not OPTIONS.is_signing: + banner("userdata") + AddUserdata(output_zip) + banner("cache") + AddCache(output_zip) # For devices using A/B update, copy over images from RADIO/ to IMAGES/ and # make sure we have all the needed images ready under IMAGES/. @@ -414,6 +440,8 @@ def main(argv): OPTIONS.replace_verity_private_key = (True, a) elif o == "--replace_verity_public_key": OPTIONS.replace_verity_public_key = (True, a) + elif o == "--is_signing": + OPTIONS.is_signing = True elif o == "--verity_signer_path": OPTIONS.verity_signer_path = a else: @@ -425,6 +453,7 @@ def main(argv): extra_long_opts=["add_missing", "rebuild_recovery", "replace_verity_public_key=", "replace_verity_private_key=", + "is_signing", "verity_signer_path="], extra_option_handler=option_handler) diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py index 24ecd1525a..fdf7271c54 100755 --- a/tools/releasetools/build_image.py +++ b/tools/releasetools/build_image.py @@ -109,7 +109,8 @@ def AdjustPartitionSizeForVerity(partition_size, fec_supported): Args: partition_size: the size of the partition to be verified. Returns: - The size of the partition adjusted for verity metadata. + A tuple of the size of the partition adjusted for verity metadata, and + the size of verity metadata. """ key = "%d %d" % (partition_size, fec_supported) if key in AdjustPartitionSizeForVerity.results: @@ -121,27 +122,31 @@ def AdjustPartitionSizeForVerity(partition_size, fec_supported): # verity tree and fec sizes depend on the partition size, which # means this estimate is always going to be unnecessarily small - lo = partition_size - GetVeritySize(hi, fec_supported) + verity_size = GetVeritySize(hi, fec_supported) + lo = partition_size - verity_size result = lo # do a binary search for the optimal size while lo < hi: i = ((lo + hi) // (2 * BLOCK_SIZE)) * BLOCK_SIZE - size = i + GetVeritySize(i, fec_supported) - if size <= partition_size: + v = GetVeritySize(i, fec_supported) + if i + v <= partition_size: if result < i: result = i + verity_size = v lo = i + BLOCK_SIZE else: hi = i - AdjustPartitionSizeForVerity.results[key] = result - return result + AdjustPartitionSizeForVerity.results[key] = (result, verity_size) + return (result, verity_size) AdjustPartitionSizeForVerity.results = {} -def BuildVerityFEC(sparse_image_path, verity_path, verity_fec_path): - cmd = "fec -e %s %s %s" % (sparse_image_path, verity_path, verity_fec_path) +def BuildVerityFEC(sparse_image_path, verity_path, verity_fec_path, + padding_size): + cmd = "fec -e -p %d %s %s %s" % (padding_size, sparse_image_path, + verity_path, verity_fec_path) print cmd status, output = commands.getstatusoutput(cmd) if status: @@ -207,7 +212,7 @@ def Append(target, file_to_append, error_message): def BuildVerifiedImage(data_image_path, verity_image_path, verity_metadata_path, verity_fec_path, - fec_supported): + padding_size, fec_supported): if not Append(verity_image_path, verity_metadata_path, "Could not append verity metadata!"): return False @@ -215,7 +220,7 @@ def BuildVerifiedImage(data_image_path, verity_image_path, if fec_supported: # build FEC for the entire partition, including metadata if not BuildVerityFEC(data_image_path, verity_image_path, - verity_fec_path): + verity_fec_path, padding_size): return False if not Append(verity_image_path, verity_fec_path, "Could not append FEC!"): @@ -253,7 +258,7 @@ def MakeVerityEnabledImage(out_file, fec_supported, prop_dict): True on success, False otherwise. """ # get properties - image_size = prop_dict["partition_size"] + image_size = int(prop_dict["partition_size"]) block_dev = prop_dict["verity_block_device"] signer_key = prop_dict["verity_key"] + ".pk8" if OPTIONS.verity_signer_path is not None: @@ -284,10 +289,17 @@ def MakeVerityEnabledImage(out_file, fec_supported, prop_dict): return False # build the full verified image + target_size = int(prop_dict["original_partition_size"]) + verity_size = int(prop_dict["verity_size"]) + + padding_size = target_size - image_size - verity_size + assert padding_size >= 0 + if not BuildVerifiedImage(out_file, verity_image_path, verity_metadata_path, verity_fec_path, + padding_size, fec_supported): shutil.rmtree(tempdir_name, ignore_errors=True) return False @@ -358,12 +370,13 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None): # verified. if verity_supported and is_verity_partition: partition_size = int(prop_dict.get("partition_size")) - adjusted_size = AdjustPartitionSizeForVerity(partition_size, - verity_fec_supported) + (adjusted_size, verity_size) = AdjustPartitionSizeForVerity(partition_size, + verity_fec_supported) if not adjusted_size: return False prop_dict["partition_size"] = str(adjusted_size) prop_dict["original_partition_size"] = str(partition_size) + prop_dict["verity_size"] = str(verity_size) if fs_type.startswith("ext"): build_command = ["mkuserimg.sh"] @@ -436,11 +449,11 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None): shutil.rmtree(staging_system, ignore_errors=True) shutil.copytree(origin_in, staging_system, symlinks=True) - reserved_blocks = prop_dict.get("has_ext4_reserved_blocks") == "true" + has_reserved_blocks = prop_dict.get("has_ext4_reserved_blocks") == "true" ext4fs_output = None try: - if reserved_blocks and fs_type.startswith("ext4"): + if fs_type.startswith("ext4"): (ext4fs_output, exit_code) = RunCommand(build_command) else: (_, exit_code) = RunCommand(build_command) @@ -461,7 +474,9 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None): # not writable even with root privilege. It only affects devices using # file-based OTA and a kernel version of 3.10 or greater (currently just # sprout). - if reserved_blocks and fs_type.startswith("ext4"): + # Separately, check if there's enough headroom space available. This is useful for + # devices with low disk space that have system image variation between builds. + if (has_reserved_blocks or "partition_headroom" in prop_dict) and fs_type.startswith("ext4"): assert ext4fs_output is not None ext4fs_stats = re.compile( r'Created filesystem with .* (?P<used_blocks>[0-9]+)/' @@ -469,14 +484,21 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None): m = ext4fs_stats.match(ext4fs_output.strip().split('\n')[-1]) used_blocks = int(m.groupdict().get('used_blocks')) total_blocks = int(m.groupdict().get('total_blocks')) - reserved_blocks = min(4096, int(total_blocks * 0.02)) - adjusted_blocks = total_blocks - reserved_blocks + reserved_blocks = 0 + headroom_blocks = 0 + adjusted_blocks = total_blocks + if has_reserved_blocks: + reserved_blocks = min(4096, int(total_blocks * 0.02)) + adjusted_blocks -= reserved_blocks + if "partition_headroom" in prop_dict: + headroom_blocks = int(prop_dict.get('partition_headroom')) / BLOCK_SIZE + adjusted_blocks -= headroom_blocks if used_blocks > adjusted_blocks: mount_point = prop_dict.get("mount_point") print("Error: Not enough room on %s (total: %d blocks, used: %d blocks, " - "reserved: %d blocks, available: %d blocks)" % ( + "reserved: %d blocks, headroom: %d blocks, available: %d blocks)" % ( mount_point, total_blocks, used_blocks, reserved_blocks, - adjusted_blocks)) + headroom_blocks, adjusted_blocks)) return False if not fs_spans_partition: @@ -544,9 +566,10 @@ def ImagePropFromGlobalDict(glob_dict, mount_point): d["mount_point"] = mount_point if mount_point == "system": copy_prop("fs_type", "fs_type") - # Copy the generic sysetem fs type first, override with specific one if + # Copy the generic system fs type first, override with specific one if # available. copy_prop("system_fs_type", "fs_type") + copy_prop("system_headroom", "partition_headroom") copy_prop("system_size", "partition_size") copy_prop("system_journal_size", "journal_size") copy_prop("system_verity_block_device", "verity_block_device") diff --git a/tools/releasetools/edify_generator.py b/tools/releasetools/edify_generator.py index 2ecc5cbb86..73131a606f 100644 --- a/tools/releasetools/edify_generator.py +++ b/tools/releasetools/edify_generator.py @@ -77,26 +77,28 @@ class EdifyGenerator(object): with temporary=True) to this one.""" self.script.extend(other.script) - def AssertOemProperty(self, name, value): - """Assert that a property on the OEM paritition matches a value.""" + def AssertOemProperty(self, name, values): + """Assert that a property on the OEM paritition matches allowed values.""" if not name: raise ValueError("must specify an OEM property") - if not value: + if not values: raise ValueError("must specify the OEM value") + get_prop_command = None if common.OPTIONS.oem_no_mount: - cmd = ('getprop("{name}") == "{value}" || ' - 'abort("E{code}: This package expects the value \\"{value}\\" for ' - '\\"{name}\\"; this has value \\"" + ' - 'getprop("{name}") + "\\".");').format( - code=common.ErrorCode.OEM_PROP_MISMATCH, - name=name, value=value) + get_prop_command = 'getprop("%s")' % name else: - cmd = ('file_getprop("/oem/oem.prop", "{name}") == "{value}" || ' - 'abort("E{code}: This package expects the value \\"{value}\\" for ' - '\\"{name}\\" on the OEM partition; this has value \\"" + ' - 'file_getprop("/oem/oem.prop", "{name}") + "\\".");').format( - code=common.ErrorCode.OEM_PROP_MISMATCH, - name=name, value=value) + get_prop_command = 'file_getprop("/oem/oem.prop", "%s")' % name + + cmd = '' + for value in values: + cmd += '%s == "%s" || ' % (get_prop_command, value) + cmd += ( + 'abort("E{code}: This package expects the value \\"{values}\\" for ' + '\\"{name}\\"; this has value \\"" + ' + '{get_prop_command} + "\\".");').format( + code=common.ErrorCode.OEM_PROP_MISMATCH, + get_prop_command=get_prop_command, name=name, + values='\\" or \\"'.join(values)) self.script.append(cmd) def AssertSomeFingerprint(self, *fp): @@ -121,6 +123,17 @@ class EdifyGenerator(object): common.ErrorCode.THUMBPRINT_MISMATCH, " or ".join(fp)) self.script.append(cmd) + def AssertFingerprintOrThumbprint(self, fp, tp): + """Assert that the current recovery build fingerprint is fp, or thumbprint + is tp.""" + cmd = ('getprop("ro.build.fingerprint") == "{fp}" ||\n' + ' getprop("ro.build.thumbprint") == "{tp}" ||\n' + ' abort("Package expects build fingerprint of {fp} or ' + 'thumbprint of {tp}; this device has a fingerprint of " ' + '+ getprop("ro.build.fingerprint") + " and a thumbprint of " ' + '+ getprop("ro.build.thumbprint") + ".");').format(fp=fp, tp=tp) + self.script.append(cmd) + def AssertOlderBuild(self, timestamp, timestamp_text): """Assert that the build on the device is older (or the same as) the given timestamp.""" diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py index 24b42eefc2..199e700cc6 100755 --- a/tools/releasetools/ota_from_target_files.py +++ b/tools/releasetools/ota_from_target_files.py @@ -50,9 +50,11 @@ Usage: ota_from_target_files [flags] input_target_files output_ota_package Remount and verify the checksums of the files written to the system and vendor (if used) partitions. Incremental builds only. - -o (--oem_settings) <file> - Use the file to specify the expected OEM-specific properties - on the OEM partition of the intended device. + -o (--oem_settings) <main_file[,additional_files...]> + Comma seperated list of files used to specify the expected OEM-specific + properties on the OEM partition of the intended device. + Multiple expected values can be used by providing multiple files. + --oem_no_mount For devices with OEM-specific properties but without an OEM partition, @@ -464,20 +466,38 @@ def SignOutput(temp_zip_name, output_zip_name): whole_file=True) -def AppendAssertions(script, info_dict, oem_dict=None): +def AppendAssertions(script, info_dict, oem_dicts=None): oem_props = info_dict.get("oem_fingerprint_properties") - if oem_props is None or len(oem_props) == 0: + if not oem_props: device = GetBuildProp("ro.product.device", info_dict) script.AssertDevice(device) else: - if oem_dict is None: + if not oem_dicts: raise common.ExternalError( "No OEM file provided to answer expected assertions") for prop in oem_props.split(): - if oem_dict.get(prop) is None: + values = [] + for oem_dict in oem_dicts: + if oem_dict.get(prop): + values.append(oem_dict[prop]) + if not values: raise common.ExternalError( "The OEM file is missing the property %s" % prop) - script.AssertOemProperty(prop, oem_dict.get(prop)) + script.AssertOemProperty(prop, values) + + +def _LoadOemDicts(script, recovery_mount_options=None): + """Returns the list of loaded OEM properties dict.""" + oem_dicts = None + if OPTIONS.oem_source is None: + raise common.ExternalError("OEM source required for this build") + if not OPTIONS.oem_no_mount: + script.Mount("/oem", recovery_mount_options) + oem_dicts = [] + for oem_file in OPTIONS.oem_source: + oem_dicts.append(common.LoadDictionaryFromLines( + open(oem_file).readlines())) + return oem_dicts def _WriteRecoveryImageToBoot(script, output_zip): @@ -590,19 +610,15 @@ def WriteFullOTAPackage(input_zip, output_zip): oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - if not OPTIONS.oem_no_mount: - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines( - open(OPTIONS.oem_source).readlines()) + oem_dicts = None + if oem_props: + oem_dicts = _LoadOemDicts(script, recovery_mount_options) metadata = { - "post-build": CalculateFingerprint(oem_props, oem_dict, + "post-build": CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0], OPTIONS.info_dict), - "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, + "pre-device": GetOemProperty("ro.product.device", oem_props, + oem_dicts and oem_dicts[0], OPTIONS.info_dict), "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict), } @@ -626,7 +642,7 @@ def WriteFullOTAPackage(input_zip, output_zip): ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict) script.AssertOlderBuild(ts, ts_text) - AppendAssertions(script, OPTIONS.info_dict, oem_dict) + AppendAssertions(script, OPTIONS.info_dict, oem_dicts) device_specific.FullOTA_Assertions() # Two-step package strategy (in chronological order, which is *not* @@ -677,7 +693,7 @@ else if get_stage("%(bcb_dev)s") == "3/3" then # Dump fingerprints script.Print("Target: %s" % CalculateFingerprint( - oem_props, oem_dict, OPTIONS.info_dict)) + oem_props, oem_dicts and oem_dicts[0], OPTIONS.info_dict)) device_specific.FullOTA_InstallBegin() @@ -876,20 +892,17 @@ def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip): source_version, OPTIONS.target_info_dict, fstab=OPTIONS.source_info_dict["fstab"]) - oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") recovery_mount_options = OPTIONS.source_info_dict.get( "recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - if not OPTIONS.oem_no_mount: - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines( - open(OPTIONS.oem_source).readlines()) + source_oem_props = OPTIONS.source_info_dict.get("oem_fingerprint_properties") + target_oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties") + oem_dicts = None + if source_oem_props or target_oem_props: + oem_dicts = _LoadOemDicts(script, recovery_mount_options) metadata = { - "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, + "pre-device": GetOemProperty("ro.product.device", source_oem_props, + oem_dicts and oem_dicts[0], OPTIONS.source_info_dict), "ota-type": "BLOCK", } @@ -906,9 +919,9 @@ def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip): metadata=metadata, info_dict=OPTIONS.source_info_dict) - source_fp = CalculateFingerprint(oem_props, oem_dict, + source_fp = CalculateFingerprint(source_oem_props, oem_dicts and oem_dicts[0], OPTIONS.source_info_dict) - target_fp = CalculateFingerprint(oem_props, oem_dict, + target_fp = CalculateFingerprint(target_oem_props, oem_dicts and oem_dicts[0], OPTIONS.target_info_dict) metadata["pre-build"] = source_fp metadata["post-build"] = target_fp @@ -973,7 +986,7 @@ def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip): else: vendor_diff = None - AppendAssertions(script, OPTIONS.target_info_dict, oem_dict) + AppendAssertions(script, OPTIONS.target_info_dict, oem_dicts) device_specific.IncrementalOTA_Assertions() # Two-step incremental package strategy (in chronological order, @@ -1024,32 +1037,39 @@ else if get_stage("%(bcb_dev)s") != "3/3" then script.Comment("Stage 1/3") # Dump fingerprints - script.Print("Source: %s" % CalculateFingerprint( - oem_props, oem_dict, OPTIONS.source_info_dict)) - script.Print("Target: %s" % CalculateFingerprint( - oem_props, oem_dict, OPTIONS.target_info_dict)) + script.Print("Source: %s" % (source_fp,)) + script.Print("Target: %s" % (target_fp,)) script.Print("Verifying current system...") device_specific.IncrementalOTA_VerifyBegin() - 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: + # 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: + if source_oem_props is None: script.AssertSomeFingerprint(source_fp) else: - script.AssertSomeFingerprint(source_fp, target_fp) - else: - if blockimgdiff_version <= 2: script.AssertSomeThumbprint( GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) - else: + + else: # blockimgdiff_version > 2 + if source_oem_props is None and target_oem_props is None: + script.AssertSomeFingerprint(source_fp, target_fp) + elif source_oem_props is not None and target_oem_props is not None: script.AssertSomeThumbprint( GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict), GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) + elif source_oem_props is None and target_oem_props is not None: + script.AssertFingerprintOrThumbprint( + source_fp, + GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict)) + else: + script.AssertFingerprintOrThumbprint( + target_fp, + GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) # Check the required cache size (i.e. stashed blocks). size = [] @@ -1176,18 +1196,16 @@ def WriteVerifyPackage(input_zip, output_zip): oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") recovery_mount_options = OPTIONS.info_dict.get( "recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines( - open(OPTIONS.oem_source).readlines()) + oem_dicts = None + if oem_props: + oem_dicts = _LoadOemDicts(script, recovery_mount_options) - target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.info_dict) + target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0], + OPTIONS.info_dict) metadata = { "post-build": target_fp, - "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, + "pre-device": GetOemProperty("ro.product.device", oem_props, + oem_dicts and oem_dicts[0], OPTIONS.info_dict), "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict), } @@ -1201,7 +1219,7 @@ def WriteVerifyPackage(input_zip, output_zip): metadata=metadata, info_dict=OPTIONS.info_dict) - AppendAssertions(script, OPTIONS.info_dict, oem_dict) + AppendAssertions(script, OPTIONS.info_dict, oem_dicts) script.Print("Verifying device images against %s..." % target_fp) script.AppendExtra("") @@ -1273,26 +1291,25 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file, # Metadata to comply with Android OTA package format. oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties", None) - oem_dict = None + oem_dicts = None if oem_props: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - oem_dict = common.LoadDictionaryFromLines( - open(OPTIONS.oem_source).readlines()) + oem_dicts = _LoadOemDicts(None) metadata = { - "post-build": CalculateFingerprint(oem_props, oem_dict, + "post-build": CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0], OPTIONS.info_dict), "post-build-incremental" : GetBuildProp("ro.build.version.incremental", OPTIONS.info_dict), - "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, + "pre-device": GetOemProperty("ro.product.device", oem_props, + oem_dicts and oem_dicts[0], OPTIONS.info_dict), "ota-required-cache": "0", "ota-type": "AB", } if source_file is not None: - metadata["pre-build"] = CalculateFingerprint(oem_props, oem_dict, + metadata["pre-build"] = CalculateFingerprint(oem_props, + oem_dicts and oem_dicts[0], OPTIONS.source_info_dict) metadata["pre-build-incremental"] = GetBuildProp( "ro.build.version.incremental", OPTIONS.source_info_dict) @@ -1562,20 +1579,17 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): source_version, OPTIONS.target_info_dict, fstab=OPTIONS.source_info_dict["fstab"]) - oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") recovery_mount_options = OPTIONS.source_info_dict.get( "recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - if not OPTIONS.oem_no_mount: - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines( - open(OPTIONS.oem_source).readlines()) + source_oem_props = OPTIONS.source_info_dict.get("oem_fingerprint_properties") + target_oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties") + oem_dicts = None + if source_oem_props or target_oem_props: + oem_dicts = _LoadOemDicts(script, recovery_mount_options) metadata = { - "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, + "pre-device": GetOemProperty("ro.product.device", source_oem_props, + oem_dicts and oem_dicts[0], OPTIONS.source_info_dict), "ota-type": "FILE", } @@ -1600,17 +1614,25 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): else: vendor_diff = None - target_fp = CalculateFingerprint(oem_props, oem_dict, + target_fp = CalculateFingerprint(target_oem_props, oem_dicts and oem_dicts[0], OPTIONS.target_info_dict) - source_fp = CalculateFingerprint(oem_props, oem_dict, + source_fp = CalculateFingerprint(source_oem_props, oem_dicts and oem_dicts[0], OPTIONS.source_info_dict) - if oem_props is None: + if source_oem_props is None and target_oem_props is None: script.AssertSomeFingerprint(source_fp, target_fp) - else: + elif source_oem_props is not None and target_oem_props is not None: script.AssertSomeThumbprint( GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict), GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) + elif source_oem_props is None and target_oem_props is not None: + script.AssertFingerprintOrThumbprint( + source_fp, + GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict)) + else: + script.AssertFingerprintOrThumbprint( + target_fp, + GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) metadata["pre-build"] = source_fp metadata["post-build"] = target_fp @@ -1640,7 +1662,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): # 0.1 for unpacking verbatim files, symlinking, and doing the # device-specific commands. - AppendAssertions(script, OPTIONS.target_info_dict, oem_dict) + AppendAssertions(script, OPTIONS.target_info_dict, oem_dicts) device_specific.IncrementalOTA_Assertions() # Two-step incremental package strategy (in chronological order, @@ -1980,7 +2002,7 @@ def main(argv): elif o == "--override_timestamp": OPTIONS.timestamp = True elif o in ("-o", "--oem_settings"): - OPTIONS.oem_source = a + OPTIONS.oem_source = a.split(',') elif o == "--oem_no_mount": OPTIONS.oem_no_mount = True elif o in ("-e", "--extra_script"): diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py index 1677a44a7f..52b526cd9a 100755 --- a/tools/releasetools/sign_target_files_apks.py +++ b/tools/releasetools/sign_target_files_apks.py @@ -713,7 +713,9 @@ def main(argv): common.ZipClose(input_zip) common.ZipClose(output_zip) - add_img_to_target_files.AddImagesToTargetFiles(args[1]) + # Skip building userdata.img and cache.img when signing the target files. + new_args = ["--is_signing", args[1]] + add_img_to_target_files.main(new_args) print "done." |