Support forcefully generating non-AB packages.

Force generate a non-A/B update package when requested.

Bug: 154344887
Test: ota_from_target_files.py --force_non_ab ...
Test: apply it as well

Change-Id: I5e81eb161722e07ef50081b6a16685cbc9963ae2
This commit is contained in:
Yifan Hong 2020-04-17 10:08:10 -07:00
parent 9b36bb4632
commit 7169f754cc
7 changed files with 93 additions and 17 deletions

View File

@ -3349,10 +3349,10 @@ endif
# When building a standalone recovery image for non-A/B devices, recovery image must be self-signed
# to be verified independently, and cannot be chained into vbmeta.img. See the link below for
# details.
ifneq ($(AB_OTA_UPDATER),true)
ifeq ($(TARGET_OTA_ALLOW_NON_AB),true)
ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
$(if $(BOARD_AVB_RECOVERY_KEY_PATH),,\
$(error BOARD_AVB_RECOVERY_KEY_PATH must be defined for non-A/B devices. \
$(error BOARD_AVB_RECOVERY_KEY_PATH must be defined for if non-A/B is supported. \
See https://android.googlesource.com/platform/external/avb/+/master/README.md#booting-into-recovery))
endif
endif
@ -3443,7 +3443,7 @@ $(eval $(_signing_args) := \
# The recovery partition in non-A/B devices should be verified separately. Skip adding the chain
# partition descriptor for recovery partition into vbmeta.img.
$(if $(or $(filter true,$(AB_OTA_UPDATER)),$(filter-out recovery,$(part))),\
$(if $(or $(filter-out true,$(TARGET_OTA_ALLOW_NON_AB)),$(filter-out recovery,$(part))),\
$(eval INTERNAL_AVB_MAKE_VBMETA_IMAGE_ARGS += \
--chain_partition $(part):$($(_rollback_index_location)):$(AVB_CHAIN_KEY_DIR)/$(part).avbpubkey))
@ -4235,6 +4235,9 @@ ifeq ($(AB_OTA_UPDATER),true)
$(hide) echo "build_type=$(TARGET_BUILD_VARIANT)" >> $@
$(hide) echo "ab_update=true" >> $@
endif
ifeq ($(TARGET_OTA_ALLOW_NON_AB),true)
$(hide) echo "allow_non_ab=true" >> $@
endif
ifdef BOARD_PREBUILT_DTBOIMAGE
$(hide) echo "has_dtbo=true" >> $@
ifeq ($(BOARD_AVB_ENABLE),true)
@ -4312,10 +4315,13 @@ $(BUILT_TARGET_FILES_PACKAGE): PRIVATE_TOOL_EXTENSION := $(tool_extension)
ifeq ($(AB_OTA_UPDATER),true)
updater_dep := system/update_engine/update_engine.conf
else
# Build OTA tools if not using the AB Updater.
endif
# Build OTA tools if non-A/B is allowed
ifeq ($(TARGET_OTA_ALLOW_NON_AB),true)
updater_dep := $(built_ota_tools)
endif
$(BUILT_TARGET_FILES_PACKAGE): $(updater_dep)
# If we are using recovery as boot, output recovery files to BOOT/.
@ -4591,7 +4597,7 @@ endif
@# Extra contents of the OTA package
$(hide) mkdir -p $(zip_root)/OTA
$(hide) cp $(INSTALLED_ANDROID_INFO_TXT_TARGET) $(zip_root)/OTA/
ifneq ($(AB_OTA_UPDATER),true)
ifeq ($(TARGET_OTA_ALLOW_NON_AB),true)
ifneq ($(built_ota_tools),)
$(hide) mkdir -p $(zip_root)/OTA/bin
$(hide) cp $(PRIVATE_OTA_TOOLS) $(zip_root)/OTA/bin/
@ -4628,7 +4634,7 @@ ifneq ($(PRODUCT_ODM_BASE_FS_PATH),)
$(hide) cp $(PRODUCT_ODM_BASE_FS_PATH) \
$(zip_root)/META/$(notdir $(PRODUCT_ODM_BASE_FS_PATH))
endif
ifneq ($(AB_OTA_UPDATER),true)
ifeq ($(TARGET_OTA_ALLOW_NON_AB),true)
ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
$(hide) PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH MKBOOTIMG=$(MKBOOTIMG) \
$(MAKE_RECOVERY_PATCH) $(zip_root) $(zip_root)

View File

@ -549,13 +549,31 @@ endif
.KATI_READONLY := BUILDING_ODM_IMAGE
###########################################
# Ensure that only TARGET_RECOVERY_UPDATER_LIBS *or* AB_OTA_UPDATER is set.
# Ensure consistency among TARGET_RECOVERY_UPDATER_LIBS, AB_OTA_UPDATER, and PRODUCT_OTA_FORCE_NON_AB_PACKAGE.
TARGET_RECOVERY_UPDATER_LIBS ?=
AB_OTA_UPDATER ?=
.KATI_READONLY := TARGET_RECOVERY_UPDATER_LIBS AB_OTA_UPDATER
ifeq ($(AB_OTA_UPDATER),true)
# Ensure that if PRODUCT_OTA_FORCE_NON_AB_PACKAGE == true, then AB_OTA_UPDATER must be true
ifeq ($(PRODUCT_OTA_FORCE_NON_AB_PACKAGE),true)
ifneq ($(AB_OTA_UPDATER),true)
$(error AB_OTA_UPDATER must be set to true when PRODUCT_OTA_FORCE_NON_AB_PACKAGE is true)
endif
endif
# In some configurations, A/B and non-A/B may coexist. Check TARGET_OTA_ALLOW_NON_AB
# to see if non-A/B is supported.
TARGET_OTA_ALLOW_NON_AB := false
ifneq ($(AB_OTA_UPDATER),true)
TARGET_OTA_ALLOW_NON_AB := true
else ifeq ($(PRODUCT_OTA_FORCE_NON_AB_PACKAGE),true)
TARGET_OTA_ALLOW_NON_AB := true
endif
.KATI_READONLY := TARGET_OTA_ALLOW_NON_AB
ifneq ($(TARGET_OTA_ALLOW_NON_AB),true)
ifneq ($(strip $(TARGET_RECOVERY_UPDATER_LIBS)),)
$(error Do not use TARGET_RECOVERY_UPDATER_LIBS when using AB_OTA_UPDATER)
$(error Do not use TARGET_RECOVERY_UPDATER_LIBS when using TARGET_OTA_ALLOW_NON_AB)
endif
endif

View File

@ -393,6 +393,13 @@ _product_single_value_vars += PRODUCT_VIRTUAL_AB_OTA
# If set, device retrofits virtual A/B.
_product_single_value_vars += PRODUCT_VIRTUAL_AB_OTA_RETROFIT
# If set, forcefully generate a non-A/B update package.
# Note: A device configuration should inherit from virtual_ab_ota_plus_non_ab.mk
# instead of setting this variable directly.
# Note: Use TARGET_OTA_ALLOW_NON_AB in the build system because
# TARGET_OTA_ALLOW_NON_AB takes the value of AB_OTA_UPDATER into account.
_product_single_value_vars += PRODUCT_OTA_FORCE_NON_AB_PACKAGE
# If set, Java module in product partition cannot use hidden APIs.
_product_single_value_vars += PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE

View File

@ -0,0 +1,21 @@
#
# Copyright (C) 2020 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.
#
$(call inherit-product, $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)
PRODUCT_OTA_FORCE_NON_AB_PACKAGE := true
PRODUCT_PROPERTY_OVERRIDES += ro.virtual_ab.allow_non_ab=true

View File

@ -1558,6 +1558,7 @@ class BlockImageDiff(object):
split_large_apks = []
cache_size = common.OPTIONS.cache_size
split_threshold = 0.125
assert cache_size is not None
max_blocks_per_transfer = int(cache_size * split_threshold /
self.tgt.blocksize)
empty = RangeSet()

View File

@ -702,12 +702,13 @@ def LoadDictionaryFromLines(lines):
def LoadRecoveryFSTab(read_helper, fstab_version, recovery_fstab_path,
system_root_image=False):
class Partition(object):
def __init__(self, mount_point, fs_type, device, length, context):
def __init__(self, mount_point, fs_type, device, length, context, slotselect):
self.mount_point = mount_point
self.fs_type = fs_type
self.device = device
self.length = length
self.context = context
self.slotselect = slotselect
try:
data = read_helper(recovery_fstab_path)
@ -735,10 +736,13 @@ def LoadRecoveryFSTab(read_helper, fstab_version, recovery_fstab_path,
# It's a good line, parse it.
length = 0
slotselect = False
options = options.split(",")
for i in options:
if i.startswith("length="):
length = int(i[7:])
elif i == "slotselect":
slotselect = True
else:
# Ignore all unknown options in the unified fstab.
continue
@ -752,7 +756,8 @@ def LoadRecoveryFSTab(read_helper, fstab_version, recovery_fstab_path,
mount_point = pieces[1]
d[mount_point] = Partition(mount_point=mount_point, fs_type=pieces[2],
device=pieces[0], length=length, context=context)
device=pieces[0], length=length, context=context,
slotselect=slotselect)
# / is used for the system mount point when the root directory is included in
# system. Other areas assume system is always at "/system" so point /system
@ -767,7 +772,8 @@ def _FindAndLoadRecoveryFstab(info_dict, input_file, read_helper):
"""Finds the path to recovery fstab and loads its contents."""
# recovery fstab is only meaningful when installing an update via recovery
# (i.e. non-A/B OTA). Skip loading fstab if device used A/B OTA.
if info_dict.get('ab_update') == 'true':
if info_dict.get('ab_update') == 'true' and \
info_dict.get("allow_non_ab") != "true":
return None
# We changed recovery.fstab path in Q, from ../RAMDISK/etc/recovery.fstab to

View File

@ -78,6 +78,13 @@ Common options that apply to both of non-A/B and A/B OTAs
Write a copy of the metadata to a separate file. Therefore, users can
read the post build fingerprint without extracting the OTA package.
--force_non_ab
This flag can only be set on an A/B device that also supports non-A/B
updates. Implies --two_step.
If set, generate that non-A/B update package.
If not set, generates A/B package for A/B device and non-A/B package for
non-A/B device.
Non-A/B OTA specific options
-b (--binary) <file>
@ -247,6 +254,7 @@ OPTIONS.retrofit_dynamic_partitions = False
OPTIONS.skip_compatibility_check = False
OPTIONS.output_metadata_path = None
OPTIONS.disable_fec_computation = False
OPTIONS.force_non_ab = False
METADATA_NAME = 'META-INF/com/android/metadata'
@ -928,7 +936,7 @@ def GetPackageMetadata(target_info, source_info=None):
'ro.build.version.security_patch'),
}
if target_info.is_ab:
if target_info.is_ab and not OPTIONS.force_non_ab:
metadata['ota-type'] = 'AB'
metadata['ota-required-cache'] = '0'
else:
@ -2032,6 +2040,8 @@ def main(argv):
OPTIONS.output_metadata_path = a
elif o == "--disable_fec_computation":
OPTIONS.disable_fec_computation = True
elif o == "--force_non_ab":
OPTIONS.force_non_ab = True
else:
return False
return True
@ -2068,6 +2078,7 @@ def main(argv):
"skip_compatibility_check",
"output_metadata_path=",
"disable_fec_computation",
"force_non_ab",
], extra_option_handler=option_handler)
if len(args) != 2:
@ -2129,11 +2140,17 @@ def main(argv):
OPTIONS.skip_postinstall = True
ab_update = OPTIONS.info_dict.get("ab_update") == "true"
allow_non_ab = OPTIONS.info_dict.get("allow_non_ab") == "true"
if OPTIONS.force_non_ab:
assert allow_non_ab, "--force_non_ab only allowed on devices that supports non-A/B"
assert ab_update, "--force_non_ab only allowed on A/B devices"
generate_ab = not OPTIONS.force_non_ab and ab_update
# Use the default key to sign the package if not specified with package_key.
# package_keys are needed on ab_updates, so always define them if an
# ab_update is getting created.
if not OPTIONS.no_signing or ab_update:
# A/B update is getting created.
if not OPTIONS.no_signing or generate_ab:
if OPTIONS.package_key is None:
OPTIONS.package_key = OPTIONS.info_dict.get(
"default_system_dev_certificate",
@ -2141,7 +2158,7 @@ def main(argv):
# Get signing keys
OPTIONS.key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
if ab_update:
if generate_ab:
GenerateAbOtaPackage(
target_file=args[0],
output_file=args[1],