Merge "Remove emulator dependencies on non emulator targets (1)"
diff --git a/core/main.mk b/core/main.mk
index 9ddd990..a738dd9 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -2194,6 +2194,7 @@
rm -rf $@
$(GEN_SBOM) --output_file $@ --metadata $(PRODUCT_OUT)/sbom-metadata.csv --product_out_dir=$(PRODUCT_OUT) --build_version $(BUILD_FINGERPRINT_FROM_FILE) --product_mfr="$(PRODUCT_MANUFACTURER)" --json
+$(call dist-for-goals,droid,$(PRODUCT_OUT)/sbom.spdx.json)
else
apps_only_sbom_files := $(sort $(patsubst %,%.spdx,$(apps_only_installed_files)))
$(apps_only_sbom_files): $(PRODUCT_OUT)/sbom-metadata.csv $(GEN_SBOM)
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index 95b3d37..b160648 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -104,7 +104,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 := 2023-03-05
+ PLATFORM_SECURITY_PATCH := 2023-04-05
endif
include $(BUILD_SYSTEM)/version_util.mk
diff --git a/tools/finalization/build-step-1-and-2.sh b/tools/finalization/build-step-1-and-2.sh
index a5aba08..84e2782 100755
--- a/tools/finalization/build-step-1-and-2.sh
+++ b/tools/finalization/build-step-1-and-2.sh
@@ -6,14 +6,18 @@
local top="$(dirname "$0")"/../../../..
source $top/build/make/tools/finalization/environment.sh
- # SDK codename -> int
- source $top/build/make/tools/finalization/finalize-aidl-vndk-sdk-resources.sh
+ if [ "$FINAL_STATE" = "unfinalized" ] ; then
+ # SDK codename -> int
+ source $top/build/make/tools/finalization/finalize-aidl-vndk-sdk-resources.sh
+ fi;
- # ADB, Platform/Mainline SDKs build and move to prebuilts
- source $top/build/make/tools/finalization/localonly-steps.sh
+ if [ "$FINAL_STATE" = "unfinalized" ] || [ "$FINAL_STATE" = "sdk" ] ; then
+ # ADB, Platform/Mainline SDKs build and move to prebuilts
+ source $top/build/make/tools/finalization/localonly-steps.sh
- # REL
- source $top/build/make/tools/finalization/finalize-sdk-rel.sh
+ # REL
+ source $top/build/make/tools/finalization/finalize-sdk-rel.sh
+ fi;
}
finalize_main_step12
diff --git a/tools/finalization/build-step-1.sh b/tools/finalization/build-step-1.sh
index a8d590f..3c618fe 100755
--- a/tools/finalization/build-step-1.sh
+++ b/tools/finalization/build-step-1.sh
@@ -6,8 +6,11 @@
local top="$(dirname "$0")"/../../../..
source $top/build/make/tools/finalization/environment.sh
- # Build finalization artifacts.
- source $top/build/make/tools/finalization/finalize-aidl-vndk-sdk-resources.sh
+ if [ "$FINAL_STATE" = "unfinalized" ] ; then
+ # Build finalization artifacts.
+ # source $top/build/make/tools/finalization/finalize-aidl-vndk-sdk-resources.sh
+ echo "Build finalization artifacts."
+ fi;
}
finalize_main_step1
diff --git a/tools/finalization/environment.sh b/tools/finalization/environment.sh
index 14951b8..8c838aa 100755
--- a/tools/finalization/environment.sh
+++ b/tools/finalization/environment.sh
@@ -12,4 +12,10 @@
export FINAL_BUILD_PREFIX='UP1A'
-export FINAL_MAINLINE_EXTENSION='7'
\ No newline at end of file
+export FINAL_MAINLINE_EXTENSION='7'
+
+# Options:
+# 'unfinalized' - branch is in development state,
+# 'sdk' - SDK/API is finalized
+# 'rel' - branch is finalized, switched to REL
+export FINAL_STATE='unfinalized'
diff --git a/tools/finalization/step-1.sh b/tools/finalization/step-1.sh
index cf21e45..0dd4b3a 100755
--- a/tools/finalization/step-1.sh
+++ b/tools/finalization/step-1.sh
@@ -9,7 +9,7 @@
if [[ $(git status --short) ]]; then
repo start "$FINAL_PLATFORM_CODENAME-SDK-Finalization" ;
git add -A . ;
- git commit -m "$FINAL_PLATFORM_CODENAME is now $FINAL_PLATFORM_SDK_VERSION" \
+ git commit -m "$FINAL_PLATFORM_CODENAME is now $FINAL_PLATFORM_SDK_VERSION and extension version $FINAL_MAINLINE_EXTENSION" \
-m "Ignore-AOSP-First: $FINAL_PLATFORM_CODENAME Finalization
Bug: $FINAL_BUG_ID
Test: build";
diff --git a/tools/finalization/update-step-1.sh b/tools/finalization/update-step-1.sh
old mode 100644
new mode 100755
index fd07b7b..b469988
--- a/tools/finalization/update-step-1.sh
+++ b/tools/finalization/update-step-1.sh
@@ -1,6 +1,9 @@
#!/bin/bash
# Script to perform a 1st step of Android Finalization: API/SDK finalization, update CLs and upload to Gerrit.
+# WIP, does not work yet
+exit 10
+
set -ex
function update_step_1_changes() {
diff --git a/tools/finalization/update-step-2.sh b/tools/finalization/update-step-2.sh
index e65d35a..d2b8592 100755
--- a/tools/finalization/update-step-2.sh
+++ b/tools/finalization/update-step-2.sh
@@ -1,6 +1,11 @@
#!/bin/bash
# Script to perform a 2nd step of Android Finalization: REL finalization, create CLs and upload to Gerrit.
+# WIP, does not work yet
+exit 10
+
+set -ex
+
function update_step_2_changes() {
set +e
repo forall -c '\
diff --git a/tools/generate-sbom.py b/tools/generate-sbom.py
index eae7945..9583395 100755
--- a/tools/generate-sbom.py
+++ b/tools/generate-sbom.py
@@ -87,6 +87,7 @@
ISSUE_NO_METADATA_FILE = 'No METADATA file found for installed file:'
ISSUE_METADATA_FILE_INCOMPLETE = 'METADATA file incomplete:'
ISSUE_UNKNOWN_SECURITY_TAG_TYPE = 'Unknown security tag type:'
+ISSUE_INSTALLED_FILE_NOT_EXIST = 'Non-exist installed files:'
INFO_METADATA_FOUND_FOR_PACKAGE = 'METADATA file found for packages:'
@@ -597,11 +598,12 @@
# Report on some issues and information
report = {
- ISSUE_NO_METADATA: [],
- ISSUE_NO_METADATA_FILE: [],
- ISSUE_METADATA_FILE_INCOMPLETE: [],
- ISSUE_UNKNOWN_SECURITY_TAG_TYPE: [],
- INFO_METADATA_FOUND_FOR_PACKAGE: []
+ ISSUE_NO_METADATA: [],
+ ISSUE_NO_METADATA_FILE: [],
+ ISSUE_METADATA_FILE_INCOMPLETE: [],
+ ISSUE_UNKNOWN_SECURITY_TAG_TYPE: [],
+ ISSUE_INSTALLED_FILE_NOT_EXIST: [],
+ INFO_METADATA_FOUND_FOR_PACKAGE: [],
}
# Scan the metadata in CSV file and create the corresponding package and file records in SPDX
@@ -619,6 +621,10 @@
if not installed_file_has_metadata(installed_file_metadata, report):
continue
+ file_path = args.product_out_dir + '/' + installed_file
+ if not (os.path.islink(file_path) or os.path.isfile(file_path)):
+ report[ISSUE_INSTALLED_FILE_NOT_EXIST].append(installed_file)
+ continue
file_id = new_file_id(installed_file)
product_files.append(new_file_record(file_id, installed_file, checksum(installed_file)))
diff --git a/tools/post_process_props.py b/tools/post_process_props.py
index 38d17a8..31a460d 100755
--- a/tools/post_process_props.py
+++ b/tools/post_process_props.py
@@ -43,7 +43,7 @@
"""Validate GRF properties if exist.
If ro.board.first_api_level is defined, check if its value is valid for the
- sdk version.
+ sdk version. This is only for the release version.
Also, validate the value of ro.board.api_level if defined.
Returns:
@@ -51,6 +51,7 @@
"""
grf_api_level = prop_list.get_value("ro.board.first_api_level")
board_api_level = prop_list.get_value("ro.board.api_level")
+ platform_version_codename = prop_list.get_value("ro.build.version.codename")
if not grf_api_level:
if board_api_level:
@@ -61,6 +62,18 @@
return True
grf_api_level = int(grf_api_level)
+ if board_api_level:
+ board_api_level = int(board_api_level)
+ if board_api_level < grf_api_level:
+ sys.stderr.write("error: ro.board.api_level(%d) must be greater than "
+ "ro.board.first_api_level(%d)\n"
+ % (board_api_level, grf_api_level))
+ return False
+
+ # skip sdk version validation for dev-stage non-REL devices
+ if platform_version_codename != "REL":
+ return True
+
if grf_api_level > sdk_version:
sys.stderr.write("error: ro.board.first_api_level(%d) must be less than "
"or equal to ro.build.version.sdk(%d)\n"
@@ -68,12 +81,10 @@
return False
if board_api_level:
- board_api_level = int(board_api_level)
- if board_api_level < grf_api_level or board_api_level > sdk_version:
- sys.stderr.write("error: ro.board.api_level(%d) must be neither less "
- "than ro.board.first_api_level(%d) nor greater than "
- "ro.build.version.sdk(%d)\n"
- % (board_api_level, grf_api_level, sdk_version))
+ if board_api_level > sdk_version:
+ sys.stderr.write("error: ro.board.api_level(%d) must be less than or "
+ "equal to ro.build.version.sdk(%d)\n"
+ % (board_api_level, sdk_version))
return False
return True
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 9bbdc51..3904a78 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -4001,3 +4001,26 @@
# Magic for android sparse image format
# https://source.android.com/devices/bootloader/images
return fp.read(4) == b'\x3A\xFF\x26\xED'
+
+def ParseUpdateEngineConfig(path: str):
+ """Parse the update_engine config stored in file `path`
+ Args
+ path: Path to update_engine_config.txt file in target_files
+
+ Returns
+ A tuple of (major, minor) version number . E.g. (2, 8)
+ """
+ with open(path, "r") as fp:
+ # update_engine_config.txt is only supposed to contain two lines,
+ # PAYLOAD_MAJOR_VERSION and PAYLOAD_MINOR_VERSION. 1024 should be more than
+ # sufficient. If the length is more than that, something is wrong.
+ data = fp.read(1024)
+ major = re.search(r"PAYLOAD_MAJOR_VERSION=(\d+)", data)
+ if not major:
+ raise ValueError(
+ f"{path} is an invalid update_engine config, missing PAYLOAD_MAJOR_VERSION {data}")
+ minor = re.search(r"PAYLOAD_MINOR_VERSION=(\d+)", data)
+ if not minor:
+ raise ValueError(
+ f"{path} is an invalid update_engine config, missing PAYLOAD_MINOR_VERSION {data}")
+ return (int(major.group(1)), int(minor.group(1)))
\ No newline at end of file
diff --git a/tools/releasetools/merge/merge_meta.py b/tools/releasetools/merge/merge_meta.py
index 3288ef7..b61f039 100644
--- a/tools/releasetools/merge/merge_meta.py
+++ b/tools/releasetools/merge/merge_meta.py
@@ -29,6 +29,7 @@
import merge_utils
import sparse_img
import verity_utils
+from ota_utils import ParseUpdateEngineConfig
from common import ExternalError
@@ -52,28 +53,6 @@
MODULE_KEY_PATTERN = re.compile(r'name="(.+)\.(apex|apk)"')
-def ParseUpdateEngineConfig(path: str):
- """Parse the update_engine config stored in file `path`
- Args
- path: Path to update_engine_config.txt file in target_files
-
- Returns
- A tuple of (major, minor) version number . E.g. (2, 8)
- """
- with open(path, "r") as fp:
- # update_engine_config.txt is only supposed to contain two lines,
- # PAYLOAD_MAJOR_VERSION and PAYLOAD_MINOR_VERSION. 1024 should be more than
- # sufficient. If the length is more than that, something is wrong.
- data = fp.read(1024)
- major = re.search(r"PAYLOAD_MAJOR_VERSION=(\d+)", data)
- if not major:
- raise ValueError(
- f"{path} is an invalid update_engine config, missing PAYLOAD_MAJOR_VERSION {data}")
- minor = re.search(r"PAYLOAD_MINOR_VERSION=(\d+)", data)
- if not minor:
- raise ValueError(
- f"{path} is an invalid update_engine config, missing PAYLOAD_MINOR_VERSION {data}")
- return (int(major.group(1)), int(minor.group(1)))
def MergeUpdateEngineConfig(input_metadir1, input_metadir2, merged_meta_dir):
@@ -99,16 +78,16 @@
"""Merges various files in META/*."""
framework_meta_dir = os.path.join(temp_dir, 'framework_meta', 'META')
- merge_utils.ExtractItems(
- input_zip=OPTIONS.framework_target_files,
+ merge_utils.CollectTargetFiles(
+ input_zipfile_or_dir=OPTIONS.framework_target_files,
output_dir=os.path.dirname(framework_meta_dir),
- extract_item_list=('META/*',))
+ item_list=('META/*',))
vendor_meta_dir = os.path.join(temp_dir, 'vendor_meta', 'META')
- merge_utils.ExtractItems(
- input_zip=OPTIONS.vendor_target_files,
+ merge_utils.CollectTargetFiles(
+ input_zipfile_or_dir=OPTIONS.vendor_target_files,
output_dir=os.path.dirname(vendor_meta_dir),
- extract_item_list=('META/*',))
+ item_list=('META/*',))
merged_meta_dir = os.path.join(merged_dir, 'META')
diff --git a/tools/releasetools/merge/merge_target_files.py b/tools/releasetools/merge/merge_target_files.py
index 54122b0..8f93688 100755
--- a/tools/releasetools/merge/merge_target_files.py
+++ b/tools/releasetools/merge/merge_target_files.py
@@ -26,9 +26,9 @@
Usage: merge_target_files [args]
- --framework-target-files framework-target-files-zip-archive
+ --framework-target-files framework-target-files-package
The input target files package containing framework bits. This is a zip
- archive.
+ archive or a directory.
--framework-item-list framework-item-list-file
The optional path to a newline-separated config file of items that
@@ -38,9 +38,9 @@
The optional path to a newline-separated config file of keys to
extract from the framework META/misc_info.txt file.
- --vendor-target-files vendor-target-files-zip-archive
+ --vendor-target-files vendor-target-files-package
The input target files package containing vendor bits. This is a zip
- archive.
+ archive or a directory.
--vendor-item-list vendor-item-list-file
The optional path to a newline-separated config file of items that
@@ -172,18 +172,18 @@
Path to merged package under temp directory.
"""
# Extract "as is" items from the input framework and vendor partial target
- # files packages directly into the output temporary directory, since these items
- # do not need special case processing.
+ # files packages directly into the output temporary directory, since these
+ # items do not need special case processing.
output_target_files_temp_dir = os.path.join(temp_dir, 'output')
- merge_utils.ExtractItems(
- input_zip=OPTIONS.framework_target_files,
+ merge_utils.CollectTargetFiles(
+ input_zipfile_or_dir=OPTIONS.framework_target_files,
output_dir=output_target_files_temp_dir,
- extract_item_list=OPTIONS.framework_item_list)
- merge_utils.ExtractItems(
- input_zip=OPTIONS.vendor_target_files,
+ item_list=OPTIONS.framework_item_list)
+ merge_utils.CollectTargetFiles(
+ input_zipfile_or_dir=OPTIONS.vendor_target_files,
output_dir=output_target_files_temp_dir,
- extract_item_list=OPTIONS.vendor_item_list)
+ item_list=OPTIONS.vendor_item_list)
# Perform special case processing on META/* items.
# After this function completes successfully, all the files we need to create
@@ -231,7 +231,8 @@
def copy_selinux_file(input_path, output_filename):
input_filename = os.path.join(target_files_dir, input_path)
if not os.path.exists(input_filename):
- input_filename = input_filename.replace('SYSTEM_EXT/', 'SYSTEM/system_ext/') \
+ input_filename = input_filename.replace('SYSTEM_EXT/',
+ 'SYSTEM/system_ext/') \
.replace('PRODUCT/', 'SYSTEM/product/')
if not os.path.exists(input_filename):
logger.info('Skipping copy_selinux_file for %s', input_filename)
@@ -272,7 +273,10 @@
vendor_target_files_dir = common.MakeTempDir(
prefix='merge_target_files_vendor_target_files_')
common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
- common.UnzipToDir(OPTIONS.vendor_target_files, vendor_target_files_dir)
+ merge_utils.CollectTargetFiles(
+ input_zipfile_or_dir=OPTIONS.vendor_target_files,
+ output_dir=vendor_target_files_dir,
+ item_list=OPTIONS.vendor_item_list)
# Copy the partition contents from the merged target-files archive to the
# vendor target-files archive.
@@ -303,8 +307,9 @@
shutil.move(
os.path.join(vendor_target_files_dir, 'IMAGES', partition_img),
os.path.join(target_files_dir, 'IMAGES', partition_img))
- move_only_exists(os.path.join(vendor_target_files_dir, 'IMAGES', partition_map),
- os.path.join(target_files_dir, 'IMAGES', partition_map))
+ move_only_exists(
+ os.path.join(vendor_target_files_dir, 'IMAGES', partition_map),
+ os.path.join(target_files_dir, 'IMAGES', partition_map))
def copy_recovery_file(filename):
for subdir in ('VENDOR', 'SYSTEM/vendor'):
@@ -578,10 +583,10 @@
common.Usage(__doc__)
sys.exit(1)
- with zipfile.ZipFile(OPTIONS.framework_target_files, allowZip64=True) as fz:
- framework_namelist = fz.namelist()
- with zipfile.ZipFile(OPTIONS.vendor_target_files, allowZip64=True) as vz:
- vendor_namelist = vz.namelist()
+ framework_namelist = merge_utils.GetTargetFilesItems(
+ OPTIONS.framework_target_files)
+ vendor_namelist = merge_utils.GetTargetFilesItems(
+ OPTIONS.vendor_target_files)
if OPTIONS.framework_item_list:
OPTIONS.framework_item_list = common.LoadListFromFile(
diff --git a/tools/releasetools/merge/merge_utils.py b/tools/releasetools/merge/merge_utils.py
index e056195..c284338 100644
--- a/tools/releasetools/merge/merge_utils.py
+++ b/tools/releasetools/merge/merge_utils.py
@@ -49,28 +49,80 @@
common.UnzipToDir(input_zip, output_dir, filtered_extract_item_list)
-def CopyItems(from_dir, to_dir, patterns):
- """Similar to ExtractItems() except uses an input dir instead of zip."""
- file_paths = []
- for dirpath, _, filenames in os.walk(from_dir):
- file_paths.extend(
- os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
- for filename in filenames)
+def CopyItems(from_dir, to_dir, copy_item_list):
+ """Copies the items in copy_item_list from source to destination directory.
- filtered_file_paths = set()
- for pattern in patterns:
- filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
+ copy_item_list may include files and directories. Will copy the matched
+ files and create the matched directories.
- for file_path in filtered_file_paths:
- original_file_path = os.path.join(from_dir, file_path)
- copied_file_path = os.path.join(to_dir, file_path)
- copied_file_dir = os.path.dirname(copied_file_path)
- if not os.path.exists(copied_file_dir):
- os.makedirs(copied_file_dir)
- if os.path.islink(original_file_path):
- os.symlink(os.readlink(original_file_path), copied_file_path)
+ Args:
+ from_dir: The source directory.
+ to_dir: The destination directory.
+ copy_item_list: Items to be copied.
+ """
+ item_paths = []
+ for root, dirs, files in os.walk(from_dir):
+ item_paths.extend(
+ os.path.relpath(path=os.path.join(root, item_name), start=from_dir)
+ for item_name in files + dirs)
+
+ filtered = set()
+ for pattern in copy_item_list:
+ filtered.update(fnmatch.filter(item_paths, pattern))
+
+ for item in filtered:
+ original_path = os.path.join(from_dir, item)
+ copied_path = os.path.join(to_dir, item)
+ copied_parent_path = os.path.dirname(copied_path)
+ if not os.path.exists(copied_parent_path):
+ os.makedirs(copied_parent_path)
+ if os.path.islink(original_path):
+ os.symlink(os.readlink(original_path), copied_path)
+ elif os.path.isdir(original_path):
+ if not os.path.exists(copied_path):
+ os.makedirs(copied_path)
else:
- shutil.copyfile(original_file_path, copied_file_path)
+ shutil.copyfile(original_path, copied_path)
+
+
+def GetTargetFilesItems(target_files_zipfile_or_dir):
+ """Gets a list of target files items."""
+ if zipfile.is_zipfile(target_files_zipfile_or_dir):
+ with zipfile.ZipFile(target_files_zipfile_or_dir, allowZip64=True) as fz:
+ return fz.namelist()
+ elif os.path.isdir(target_files_zipfile_or_dir):
+ item_list = []
+ for root, dirs, files in os.walk(target_files_zipfile_or_dir):
+ item_list.extend(
+ os.path.relpath(path=os.path.join(root, item),
+ start=target_files_zipfile_or_dir)
+ for item in dirs + files)
+ return item_list
+ else:
+ raise ValueError('Target files should be either zipfile or directory.')
+
+
+def CollectTargetFiles(input_zipfile_or_dir, output_dir, item_list=None):
+ """Extracts input zipfile or copy input directory to output directory.
+
+ Extracts the input zipfile if `input_zipfile_or_dir` is a zip archive, or
+ copies the items if `input_zipfile_or_dir` is a directory.
+
+ Args:
+ input_zipfile_or_dir: The input target files, could be either a zipfile to
+ extract or a directory to copy.
+ output_dir: The output directory that the input files are either extracted
+ or copied.
+ item_list: Files to be extracted or copied. Will extract or copy all files
+ if omitted.
+ """
+ patterns = item_list if item_list else ('*',)
+ if zipfile.is_zipfile(input_zipfile_or_dir):
+ ExtractItems(input_zipfile_or_dir, output_dir, patterns)
+ elif os.path.isdir(input_zipfile_or_dir):
+ CopyItems(input_zipfile_or_dir, output_dir, patterns)
+ else:
+ raise ValueError('Target files should be either zipfile or directory.')
def WriteSortedData(data, path):
diff --git a/tools/releasetools/merge/test_merge_utils.py b/tools/releasetools/merge/test_merge_utils.py
index 1ae1f54..b4c47ae 100644
--- a/tools/releasetools/merge/test_merge_utils.py
+++ b/tools/releasetools/merge/test_merge_utils.py
@@ -35,22 +35,27 @@
open(path, 'a').close()
return path
+ def createEmptyFolder(path):
+ os.makedirs(path)
+ return path
+
def createSymLink(source, dest):
os.symlink(source, dest)
return dest
def getRelPaths(start, filepaths):
return set(
- os.path.relpath(path=filepath, start=start) for filepath in filepaths)
+ os.path.relpath(path=filepath, start=start)
+ for filepath in filepaths)
input_dir = common.MakeTempDir()
output_dir = common.MakeTempDir()
expected_copied_items = []
actual_copied_items = []
- patterns = ['*.cpp', 'subdir/*.txt']
+ patterns = ['*.cpp', 'subdir/*.txt', 'subdir/empty_dir']
- # Create various files that we expect to get copied because they
- # match one of the patterns.
+ # Create various files and empty directories that we expect to get copied
+ # because they match one of the patterns.
expected_copied_items.extend([
createEmptyFile(os.path.join(input_dir, 'a.cpp')),
createEmptyFile(os.path.join(input_dir, 'b.cpp')),
@@ -58,6 +63,7 @@
createEmptyFile(os.path.join(input_dir, 'subdir', 'd.txt')),
createEmptyFile(
os.path.join(input_dir, 'subdir', 'subsubdir', 'e.txt')),
+ createEmptyFolder(os.path.join(input_dir, 'subdir', 'empty_dir')),
createSymLink('a.cpp', os.path.join(input_dir, 'a_link.cpp')),
])
# Create some more files that we expect to not get copied.
@@ -70,9 +76,13 @@
merge_utils.CopyItems(input_dir, output_dir, patterns)
# Assert the actual copied items match the ones we expected.
- for dirpath, _, filenames in os.walk(output_dir):
+ for root_dir, dirs, files in os.walk(output_dir):
actual_copied_items.extend(
- os.path.join(dirpath, filename) for filename in filenames)
+ os.path.join(root_dir, filename) for filename in files)
+ for dirname in dirs:
+ dir_path = os.path.join(root_dir, dirname)
+ if not os.listdir(dir_path):
+ actual_copied_items.append(dir_path)
self.assertEqual(
getRelPaths(output_dir, actual_copied_items),
getRelPaths(input_dir, expected_copied_items))
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 39e380e..2458244 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -906,7 +906,8 @@
OPTIONS.enable_vabc_xor = False
if OPTIONS.vabc_compression_param == "none":
- logger.info("VABC Compression algorithm is set to 'none', disabling VABC xor")
+ logger.info(
+ "VABC Compression algorithm is set to 'none', disabling VABC xor")
OPTIONS.enable_vabc_xor = False
additional_args = []
@@ -922,7 +923,6 @@
elif OPTIONS.partial:
target_file = GetTargetFilesZipForPartialUpdates(target_file,
OPTIONS.partial)
- additional_args += ["--is_partial_update", "true"]
elif OPTIONS.vabc_compression_param:
target_file = GetTargetFilesZipForCustomVABCCompression(
target_file, OPTIONS.vabc_compression_param)
@@ -938,7 +938,8 @@
# Metadata to comply with Android OTA package format.
metadata = GetPackageMetadata(target_info, source_info)
# Generate payload.
- payload = PayloadGenerator(wipe_user_data=OPTIONS.wipe_user_data)
+ payload = PayloadGenerator(
+ wipe_user_data=OPTIONS.wipe_user_data, minor_version=OPTIONS.force_minor_version, is_partial_update=OPTIONS.partial)
partition_timestamps_flags = []
# Enforce a max timestamp this payload can be applied on top of.
@@ -965,7 +966,7 @@
additional_args += ["--security_patch_level", security_patch_level]
- additional_args += ["--enable_zucchini",
+ additional_args += ["--enable_zucchini=" +
str(OPTIONS.enable_zucchini).lower()]
if not ota_utils.IsLz4diffCompatible(source_file, target_file):
@@ -973,7 +974,7 @@
"Source build doesn't support lz4diff, or source/target don't have compatible lz4diff versions. Disabling lz4diff.")
OPTIONS.enable_lz4diff = False
- additional_args += ["--enable_lz4diff",
+ additional_args += ["--enable_lz4diff=" +
str(OPTIONS.enable_lz4diff).lower()]
if source_file and OPTIONS.enable_lz4diff:
@@ -989,20 +990,13 @@
additional_args += ["--erofs_compression_param", erofs_compression_param]
if OPTIONS.disable_vabc:
- additional_args += ["--disable_vabc", "true"]
+ additional_args += ["--disable_vabc=true"]
if OPTIONS.enable_vabc_xor:
- additional_args += ["--enable_vabc_xor", "true"]
- if OPTIONS.force_minor_version:
- additional_args += ["--force_minor_version", OPTIONS.force_minor_version]
+ additional_args += ["--enable_vabc_xor=true"]
if OPTIONS.compressor_types:
additional_args += ["--compressor_types", OPTIONS.compressor_types]
additional_args += ["--max_timestamp", max_timestamp]
- if SupportsMainlineGkiUpdates(source_file):
- logger.warning(
- "Detected build with mainline GKI, include full boot image.")
- additional_args.extend(["--full_boot", "true"])
-
payload.Generate(
target_file,
source_file,
@@ -1363,7 +1357,8 @@
"what(even if data wipe is done), so SPL downgrade on any "
"release-keys build is not allowed.".format(target_spl, source_spl))
- logger.info("SPL downgrade on %s", target_build_prop.GetProp("ro.build.tags"))
+ logger.info("SPL downgrade on %s",
+ target_build_prop.GetProp("ro.build.tags"))
if is_spl_downgrade and not OPTIONS.spl_downgrade and not OPTIONS.downgrade:
raise common.ExternalError(
"Target security patch level {} is older than source SPL {} applying "
diff --git a/tools/releasetools/ota_utils.py b/tools/releasetools/ota_utils.py
index e2ce31d..c419537 100644
--- a/tools/releasetools/ota_utils.py
+++ b/tools/releasetools/ota_utils.py
@@ -25,7 +25,7 @@
from common import (ZipDelete, OPTIONS, MakeTempFile,
ZipWriteStr, BuildInfo, LoadDictionaryFromFile,
SignFile, PARTITIONS_WITH_BUILD_PROP, PartitionBuildProps,
- GetRamdiskFormat)
+ GetRamdiskFormat, ParseUpdateEngineConfig)
from payload_signer import PayloadSigner
@@ -135,7 +135,8 @@
logger.info(f"Signing disabled for output file {output_file}")
shutil.copy(prelim_signing, output_file)
else:
- logger.info(f"Signing the output file {output_file} with key {package_key}")
+ logger.info(
+ f"Signing the output file {output_file} with key {package_key}")
SignOutput(prelim_signing, output_file, package_key, pw)
# Reopen the final signed zip to double check the streaming metadata.
@@ -721,6 +722,45 @@
return sourceEntry and targetEntry and sourceEntry == targetEntry
+def ExtractTargetFiles(path: str):
+ if os.path.isdir(path):
+ logger.info("target files %s is already extracted", path)
+ return path
+ extracted_dir = common.MakeTempDir("target_files")
+ common.UnzipToDir(path, extracted_dir, UNZIP_PATTERN)
+ return extracted_dir
+
+
+def LocatePartitionPath(target_files_dir: str, partition: str, allow_empty):
+ path = os.path.join(target_files_dir, "RADIO", partition + ".img")
+ if os.path.exists(path):
+ return path
+ path = os.path.join(target_files_dir, "IMAGES", partition + ".img")
+ if os.path.exists(path):
+ return path
+ if allow_empty:
+ return ""
+ raise common.ExternalError(
+ "Partition {} not found in target files {}".format(partition, target_files_dir))
+
+
+def GetPartitionImages(target_files_dir: str, ab_partitions, allow_empty=True):
+ assert os.path.isdir(target_files_dir)
+ return ":".join([LocatePartitionPath(target_files_dir, partition, allow_empty) for partition in ab_partitions])
+
+
+def LocatePartitionMap(target_files_dir: str, partition: str):
+ path = os.path.join(target_files_dir, "RADIO", partition + ".map")
+ if os.path.exists(path):
+ return path
+ return ""
+
+
+def GetPartitionMaps(target_files_dir: str, ab_partitions):
+ assert os.path.isdir(target_files_dir)
+ return ":".join([LocatePartitionMap(target_files_dir, partition) for partition in ab_partitions])
+
+
class PayloadGenerator(object):
"""Manages the creation and the signing of an A/B OTA Payload."""
@@ -729,7 +769,7 @@
SECONDARY_PAYLOAD_BIN = 'secondary/payload.bin'
SECONDARY_PAYLOAD_PROPERTIES_TXT = 'secondary/payload_properties.txt'
- def __init__(self, secondary=False, wipe_user_data=False):
+ def __init__(self, secondary=False, wipe_user_data=False, minor_version=None, is_partial_update=False):
"""Initializes a Payload instance.
Args:
@@ -739,6 +779,8 @@
self.payload_properties = None
self.secondary = secondary
self.wipe_user_data = wipe_user_data
+ self.minor_version = minor_version
+ self.is_partial_update = is_partial_update
def _Run(self, cmd): # pylint: disable=no-self-use
# Don't pipe (buffer) the output if verbose is set. Let
@@ -757,21 +799,53 @@
source_file: The filename of the source build target-files zip; or None if
generating a full OTA.
additional_args: A list of additional args that should be passed to
- brillo_update_payload script; or None.
+ delta_generator binary; or None.
"""
if additional_args is None:
additional_args = []
payload_file = common.MakeTempFile(prefix="payload-", suffix=".bin")
- cmd = ["brillo_update_payload", "generate",
- "--payload", payload_file,
- "--target_image", target_file]
+ target_dir = ExtractTargetFiles(target_file)
+ cmd = ["delta_generator",
+ "--out_file", payload_file]
+ with open(os.path.join(target_dir, "META", "ab_partitions.txt")) as fp:
+ ab_partitions = fp.read().strip().split("\n")
+ cmd.extend(["--partition_names", ":".join(ab_partitions)])
+ cmd.extend(
+ ["--new_partitions", GetPartitionImages(target_dir, ab_partitions, False)])
+ cmd.extend(
+ ["--new_mapfiles", GetPartitionMaps(target_dir, ab_partitions)])
if source_file is not None:
- cmd.extend(["--source_image", source_file])
+ source_dir = ExtractTargetFiles(source_file)
+ cmd.extend(
+ ["--old_partitions", GetPartitionImages(source_dir, ab_partitions, True)])
+ cmd.extend(
+ ["--old_mapfiles", GetPartitionMaps(source_dir, ab_partitions)])
+
if OPTIONS.disable_fec_computation:
- cmd.extend(["--disable_fec_computation", "true"])
+ cmd.extend(["--disable_fec_computation=true"])
if OPTIONS.disable_verity_computation:
- cmd.extend(["--disable_verity_computation", "true"])
+ cmd.extend(["--disable_verity_computation=true"])
+ postinstall_config = os.path.join(
+ target_dir, "META", "postinstall_config.txt")
+
+ if os.path.exists(postinstall_config):
+ cmd.extend(["--new_postinstall_config_file", postinstall_config])
+ dynamic_partition_info = os.path.join(
+ target_dir, "META", "dynamic_partitions_info.txt")
+
+ if os.path.exists(dynamic_partition_info):
+ cmd.extend(["--dynamic_partition_info_file", dynamic_partition_info])
+
+ major_version, minor_version = ParseUpdateEngineConfig(
+ os.path.join(target_dir, "META", "update_engine_config.txt"))
+ if self.minor_version:
+ minor_version = self.minor_version
+ cmd.extend(["--major_version", str(major_version)])
+ if source_file is not None or self.is_partial_update:
+ cmd.extend(["--minor_version", str(minor_version)])
+ if self.is_partial_update:
+ cmd.extend(["--is_partial_update=true"])
cmd.extend(additional_args)
self._Run(cmd)
diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py
index 8c9655ad0..0e4626b 100644
--- a/tools/releasetools/test_common.py
+++ b/tools/releasetools/test_common.py
@@ -452,12 +452,14 @@
test_file.write(bytes(data))
test_file.close()
- expected_stat = os.stat(test_file_name)
expected_mode = extra_zipwrite_args.get("perms", 0o644)
expected_compress_type = extra_zipwrite_args.get("compress_type",
zipfile.ZIP_STORED)
- time.sleep(5) # Make sure the atime/mtime will change measurably.
+ # Arbitrary timestamp, just to make sure common.ZipWrite() restores
+ # the timestamp after writing.
+ os.utime(test_file_name, (1234567, 1234567))
+ expected_stat = os.stat(test_file_name)
common.ZipWrite(zip_file, test_file_name, **extra_zipwrite_args)
zip_file.close()
@@ -480,8 +482,6 @@
try:
expected_compress_type = extra_args.get("compress_type",
zipfile.ZIP_STORED)
- time.sleep(5) # Make sure the atime/mtime will change measurably.
-
if not isinstance(zinfo_or_arcname, zipfile.ZipInfo):
arcname = zinfo_or_arcname
expected_mode = extra_args.get("perms", 0o644)
@@ -528,11 +528,13 @@
test_file.write(data)
test_file.close()
+ # Arbitrary timestamp, just to make sure common.ZipWrite() restores
+ # the timestamp after writing.
+ os.utime(test_file_name, (1234567, 1234567))
expected_stat = os.stat(test_file_name)
expected_mode = 0o644
expected_compress_type = extra_args.get("compress_type",
zipfile.ZIP_STORED)
- time.sleep(5) # Make sure the atime/mtime will change measurably.
common.ZipWrite(zip_file, test_file_name, **extra_args)
common.ZipWriteStr(zip_file, arcname_small, small, **extra_args)
diff --git a/tools/test_post_process_props.py b/tools/test_post_process_props.py
index 236f9ed..439fc9f 100644
--- a/tools/test_post_process_props.py
+++ b/tools/test_post_process_props.py
@@ -256,6 +256,7 @@
with contextlib.redirect_stderr(stderr_redirect):
props = PropList("hello")
props.put("ro.board.first_api_level","25")
+ props.put("ro.build.version.codename", "REL")
# ro.board.first_api_level must be less than or equal to the sdk version
self.assertFalse(validate_grf_props(props, 20))
@@ -273,5 +274,10 @@
# ro.board.api_level must be less than or equal to the sdk version
self.assertFalse(validate_grf_props(props, 25))
+ # allow setting future api_level before release
+ props.get_all_props()[-2].make_as_comment()
+ props.put("ro.build.version.codename", "NonRel")
+ self.assertTrue(validate_grf_props(props, 24))
+
if __name__ == '__main__':
unittest.main(verbosity=2)