diff options
54 files changed, 1075 insertions, 1832 deletions
diff --git a/METADATA b/METADATA deleted file mode 100644 index 44781a7088..0000000000 --- a/METADATA +++ /dev/null @@ -1,8 +0,0 @@ -third_party { - license_note: "would be NOTICE save for GPL in:\n" - " core/LINUX_KERNEL_COPYING\n" - " tools/droiddoc/templates-pdk/assets/jquery-1.6.2.min.js\n" - " tools/droiddoc/templates-pdk/assets/jquery-history.js\n" - " tools/droiddoc/templates-pdk/assets/jquery-resizable.min.js" - license_type: RESTRICTED -} diff --git a/core/Makefile b/core/Makefile index 712719a300..02deaddd82 100644 --- a/core/Makefile +++ b/core/Makefile @@ -3406,12 +3406,12 @@ endif FULL_SYSTEMIMAGE_DEPS += $(INTERNAL_ROOT_FILES) $(INSTALLED_FILES_FILE_ROOT) -# Returns a list of all the zip files from EXTRA_INSTALL_ZIPS whose install destination is -# under $(1) +# Returns a list of EXTRA_INSTALL_ZIPS trios whose primary file is contained within $(1) +# The trios will contain the primary installed file : the directory to unzip the zip to : the zip define relevant-extra-install-zips $(strip $(foreach p,$(EXTRA_INSTALL_ZIPS), \ - $(if $(filter $(1)/%,$(call word-colon,1,$(p))/), \ - $(call word-colon,2,$(p))))) + $(if $(filter $(call word-colon,1,$(p)),$(1)), \ + $(p)))) endef # Writes a text file that contains all of the files that will be inside a partition. @@ -3423,12 +3423,12 @@ endef # $(2): The partition's staging directory # $(3): Files to include in the partition define write-partition-file-list -$(1): $$(HOST_OUT_EXECUTABLES)/extra_install_zips_file_list $(call relevant-extra-install-zips,$(2)) +$(1): $$(HOST_OUT_EXECUTABLES)/extra_install_zips_file_list $(foreach p,$(call relevant-extra-install-zips,$(filter $(2)/%,$(3))),$(call word-colon,3,$(p))) @echo Writing $$@ rm -f $$@ echo -n > $$@ $$(foreach f,$(subst $(2)/,,$(filter $(2)/%,$(3))),echo "$$(f)" >> $$@$$(newline)) - $$(HOST_OUT_EXECUTABLES)/extra_install_zips_file_list $(2) $$(EXTRA_INSTALL_ZIPS) >> $$@ + $$(HOST_OUT_EXECUTABLES)/extra_install_zips_file_list $(2) $(call relevant-extra-install-zips,$(filter $(2)/%,$(3))) >> $$@ endef # ----------------------------------------------------------------- diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk index ed72fc3a0d..c43081e4a9 100644 --- a/core/android_soong_config_vars.mk +++ b/core/android_soong_config_vars.mk @@ -94,6 +94,7 @@ $(call add_soong_config_var_value,ANDROID,release_avf_enable_device_assignment,$ $(call add_soong_config_var_value,ANDROID,release_avf_enable_dice_changes,$(RELEASE_AVF_ENABLE_DICE_CHANGES)) $(call add_soong_config_var_value,ANDROID,release_avf_enable_llpvm_changes,$(RELEASE_AVF_ENABLE_LLPVM_CHANGES)) $(call add_soong_config_var_value,ANDROID,release_avf_enable_multi_tenant_microdroid_vm,$(RELEASE_AVF_ENABLE_MULTI_TENANT_MICRODROID_VM)) +$(call add_soong_config_var_value,ANDROID,release_avf_enable_network,$(RELEASE_AVF_ENABLE_NETWORK)) $(call add_soong_config_var_value,ANDROID,release_avf_enable_remote_attestation,$(RELEASE_AVF_ENABLE_REMOTE_ATTESTATION)) $(call add_soong_config_var_value,ANDROID,release_avf_enable_vendor_modules,$(RELEASE_AVF_ENABLE_VENDOR_MODULES)) $(call add_soong_config_var_value,ANDROID,release_avf_enable_virt_cpufreq,$(RELEASE_AVF_ENABLE_VIRT_CPUFREQ)) diff --git a/core/art_config.mk b/core/art_config.mk index 196db4f30b..9e87a7bbe9 100644 --- a/core/art_config.mk +++ b/core/art_config.mk @@ -22,17 +22,16 @@ ENABLE_UFFD_GC := $(config_enable_uffd_gc) # Create APEX_BOOT_JARS_EXCLUDED which is a list of jars to be removed from # ApexBoorJars when built from mainline prebuilts. -# soong variables indicate whether the prebuilt is enabled: -# - $(m)_module/source_build for art and TOGGLEABLE_PREBUILT_MODULES -# - ANDROID/module_build_from_source for other mainline modules # Note that RELEASE_APEX_BOOT_JARS_PREBUILT_EXCLUDED_LIST is the list of module names # and library names of jars that need to be removed. We have to keep separated list per # release config due to possibility of different prebuilt content. -APEX_BOOT_JARS_EXCLUDED := -$(foreach pair, $(RELEASE_APEX_BOOT_JARS_PREBUILT_EXCLUDED_LIST),\ - $(eval m := $(subst com.android.,,$(call word-colon,1,$(pair)))) \ - $(if $(call soong_config_get,$(m)_module,source_build), \ - $(if $(filter true,$(call soong_config_get,$(m)_module,source_build)),, \ - $(eval APEX_BOOT_JARS_EXCLUDED += $(pair))), \ - $(if $(filter true,$(call soong_config_get,ANDROID,module_build_from_source)),, \ - $(eval APEX_BOOT_JARS_EXCLUDED += $(pair))))) +# +# If a device has opted to not use google prebuilts (determined using +# PRODUCT_BUILD_IGNORE_APEX_CONTRIBUTION_CONTENTS), then no jars need to be removed. +# Example of products where PRODUCT_BUILD_IGNORE_APEX_CONTRIBUTION_CONTENTS is true are +# 1. aosp devices (they do not use google apexes) +# 2. hwasan devices (apex prebuilts are not compatible with these devices) +# 3. coverage builds +ifneq (true, $(PRODUCT_BUILD_IGNORE_APEX_CONTRIBUTION_CONTENTS)) + APEX_BOOT_JARS_EXCLUDED += $(RELEASE_APEX_BOOT_JARS_PREBUILT_EXCLUDED_LIST) +endif diff --git a/core/envsetup.mk b/core/envsetup.mk index 1c3a1b3b6b..3271079abc 100644 --- a/core/envsetup.mk +++ b/core/envsetup.mk @@ -255,6 +255,7 @@ endif HOST_PREBUILT_ARCH := x86 # This is the standard way to name a directory containing prebuilt host # objects. E.g., prebuilt/$(HOST_PREBUILT_TAG)/cc +# This must match the logic in get_host_prebuilt_prefix in envsetup.sh HOST_PREBUILT_TAG := $(BUILD_OS)-$(HOST_PREBUILT_ARCH) # TARGET_COPY_OUT_* are all relative to the staging directory, ie PRODUCT_OUT. diff --git a/core/main.mk b/core/main.mk index d700fcb231..62fa53d08e 100644 --- a/core/main.mk +++ b/core/main.mk @@ -276,7 +276,7 @@ FULL_BUILD := true # Include all of the makefiles in the system # -subdir_makefiles := $(SOONG_ANDROID_MK) +subdir_makefiles := $(SOONG_OUT_DIR)/installs-$(TARGET_PRODUCT).mk $(SOONG_ANDROID_MK) # Android.mk files are only used on Linux builds, Mac only supports Android.bp ifeq ($(HOST_OS),linux) subdir_makefiles += $(file <$(OUT_DIR)/.module_paths/Android.mk.list) @@ -287,8 +287,6 @@ subdir_makefiles_total := $(words int $(subdir_makefiles) post finish) $(foreach mk,$(subdir_makefiles),$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] including $(mk) ...)$(eval include $(mk))) -include $(SOONG_OUT_DIR)/installs-$(TARGET_PRODUCT).mk - # For an unbundled image, we can skip blueprint_tools because unbundled image # aims to remove a large number framework projects from the manifest, the # sources or dependencies for these tools may be missing from the tree. diff --git a/core/product.mk b/core/product.mk index 0a761fb44e..15faf7d88f 100644 --- a/core/product.mk +++ b/core/product.mk @@ -447,7 +447,8 @@ _product_list_vars += PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS # device may have to re-compile everything on the first boot if the kernel doesn't support # userfaultfd # - "false": disallows the build system and the runtime to use userfaultfd GC even if the device -# supports it +# supports it. This option is temporary - the plan is to remove it by Aug 2025, at which time +# Mainline updates of the ART module will ignore it as well. _product_single_value_vars += PRODUCT_ENABLE_UFFD_GC # Specifies COW version to be used by update_engine and libsnapshot. If this value is not @@ -483,6 +484,9 @@ _product_single_value_vars += PRODUCT_EXPORT_RUNTIME_APIS # TODO(b/325991735): link to documentation once it is done. _product_single_value_vars += PRODUCT_AVF_MICRODROID_GUEST_GKI_VERSION +# Enables 16KB developer option for device if set. +_product_single_value_vars += PRODUCT_16K_DEVELOPER_OPTION + .KATI_READONLY := _product_single_value_vars _product_list_vars _product_var_list :=$= $(_product_single_value_vars) $(_product_list_vars) diff --git a/core/release_config.mk b/core/release_config.mk index 97c8dd3571..887c78b07d 100644 --- a/core/release_config.mk +++ b/core/release_config.mk @@ -14,6 +14,16 @@ # ----------------------------------------------------------------- +# Determine which pass this is. +# ----------------------------------------------------------------- +# On the first pass, we are asked for only PRODUCT_RELEASE_CONFIG_MAPS, +# on the second pass, we are asked for whatever else is wanted. +_final_product_config_pass:= +ifneq (PRODUCT_RELEASE_CONFIG_MAPS,$(DUMP_MANY_VARS)) + _final_product_config_pass:=true +endif + +# ----------------------------------------------------------------- # Choose the flag files # ----------------------------------------------------------------- # Release configs are defined in reflease_config_map files, which map @@ -90,7 +100,7 @@ $(foreach map,$(protobuf_map_files), \ ifneq (,$(_must_protobuf)) ifeq (,$(_can_protobuf)) - # We must use protobuf, but we cannot use protobuf. + # We must use protobuf, but we cannot use protobuf. $(error release config is a mixture of .scl and .textproto) endif endif @@ -120,15 +130,40 @@ ifneq (,$(_use_protobuf)) # Disable the build flag in release-config. _args += --guard=false endif - _flags_file:=$(OUT_DIR)/soong/release-config/release_config-$(TARGET_PRODUCT)-$(TARGET_RELEASE).mk - $(KATI_shell_no_rerun $(OUT_DIR)/release-config $(_args) >$(OUT_DIR)/release-config.out 2>&1 && touch -t 200001010000 $(OUT_DIR)/release-config.out $(_flags_file)) + _flags_dir:=$(OUT_DIR)/soong/release-config + _flags_file:=$(_flags_dir)/release_config-$(TARGET_PRODUCT)-$(TARGET_RELEASE).vars + # release-config generates $(_flags_varmk) + _flags_varmk:=$(_flags_file:.vars=.varmk) + $(shell $(OUT_DIR)/release-config $(_args) >$(OUT_DIR)/release-config.out && touch -t 200001010000 $(_flags_varmk)) $(if $(filter-out 0,$(.SHELLSTATUS)),$(error release-config failed to run)) - # This will also set _all_release_configs for us. - $(eval include $(OUT_DIR)/soong/release-config/release_config-$(TARGET_PRODUCT)-$(TARGET_RELEASE).mk) - $(KATI_extra_file_deps $(OUT_DIR)/release-config $(config_map_files)) + ifneq (,$(_final_product_config_pass)) + # Save the final version of the config. + $(shell if ! cmp --quiet $(_flags_varmk) $(_flags_file); then cp $(_flags_varmk) $(_flags_file); fi) + # This will also set _all_release_configs and _used_files for us. + $(eval include $(_flags_file)) + $(KATI_extra_file_deps $(OUT_DIR)/release-config $(protobuf_map_files) $(_flags_file)) + else + # This is the first pass of product config. + $(eval include $(_flags_varmk)) + endif + _used_files := ifeq (,$(_must_protobuf)$(RELEASE_BUILD_FLAGS_IN_PROTOBUF)) _use_protobuf := + else + _base_all_release := all_release_configs-$(TARGET_PRODUCT) + $(call dist-for-goals,droid,\ + $(_flags_dir)/$(_base_all_release).pb:build_flags/all_release_configs.pb \ + $(_flags_dir)/$(_base_all_release).textproto:build_flags/all_release_configs.textproto \ + $(_flags_dir)/$(_base_all_release).json:build_flags/all_release_configs.json \ + ) +# These are always created, add an empty rule for them to keep ninja happy. +$(_flags_dir)/$(_base_all_release).pb $(_flags_dir)/$(_base_all_release).textproto $(_flags_dir)/$(_base_all_release).json: + : created by $(OUT_DIR)/release-config + _base_all_release := endif + _flags_dir:= + _flags_file:= + _flags_varmk:= endif ifeq (,$(_use_protobuf)) # The .mk files are the canonical source of truth. @@ -238,7 +273,7 @@ endif # During pass 1 of product config, using a non-existent release config is not an error. # We can safely assume that we are doing pass 1 if DUMP_MANY_VARS=="PRODUCT_RELEASE_CONFIG_MAPS". -ifneq (PRODUCT_RELEASE_CONFIG_MAPS,$(DUMP_MANY_VARS)) +ifneq (,$(_final_product_config_pass)) ifeq ($(filter $(_all_release_configs), $(TARGET_RELEASE)),) $(error No release config found for TARGET_RELEASE: $(TARGET_RELEASE). Available releases are: $(_all_release_configs)) endif diff --git a/core/soong_config.mk b/core/soong_config.mk index acd213c776..7402d2b0ed 100644 --- a/core/soong_config.mk +++ b/core/soong_config.mk @@ -167,13 +167,16 @@ $(call add_json_list, ModulesLoadedByPrivilegedModules, $(PRODUCT_LOADED_BY_PRI $(call add_json_list, BootJars, $(PRODUCT_BOOT_JARS)) $(call add_json_list, ApexBootJars, $(filter-out $(APEX_BOOT_JARS_EXCLUDED), $(PRODUCT_APEX_BOOT_JARS))) -$(call add_json_bool, VndkUseCoreVariant, $(TARGET_VNDK_USE_CORE_VARIANT)) $(call add_json_bool, VndkSnapshotBuildArtifacts, $(VNDK_SNAPSHOT_BUILD_ARTIFACTS)) $(call add_json_map, BuildFlags) $(foreach flag,$(_ALL_RELEASE_FLAGS),\ $(call add_json_str,$(flag),$(_ALL_RELEASE_FLAGS.$(flag).VALUE))) $(call end_json_map) +$(call add_json_map, BuildFlagTypes) +$(foreach flag,$(_ALL_RELEASE_FLAGS),\ + $(call add_json_str,$(flag),$(_ALL_RELEASE_FLAGS.$(flag).TYPE))) +$(call end_json_map) $(call add_json_bool, DirectedVendorSnapshot, $(DIRECTED_VENDOR_SNAPSHOT)) $(call add_json_map, VendorSnapshotModules) diff --git a/core/sysprop_config.mk b/core/sysprop_config.mk index a019a7d2c3..e8428c8eaf 100644 --- a/core/sysprop_config.mk +++ b/core/sysprop_config.mk @@ -265,6 +265,9 @@ ADDITIONAL_SYSTEM_PROPERTIES += ro.force.debuggable=0 config_enable_uffd_gc := \ $(firstword $(OVERRIDE_ENABLE_UFFD_GC) $(PRODUCT_ENABLE_UFFD_GC) default) +# This is a temporary system property that controls the ART module. The plan is +# to remove it by Aug 2025, at which time Mainline updates of the ART module +# will ignore it as well. # If the value is "default", it will be mangled by post_process_props.py. ADDITIONAL_PRODUCT_PROPERTIES += ro.dalvik.vm.enable_uffd_gc=$(config_enable_uffd_gc) diff --git a/core/tasks/device-platinum-tests.mk b/core/tasks/device-platinum-tests.mk new file mode 100644 index 0000000000..75f4c4c29b --- /dev/null +++ b/core/tasks/device-platinum-tests.mk @@ -0,0 +1,71 @@ +# Copyright (C) 2024 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. + + +.PHONY: device-platinum-tests + +device_platinum_tests_zip := $(PRODUCT_OUT)/device-platinum-tests.zip +# Create an artifact to include a list of test config files in device-platinum-tests. +device_platinum_tests_list_zip := $(PRODUCT_OUT)/device-platinum-tests_list.zip +# Create an artifact to include all test config files in device-platinum-tests. +device_platinum_tests_configs_zip := $(PRODUCT_OUT)/device-platinum-tests_configs.zip +my_host_shared_lib_for_device_platinum_tests := $(call copy-many-files,$(COMPATIBILITY.device-platinum-tests.HOST_SHARED_LIBRARY.FILES)) +device_platinum_tests_host_shared_libs_zip := $(PRODUCT_OUT)/device-platinum-tests_host-shared-libs.zip + +$(device_platinum_tests_zip) : .KATI_IMPLICIT_OUTPUTS := $(device_platinum_tests_list_zip) $(device_platinum_tests_configs_zip) $(device_platinum_tests_host_shared_libs_zip) +$(device_platinum_tests_zip) : PRIVATE_device_platinum_tests_list_zip := $(device_platinum_tests_list_zip) +$(device_platinum_tests_zip) : PRIVATE_device_platinum_tests_configs_zip := $(device_platinum_tests_configs_zip) +$(device_platinum_tests_zip) : PRIVATE_device_platinum_tests_list := $(PRODUCT_OUT)/device-platinum-tests_list +$(device_platinum_tests_zip) : PRIVATE_HOST_SHARED_LIBS := $(my_host_shared_lib_for_device_platinum_tests) +$(device_platinum_tests_zip) : PRIVATE_device_host_shared_libs_zip := $(device_platinum_tests_host_shared_libs_zip) +$(device_platinum_tests_zip) : $(COMPATIBILITY.device-platinum-tests.FILES) $(my_host_shared_lib_for_device_platinum_tests) $(SOONG_ZIP) + rm -f $@-shared-libs.list + rm -f $(PRIVATE_device_platinum_tests_list_zip) + echo $(sort $(COMPATIBILITY.device-platinum-tests.FILES)) | tr " " "\n" > $@.list + grep $(HOST_OUT_TESTCASES) $@.list > $@-host.list || true + grep -e .*\\.config$$ $@-host.list > $@-host-test-configs.list || true + $(hide) for shared_lib in $(PRIVATE_HOST_SHARED_LIBS); do \ + echo $$shared_lib >> $@-host.list; \ + echo $$shared_lib >> $@-shared-libs.list; \ + done + grep $(HOST_OUT_TESTCASES) $@-shared-libs.list > $@-host-shared-libs.list || true + grep $(TARGET_OUT_TESTCASES) $@.list > $@-target.list || true + grep -e .*\\.config$$ $@-target.list > $@-target-test-configs.list || true + $(hide) $(SOONG_ZIP) -d -o $@ -P host -C $(HOST_OUT) -l $@-host.list -P target -C $(PRODUCT_OUT) -l $@-target.list -sha256 + $(hide) $(SOONG_ZIP) -d -o $(PRIVATE_device_platinum_tests_configs_zip) \ + -P host -C $(HOST_OUT) -l $@-host-test-configs.list \ + -P target -C $(PRODUCT_OUT) -l $@-target-test-configs.list + $(SOONG_ZIP) -d -o $(PRIVATE_device_host_shared_libs_zip) \ + -P host -C $(HOST_OUT) -l $@-host-shared-libs.list + rm -f $(PRIVATE_device_platinum_tests_list) + $(hide) grep -e .*\\.config$$ $@-host.list | sed s%$(HOST_OUT)%host%g > $(PRIVATE_device_platinum_tests_list) + $(hide) grep -e .*\\.config$$ $@-target.list | sed s%$(PRODUCT_OUT)%target%g >> $(PRIVATE_device_platinum_tests_list) + $(hide) $(SOONG_ZIP) -d -o $(PRIVATE_device_platinum_tests_list_zip) -C $(dir $@) -f $(PRIVATE_device_platinum_tests_list) + rm -f $@.list $@-host.list $@-target.list $@-host-test-configs.list $@-target-test-configs.list \ + $@-shared-libs.list $@-host-shared-libs.list $(PRIVATE_device_platinum_tests_list) + +device-platinum-tests: $(device_platinum_tests_zip) +$(call dist-for-goals, device-platinum-tests, $(device_platinum_tests_zip) $(device_platinum_tests_list_zip) $(device_platinum_tests_configs_zip) $(device_platinum_tests_host_shared_libs_zip)) + +$(call declare-1p-container,$(device_platinum_tests_zip),) +$(call declare-container-license-deps,$(device_platinum_tests_zip),$(COMPATIBILITY.device-platinum-tests.FILES) $(my_host_shared_lib_for_device_platinum_tests),$(PRODUCT_OUT)/:/) + +tests: device-platinum-tests + +# Reset temp vars +device_platinum_tests_zip := +device_platinum_tests_list_zip := +device_platinum_tests_configs_zip := +my_host_shared_lib_for_device_platinum_tests := +device_platinum_tests_host_shared_libs_zip := diff --git a/core/tasks/meta-lic.mk b/core/tasks/meta-lic.mk index 2126bd02ba..c41de63b0a 100644 --- a/core/tasks/meta-lic.mk +++ b/core/tasks/meta-lic.mk @@ -140,3 +140,10 @@ $(eval $(call declare-1p-copy-files,frameworks/base,.idc)) $(eval $(call declare-1p-copy-files,frameworks/base,dirty-image-objects)) $(eval $(call declare-1p-copy-files,frameworks/base/config,)) $(eval $(call declare-1p-copy-files,frameworks/native/data,)) + +# Moved here from hardware/google/camera/Android.mk +$(eval $(call declare-1p-copy-files,hardware/google/camera,)) + +# Moved here from hardware/interfaces/tv/Android.mk +$(eval $(call declare-1p-copy-files,hardware/interfaces/tv,tuner_vts_config_1_0.xml)) +$(eval $(call declare-1p-copy-files,hardware/interfaces/tv,tuner_vts_config_1_1.xml)) diff --git a/core/tasks/module-info.mk b/core/tasks/module-info.mk index aa695eb31c..daa708938f 100644 --- a/core/tasks/module-info.mk +++ b/core/tasks/module-info.mk @@ -32,6 +32,7 @@ $(MODULE_INFO_JSON): $(SOONG_MODULE_INFO) $(call write-optional-json-list, "auto_test_config", $(sort $(ALL_MODULES.$(m).auto_test_config))) \ $(call write-optional-json-list, "test_config", $(strip $(ALL_MODULES.$(m).TEST_CONFIG) $(ALL_MODULES.$(m).EXTRA_TEST_CONFIGS))) \ $(call write-optional-json-list, "dependencies", $(sort $(ALL_MODULES.$(m).ALL_DEPS))) \ + $(call write-optional-json-list, "required", $(sort $(ALL_MODULES.$(m).REQUIRED_FROM_TARGET))) \ $(call write-optional-json-list, "shared_libs", $(sort $(ALL_MODULES.$(m).SHARED_LIBS))) \ $(call write-optional-json-list, "static_libs", $(sort $(ALL_MODULES.$(m).STATIC_LIBS))) \ $(call write-optional-json-list, "system_shared_libs", $(sort $(ALL_MODULES.$(m).SYSTEM_SHARED_LIBS))) \ @@ -52,6 +53,8 @@ $(MODULE_INFO_JSON): $(SOONG_MODULE_INFO) $(PRIVATE_MERGE_JSON_OBJECTS) -o $@ $(PRIVATE_SOONG_MODULE_INFO) $@.tmp rm $@.tmp +.PHONY: module-info +module-info: $(MODULE_INFO_JSON) droidcore-unbundled: $(MODULE_INFO_JSON) diff --git a/core/tasks/performance-tests.mk b/core/tasks/performance-tests.mk new file mode 100644 index 0000000000..8702756f31 --- /dev/null +++ b/core/tasks/performance-tests.mk @@ -0,0 +1,56 @@ +# Copyright (C) 2024 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. + + +.PHONY: performance-tests + +performance_tests_zip := $(PRODUCT_OUT)/performance-tests.zip +# Create an artifact to include a list of test config files in performance-tests. +performance_tests_list_zip := $(PRODUCT_OUT)/performance-tests_list.zip +# Create an artifact to include all test config files in performance-tests. +performance_tests_configs_zip := $(PRODUCT_OUT)/performance-tests_configs.zip + +$(performance_tests_zip) : .KATI_IMPLICIT_OUTPUTS := $(performance_tests_list_zip) $(performance_tests_configs_zip) +$(performance_tests_zip) : PRIVATE_performance_tests_list_zip := $(performance_tests_list_zip) +$(performance_tests_zip) : PRIVATE_performance_tests_configs_zip := $(performance_tests_configs_zip) +$(performance_tests_zip) : PRIVATE_performance_tests_list := $(PRODUCT_OUT)/performance-tests_list +$(performance_tests_zip) : $(COMPATIBILITY.performance-tests.FILES) $(SOONG_ZIP) + echo $(sort $(COMPATIBILITY.performance-tests.FILES)) | tr " " "\n" > $@.list + grep $(HOST_OUT_TESTCASES) $@.list > $@-host.list || true + grep -e .*\\.config$$ $@-host.list > $@-host-test-configs.list || true + grep $(TARGET_OUT_TESTCASES) $@.list > $@-target.list || true + grep -e .*\\.config$$ $@-target.list > $@-target-test-configs.list || true + $(hide) $(SOONG_ZIP) -d -o $@ -P host -C $(HOST_OUT) -l $@-host.list -P target -C $(PRODUCT_OUT) -l $@-target.list -sha256 + $(hide) $(SOONG_ZIP) -d -o $(PRIVATE_performance_tests_configs_zip) \ + -P host -C $(HOST_OUT) -l $@-host-test-configs.list \ + -P target -C $(PRODUCT_OUT) -l $@-target-test-configs.list + rm -f $(PRIVATE_performance_tests_list) + $(hide) grep -e .*\\.config$$ $@-host.list | sed s%$(HOST_OUT)%host%g > $(PRIVATE_performance_tests_list) + $(hide) grep -e .*\\.config$$ $@-target.list | sed s%$(PRODUCT_OUT)%target%g >> $(PRIVATE_performance_tests_list) + $(hide) $(SOONG_ZIP) -d -o $(PRIVATE_performance_tests_list_zip) -C $(dir $@) -f $(PRIVATE_performance_tests_list) + rm -f $@.list $@-host.list $@-target.list $@-host-test-configs.list $@-target-test-configs.list \ + $(PRIVATE_performance_tests_list) + +performance-tests: $(performance_tests_zip) +$(call dist-for-goals, performance-tests, $(performance_tests_zip) $(performance_tests_list_zip) $(performance_tests_configs_zip)) + +$(call declare-1p-container,$(performance_tests_zip),) +$(call declare-container-license-deps,$(performance_tests_zip),$(COMPATIBILITY.performance-tests.FILES),$(PRODUCT_OUT)/:/) + +tests: performance-tests + +# Reset temp vars +performance_tests_zip := +performance_tests_list_zip := +performance_tests_configs_zip := diff --git a/envsetup.sh b/envsetup.sh index 50fec5146a..647c106380 100644 --- a/envsetup.sh +++ b/envsetup.sh @@ -48,81 +48,13 @@ if [ ! "$T" ]; then fi IMPORTING_ENVSETUP=true source $T/build/make/shell_utils.sh - -# Help -function hmm() { -cat <<EOF - -Run "m help" for help with the build system itself. - -Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment: -- lunch: lunch <product_name>-<release_type>-<build_variant> - Selects <product_name> as the product to build, and <build_variant> as the variant to - build, and stores those selections in the environment to be read by subsequent - invocations of 'm' etc. -- tapas: tapas [<App1> <App2> ...] [arm|x86|arm64|x86_64] [eng|userdebug|user] - Sets up the build environment for building unbundled apps (APKs). -- banchan: banchan <module1> [<module2> ...] \\ - [arm|x86|arm64|riscv64|x86_64|arm64_only|x86_64only] [eng|userdebug|user] - Sets up the build environment for building unbundled modules (APEXes). -- croot: Changes directory to the top of the tree, or a subdirectory thereof. -- m: Makes from the top of the tree. -- mm: Builds and installs all of the modules in the current directory, and their - dependencies. -- mmm: Builds and installs all of the modules in the supplied directories, and their - dependencies. - To limit the modules being built use the syntax: mmm dir/:target1,target2. -- mma: Same as 'mm' -- mmma: Same as 'mmm' -- provision: Flash device with all required partitions. Options will be passed on to fastboot. -- cgrep: Greps on all local C/C++ files. -- ggrep: Greps on all local Gradle files. -- gogrep: Greps on all local Go files. -- jgrep: Greps on all local Java files. -- jsongrep: Greps on all local Json files. -- ktgrep: Greps on all local Kotlin files. -- resgrep: Greps on all local res/*.xml files. -- mangrep: Greps on all local AndroidManifest.xml files. -- mgrep: Greps on all local Makefiles and *.bp files. -- owngrep: Greps on all local OWNERS files. -- rsgrep: Greps on all local Rust files. -- sepgrep: Greps on all local sepolicy files. -- sgrep: Greps on all local source files. -- tomlgrep: Greps on all local Toml files. -- pygrep: Greps on all local Python files. -- godir: Go to the directory containing a file. -- allmod: List all modules. -- gomod: Go to the directory containing a module. -- bmod: Get the Bazel label of a Soong module if it is converted with bp2build. -- pathmod: Get the directory containing a module. -- outmod: Gets the location of a module's installed outputs with a certain extension. -- dirmods: Gets the modules defined in a given directory. -- installmod: Adb installs a module's built APK. -- refreshmod: Refresh list of modules for allmod/gomod/pathmod/outmod/installmod. -- syswrite: Remount partitions (e.g. system.img) as writable, rebooting if necessary. - -Environment options: -- SANITIZE_HOST: Set to 'address' to use ASAN for all host modules. -- ANDROID_QUIET_BUILD: set to 'true' to display only the essential messages. - -Look at the source to view more functions. The complete list is: -EOF - local T=$(gettop) - local A="" - local i - for i in `cat $T/build/envsetup.sh | sed -n "/^[[:blank:]]*function /s/function \([a-z_]*\).*/\1/p" | sort | uniq`; do - A="$A $i" - done - echo $A -} - # Get all the build variables needed by this script in a single call to the build system. function build_build_var_cache() { local T=$(gettop) # Grep out the variable names from the script. - cached_vars=(`cat $T/build/envsetup.sh | tr '()' ' ' | awk '{for(i=1;i<=NF;i++) if($i~/get_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`) - cached_abs_vars=(`cat $T/build/envsetup.sh | tr '()' ' ' | awk '{for(i=1;i<=NF;i++) if($i~/get_abs_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`) + cached_vars=(`cat $T/build/envsetup.sh | tr '()' ' ' | awk '{for(i=1;i<=NF;i++) if($i~/_get_build_var_cached/) print $(i+1)}' | sort -u | tr '\n' ' '`) + cached_abs_vars=(`cat $T/build/envsetup.sh | tr '()' ' ' | awk '{for(i=1;i<=NF;i++) if($i~/_get_abs_build_var_cached/) print $(i+1)}' | sort -u | tr '\n' ' '`) # Call the build system to dump the "<val>=<value>" pairs as a shell script. build_dicts_script=`\builtin cd $T; build/soong/soong_ui.bash --dumpvars-mode \ --vars="${cached_vars[*]}" \ @@ -163,7 +95,7 @@ function destroy_build_var_cache() } # Get the value of a build variable as an absolute path. -function get_abs_build_var() +function _get_abs_build_var_cached() { if [ "$BUILD_VAR_CACHE_READY" = "true" ] then @@ -180,7 +112,7 @@ function get_abs_build_var() } # Get the exact value of a build variable. -function get_build_var() +function _get_build_var_cached() { if [ "$BUILD_VAR_CACHE_READY" = "true" ] then @@ -196,40 +128,19 @@ function get_build_var() (\cd $T; build/soong/soong_ui.bash --dumpvar-mode $1) } -# check to see if the supplied product is one we can build -function check_product() -{ - local T=$(gettop) - if [ ! "$T" ]; then - echo "Couldn't locate the top of the tree. Try setting TOP." >&2 - return - fi - TARGET_PRODUCT=$1 \ - TARGET_RELEASE= \ - TARGET_BUILD_VARIANT= \ - TARGET_BUILD_TYPE= \ - TARGET_BUILD_APPS= \ - get_build_var TARGET_DEVICE > /dev/null - # hide successful answers, but allow the errors to show -} - -VARIANT_CHOICES=(user userdebug eng) - -# check to see if the supplied variant is valid -function check_variant() +# This logic matches envsetup.mk +function get_host_prebuilt_prefix { - local v - for v in ${VARIANT_CHOICES[@]} - do - if [ "$v" = "$1" ] - then - return 0 - fi - done - return 1 + local un=$(uname) + if [[ $un == "Linux" ]] ; then + echo linux-x86 + elif [[ $un == "Darwin" ]] ; then + echo darwin-x86 + else + echo "Error: Invalid host operating system: $un" 1>&2 + fi } - # Add directories to PATH that are dependent on the lunch target. # For directories that are not lunch-specific, add them in set_global_paths function set_lunch_paths() @@ -273,25 +184,25 @@ function set_lunch_paths() fi # And in with the new... - ANDROID_LUNCH_BUILD_PATHS=$(get_abs_build_var SOONG_HOST_OUT_EXECUTABLES) - ANDROID_LUNCH_BUILD_PATHS+=:$(get_abs_build_var HOST_OUT_EXECUTABLES) + ANDROID_LUNCH_BUILD_PATHS=$(_get_abs_build_var_cached SOONG_HOST_OUT_EXECUTABLES) + ANDROID_LUNCH_BUILD_PATHS+=:$(_get_abs_build_var_cached HOST_OUT_EXECUTABLES) # Append llvm binutils prebuilts path to ANDROID_LUNCH_BUILD_PATHS. - local ANDROID_LLVM_BINUTILS=$(get_abs_build_var ANDROID_CLANG_PREBUILTS)/llvm-binutils-stable + local ANDROID_LLVM_BINUTILS=$(_get_abs_build_var_cached ANDROID_CLANG_PREBUILTS)/llvm-binutils-stable ANDROID_LUNCH_BUILD_PATHS+=:$ANDROID_LLVM_BINUTILS # Set up ASAN_SYMBOLIZER_PATH for SANITIZE_HOST=address builds. export ASAN_SYMBOLIZER_PATH=$ANDROID_LLVM_BINUTILS/llvm-symbolizer # Append asuite prebuilts path to ANDROID_LUNCH_BUILD_PATHS. - local os_arch=$(get_build_var HOST_PREBUILT_TAG) + local os_arch=$(_get_build_var_cached HOST_PREBUILT_TAG) ANDROID_LUNCH_BUILD_PATHS+=:$T/prebuilts/asuite/acloud/$os_arch ANDROID_LUNCH_BUILD_PATHS+=:$T/prebuilts/asuite/aidegen/$os_arch ANDROID_LUNCH_BUILD_PATHS+=:$T/prebuilts/asuite/atest/$os_arch - export ANDROID_JAVA_HOME=$(get_abs_build_var ANDROID_JAVA_HOME) + export ANDROID_JAVA_HOME=$(_get_abs_build_var_cached ANDROID_JAVA_HOME) export JAVA_HOME=$ANDROID_JAVA_HOME - export ANDROID_JAVA_TOOLCHAIN=$(get_abs_build_var ANDROID_JAVA_TOOLCHAIN) + export ANDROID_JAVA_TOOLCHAIN=$(_get_abs_build_var_cached ANDROID_JAVA_TOOLCHAIN) ANDROID_LUNCH_BUILD_PATHS+=:$ANDROID_JAVA_TOOLCHAIN # Fix up PYTHONPATH @@ -320,20 +231,20 @@ function set_lunch_paths() export PYTHONPATH=$ANDROID_PYTHONPATH$PYTHONPATH unset ANDROID_PRODUCT_OUT - export ANDROID_PRODUCT_OUT=$(get_abs_build_var PRODUCT_OUT) + export ANDROID_PRODUCT_OUT=$(_get_abs_build_var_cached PRODUCT_OUT) export OUT=$ANDROID_PRODUCT_OUT unset ANDROID_HOST_OUT - export ANDROID_HOST_OUT=$(get_abs_build_var HOST_OUT) + export ANDROID_HOST_OUT=$(_get_abs_build_var_cached HOST_OUT) unset ANDROID_SOONG_HOST_OUT - export ANDROID_SOONG_HOST_OUT=$(get_abs_build_var SOONG_HOST_OUT) + export ANDROID_SOONG_HOST_OUT=$(_get_abs_build_var_cached SOONG_HOST_OUT) unset ANDROID_HOST_OUT_TESTCASES - export ANDROID_HOST_OUT_TESTCASES=$(get_abs_build_var HOST_OUT_TESTCASES) + export ANDROID_HOST_OUT_TESTCASES=$(_get_abs_build_var_cached HOST_OUT_TESTCASES) unset ANDROID_TARGET_OUT_TESTCASES - export ANDROID_TARGET_OUT_TESTCASES=$(get_abs_build_var TARGET_OUT_TESTCASES) + export ANDROID_TARGET_OUT_TESTCASES=$(_get_abs_build_var_cached TARGET_OUT_TESTCASES) # Finally, set PATH export PATH=$ANDROID_LUNCH_BUILD_PATHS:$PATH @@ -406,7 +317,7 @@ function printconfig() echo "Couldn't locate the top of the tree. Try setting TOP." >&2 return fi - get_build_var report_config + _get_build_var_cached report_config } function set_stuff_for_environment() @@ -467,9 +378,6 @@ function addcompletions() fi done - if should_add_completion bit ; then - complete -C "bit --tab" bit - fi if [ -z "$ZSH_VERSION" ]; then # Doesn't work in zsh. complete -o nospace -F _croot croot @@ -482,240 +390,9 @@ function addcompletions() complete -F _complete_android_module_names gomod complete -F _complete_android_module_names outmod complete -F _complete_android_module_names installmod - complete -F _complete_android_module_names bmod complete -F _complete_android_module_names m } -function multitree_lunch_help() -{ - echo "usage: lunch PRODUCT-RELEASE-VARIANT" 1>&2 - echo " Set up android build environment based on a product short name and variant" 1>&2 - echo 1>&2 - echo "lunch COMBO_FILE VARIANT" 1>&2 - echo " Set up android build environment based on a specific lunch combo file" 1>&2 - echo " and variant." 1>&2 - echo 1>&2 - echo "lunch --print [CONFIG]" 1>&2 - echo " Print the contents of a configuration. If CONFIG is supplied, that config" 1>&2 - echo " will be flattened and printed. If CONFIG is not supplied, the currently" 1>&2 - echo " selected config will be printed. Returns 0 on success or nonzero on error." 1>&2 - echo 1>&2 - echo "lunch --list" 1>&2 - echo " List all possible combo files available in the current tree" 1>&2 - echo 1>&2 - echo "lunch --help" 1>&2 - echo "lunch -h" 1>&2 - echo " Prints this message." 1>&2 -} - -function multitree_lunch() -{ - local code - local results - # Lunch must be run in the topdir, but this way we get a clear error - # message, instead of FileNotFound. - local T=$(multitree_gettop) - if [ -z "$T" ]; then - _multitree_lunch_error - return 1 - fi - if $(echo "$1" | grep -q '^-') ; then - # Calls starting with a -- argument are passed directly and the function - # returns with the lunch.py exit code. - "${T}/orchestrator/build/orchestrator/core/lunch.py" "$@" - code=$? - if [[ $code -eq 2 ]] ; then - echo 1>&2 - multitree_lunch_help - return $code - elif [[ $code -ne 0 ]] ; then - return $code - fi - else - # All other calls go through the --lunch variant of lunch.py - results=($(${T}/orchestrator/build/orchestrator/core/lunch.py --lunch "$@")) - code=$? - if [[ $code -eq 2 ]] ; then - echo 1>&2 - multitree_lunch_help - return $code - elif [[ $code -ne 0 ]] ; then - return $code - fi - - export TARGET_BUILD_COMBO=${results[0]} - export TARGET_BUILD_VARIANT=${results[1]} - fi -} - -function choosetype() -{ - echo "Build type choices are:" - echo " 1. release" - echo " 2. debug" - echo - - local DEFAULT_NUM DEFAULT_VALUE - DEFAULT_NUM=1 - DEFAULT_VALUE=release - - export TARGET_BUILD_TYPE= - local ANSWER - while [ -z $TARGET_BUILD_TYPE ] - do - echo -n "Which would you like? ["$DEFAULT_NUM"] " - if [ -z "$1" ] ; then - read ANSWER - else - echo $1 - ANSWER=$1 - fi - case $ANSWER in - "") - export TARGET_BUILD_TYPE=$DEFAULT_VALUE - ;; - 1) - export TARGET_BUILD_TYPE=release - ;; - release) - export TARGET_BUILD_TYPE=release - ;; - 2) - export TARGET_BUILD_TYPE=debug - ;; - debug) - export TARGET_BUILD_TYPE=debug - ;; - *) - echo - echo "I didn't understand your response. Please try again." - echo - ;; - esac - if [ -n "$1" ] ; then - break - fi - done - - build_build_var_cache - set_stuff_for_environment - destroy_build_var_cache -} - -# -# This function isn't really right: It chooses a TARGET_PRODUCT -# based on the list of boards. Usually, that gets you something -# that kinda works with a generic product, but really, you should -# pick a product by name. -# -function chooseproduct() -{ - local default_value - if [ "x$TARGET_PRODUCT" != x ] ; then - default_value=$TARGET_PRODUCT - else - default_value=aosp_arm - fi - - export TARGET_BUILD_APPS= - export TARGET_PRODUCT= - local ANSWER - while [ -z "$TARGET_PRODUCT" ] - do - echo -n "Which product would you like? [$default_value] " - if [ -z "$1" ] ; then - read ANSWER - else - echo $1 - ANSWER=$1 - fi - - if [ -z "$ANSWER" ] ; then - export TARGET_PRODUCT=$default_value - else - if check_product $ANSWER - then - export TARGET_PRODUCT=$ANSWER - else - echo "** Not a valid product: $ANSWER" - fi - fi - if [ -n "$1" ] ; then - break - fi - done - - build_build_var_cache - set_stuff_for_environment - destroy_build_var_cache -} - -function choosevariant() -{ - echo "Variant choices are:" - local index=1 - local v - for v in ${VARIANT_CHOICES[@]} - do - # The product name is the name of the directory containing - # the makefile we found, above. - echo " $index. $v" - index=$(($index+1)) - done - - local default_value=eng - local ANSWER - - export TARGET_BUILD_VARIANT= - while [ -z "$TARGET_BUILD_VARIANT" ] - do - echo -n "Which would you like? [$default_value] " - if [ -z "$1" ] ; then - read ANSWER - else - echo $1 - ANSWER=$1 - fi - - if [ -z "$ANSWER" ] ; then - export TARGET_BUILD_VARIANT=$default_value - elif (echo -n $ANSWER | grep -q -e "^[0-9][0-9]*$") ; then - if [ "$ANSWER" -le "${#VARIANT_CHOICES[@]}" ] ; then - export TARGET_BUILD_VARIANT=${VARIANT_CHOICES[@]:$(($ANSWER-1)):1} - fi - else - if check_variant $ANSWER - then - export TARGET_BUILD_VARIANT=$ANSWER - else - echo "** Not a valid variant: $ANSWER" - fi - fi - if [ -n "$1" ] ; then - break - fi - done -} - -function choosecombo() -{ - choosetype $1 - - echo - echo - chooseproduct $2 - - echo - echo - choosevariant $3 - - echo - build_build_var_cache - set_stuff_for_environment - printconfig - destroy_build_var_cache -} - function add_lunch_combo() { if [ -n "$ZSH_VERSION" ]; then @@ -730,7 +407,7 @@ function print_lunch_menu() { local uname=$(uname) local choices - choices=$(TARGET_BUILD_APPS= TARGET_PRODUCT= TARGET_RELEASE= TARGET_BUILD_VARIANT= get_build_var COMMON_LUNCH_CHOICES 2>/dev/null) + choices=$(TARGET_BUILD_APPS= TARGET_PRODUCT= TARGET_RELEASE= TARGET_BUILD_VARIANT= _get_build_var_cached COMMON_LUNCH_CHOICES 2>/dev/null) local ret=$? echo @@ -789,7 +466,7 @@ function lunch() selection=aosp_cf_x86_64_phone-trunk_staging-eng elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$") then - local choices=($(TARGET_BUILD_APPS= TARGET_PRODUCT= TARGET_RELEASE= TARGET_BUILD_VARIANT= get_build_var COMMON_LUNCH_CHOICES 2>/dev/null)) + local choices=($(TARGET_BUILD_APPS= TARGET_PRODUCT= TARGET_RELEASE= TARGET_BUILD_VARIANT= _get_build_var_cached COMMON_LUNCH_CHOICES 2>/dev/null)) if [ $answer -le ${#choices[@]} ] then # array in zsh starts from 1 instead of 0. @@ -831,8 +508,8 @@ function lunch() fi return 1 fi - export TARGET_PRODUCT=$(get_build_var TARGET_PRODUCT) - export TARGET_BUILD_VARIANT=$(get_build_var TARGET_BUILD_VARIANT) + export TARGET_PRODUCT=$(_get_build_var_cached TARGET_PRODUCT) + export TARGET_BUILD_VARIANT=$(_get_build_var_cached TARGET_BUILD_VARIANT) export TARGET_RELEASE=$release # Note this is the string "release", not the value of the variable. export TARGET_BUILD_TYPE=release @@ -869,7 +546,7 @@ function _lunch() prev="${COMP_WORDS[COMP_CWORD-1]}" if [ -z "$COMMON_LUNCH_CHOICES_CACHE" ]; then - COMMON_LUNCH_CHOICES_CACHE=$(TARGET_BUILD_APPS= get_build_var COMMON_LUNCH_CHOICES) + COMMON_LUNCH_CHOICES_CACHE=$(TARGET_BUILD_APPS= _get_build_var_cached COMMON_LUNCH_CHOICES) fi COMPREPLY=( $(compgen -W "${COMMON_LUNCH_CHOICES_CACHE}" -- ${cur}) ) @@ -1013,34 +690,6 @@ function banchan() destroy_build_var_cache } -# TODO: Merge into gettop as part of launching multitree -function multitree_gettop -{ - local TOPFILE=orchestrator/build/make/core/envsetup.mk - if [ -n "$TOP" -a -f "$TOP/$TOPFILE" ] ; then - # The following circumlocution ensures we remove symlinks from TOP. - (cd "$TOP"; PWD= /bin/pwd) - else - if [ -f $TOPFILE ] ; then - # The following circumlocution (repeated below as well) ensures - # that we record the true directory name and not one that is - # faked up with symlink names. - PWD= /bin/pwd - else - local HERE=$PWD - local T= - while [ \( ! \( -f $TOPFILE \) \) -a \( "$PWD" != "/" \) ]; do - \cd .. - T=`PWD= /bin/pwd -P` - done - \cd "$HERE" - if [ -f "$T/$TOPFILE" ]; then - echo "$T" - fi - fi - fi -} - function croot() { local T=$(gettop) @@ -1131,11 +780,11 @@ function run_tool_with_logging() { # Remove the trap to prevent duplicate log. trap - EXIT; "${logger}" \ - --tool_tag "${tool_tag}" \ - --start_timestamp "${start_time}" \ - --end_timestamp "$(date +%s.%N)" \ - --tool_args "$*" \ - --exit_code "${exit_code}" \ + --tool_tag="${tool_tag}" \ + --start_timestamp="${start_time}" \ + --end_timestamp="$(date +%s.%N)" \ + --tool_args="$*" \ + --exit_code="${exit_code}" \ ${ANDROID_TOOL_LOGGER_EXTRA_ARGS} \ > /dev/null 2>&1 & exit ${exit_code} @@ -1146,289 +795,6 @@ function run_tool_with_logging() { ) } -# simplified version of ps; output in the form -# <pid> <procname> -function qpid() { - local prepend='' - local append='' - if [ "$1" = "--exact" ]; then - prepend=' ' - append='$' - shift - elif [ "$1" = "--help" -o "$1" = "-h" ]; then - echo "usage: qpid [[--exact] <process name|pid>" - return 255 - fi - - local EXE="$1" - if [ "$EXE" ] ; then - qpid | \grep "$prepend$EXE$append" - else - adb shell ps \ - | tr -d '\r' \ - | sed -e 1d -e 's/^[^ ]* *\([0-9]*\).* \([^ ]*\)$/\1 \2/' - fi -} - -# syswrite - disable verity, reboot if needed, and remount image -# -# Easy way to make system.img/etc writable -function syswrite() { - adb wait-for-device && adb root && adb wait-for-device || return 1 - if [[ $(adb disable-verity | grep -i "reboot") ]]; then - echo "rebooting" - adb reboot && adb wait-for-device && adb root && adb wait-for-device || return 1 - fi - adb remount || return 1 -} - -# coredump_setup - enable core dumps globally for any process -# that has the core-file-size limit set correctly -# -# NOTE: You must call also coredump_enable for a specific process -# if its core-file-size limit is not set already. -# NOTE: Core dumps are written to ramdisk; they will not survive a reboot! - -function coredump_setup() -{ - echo "Getting root..."; - adb root; - adb wait-for-device; - - echo "Remounting root partition read-write..."; - adb shell mount -w -o remount -t rootfs rootfs; - sleep 1; - adb wait-for-device; - adb shell mkdir -p /cores; - adb shell mount -t tmpfs tmpfs /cores; - adb shell chmod 0777 /cores; - - echo "Granting SELinux permission to dump in /cores..."; - adb shell restorecon -R /cores; - - echo "Set core pattern."; - adb shell 'echo /cores/core.%p > /proc/sys/kernel/core_pattern'; - - echo "Done." -} - -# coredump_enable - enable core dumps for the specified process -# $1 = PID of process (e.g., $(pid mediaserver)) -# -# NOTE: coredump_setup must have been called as well for a core -# dump to actually be generated. - -function coredump_enable() -{ - local PID=$1; - if [ -z "$PID" ]; then - printf "Expecting a PID!\n"; - return; - fi; - echo "Setting core limit for $PID to infinite..."; - adb shell /system/bin/ulimit -P $PID -c unlimited -} - -# core - send SIGV and pull the core for process -# $1 = PID of process (e.g., $(pid mediaserver)) -# -# NOTE: coredump_setup must be called once per boot for core dumps to be -# enabled globally. - -function core() -{ - local PID=$1; - - if [ -z "$PID" ]; then - printf "Expecting a PID!\n"; - return; - fi; - - local CORENAME=core.$PID; - local COREPATH=/cores/$CORENAME; - local SIG=SEGV; - - coredump_enable $1; - - local done=0; - while [ $(adb shell "[ -d /proc/$PID ] && echo -n yes") ]; do - printf "\tSending SIG%s to %d...\n" $SIG $PID; - adb shell kill -$SIG $PID; - sleep 1; - done; - - adb shell "while [ ! -f $COREPATH ] ; do echo waiting for $COREPATH to be generated; sleep 1; done" - echo "Done: core is under $COREPATH on device."; -} - -# systemstack - dump the current stack trace of all threads in the system process -# to the usual ANR traces file -function systemstack() -{ - stacks system_server -} - -# Read the ELF header from /proc/$PID/exe to determine if the process is -# 64-bit. -function is64bit() -{ - local PID="$1" - if [ "$PID" ] ; then - if [[ "$(adb shell cat /proc/$PID/exe | xxd -l 1 -s 4 -p)" -eq "02" ]] ; then - echo "64" - else - echo "" - fi - else - echo "" - fi -} - -case `uname -s` in - Darwin) - function sgrep() - { - find -E . -name .repo -prune -o -name .git -prune -o -type f -iregex '.*\.(c|h|cc|cpp|hpp|S|java|kt|xml|sh|mk|aidl|vts|proto|rs|go)' \ - -exec grep --color -n "$@" {} + - } - - ;; - *) - function sgrep() - { - find . -name .repo -prune -o -name .git -prune -o -type f -iregex '.*\.\(c\|h\|cc\|cpp\|hpp\|S\|java\|kt\|xml\|sh\|mk\|aidl\|vts\|proto\|rs\|go\)' \ - -exec grep --color -n "$@" {} + - } - ;; -esac - -function gettargetarch -{ - get_build_var TARGET_ARCH -} - -function ggrep() -{ - find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.gradle" \ - -exec grep --color -n "$@" {} + -} - -function gogrep() -{ - find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.go" \ - -exec grep --color -n "$@" {} + -} - -function jgrep() -{ - find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.java" \ - -exec grep --color -n "$@" {} + -} - -function rsgrep() -{ - find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.rs" \ - -exec grep --color -n "$@" {} + -} - -function jsongrep() -{ - find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.json" \ - -exec grep --color -n "$@" {} + -} - -function tomlgrep() -{ - find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.toml" \ - -exec grep --color -n "$@" {} + -} - -function ktgrep() -{ - find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.kt" \ - -exec grep --color -n "$@" {} + -} - -function cgrep() -{ - find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) \ - -exec grep --color -n "$@" {} + -} - -function resgrep() -{ - local dir - for dir in `find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -name res -type d`; do - find $dir -type f -name '*\.xml' -exec grep --color -n "$@" {} + - done -} - -function mangrep() -{ - find . -name .repo -prune -o -name .git -prune -o -path ./out -prune -o -type f -name 'AndroidManifest.xml' \ - -exec grep --color -n "$@" {} + -} - -function owngrep() -{ - find . -name .repo -prune -o -name .git -prune -o -path ./out -prune -o -type f -name 'OWNERS' \ - -exec grep --color -n "$@" {} + -} - -function sepgrep() -{ - find . -name .repo -prune -o -name .git -prune -o -path ./out -prune -o -name sepolicy -type d \ - -exec grep --color -n -r --exclude-dir=\.git "$@" {} + -} - -function rcgrep() -{ - find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.rc*" \ - -exec grep --color -n "$@" {} + -} - -function pygrep() -{ - find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.py" \ - -exec grep --color -n "$@" {} + -} - -case `uname -s` in - Darwin) - function mgrep() - { - find -E . -name .repo -prune -o -name .git -prune -o -path ./out -prune -o \( -iregex '.*/(Makefile|Makefile\..*|.*\.make|.*\.mak|.*\.mk|.*\.bp)' -o -regex '(.*/)?(build|soong)/.*[^/]*\.go' \) -type f \ - -exec grep --color -n "$@" {} + - } - - function treegrep() - { - find -E . -name .repo -prune -o -name .git -prune -o -type f -iregex '.*\.(c|h|cpp|hpp|S|java|kt|xml)' \ - -exec grep --color -n -i "$@" {} + - } - - ;; - *) - function mgrep() - { - find . -name .repo -prune -o -name .git -prune -o -path ./out -prune -o \( -regextype posix-egrep -iregex '(.*\/Makefile|.*\/Makefile\..*|.*\.make|.*\.mak|.*\.mk|.*\.bp)' -o -regextype posix-extended -regex '(.*/)?(build|soong)/.*[^/]*\.go' \) -type f \ - -exec grep --color -n "$@" {} + - } - - function treegrep() - { - find . -name .repo -prune -o -name .git -prune -o -regextype posix-egrep -iregex '.*\.(c|h|cpp|hpp|S|java|kt|xml)' -type f \ - -exec grep --color -n -i "$@" {} + - } - - ;; -esac - -function getprebuilt -{ - get_abs_build_var ANDROID_PREBUILTS -} - # communicate with a running device or emulator, set up necessary state, # and run the hat command. function runhat() @@ -1481,111 +847,6 @@ function runhat() hat -JXmx512m $localFile } -function getbugreports() -{ - local reports=(`adb shell ls /sdcard/bugreports | tr -d '\r'`) - - if [ ! "$reports" ]; then - echo "Could not locate any bugreports." - return - fi - - local report - for report in ${reports[@]} - do - echo "/sdcard/bugreports/${report}" - adb pull /sdcard/bugreports/${report} ${report} - gunzip ${report} - done -} - -function getsdcardpath() -{ - adb ${adbOptions} shell echo -n \$\{EXTERNAL_STORAGE\} -} - -function getscreenshotpath() -{ - echo "$(getsdcardpath)/Pictures/Screenshots" -} - -function getlastscreenshot() -{ - local screenshot_path=$(getscreenshotpath) - local screenshot=`adb ${adbOptions} ls ${screenshot_path} | grep Screenshot_[0-9-]*.*\.png | sort -rk 3 | cut -d " " -f 4 | head -n 1` - if [ "$screenshot" = "" ]; then - echo "No screenshots found." - return - fi - echo "${screenshot}" - adb ${adbOptions} pull ${screenshot_path}/${screenshot} -} - -function startviewserver() -{ - local port=4939 - if [ $# -gt 0 ]; then - port=$1 - fi - adb shell service call window 1 i32 $port -} - -function stopviewserver() -{ - adb shell service call window 2 -} - -function isviewserverstarted() -{ - adb shell service call window 3 -} - -function key_home() -{ - adb shell input keyevent 3 -} - -function key_back() -{ - adb shell input keyevent 4 -} - -function key_menu() -{ - adb shell input keyevent 82 -} - -function smoketest() -{ - if [ ! "$ANDROID_PRODUCT_OUT" ]; then - echo "Couldn't locate output files. Try running 'lunch' first." >&2 - return - fi - local T=$(gettop) - if [ ! "$T" ]; then - echo "Couldn't locate the top of the tree. Try setting TOP." >&2 - return - fi - - (\cd "$T" && mmm tests/SmokeTest) && - adb uninstall com.android.smoketest > /dev/null && - adb uninstall com.android.smoketest.tests > /dev/null && - adb install $ANDROID_PRODUCT_OUT/data/app/SmokeTestApp.apk && - adb install $ANDROID_PRODUCT_OUT/data/app/SmokeTest.apk && - adb shell am instrument -w com.android.smoketest.tests/android.test.InstrumentationTestRunner -} - -# simple shortcut to the runtest command -function runtest() -{ - local T=$(gettop) - if [ ! "$T" ]; then - echo "Couldn't locate the top of the tree. Try setting TOP." >&2 - return - fi - ("$T"/development/testrunner/runtest.py $@) -} - function godir () { if [[ -z "$1" ]]; then echo "Usage: godir <regex>" @@ -1637,146 +898,10 @@ function godir () { \cd $T/$pathname } -# Update module-info.json in out. -function refreshmod() { - if [ ! "$ANDROID_PRODUCT_OUT" ]; then - echo "No ANDROID_PRODUCT_OUT. Try running 'lunch' first." >&2 - return 1 - fi - - echo "Refreshing modules (building module-info.json). Log at $ANDROID_PRODUCT_OUT/module-info.json.build.log." >&2 - - # for the output of the next command - mkdir -p $ANDROID_PRODUCT_OUT || return 1 - - # Note, can't use absolute path because of the way make works. - m $(get_build_var PRODUCT_OUT)/module-info.json \ - > $ANDROID_PRODUCT_OUT/module-info.json.build.log 2>&1 -} - -# Verifies that module-info.txt exists, returning nonzero if it doesn't. -function verifymodinfo() { - if [ ! "$ANDROID_PRODUCT_OUT" ]; then - if [ "$QUIET_VERIFYMODINFO" != "true" ] ; then - echo "No ANDROID_PRODUCT_OUT. Try running 'lunch' first." >&2 - fi - return 1 - fi - - if [ ! -f "$ANDROID_PRODUCT_OUT/module-info.json" ]; then - if [ "$QUIET_VERIFYMODINFO" != "true" ] ; then - echo "Could not find module-info.json. Please run 'refreshmod' first." >&2 - fi - return 1 - fi -} - -# List all modules for the current device, as cached in all_modules.txt. If any build change is -# made and it should be reflected in the output, you should run `m nothing` first. -function allmod() { - cat $ANDROID_PRODUCT_OUT/all_modules.txt 2>/dev/null -} - -# Return the Bazel label of a Soong module if it is converted with bp2build. -function bmod() -( - if [ $# -eq 0 ]; then - echo "usage: bmod <module 1> <module 2> ... <module n>" >&2 - return 1 - fi - - # We could run bp2build here, but it might trigger bp2build invalidation - # when used with `b` (e.g. --run_soong_tests) and/or add unnecessary waiting - # time overhead. - # - # For a snappy result, use the latest generated version in soong_injection, - # and ask users to run m bp2build if it doesn't exist. - converted_json="$(get_abs_build_var OUT_DIR)/soong/soong_injection/metrics/converted_modules_path_map.json" - - if [ ! -f ${converted_json} ]; then - echo "bp2build files not found. Have you ran 'm bp2build'?" >&2 - return 1 - fi - - modules=() - for m in "$@"; do - modules+=("\"$m\",") - done - local res=$(python3 -c "import json -modules = [${modules[*]}] -converted_json='$converted_json' -bp2build_converted_map = json.load(open(converted_json)) -for module in modules: - if module not in bp2build_converted_map: - print(module + ' is not converted to Bazel.') - else: - print(bp2build_converted_map[module] + ':' + module)") - - echo "${res}" - unconverted_count=$(echo "${res}" | grep -c "not converted to Bazel") - if [[ ${unconverted_count} -ne 0 ]]; then - return 1 - fi -) - -# Get the path of a specific module in the android tree, as cached in module-info.json. -# If any build change is made, and it should be reflected in the output, you should run -# 'refreshmod' first. Note: This is the inverse of dirmods. -function pathmod() { - if [[ $# -ne 1 ]]; then - echo "usage: pathmod <module>" >&2 - return 1 - fi - - verifymodinfo || return 1 - - local relpath=$(python3 -c "import json, os -module = '$1' -module_info = json.load(open('$ANDROID_PRODUCT_OUT/module-info.json')) -if module not in module_info: - exit(1) -print(module_info[module]['path'][0])" 2>/dev/null) - - if [ -z "$relpath" ]; then - echo "Could not find module '$1' (try 'refreshmod' if there have been build changes?)." >&2 - return 1 - else - echo "$ANDROID_BUILD_TOP/$relpath" - fi -} - -# Get the path of a specific module in the android tree, as cached in module-info.json. -# If any build change is made, and it should be reflected in the output, you should run -# 'refreshmod' first. Note: This is the inverse of pathmod. -function dirmods() { - if [[ $# -ne 1 ]]; then - echo "usage: dirmods <path>" >&2 - return 1 - fi - - verifymodinfo || return 1 - - python3 -c "import json, os -dir = '$1' -while dir.endswith('/'): - dir = dir[:-1] -prefix = dir + '/' -module_info = json.load(open('$ANDROID_PRODUCT_OUT/module-info.json')) -results = set() -for m in module_info.values(): - for path in m.get(u'path', []): - if path == dir or path.startswith(prefix): - name = m.get(u'module_name') - if name: - results.add(name) -for name in sorted(results): - print(name) -" -} - - # Go to a specific module in the android tree, as cached in module-info.json. If any build change # is made, and it should be reflected in the output, you should run 'refreshmod' first. +# Note: This function is in envsetup because changing the directory needs to happen in the current +# shell. All other functions that use module-info.json should be in build/soong/bin. function gomod() { if [[ $# -ne 1 ]]; then echo "usage: gomod <module>" >&2 @@ -1790,90 +915,11 @@ function gomod() { cd $path } -# Gets the list of a module's installed outputs, as cached in module-info.json. -# If any build change is made, and it should be reflected in the output, you should run 'refreshmod' first. -function outmod() { - if [[ $# -ne 1 ]]; then - echo "usage: outmod <module>" >&2 - return 1 - fi - - verifymodinfo || return 1 - - local relpath - relpath=$(python3 -c "import json, os -module = '$1' -module_info = json.load(open('$ANDROID_PRODUCT_OUT/module-info.json')) -if module not in module_info: - exit(1) -for output in module_info[module]['installed']: - print(os.path.join('$ANDROID_BUILD_TOP', output))" 2>/dev/null) - - if [ $? -ne 0 ]; then - echo "Could not find module '$1' (try 'refreshmod' if there have been build changes?)" >&2 - return 1 - elif [ ! -z "$relpath" ]; then - echo "$relpath" - fi -} - -# adb install a module's apk, as cached in module-info.json. If any build change -# is made, and it should be reflected in the output, you should run 'refreshmod' first. -# Usage: installmod [adb install arguments] <module> -# For example: installmod -r Dialer -> adb install -r /path/to/Dialer.apk -function installmod() { - if [[ $# -eq 0 ]]; then - echo "usage: installmod [adb install arguments] <module>" >&2 - echo "" >&2 - echo "Only flags to be passed after the \"install\" in adb install are supported," >&2 - echo "with the exception of -s. If -s is passed it will be placed before the \"install\"." >&2 - echo "-s must be the first flag passed if it exists." >&2 - return 1 - fi - - local _path - _path=$(outmod ${@:$#:1}) - if [ $? -ne 0 ]; then - return 1 - fi - - _path=$(echo "$_path" | grep -E \\.apk$ | head -n 1) - if [ -z "$_path" ]; then - echo "Module '$1' does not produce a file ending with .apk (try 'refreshmod' if there have been build changes?)" >&2 - return 1 - fi - local serial_device="" - if [[ "$1" == "-s" ]]; then - if [[ $# -le 2 ]]; then - echo "-s requires an argument" >&2 - return 1 - fi - serial_device="-s $2" - shift 2 - fi - local length=$(( $# - 1 )) - echo adb $serial_device install ${@:1:$length} $_path - adb $serial_device install ${@:1:$length} $_path -} - function _complete_android_module_names() { local word=${COMP_WORDS[COMP_CWORD]} COMPREPLY=( $(allmod | grep -E "^$word") ) } -# Print colored exit condition -function pez { - "$@" - local retval=$? - if [ $retval -ne 0 ] - then - echo $'\E'"[0;31mFAILURE\e[00m" - else - echo $'\E'"[0;32mSUCCESS\e[00m" - fi - return $retval -} - function get_make_command() { # If we're in the top of an Android tree, use soong_ui.bash instead of make @@ -1891,142 +937,11 @@ function get_make_command() fi } -function _wrap_build() -{ - if [[ "${ANDROID_QUIET_BUILD:-}" == true ]]; then - "$@" - return $? - fi - local start_time=$(date +"%s") - "$@" - local ret=$? - local end_time=$(date +"%s") - local tdiff=$(($end_time-$start_time)) - local hours=$(($tdiff / 3600 )) - local mins=$((($tdiff % 3600) / 60)) - local secs=$(($tdiff % 60)) - local ncolors=$(tput colors 2>/dev/null) - if [ -n "$ncolors" ] && [ $ncolors -ge 8 ]; then - color_failed=$'\E'"[0;31m" - color_success=$'\E'"[0;32m" - color_warning=$'\E'"[0;33m" - color_reset=$'\E'"[00m" - else - color_failed="" - color_success="" - color_reset="" - fi - - echo - if [ $ret -eq 0 ] ; then - echo -n "${color_success}#### build completed successfully " - else - echo -n "${color_failed}#### failed to build some targets " - fi - if [ $hours -gt 0 ] ; then - printf "(%02g:%02g:%02g (hh:mm:ss))" $hours $mins $secs - elif [ $mins -gt 0 ] ; then - printf "(%02g:%02g (mm:ss))" $mins $secs - elif [ $secs -gt 0 ] ; then - printf "(%s seconds)" $secs - fi - echo " ####${color_reset}" - echo - return $ret -} - -function _trigger_build() -( - local -r bc="$1"; shift - local T=$(gettop) - if [ -n "$T" ]; then - _wrap_build "$T/build/soong/soong_ui.bash" --build-mode --${bc} --dir="$(pwd)" "$@" - else - >&2 echo "Couldn't locate the top of the tree. Try setting TOP." - return 1 - fi - local ret=$? - if [[ ret -eq 0 && -z "${ANDROID_QUIET_BUILD:-}" && -n "${ANDROID_BUILD_BANNER}" ]]; then - echo "${ANDROID_BUILD_BANNER}" - fi - return $ret -) - -function m() -( - _trigger_build "all-modules" "$@" -) - -function mm() -( - _trigger_build "modules-in-a-dir-no-deps" "$@" -) - -function mmm() -( - _trigger_build "modules-in-dirs-no-deps" "$@" -) - -function mma() -( - _trigger_build "modules-in-a-dir" "$@" -) - -function mmma() -( - _trigger_build "modules-in-dirs" "$@" -) - function make() { _wrap_build $(get_make_command "$@") "$@" } -function _multitree_lunch_error() -{ - >&2 echo "Couldn't locate the top of the tree. Please run \'source build/envsetup.sh\' and multitree_lunch from the root of your workspace." -} - -function multitree_build() -{ - local T=$(multitree_gettop) - if [ -n "$T" ]; then - "$T/orchestrator/build/orchestrator/core/orchestrator.py" "$@" - else - _multitree_lunch_error - return 1 - fi -} - -function provision() -{ - if [ ! "$ANDROID_PRODUCT_OUT" ]; then - echo "Couldn't locate output files. Try running 'lunch' first." >&2 - return 1 - fi - if [ ! -e "$ANDROID_PRODUCT_OUT/provision-device" ]; then - echo "There is no provisioning script for the device." >&2 - return 1 - fi - - # Check if user really wants to do this. - if [ "$1" = "--no-confirmation" ]; then - shift 1 - else - echo "This action will reflash your device." - echo "" - echo "ALL DATA ON THE DEVICE WILL BE IRREVOCABLY ERASED." - echo "" - echo -n "Are you sure you want to do this (yes/no)? " - read - if [[ "${REPLY}" != "yes" ]] ; then - echo "Not taking any action. Exiting." >&2 - return 1 - fi - fi - "$ANDROID_PRODUCT_OUT/provision-device" "$@" -} - # Zsh needs bashcompinit called to support bash-style completion. function enable_zsh_completion() { # Don't override user's options if bash-style completion is already enabled. @@ -2108,7 +1023,7 @@ function showcommands() { return ;; esac - OUT_DIR="$(get_abs_build_var OUT_DIR)" + OUT_DIR="$(_get_abs_build_var_cached OUT_DIR)" if [[ "$1" == "--regenerate" ]]; then shift 1 NINJA_ARGS="-t commands $@" m @@ -2119,25 +1034,67 @@ function showcommands() { fi } -function avbtool() { - if [[ ! -f "$ANDROID_SOONG_HOST_OUT"/bin/avbtool ]]; then - m avbtool - fi - "$ANDROID_SOONG_HOST_OUT"/bin/avbtool $@ -} +# These functions used to be here but are now standalone scripts +# in build/soong/bin. Unset these for the time being so the real +# script is picked up. +# TODO: Remove this some time after a suitable delay (maybe 2025?) +unset allmod +unset aninja +unset cgrep +unset core +unset coredump_enable +unset coredump_setup +unset dirmods +unset get_build_var +unset get_abs_build_var +unset getlastscreenshot +unset getprebuilt +unset getscreenshotpath +unset getsdcardpath +unset gettargetarch +unset ggrep +unset gogrep +unset hmm +unset installmod +unset is64bit +unset isviewserverstarted +unset jgrep +unset jsongrep +unset key_back +unset key_home +unset key_menu +unset ktgrep +unset m +unset mangrep +unset mgrep +unset mm +unset mma +unset mmm +unset mmma +unset outmod +unset overrideflags +unset owngrep +unset pathmod +unset pez +unset pygrep +unset qpid +unset rcgrep +unset refreshmod +unset resgrep +unset rsgrep +unset sepgrep +unset sgrep +unset startviewserver +unset stopviewserver +unset systemstack +unset syswrite +unset tomlgrep +unset treegrep -function overrideflags() { - local T="$(gettop)" - (\cd "${T}" && build/make/tools/overrideflags.sh "$@") -} - -function aninja() { - local T="$(gettop)" - (\cd "${T}" && prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-${TARGET_PRODUCT}.ninja "$@") -} validate_current_shell set_global_paths source_vendorsetup addcompletions + diff --git a/shell_utils.sh b/shell_utils.sh index 9de5a504e5..450bb836a6 100644 --- a/shell_utils.sh +++ b/shell_utils.sh @@ -40,15 +40,24 @@ function gettop fi } -# Sets TOP, or if the root of the tree can't be found, prints a message and -# exits. Since this function exits, it should not be called from functions -# defined in envsetup.sh. +# Asserts that the root of the tree can be found. if [ -z "${IMPORTING_ENVSETUP:-}" ] ; then function require_top { TOP=$(gettop) if [[ ! $TOP ]] ; then - echo "Can not locate root of source tree. $(basename $0) must be run from within the Android source tree." >&2 + echo "Can not locate root of source tree. $(basename $0) must be run from within the Android source tree or TOP must be set." >&2 + exit 1 + fi +} +fi + +# Asserts that the lunch variables have been set +if [ -z "${IMPORTING_ENVSETUP:-}" ] ; then +function require_lunch +{ + if [[ ! $TARGET_PRODUCT || ! $TARGET_RELEASE || ! $TARGET_BUILD_VARIANT ]] ; then + echo "Please run lunch and try again." >&2 exit 1 fi } @@ -71,4 +80,50 @@ function getoutdir echo "${out_dir}" } +# Pretty print the build status and duration +function _wrap_build() +{ + if [[ "${ANDROID_QUIET_BUILD:-}" == true ]]; then + "$@" + return $? + fi + local start_time=$(date +"%s") + "$@" + local ret=$? + local end_time=$(date +"%s") + local tdiff=$(($end_time-$start_time)) + local hours=$(($tdiff / 3600 )) + local mins=$((($tdiff % 3600) / 60)) + local secs=$(($tdiff % 60)) + local ncolors=$(tput colors 2>/dev/null) + if [ -n "$ncolors" ] && [ $ncolors -ge 8 ]; then + color_failed=$'\E'"[0;31m" + color_success=$'\E'"[0;32m" + color_warning=$'\E'"[0;33m" + color_reset=$'\E'"[00m" + else + color_failed="" + color_success="" + color_reset="" + fi + + echo + if [ $ret -eq 0 ] ; then + echo -n "${color_success}#### build completed successfully " + else + echo -n "${color_failed}#### failed to build some targets " + fi + if [ $hours -gt 0 ] ; then + printf "(%02g:%02g:%02g (hh:mm:ss))" $hours $mins $secs + elif [ $mins -gt 0 ] ; then + printf "(%02g:%02g (mm:ss))" $mins $secs + elif [ $secs -gt 0 ] ; then + printf "(%s seconds)" $secs + fi + echo " ####${color_reset}" + echo + return $ret +} + + diff --git a/target/board/ndk/BoardConfig.mk b/target/board/ndk/BoardConfig.mk index d5399b226b..e367918a8d 100644 --- a/target/board/ndk/BoardConfig.mk +++ b/target/board/ndk/BoardConfig.mk @@ -14,7 +14,3 @@ # TARGET_ARCH_SUITE := ndk - -MALLOC_LOW_MEMORY := true - -USE_SAFESTACK := false diff --git a/target/product/base_system.mk b/target/product/base_system.mk index 22284b1c18..634bf668ce 100644 --- a/target/product/base_system.mk +++ b/target/product/base_system.mk @@ -172,7 +172,6 @@ PRODUCT_PACKAGES += \ libjpeg \ liblog \ libm.bootstrap \ - libmdnssd \ libmedia \ libmedia_jni \ libmediandk \ @@ -289,6 +288,7 @@ PRODUCT_PACKAGES += \ uncrypt \ usbd \ vdc \ + vintf \ voip-common \ vold \ watchdogd \ diff --git a/target/product/gsi_release.mk b/target/product/gsi_release.mk index 884b419868..5044a39184 100644 --- a/target/product/gsi_release.mk +++ b/target/product/gsi_release.mk @@ -50,10 +50,13 @@ PRODUCT_PACKAGES += \ init.gsi.rc \ init.vndk-nodef.rc \ + # Overlay the GSI specific SystemUI setting -PRODUCT_PACKAGES += gsi_overlay_systemui -PRODUCT_COPY_FILES += \ - device/generic/common/overlays/overlay-config.xml:$(TARGET_COPY_OUT_SYSTEM_EXT)/overlay/config/config.xml +ifneq ($(PRODUCT_IS_AUTOMOTIVE),true) + PRODUCT_PACKAGES += gsi_overlay_systemui + PRODUCT_COPY_FILES += \ + device/generic/common/overlays/overlay-config.xml:$(TARGET_COPY_OUT_SYSTEM_EXT)/overlay/config/config.xml +endif # b/308878144 no more VNDK on 24Q1 and beyond KEEP_VNDK ?= false diff --git a/target/product/ndk.mk b/target/product/ndk.mk index 1dfd0db328..e4f77f74c4 100644 --- a/target/product/ndk.mk +++ b/target/product/ndk.mk @@ -19,3 +19,5 @@ PRODUCT_NAME := ndk PRODUCT_BRAND := Android PRODUCT_DEVICE := ndk + +PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO := true diff --git a/target/product/virtual_ab_ota/vabc_features.mk b/target/product/virtual_ab_ota/vabc_features.mk index 3f484e4f3e..1219763b0d 100644 --- a/target/product/virtual_ab_ota/vabc_features.mk +++ b/target/product/virtual_ab_ota/vabc_features.mk @@ -34,6 +34,21 @@ PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.io_uring.enabled=true PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.xor.enabled=true PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.batch_writes=true +# Low memory device configurations. If memory usage and cpu utilization is +# a bottleneck during OTA, the below configurations can be added to a +# device's .mk file improve performance for low mem devices. Disabling +# ro.virtual_ab.compression.xor.enabled and ro.virtual_ab.io_uring.enabled +# is also recommended +# +# PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.o_direct.enabled=true +# PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.merge_thread_priority=19 +# PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.worker_thread_priority=0 +# PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.num_worker_threads=3 +# PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.num_merge_threads=1 +# PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.num_verify_threads=1 +# PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.cow_op_merge_size=16 +# PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.verify_threshold_size=1073741824 +# PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.verify_block_size=1048576 # Enabling this property, will improve OTA install time # but will use an additional CPU core diff --git a/tests/run_tool_with_logging_test.py b/tests/run_tool_with_logging_test.py index 18abd8e54f..6f9b59c5c8 100644 --- a/tests/run_tool_with_logging_test.py +++ b/tests/run_tool_with_logging_test.py @@ -90,8 +90,8 @@ class RunToolWithLoggingTest(unittest.TestCase): test_tool.assert_called_once_with_args("arg1 arg2") expected_logger_args = ( - "--tool_tag FAKE_TOOL --start_timestamp \d+\.\d+ --end_timestamp" - " \d+\.\d+ --tool_args arg1 arg2 --exit_code 0" + "--tool_tag=FAKE_TOOL --start_timestamp=\d+\.\d+ --end_timestamp=" + "\d+\.\d+ --tool_args=arg1 arg2 --exit_code=0" ) test_logger.assert_called_once_with_args(expected_logger_args) @@ -163,8 +163,8 @@ class RunToolWithLoggingTest(unittest.TestCase): self.assertEqual(returncode, INTERRUPTED_RETURN_CODE) expected_logger_args = ( - "--tool_tag FAKE_TOOL --start_timestamp \d+\.\d+ --end_timestamp" - " \d+\.\d+ --tool_args arg1 arg2 --exit_code 130" + "--tool_tag=FAKE_TOOL --start_timestamp=\d+\.\d+ --end_timestamp=" + "\d+\.\d+ --tool_args=arg1 arg2 --exit_code=130" ) test_logger.assert_called_once_with_args(expected_logger_args) @@ -205,6 +205,19 @@ class RunToolWithLoggingTest(unittest.TestCase): self._assert_logger_dry_run() + def test_tool_args_do_not_fail_logger(self): + test_tool = TestScript.create(self.working_dir) + logger_path = self._import_logger() + + self._run_script_and_wait(f""" + TMPDIR="{self.working_dir.name}" + ANDROID_TOOL_LOGGER="{logger_path}" + ANDROID_TOOL_LOGGER_EXTRA_ARGS="--dry_run" + run_tool_with_logging "FAKE_TOOL" {test_tool.executable} --tool-arg1 + """) + + self._assert_logger_dry_run() + def _import_logger(self) -> Path: logger = "tool_event_logger" logger_path = Path(self.working_dir.name).joinpath(logger) diff --git a/tools/aconfig/aconfig/templates/cpp_source_file.template b/tools/aconfig/aconfig/templates/cpp_source_file.template index 4c098c5b41..38dda7df31 100644 --- a/tools/aconfig/aconfig/templates/cpp_source_file.template +++ b/tools/aconfig/aconfig/templates/cpp_source_file.template @@ -124,14 +124,14 @@ bool {header}_{item.flag_name}() \{ "{item.container}", aconfig_storage::StorageFileType::package_map); if (!package_map_file.ok()) \{ - ALOGI("error: failed to get package map file: %s", package_map_file.error().message().c_str()); + ALOGI("error: failed to get package map file: %s", package_map_file.error().c_str()); return result; } auto package_read_context = aconfig_storage::get_package_read_context( **package_map_file, "{package}"); if (!package_read_context.ok()) \{ - ALOGI("error: failed to get package read context: %s", package_map_file.error().message().c_str()); + ALOGI("error: failed to get package read context: %s", package_map_file.error().c_str()); return result; } @@ -141,7 +141,7 @@ bool {header}_{item.flag_name}() \{ "{item.container}", aconfig_storage::StorageFileType::flag_val); if (!flag_val_map.ok()) \{ - ALOGI("error: failed to get flag val map: %s", package_map_file.error().message().c_str()); + ALOGI("error: failed to get flag val map: %s", package_map_file.error().c_str()); return result; } @@ -149,7 +149,7 @@ bool {header}_{item.flag_name}() \{ **flag_val_map, package_read_context->boolean_start_index + {item.flag_offset}); if (!value.ok()) \{ - ALOGI("error: failed to get flag val: %s", package_map_file.error().message().c_str()); + ALOGI("error: failed to get flag val: %s", package_map_file.error().c_str()); return result; } diff --git a/tools/aconfig/aconfig_device_paths/src/lib.rs b/tools/aconfig/aconfig_device_paths/src/lib.rs index c5a6bff1f7..7480b3002c 100644 --- a/tools/aconfig/aconfig_device_paths/src/lib.rs +++ b/tools/aconfig/aconfig_device_paths/src/lib.rs @@ -21,11 +21,19 @@ use std::path::PathBuf; use std::fs; +fn read_partition_paths() -> Vec<PathBuf> { + include_str!("../partition_aconfig_flags_paths.txt") + .split(',') + .map(|s| s.trim().trim_matches('"')) + .filter(|s| !s.is_empty()) + .map(|s| PathBuf::from(s.to_string())) + .collect() +} + /// Determine all paths that contain an aconfig protobuf file. pub fn parsed_flags_proto_paths() -> Result<Vec<PathBuf>> { - let mut result: Vec<PathBuf> = [include_str!("../partition_aconfig_flags_paths.txt")] - .map(|s| PathBuf::from(s.to_string())) - .to_vec(); + let mut result: Vec<PathBuf> = read_partition_paths(); + for dir in fs::read_dir("/apex")? { let dir = dir?; @@ -45,3 +53,23 @@ pub fn parsed_flags_proto_paths() -> Result<Vec<PathBuf>> { Ok(result) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_read_partition_paths() { + assert_eq!(read_partition_paths().len(), 4); + + assert_eq!( + read_partition_paths(), + vec![ + PathBuf::from("/system/etc/aconfig_flags.pb"), + PathBuf::from("/system_ext/etc/aconfig_flags.pb"), + PathBuf::from("/product/etc/aconfig_flags.pb"), + PathBuf::from("/vendor/etc/aconfig_flags.pb") + ] + ); + } +} diff --git a/tools/aconfig/aconfig_protos/Android.bp b/tools/aconfig/aconfig_protos/Android.bp index 18c545ae96..d24199443c 100644 --- a/tools/aconfig/aconfig_protos/Android.bp +++ b/tools/aconfig/aconfig_protos/Android.bp @@ -17,7 +17,22 @@ java_library { apex_available: [ "com.android.configinfrastructure", "//apex_available:platform", - ] + ], +} + +java_library { + name: "libaconfig_java_proto_nano", + srcs: ["protos/aconfig.proto"], + static_libs: ["libprotobuf-java-nano"], + proto: { + type: "nano", + }, + sdk_version: "current", + min_sdk_version: "UpsideDownCake", + apex_available: [ + "//apex_available:platform", + ], + jarjar_rules: "jarjar-nano-rules.txt", } java_library_host { @@ -58,7 +73,7 @@ rust_defaults { ], proc_macros: [ "libpaste", - ] + ], } rust_library { diff --git a/tools/aconfig/aconfig_protos/jarjar-nano-rules.txt b/tools/aconfig/aconfig_protos/jarjar-nano-rules.txt new file mode 100644 index 0000000000..b58fa64838 --- /dev/null +++ b/tools/aconfig/aconfig_protos/jarjar-nano-rules.txt @@ -0,0 +1 @@ +rule com.google.protobuf.** android.internal.framework.protobuf.@1
\ No newline at end of file diff --git a/tools/aconfig/aconfig_storage_file/protos/aconfig_storage_metadata.proto b/tools/aconfig/aconfig_storage_file/protos/aconfig_storage_metadata.proto index f6bf1a43c4..e1c1c7ffca 100644 --- a/tools/aconfig/aconfig_storage_file/protos/aconfig_storage_metadata.proto +++ b/tools/aconfig/aconfig_storage_file/protos/aconfig_storage_metadata.proto @@ -27,9 +27,7 @@ message storage_file_info { optional string flag_map = 4; optional string flag_val = 5; optional string flag_info = 6; - optional string local_overrides = 7; - optional string default_flag_val = 8; - optional int64 timestamp = 9; + optional int64 timestamp = 7; } message storage_files { diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp index db362944c5..9b842546f5 100644 --- a/tools/aconfig/aconfig_storage_read_api/Android.bp +++ b/tools/aconfig/aconfig_storage_read_api/Android.bp @@ -9,8 +9,6 @@ rust_defaults { srcs: ["src/lib.rs"], rustlibs: [ "libanyhow", - "libonce_cell", - "libtempfile", "libmemmap2", "libcxx", "libthiserror", @@ -34,6 +32,9 @@ rust_test_host { name: "aconfig_storage_read_api.test", test_suites: ["general-tests"], defaults: ["aconfig_storage_read_api.defaults"], + rustlibs: [ + "librand", + ], data: [ "tests/package.map", "tests/flag.map", @@ -89,14 +90,6 @@ cc_library { host_supported: true, vendor_available: true, product_available: true, - static_libs: [ - "libaconfig_storage_protos_cc", - "libprotobuf-cpp-lite", - ], - shared_libs: [ - "liblog", - "libbase", - ], apex_available: [ "//apex_available:platform", "//apex_available:anyapex", @@ -108,6 +101,7 @@ cc_library { }, }, double_loadable: true, + afdo: true, } cc_defaults { diff --git a/tools/aconfig/aconfig_storage_read_api/Cargo.toml b/tools/aconfig/aconfig_storage_read_api/Cargo.toml index 30a4298826..2b27e4b491 100644 --- a/tools/aconfig/aconfig_storage_read_api/Cargo.toml +++ b/tools/aconfig/aconfig_storage_read_api/Cargo.toml @@ -8,10 +8,9 @@ default = ["cargo"] cargo = [] [dependencies] +rand = "0.8.5" anyhow = "1.0.69" memmap2 = "0.8.0" -once_cell = "1.19.0" -tempfile = "3.9.0" cxx = "1.0" thiserror = "1.0.56" aconfig_storage_file = { path = "../aconfig_storage_file" } diff --git a/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp b/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp index 0aa936a9eb..97ada3a33e 100644 --- a/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp +++ b/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp @@ -1,85 +1,56 @@ -#include <android-base/file.h> -#include <android-base/logging.h> -#include <protos/aconfig_storage_metadata.pb.h> - #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> +#include <errno.h> +#include <string.h> #include "rust/cxx.h" #include "aconfig_storage/lib.rs.h" #include "aconfig_storage/aconfig_storage_read_api.hpp" -using storage_records_pb = android::aconfig_storage_metadata::storage_files; -using storage_record_pb = android::aconfig_storage_metadata::storage_file_info; -using namespace android::base; - namespace aconfig_storage { /// Storage location pb file -static constexpr char kAvailableStorageRecordsPb[] = - "/metadata/aconfig/boot/available_storage_file_records.pb"; +static constexpr char kStorageDir[] = "/metadata/aconfig"; /// destructor MappedStorageFile::~MappedStorageFile() { munmap(file_ptr, file_size); } -/// Read aconfig storage records pb file -static Result<storage_records_pb> read_storage_records_pb(std::string const& pb_file) { - auto records = storage_records_pb(); - auto content = std::string(); - if (!ReadFileToString(pb_file, &content)) { - return ErrnoError() << "ReadFileToString failed"; - } - - if (!records.ParseFromString(content)) { - return ErrnoError() << "Unable to parse persistent storage records protobuf"; - } - return records; -} - /// Get storage file path static Result<std::string> find_storage_file( - std::string const& pb_file, + std::string const& storage_dir, std::string const& container, StorageFileType file_type) { - auto records_pb = read_storage_records_pb(pb_file); - if (!records_pb.ok()) { - return Error() << "Unable to read storage records from " << pb_file - << " : " << records_pb.error(); - } - - for (auto& entry : records_pb->files()) { - if (entry.container() == container) { - switch(file_type) { - case StorageFileType::package_map: - return entry.package_map(); - case StorageFileType::flag_map: - return entry.flag_map(); - case StorageFileType::flag_val: - return entry.flag_val(); - case StorageFileType::flag_info: - return entry.flag_info(); - default: - return Error() << "Invalid file type " << file_type; - } - } + switch(file_type) { + case StorageFileType::package_map: + return storage_dir + "/maps/" + container + ".package.map"; + case StorageFileType::flag_map: + return storage_dir + "/maps/" + container + ".flag.map"; + case StorageFileType::flag_val: + return storage_dir + "/boot/" + container + ".val"; + case StorageFileType::flag_info: + return storage_dir + "/boot/" + container + ".info"; + default: + auto result = Result<std::string>(); + result.errmsg = "Invalid storage file type"; + return result; } - - return Error() << "Unable to find storage files for container " << container;; } namespace private_internal_api { /// Get mapped file implementation. Result<MappedStorageFile*> get_mapped_file_impl( - std::string const& pb_file, + std::string const& storage_dir, std::string const& container, StorageFileType file_type) { - auto file_result = find_storage_file(pb_file, container, file_type); + auto file_result = find_storage_file(storage_dir, container, file_type); if (!file_result.ok()) { - return Error() << file_result.error(); + auto result = Result<MappedStorageFile*>(); + result.errmsg = file_result.error(); + return result; } return map_storage_file(*file_result); } @@ -90,18 +61,24 @@ Result<MappedStorageFile*> get_mapped_file_impl( Result<MappedStorageFile*> map_storage_file(std::string const& file) { int fd = open(file.c_str(), O_CLOEXEC | O_NOFOLLOW | O_RDONLY); if (fd == -1) { - return ErrnoError() << "failed to open " << file; + auto result = Result<MappedStorageFile*>(); + result.errmsg = std::string("failed to open ") + file + ": " + strerror(errno); + return result; }; struct stat fd_stat; if (fstat(fd, &fd_stat) < 0) { - return ErrnoError() << "fstat failed"; + auto result = Result<MappedStorageFile*>(); + result.errmsg = std::string("fstat failed: ") + strerror(errno); + return result; } size_t file_size = fd_stat.st_size; void* const map_result = mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0); if (map_result == MAP_FAILED) { - return ErrnoError() << "mmap failed"; + auto result = Result<MappedStorageFile*>(); + result.errmsg = std::string("mmap failed: ") + strerror(errno); + return result; } auto mapped_file = new MappedStorageFile(); @@ -112,7 +89,7 @@ Result<MappedStorageFile*> map_storage_file(std::string const& file) { } /// Map from StoredFlagType to FlagValueType -android::base::Result<FlagValueType> map_to_flag_value_type( +Result<FlagValueType> map_to_flag_value_type( StoredFlagType stored_type) { switch (stored_type) { case StoredFlagType::ReadWriteBoolean: @@ -120,7 +97,9 @@ android::base::Result<FlagValueType> map_to_flag_value_type( case StoredFlagType::FixedReadOnlyBoolean: return FlagValueType::Boolean; default: - return Error() << "Unsupported stored flag type"; + auto result = Result<FlagValueType>(); + result.errmsg = "Unsupported stored flag type"; + return result; } } @@ -129,7 +108,7 @@ Result<MappedStorageFile*> get_mapped_file( std::string const& container, StorageFileType file_type) { return private_internal_api::get_mapped_file_impl( - kAvailableStorageRecordsPb, container, file_type); + kStorageDir, container, file_type); } /// Get storage file version number @@ -140,7 +119,9 @@ Result<uint32_t> get_storage_file_version( if (version_cxx.query_success) { return version_cxx.version_number; } else { - return Error() << version_cxx.error_message; + auto result = Result<uint32_t>(); + result.errmsg = version_cxx.error_message.c_str(); + return result; } } @@ -158,7 +139,9 @@ Result<PackageReadContext> get_package_read_context( context.boolean_start_index = context_cxx.boolean_start_index; return context; } else { - return Error() << context_cxx.error_message; + auto result = Result<PackageReadContext>(); + result.errmsg = context_cxx.error_message.c_str(); + return result; } } @@ -177,7 +160,9 @@ Result<FlagReadContext> get_flag_read_context( context.flag_index = context_cxx.flag_index; return context; } else { - return Error() << context_cxx.error_message; + auto result = Result<FlagReadContext>(); + result.errmsg = context_cxx.error_message.c_str(); + return result; } } @@ -191,7 +176,9 @@ Result<bool> get_boolean_flag_value( if (value_cxx.query_success) { return value_cxx.flag_value; } else { - return Error() << value_cxx.error_message; + auto result = Result<bool>(); + result.errmsg = value_cxx.error_message.c_str(); + return result; } } @@ -207,7 +194,9 @@ Result<uint8_t> get_flag_attribute( if (info_cxx.query_success) { return info_cxx.flag_attribute; } else { - return Error() << info_cxx.error_message; + auto result = Result<uint8_t>(); + result.errmsg = info_cxx.error_message.c_str(); + return result; } } } // namespace aconfig_storage diff --git a/tools/aconfig/aconfig_storage_read_api/include/aconfig_storage/aconfig_storage_read_api.hpp b/tools/aconfig/aconfig_storage_read_api/include/aconfig_storage/aconfig_storage_read_api.hpp index e6d75373a9..b50935bf69 100644 --- a/tools/aconfig/aconfig_storage_read_api/include/aconfig_storage/aconfig_storage_read_api.hpp +++ b/tools/aconfig/aconfig_storage_read_api/include/aconfig_storage/aconfig_storage_read_api.hpp @@ -2,7 +2,7 @@ #include <stdint.h> #include <string> -#include <android-base/result.h> +#include <cassert> namespace aconfig_storage { @@ -58,46 +58,86 @@ struct FlagReadContext { uint16_t flag_index; }; + +template <class T> +class Result { + public: + + Result() + : data() + , errmsg() + , has_data(false) + {} + + Result(T const& value) + : data(value) + , errmsg() + , has_data(true) + {} + + bool ok() { + return has_data; + } + + T& operator*() { + assert(has_data); + return data; + } + + T* operator->() { + assert(has_data); + return &data; + } + + std::string const& error() { + assert(!has_data); + return errmsg; + } + + T data; + std::string errmsg; + bool has_data; +}; + /// DO NOT USE APIS IN THE FOLLOWING NAMESPACE DIRECTLY namespace private_internal_api { -android::base::Result<MappedStorageFile*> get_mapped_file_impl( +Result<MappedStorageFile*> get_mapped_file_impl( std::string const& pb_file, std::string const& container, StorageFileType file_type); - } // namespace private_internal_api /// Map a storage file -android::base::Result<MappedStorageFile*> map_storage_file( +Result<MappedStorageFile*> map_storage_file( std::string const& file); /// Map from StoredFlagType to FlagValueType /// \input stored_type: stored flag type in the storage file /// \returns the flag value type enum -android::base::Result<FlagValueType> map_to_flag_value_type( +Result<FlagValueType> map_to_flag_value_type( StoredFlagType stored_type); /// Get mapped storage file /// \input container: stoarge container name /// \input file_type: storage file type enum /// \returns a MappedStorageFileQuery -android::base::Result<MappedStorageFile*> get_mapped_file( +Result<MappedStorageFile*> get_mapped_file( std::string const& container, StorageFileType file_type); /// Get storage file version number /// \input file_path: the path to the storage file /// \returns the storage file version -android::base::Result<uint32_t> get_storage_file_version( +Result<uint32_t> get_storage_file_version( std::string const& file_path); /// Get package read context /// \input file: mapped storage file /// \input package: the flag package name /// \returns a package read context -android::base::Result<PackageReadContext> get_package_read_context( +Result<PackageReadContext> get_package_read_context( MappedStorageFile const& file, std::string const& package); @@ -106,7 +146,7 @@ android::base::Result<PackageReadContext> get_package_read_context( /// \input package_id: the flag package id obtained from package offset query /// \input flag_name: flag name /// \returns the flag read context -android::base::Result<FlagReadContext> get_flag_read_context( +Result<FlagReadContext> get_flag_read_context( MappedStorageFile const& file, uint32_t package_id, std::string const& flag_name); @@ -115,7 +155,7 @@ android::base::Result<FlagReadContext> get_flag_read_context( /// \input file: mapped storage file /// \input index: the boolean flag index in the file /// \returns the boolean flag value -android::base::Result<bool> get_boolean_flag_value( +Result<bool> get_boolean_flag_value( MappedStorageFile const& file, uint32_t index); @@ -124,7 +164,7 @@ android::base::Result<bool> get_boolean_flag_value( /// \input value_type: flag value type /// \input index: the boolean flag index in the file /// \returns the boolean flag attribute -android::base::Result<uint8_t> get_flag_attribute( +Result<uint8_t> get_flag_attribute( MappedStorageFile const& file, FlagValueType value_type, uint32_t index); diff --git a/tools/aconfig/aconfig_storage_read_api/src/lib.rs b/tools/aconfig/aconfig_storage_read_api/src/lib.rs index e4192066d5..61f9e96f84 100644 --- a/tools/aconfig/aconfig_storage_read_api/src/lib.rs +++ b/tools/aconfig/aconfig_storage_read_api/src/lib.rs @@ -42,9 +42,6 @@ pub mod flag_value_query; pub mod mapped_file; pub mod package_table_query; -#[cfg(test)] -mod test_utils; - pub use aconfig_storage_file::{AconfigStorageError, FlagValueType, StorageFileType}; pub use flag_table_query::FlagReadContext; pub use package_table_query::PackageReadContext; @@ -60,8 +57,8 @@ use memmap2::Mmap; use std::fs::File; use std::io::Read; -/// Storage file location pb file -pub const STORAGE_LOCATION_FILE: &str = "/metadata/aconfig/boot/available_storage_file_records.pb"; +/// Storage file location +pub const STORAGE_LOCATION: &str = "/metadata/aconfig"; /// Get read only mapped storage files. /// @@ -78,7 +75,7 @@ pub unsafe fn get_mapped_storage_file( container: &str, file_type: StorageFileType, ) -> Result<Mmap, AconfigStorageError> { - unsafe { crate::mapped_file::get_mapped_file(STORAGE_LOCATION_FILE, container, file_type) } + unsafe { crate::mapped_file::get_mapped_file(STORAGE_LOCATION, container, file_type) } } /// Get package read context for a specific package. @@ -394,45 +391,41 @@ pub fn get_storage_file_version_cxx(file_path: &str) -> ffi::VersionNumberQueryC mod tests { use super::*; use crate::mapped_file::get_mapped_file; - use crate::test_utils::copy_to_temp_file; - use aconfig_storage_file::protos::storage_record_pb::write_proto_to_temp_file; use aconfig_storage_file::{FlagInfoBit, StoredFlagType}; - use tempfile::NamedTempFile; - - fn create_test_storage_files() -> [NamedTempFile; 5] { - let package_map = copy_to_temp_file("./tests/package.map").unwrap(); - let flag_map = copy_to_temp_file("./tests/flag.map").unwrap(); - let flag_val = copy_to_temp_file("./tests/flag.val").unwrap(); - let flag_info = copy_to_temp_file("./tests/flag.info").unwrap(); - - let text_proto = format!( - r#" -files {{ - version: 0 - container: "mockup" - package_map: "{}" - flag_map: "{}" - flag_val: "{}" - flag_info: "{}" - timestamp: 12345 -}} -"#, - package_map.path().display(), - flag_map.path().display(), - flag_val.path().display(), - flag_info.path().display() - ); - let pb_file = write_proto_to_temp_file(&text_proto).unwrap(); - [package_map, flag_map, flag_val, flag_info, pb_file] + use rand::Rng; + use std::fs; + + fn create_test_storage_files() -> String { + let mut rng = rand::thread_rng(); + let number: u32 = rng.gen(); + let storage_dir = String::from("/tmp/") + &number.to_string(); + if std::fs::metadata(&storage_dir).is_ok() { + fs::remove_dir_all(&storage_dir).unwrap(); + } + let maps_dir = storage_dir.clone() + "/maps"; + let boot_dir = storage_dir.clone() + "/boot"; + fs::create_dir(&storage_dir).unwrap(); + fs::create_dir(&maps_dir).unwrap(); + fs::create_dir(&boot_dir).unwrap(); + + let package_map = storage_dir.clone() + "/maps/mockup.package.map"; + let flag_map = storage_dir.clone() + "/maps/mockup.flag.map"; + let flag_val = storage_dir.clone() + "/boot/mockup.val"; + let flag_info = storage_dir.clone() + "/boot/mockup.info"; + fs::copy("./tests/package.map", &package_map).unwrap(); + fs::copy("./tests/flag.map", &flag_map).unwrap(); + fs::copy("./tests/flag.val", &flag_val).unwrap(); + fs::copy("./tests/flag.info", &flag_info).unwrap(); + + return storage_dir; } #[test] // this test point locks down flag package read context query fn test_package_context_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); let package_mapped_file = unsafe { - get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap() + get_mapped_file(&storage_dir, "mockup", StorageFileType::PackageMap).unwrap() }; let package_context = @@ -460,10 +453,9 @@ files {{ #[test] // this test point locks down flag read context query fn test_flag_context_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); let flag_mapped_file = - unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagMap).unwrap() }; + unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagMap).unwrap() }; let baseline = vec![ (0, "enabled_ro", StoredFlagType::ReadOnlyBoolean, 1u16), @@ -486,10 +478,9 @@ files {{ #[test] // this test point locks down flag value query fn test_flag_value_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); let flag_value_file = - unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagVal).unwrap() }; + unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagVal).unwrap() }; let baseline: Vec<bool> = vec![false, true, true, false, true, true, true, true]; for (offset, expected_value) in baseline.into_iter().enumerate() { let flag_value = get_boolean_flag_value(&flag_value_file, offset as u32).unwrap(); @@ -500,10 +491,9 @@ files {{ #[test] // this test point locks donw flag info query fn test_flag_info_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); let flag_info_file = - unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagInfo).unwrap() }; + unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagInfo).unwrap() }; let is_rw: Vec<bool> = vec![true, false, true, true, false, false, false, true]; for (offset, expected_value) in is_rw.into_iter().enumerate() { let attribute = diff --git a/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs b/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs index 378644317c..5a1664535f 100644 --- a/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs +++ b/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs @@ -14,47 +14,12 @@ * limitations under the License. */ -use std::fs::File; -use std::io::{BufReader, Read}; - use anyhow::anyhow; use memmap2::Mmap; +use std::fs::File; -use crate::AconfigStorageError::{ - self, FileReadFail, MapFileFail, ProtobufParseFail, StorageFileNotFound, -}; +use crate::AconfigStorageError::{self, FileReadFail, MapFileFail, StorageFileNotFound}; use crate::StorageFileType; -use aconfig_storage_file::protos::{ - storage_record_pb::try_from_binary_proto, ProtoStorageFileInfo, ProtoStorageFiles, -}; - -/// Find where storage files are stored for a particular container -pub fn find_container_storage_location( - location_pb_file: &str, - container: &str, -) -> Result<ProtoStorageFileInfo, AconfigStorageError> { - let file = File::open(location_pb_file).map_err(|errmsg| { - FileReadFail(anyhow!("Failed to open file {}: {}", location_pb_file, errmsg)) - })?; - let mut reader = BufReader::new(file); - let mut bytes = Vec::new(); - reader.read_to_end(&mut bytes).map_err(|errmsg| { - FileReadFail(anyhow!("Failed to read file {}: {}", location_pb_file, errmsg)) - })?; - let storage_locations: ProtoStorageFiles = try_from_binary_proto(&bytes).map_err(|errmsg| { - ProtobufParseFail(anyhow!( - "Failed to parse storage location pb file {}: {}", - location_pb_file, - errmsg - )) - })?; - for location_info in storage_locations.files.iter() { - if location_info.container() == container { - return Ok(location_info.clone()); - } - } - Err(StorageFileNotFound(anyhow!("Storage file does not exist for {}", container))) -} /// Get the read only memory mapping of a storage file /// @@ -82,123 +47,70 @@ unsafe fn map_file(file_path: &str) -> Result<Mmap, AconfigStorageError> { /// file after being mapped. Ensure no writes can happen to this file while this /// mapping stays alive. pub unsafe fn get_mapped_file( - location_pb_file: &str, + storage_dir: &str, container: &str, file_type: StorageFileType, ) -> Result<Mmap, AconfigStorageError> { - let files_location = find_container_storage_location(location_pb_file, container)?; - match file_type { - StorageFileType::PackageMap => unsafe { map_file(files_location.package_map()) }, - StorageFileType::FlagMap => unsafe { map_file(files_location.flag_map()) }, - StorageFileType::FlagVal => unsafe { map_file(files_location.flag_val()) }, - StorageFileType::FlagInfo => unsafe { map_file(files_location.flag_info()) }, + let storage_file = match file_type { + StorageFileType::PackageMap => { + String::from(storage_dir) + "/maps/" + container + ".package.map" + } + StorageFileType::FlagMap => String::from(storage_dir) + "/maps/" + container + ".flag.map", + StorageFileType::FlagVal => String::from(storage_dir) + "/boot/" + container + ".val", + StorageFileType::FlagInfo => String::from(storage_dir) + "/boot/" + container + ".info", + }; + if std::fs::metadata(&storage_file).is_err() { + return Err(StorageFileNotFound(anyhow!("storage file {} does not exist", storage_file))); } + unsafe { map_file(&storage_file) } } #[cfg(test)] mod tests { use super::*; - use crate::test_utils::copy_to_temp_file; - use aconfig_storage_file::protos::storage_record_pb::write_proto_to_temp_file; - use tempfile::NamedTempFile; + use rand::Rng; + use std::fs; + use std::io::Read; - #[test] - fn test_find_storage_file_location() { - let text_proto = r#" -files { - version: 0 - container: "system" - package_map: "/system/etc/package.map" - flag_map: "/system/etc/flag.map" - flag_val: "/metadata/aconfig/system.val" - timestamp: 12345 -} -files { - version: 1 - container: "product" - package_map: "/product/etc/package.map" - flag_map: "/product/etc/flag.map" - flag_val: "/metadata/aconfig/product.val" - timestamp: 54321 -} -"#; - let file = write_proto_to_temp_file(&text_proto).unwrap(); - let file_full_path = file.path().display().to_string(); - let file_info = find_container_storage_location(&file_full_path, "system").unwrap(); - assert_eq!(file_info.version(), 0); - assert_eq!(file_info.container(), "system"); - assert_eq!(file_info.package_map(), "/system/etc/package.map"); - assert_eq!(file_info.flag_map(), "/system/etc/flag.map"); - assert_eq!(file_info.flag_val(), "/metadata/aconfig/system.val"); - assert_eq!(file_info.timestamp(), 12345); - - let file_info = find_container_storage_location(&file_full_path, "product").unwrap(); - assert_eq!(file_info.version(), 1); - assert_eq!(file_info.container(), "product"); - assert_eq!(file_info.package_map(), "/product/etc/package.map"); - assert_eq!(file_info.flag_map(), "/product/etc/flag.map"); - assert_eq!(file_info.flag_val(), "/metadata/aconfig/product.val"); - assert_eq!(file_info.timestamp(), 54321); - - let err = find_container_storage_location(&file_full_path, "vendor").unwrap_err(); - assert_eq!( - format!("{:?}", err), - "StorageFileNotFound(Storage file does not exist for vendor)" - ); - } - - fn map_and_verify(location_pb_file: &str, file_type: StorageFileType, actual_file: &str) { + fn map_and_verify(storage_dir: &str, file_type: StorageFileType, actual_file: &str) { let mut opened_file = File::open(actual_file).unwrap(); let mut content = Vec::new(); opened_file.read_to_end(&mut content).unwrap(); - - let mmaped_file = - unsafe { get_mapped_file(location_pb_file, "system", file_type).unwrap() }; + let mmaped_file = unsafe { get_mapped_file(storage_dir, "mockup", file_type).unwrap() }; assert_eq!(mmaped_file[..], content[..]); } - fn create_test_storage_files() -> [NamedTempFile; 4] { - let package_map = copy_to_temp_file("./tests/package.map").unwrap(); - let flag_map = copy_to_temp_file("./tests/flag.map").unwrap(); - let flag_val = copy_to_temp_file("./tests/package.map").unwrap(); + fn create_test_storage_files() -> String { + let mut rng = rand::thread_rng(); + let number: u32 = rng.gen(); + let storage_dir = String::from("/tmp/") + &number.to_string(); + if std::fs::metadata(&storage_dir).is_ok() { + fs::remove_dir_all(&storage_dir).unwrap(); + } + let maps_dir = storage_dir.clone() + "/maps"; + let boot_dir = storage_dir.clone() + "/boot"; + fs::create_dir(&storage_dir).unwrap(); + fs::create_dir(&maps_dir).unwrap(); + fs::create_dir(&boot_dir).unwrap(); + + let package_map = storage_dir.clone() + "/maps/mockup.package.map"; + let flag_map = storage_dir.clone() + "/maps/mockup.flag.map"; + let flag_val = storage_dir.clone() + "/boot/mockup.val"; + let flag_info = storage_dir.clone() + "/boot/mockup.info"; + fs::copy("./tests/package.map", &package_map).unwrap(); + fs::copy("./tests/flag.map", &flag_map).unwrap(); + fs::copy("./tests/flag.val", &flag_val).unwrap(); + fs::copy("./tests/flag.info", &flag_info).unwrap(); - let text_proto = format!( - r#" -files {{ - version: 0 - container: "system" - package_map: "{}" - flag_map: "{}" - flag_val: "{}" - timestamp: 12345 -}} -"#, - package_map.path().display(), - flag_map.path().display(), - flag_val.path().display() - ); - let pb_file = write_proto_to_temp_file(&text_proto).unwrap(); - [package_map, flag_map, flag_val, pb_file] + return storage_dir; } #[test] fn test_mapped_file_contents() { - let [package_map, flag_map, flag_val, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); - map_and_verify( - &pb_file_path, - StorageFileType::PackageMap, - &package_map.path().display().to_string(), - ); - map_and_verify( - &pb_file_path, - StorageFileType::FlagMap, - &flag_map.path().display().to_string(), - ); - map_and_verify( - &pb_file_path, - StorageFileType::FlagVal, - &flag_val.path().display().to_string(), - ); + let storage_dir = create_test_storage_files(); + map_and_verify(&storage_dir, StorageFileType::PackageMap, "./tests/package.map"); + map_and_verify(&storage_dir, StorageFileType::FlagMap, "./tests/flag.map"); + map_and_verify(&storage_dir, StorageFileType::FlagVal, "./tests/flag.val"); + map_and_verify(&storage_dir, StorageFileType::FlagInfo, "./tests/flag.info"); } } diff --git a/tools/aconfig/aconfig_storage_read_api/src/test_utils.rs b/tools/aconfig/aconfig_storage_read_api/src/test_utils.rs deleted file mode 100644 index 84f31aa710..0000000000 --- a/tools/aconfig/aconfig_storage_read_api/src/test_utils.rs +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2023 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. - */ - -use anyhow::Result; -use std::fs; -use tempfile::NamedTempFile; - -/// Create temp file copy -pub(crate) fn copy_to_temp_file(source_file: &str) -> Result<NamedTempFile> { - let file = NamedTempFile::new()?; - fs::copy(source_file, file.path())?; - Ok(file) -} diff --git a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp index 6b05ca6fb1..98944d60dc 100644 --- a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp +++ b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp @@ -7,8 +7,7 @@ rust_test { "libanyhow", "libaconfig_storage_file", "libaconfig_storage_read_api", - "libprotobuf", - "libtempfile", + "librand", ], data: [ "package.map", @@ -26,8 +25,6 @@ cc_test { ], static_libs: [ "libgmock", - "libaconfig_storage_protos_cc", - "libprotobuf-cpp-lite", "libaconfig_storage_read_api_cc", "libbase", "liblog", diff --git a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp index 5393c49a7d..6d29045efe 100644 --- a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp +++ b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp @@ -22,11 +22,9 @@ #include <sys/stat.h> #include "aconfig_storage/aconfig_storage_read_api.hpp" #include <gtest/gtest.h> -#include <protos/aconfig_storage_metadata.pb.h> #include <android-base/file.h> #include <android-base/result.h> -using android::aconfig_storage_metadata::storage_files; using namespace android::base; namespace api = aconfig_storage; @@ -34,49 +32,33 @@ namespace private_api = aconfig_storage::private_internal_api; class AconfigStorageTest : public ::testing::Test { protected: - Result<std::string> copy_to_temp_file(std::string const& source_file) { - auto temp_file = std::string(std::tmpnam(nullptr)); + Result<void> copy_file(std::string const& src_file, + std::string const& dst_file) { auto content = std::string(); - if (!ReadFileToString(source_file, &content)) { - return Error() << "failed to read file: " << source_file; + if (!ReadFileToString(src_file, &content)) { + return Error() << "failed to read file: " << src_file; } - if (!WriteStringToFile(content, temp_file)) { - return Error() << "failed to copy file: " << source_file; + if (!WriteStringToFile(content, dst_file)) { + return Error() << "failed to copy file: " << dst_file; } - return temp_file; - } - - Result<std::string> write_storage_location_pb_file(std::string const& package_map, - std::string const& flag_map, - std::string const& flag_val, - std::string const& flag_info) { - auto temp_file = std::tmpnam(nullptr); - auto proto = storage_files(); - auto* info = proto.add_files(); - info->set_version(0); - info->set_container("mockup"); - info->set_package_map(package_map); - info->set_flag_map(flag_map); - info->set_flag_val(flag_val); - info->set_flag_info(flag_info); - info->set_timestamp(12345); - - auto content = std::string(); - proto.SerializeToString(&content); - if (!WriteStringToFile(content, temp_file)) { - return Error() << "failed to write storage records pb file"; - } - return temp_file; + return {}; } void SetUp() override { auto const test_dir = android::base::GetExecutableDirectory(); - package_map = *copy_to_temp_file(test_dir + "/package.map"); - flag_map = *copy_to_temp_file(test_dir + "/flag.map"); - flag_val = *copy_to_temp_file(test_dir + "/flag.val"); - flag_info = *copy_to_temp_file(test_dir + "/flag.info"); - storage_record_pb = *write_storage_location_pb_file( - package_map, flag_map, flag_val, flag_info); + storage_dir = std::string(root_dir.path); + auto maps_dir = storage_dir + "/maps"; + auto boot_dir = storage_dir + "/boot"; + mkdir(maps_dir.c_str(), 0775); + mkdir(boot_dir.c_str(), 0775); + package_map = std::string(maps_dir) + "/mockup.package.map"; + flag_map = std::string(maps_dir) + "/mockup.flag.map"; + flag_val = std::string(boot_dir) + "/mockup.val"; + flag_info = std::string(boot_dir) + "/mockup.info"; + copy_file(test_dir + "/package.map", package_map); + copy_file(test_dir + "/flag.map", flag_map); + copy_file(test_dir + "/flag.val", flag_val); + copy_file(test_dir + "/flag.info", flag_info); } void TearDown() override { @@ -84,14 +66,14 @@ class AconfigStorageTest : public ::testing::Test { std::remove(flag_map.c_str()); std::remove(flag_val.c_str()); std::remove(flag_info.c_str()); - std::remove(storage_record_pb.c_str()); } + TemporaryDir root_dir; + std::string storage_dir; std::string package_map; std::string flag_map; std::string flag_val; std::string flag_info; - std::string storage_record_pb; }; /// Test to lock down storage file version query api @@ -113,16 +95,17 @@ TEST_F(AconfigStorageTest, test_storage_version_query) { /// Negative test to lock down the error when mapping none exist storage files TEST_F(AconfigStorageTest, test_none_exist_storage_file_mapping) { auto mapped_file_result = private_api::get_mapped_file_impl( - storage_record_pb, "vendor", api::StorageFileType::package_map); + storage_dir, "vendor", api::StorageFileType::package_map); ASSERT_FALSE(mapped_file_result.ok()); - ASSERT_EQ(mapped_file_result.error().message(), - "Unable to find storage files for container vendor"); + ASSERT_EQ(mapped_file_result.error(), + std::string("failed to open ") + storage_dir + + "/maps/vendor.package.map: No such file or directory"); } /// Test to lock down storage package context query api TEST_F(AconfigStorageTest, test_package_context_query) { auto mapped_file_result = private_api::get_mapped_file_impl( - storage_record_pb, "mockup", api::StorageFileType::package_map); + storage_dir, "mockup", api::StorageFileType::package_map); ASSERT_TRUE(mapped_file_result.ok()); auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result); @@ -151,7 +134,7 @@ TEST_F(AconfigStorageTest, test_package_context_query) { /// Test to lock down when querying none exist package TEST_F(AconfigStorageTest, test_none_existent_package_context_query) { auto mapped_file_result = private_api::get_mapped_file_impl( - storage_record_pb, "mockup", api::StorageFileType::package_map); + storage_dir, "mockup", api::StorageFileType::package_map); ASSERT_TRUE(mapped_file_result.ok()); auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result); @@ -164,7 +147,7 @@ TEST_F(AconfigStorageTest, test_none_existent_package_context_query) { /// Test to lock down storage flag context query api TEST_F(AconfigStorageTest, test_flag_context_query) { auto mapped_file_result = private_api::get_mapped_file_impl( - storage_record_pb, "mockup", api::StorageFileType::flag_map); + storage_dir, "mockup", api::StorageFileType::flag_map); ASSERT_TRUE(mapped_file_result.ok()); auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result); @@ -190,7 +173,7 @@ TEST_F(AconfigStorageTest, test_flag_context_query) { /// Test to lock down when querying none exist flag TEST_F(AconfigStorageTest, test_none_existent_flag_context_query) { auto mapped_file_result = private_api::get_mapped_file_impl( - storage_record_pb, "mockup", api::StorageFileType::flag_map); + storage_dir, "mockup", api::StorageFileType::flag_map); ASSERT_TRUE(mapped_file_result.ok()); auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result); @@ -206,7 +189,7 @@ TEST_F(AconfigStorageTest, test_none_existent_flag_context_query) { /// Test to lock down storage flag value query api TEST_F(AconfigStorageTest, test_boolean_flag_value_query) { auto mapped_file_result = private_api::get_mapped_file_impl( - storage_record_pb, "mockup", api::StorageFileType::flag_val); + storage_dir, "mockup", api::StorageFileType::flag_val); ASSERT_TRUE(mapped_file_result.ok()); auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result); @@ -222,20 +205,20 @@ TEST_F(AconfigStorageTest, test_boolean_flag_value_query) { /// Negative test to lock down the error when querying flag value out of range TEST_F(AconfigStorageTest, test_invalid_boolean_flag_value_query) { auto mapped_file_result = private_api::get_mapped_file_impl( - storage_record_pb, "mockup", api::StorageFileType::flag_val); + storage_dir, "mockup", api::StorageFileType::flag_val); ASSERT_TRUE(mapped_file_result.ok()); auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result); auto value = api::get_boolean_flag_value(*mapped_file, 8); ASSERT_FALSE(value.ok()); - ASSERT_EQ(value.error().message(), + ASSERT_EQ(value.error(), std::string("InvalidStorageFileOffset(Flag value offset goes beyond the end of the file.)")); } /// Test to lock down storage flag info query api TEST_F(AconfigStorageTest, test_boolean_flag_info_query) { auto mapped_file_result = private_api::get_mapped_file_impl( - storage_record_pb, "mockup", api::StorageFileType::flag_info); + storage_dir, "mockup", api::StorageFileType::flag_info); ASSERT_TRUE(mapped_file_result.ok()); auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result); @@ -254,12 +237,12 @@ TEST_F(AconfigStorageTest, test_boolean_flag_info_query) { /// Negative test to lock down the error when querying flag info out of range TEST_F(AconfigStorageTest, test_invalid_boolean_flag_info_query) { auto mapped_file_result = private_api::get_mapped_file_impl( - storage_record_pb, "mockup", api::StorageFileType::flag_info); + storage_dir, "mockup", api::StorageFileType::flag_info); ASSERT_TRUE(mapped_file_result.ok()); auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result); auto attribute = api::get_flag_attribute(*mapped_file, api::FlagValueType::Boolean, 8); ASSERT_FALSE(attribute.ok()); - ASSERT_EQ(attribute.error().message(), + ASSERT_EQ(attribute.error(), std::string("InvalidStorageFileOffset(Flag info offset goes beyond the end of the file.)")); } diff --git a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs index ecba573d82..afc44d4d70 100644 --- a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs +++ b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs @@ -1,71 +1,63 @@ #[cfg(not(feature = "cargo"))] mod aconfig_storage_rust_test { - use aconfig_storage_file::protos::storage_record_pb::write_proto_to_temp_file; use aconfig_storage_file::{FlagInfoBit, FlagValueType, StorageFileType, StoredFlagType}; use aconfig_storage_read_api::{ get_boolean_flag_value, get_flag_attribute, get_flag_read_context, get_package_read_context, get_storage_file_version, mapped_file::get_mapped_file, PackageReadContext, }; + use rand::Rng; use std::fs; - use tempfile::NamedTempFile; - pub fn copy_to_temp_file(source_file: &str) -> NamedTempFile { - let file = NamedTempFile::new().unwrap(); - fs::copy(source_file, file.path()).unwrap(); - file - } - - fn create_test_storage_files() -> [NamedTempFile; 5] { - let package_map = copy_to_temp_file("./package.map"); - let flag_map = copy_to_temp_file("./flag.map"); - let flag_val = copy_to_temp_file("./flag.val"); - let flag_info = copy_to_temp_file("./flag.info"); - - let text_proto = format!( - r#" -files {{ - version: 0 - container: "mockup" - package_map: "{}" - flag_map: "{}" - flag_val: "{}" - flag_info: "{}" - timestamp: 12345 -}} -"#, - package_map.path().display(), - flag_map.path().display(), - flag_val.path().display(), - flag_info.path().display() - ); - let pb_file = write_proto_to_temp_file(&text_proto).unwrap(); - [package_map, flag_map, flag_val, flag_info, pb_file] + fn create_test_storage_files() -> String { + let mut rng = rand::thread_rng(); + let number: u32 = rng.gen(); + let storage_dir = String::from("/tmp/") + &number.to_string(); + if std::fs::metadata(&storage_dir).is_ok() { + fs::remove_dir_all(&storage_dir).unwrap(); + } + let maps_dir = storage_dir.clone() + "/maps"; + let boot_dir = storage_dir.clone() + "/boot"; + fs::create_dir(&storage_dir).unwrap(); + fs::create_dir(maps_dir).unwrap(); + fs::create_dir(boot_dir).unwrap(); + + let package_map = storage_dir.clone() + "/maps/mockup.package.map"; + let flag_map = storage_dir.clone() + "/maps/mockup.flag.map"; + let flag_val = storage_dir.clone() + "/boot/mockup.val"; + let flag_info = storage_dir.clone() + "/boot/mockup.info"; + fs::copy("./package.map", package_map).unwrap(); + fs::copy("./flag.map", flag_map).unwrap(); + fs::copy("./flag.val", flag_val).unwrap(); + fs::copy("./flag.info", flag_info).unwrap(); + + storage_dir } #[test] fn test_unavailable_stoarge() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); // SAFETY: // The safety here is ensured as the test process will not write to temp storage file let err = unsafe { - get_mapped_file(&pb_file_path, "vendor", StorageFileType::PackageMap).unwrap_err() + get_mapped_file(&storage_dir, "vendor", StorageFileType::PackageMap).unwrap_err() }; assert_eq!( format!("{:?}", err), - "StorageFileNotFound(Storage file does not exist for vendor)" + format!( + "StorageFileNotFound(storage file {}/maps/vendor.package.map does not exist)", + storage_dir + ) ); } #[test] fn test_package_context_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); // SAFETY: // The safety here is ensured as the test process will not write to temp storage file let package_mapped_file = unsafe { - get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap() + get_mapped_file(&storage_dir, "mockup", StorageFileType::PackageMap).unwrap() }; let package_context = @@ -92,12 +84,11 @@ files {{ #[test] fn test_none_exist_package_context_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); // SAFETY: // The safety here is ensured as the test process will not write to temp storage file let package_mapped_file = unsafe { - get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap() + get_mapped_file(&storage_dir, "mockup", StorageFileType::PackageMap).unwrap() }; let package_context_option = @@ -108,12 +99,11 @@ files {{ #[test] fn test_flag_context_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); // SAFETY: // The safety here is ensured as the test process will not write to temp storage file let flag_mapped_file = - unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagMap).unwrap() }; + unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagMap).unwrap() }; let baseline = vec![ (0, "enabled_ro", StoredFlagType::ReadOnlyBoolean, 1u16), @@ -135,12 +125,11 @@ files {{ #[test] fn test_none_exist_flag_context_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); // SAFETY: // The safety here is ensured as the test process will not write to temp storage file let flag_mapped_file = - unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagMap).unwrap() }; + unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagMap).unwrap() }; let flag_context_option = get_flag_read_context(&flag_mapped_file, 0, "none_exist").unwrap(); assert_eq!(flag_context_option, None); @@ -152,12 +141,11 @@ files {{ #[test] fn test_boolean_flag_value_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); // SAFETY: // The safety here is ensured as the test process will not write to temp storage file let flag_value_file = - unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagVal).unwrap() }; + unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagVal).unwrap() }; let baseline: Vec<bool> = vec![false, true, true, false, true, true, true, true]; for (offset, expected_value) in baseline.into_iter().enumerate() { let flag_value = get_boolean_flag_value(&flag_value_file, offset as u32).unwrap(); @@ -167,12 +155,11 @@ files {{ #[test] fn test_invalid_boolean_flag_value_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); // SAFETY: // The safety here is ensured as the test process will not write to temp storage file let flag_value_file = - unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagVal).unwrap() }; + unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagVal).unwrap() }; let err = get_boolean_flag_value(&flag_value_file, 8u32).unwrap_err(); assert_eq!( format!("{:?}", err), @@ -182,12 +169,11 @@ files {{ #[test] fn test_flag_info_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); // SAFETY: // The safety here is ensured as the test process will not write to temp storage file let flag_info_file = - unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagInfo).unwrap() }; + unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagInfo).unwrap() }; let is_rw: Vec<bool> = vec![true, false, true, true, false, false, false, true]; for (offset, expected_value) in is_rw.into_iter().enumerate() { let attribute = @@ -200,12 +186,11 @@ files {{ #[test] fn test_invalid_boolean_flag_info_query() { - let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files(); - let pb_file_path = pb_file.path().display().to_string(); + let storage_dir = create_test_storage_files(); // SAFETY: // The safety here is ensured as the test process will not write to temp storage file let flag_info_file = - unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagInfo).unwrap() }; + unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagInfo).unwrap() }; let err = get_flag_attribute(&flag_info_file, FlagValueType::Boolean, 8u32).unwrap_err(); assert_eq!( format!("{:?}", err), diff --git a/tools/aconfig/aconfig_storage_write_api/Android.bp b/tools/aconfig/aconfig_storage_write_api/Android.bp index 4dbdbbfb2f..0f1962c3ac 100644 --- a/tools/aconfig/aconfig_storage_write_api/Android.bp +++ b/tools/aconfig/aconfig_storage_write_api/Android.bp @@ -77,7 +77,6 @@ cc_library_static { export_include_dirs: ["include"], static_libs: [ "libaconfig_storage_read_api_cc", - "libaconfig_storage_protos_cc", "libprotobuf-cpp-lite", "libbase", ], diff --git a/tools/aconfig/aconfig_storage_write_api/Cargo.toml b/tools/aconfig/aconfig_storage_write_api/Cargo.toml index eaa55f2531..2ce6edfe96 100644 --- a/tools/aconfig/aconfig_storage_write_api/Cargo.toml +++ b/tools/aconfig/aconfig_storage_write_api/Cargo.toml @@ -13,7 +13,6 @@ cxx = "1.0" memmap2 = "0.8.0" tempfile = "3.9.0" thiserror = "1.0.56" -protobuf = "3.2.0" aconfig_storage_file = { path = "../aconfig_storage_file" } aconfig_storage_read_api = { path = "../aconfig_storage_read_api" } diff --git a/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp b/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp index f529f7954c..cabc65e40c 100644 --- a/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp +++ b/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp @@ -1,7 +1,6 @@ #include <android-base/file.h> #include <android-base/logging.h> -#include <protos/aconfig_storage_metadata.pb.h> #include <sys/mman.h> #include <sys/stat.h> @@ -11,34 +10,31 @@ #include "aconfig_storage/lib.rs.h" #include "aconfig_storage/aconfig_storage_write_api.hpp" -using storage_records_pb = android::aconfig_storage_metadata::storage_files; -using storage_record_pb = android::aconfig_storage_metadata::storage_file_info; -using namespace android::base; - namespace aconfig_storage { /// Map a storage file -Result<MutableMappedStorageFile*> map_mutable_storage_file(std::string const& file) { +android::base::Result<MutableMappedStorageFile*> map_mutable_storage_file( + std::string const& file) { struct stat file_stat; if (stat(file.c_str(), &file_stat) < 0) { - return ErrnoError() << "stat failed"; + return android::base::ErrnoError() << "stat failed"; } if ((file_stat.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0) { - return Error() << "cannot map nonwriteable file"; + return android::base::Error() << "cannot map nonwriteable file"; } size_t file_size = file_stat.st_size; const int fd = open(file.c_str(), O_RDWR | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { - return ErrnoError() << "failed to open " << file; + return android::base::ErrnoError() << "failed to open " << file; }; void* const map_result = mmap(nullptr, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (map_result == MAP_FAILED) { - return ErrnoError() << "mmap failed"; + return android::base::ErrnoError() << "mmap failed"; } auto mapped_file = new MutableMappedStorageFile(); @@ -49,7 +45,7 @@ Result<MutableMappedStorageFile*> map_mutable_storage_file(std::string const& fi } /// Set boolean flag value -Result<void> set_boolean_flag_value( +android::base::Result<void> set_boolean_flag_value( const MutableMappedStorageFile& file, uint32_t offset, bool value) { @@ -57,13 +53,13 @@ Result<void> set_boolean_flag_value( static_cast<uint8_t*>(file.file_ptr), file.file_size); auto update_cxx = update_boolean_flag_value_cxx(content, offset, value); if (!update_cxx.update_success) { - return Error() << std::string(update_cxx.error_message.c_str()); + return android::base::Error() << update_cxx.error_message.c_str(); } return {}; } /// Set if flag has server override -Result<void> set_flag_has_server_override( +android::base::Result<void> set_flag_has_server_override( const MutableMappedStorageFile& file, FlagValueType value_type, uint32_t offset, @@ -73,13 +69,13 @@ Result<void> set_flag_has_server_override( auto update_cxx = update_flag_has_server_override_cxx( content, static_cast<uint16_t>(value_type), offset, value); if (!update_cxx.update_success) { - return Error() << std::string(update_cxx.error_message.c_str()); + return android::base::Error() << update_cxx.error_message.c_str(); } return {}; } /// Set if flag has local override -Result<void> set_flag_has_local_override( +android::base::Result<void> set_flag_has_local_override( const MutableMappedStorageFile& file, FlagValueType value_type, uint32_t offset, @@ -89,12 +85,12 @@ Result<void> set_flag_has_local_override( auto update_cxx = update_flag_has_local_override_cxx( content, static_cast<uint16_t>(value_type), offset, value); if (!update_cxx.update_success) { - return Error() << std::string(update_cxx.error_message.c_str()); + return android::base::Error() << update_cxx.error_message.c_str(); } return {}; } -Result<void> create_flag_info( +android::base::Result<void> create_flag_info( std::string const& package_map, std::string const& flag_map, std::string const& flag_info_out) { diff --git a/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp b/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp index ff06cbc6de..0bba7ffcfc 100644 --- a/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp +++ b/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp @@ -6,7 +6,6 @@ #include <android-base/result.h> #include <aconfig_storage/aconfig_storage_read_api.hpp> -using namespace android::base; namespace aconfig_storage { @@ -14,24 +13,24 @@ namespace aconfig_storage { struct MutableMappedStorageFile : MappedStorageFile {}; /// Map a storage file -Result<MutableMappedStorageFile*> map_mutable_storage_file( +android::base::Result<MutableMappedStorageFile*> map_mutable_storage_file( std::string const& file); /// Set boolean flag value -Result<void> set_boolean_flag_value( +android::base::Result<void> set_boolean_flag_value( const MutableMappedStorageFile& file, uint32_t offset, bool value); /// Set if flag has server override -Result<void> set_flag_has_server_override( +android::base::Result<void> set_flag_has_server_override( const MutableMappedStorageFile& file, FlagValueType value_type, uint32_t offset, bool value); /// Set if flag has local override -Result<void> set_flag_has_local_override( +android::base::Result<void> set_flag_has_local_override( const MutableMappedStorageFile& file, FlagValueType value_type, uint32_t offset, @@ -41,7 +40,7 @@ Result<void> set_flag_has_local_override( /// \input package_map: package map file /// \input flag_map: flag map file /// \input flag_info_out: flag info file to be created -Result<void> create_flag_info( +android::base::Result<void> create_flag_info( std::string const& package_map, std::string const& flag_map, std::string const& flag_info_out); diff --git a/tools/aconfig/aconfig_storage_write_api/tests/Android.bp b/tools/aconfig/aconfig_storage_write_api/tests/Android.bp index 85568e063b..f6409b7090 100644 --- a/tools/aconfig/aconfig_storage_write_api/tests/Android.bp +++ b/tools/aconfig/aconfig_storage_write_api/tests/Android.bp @@ -25,8 +25,6 @@ cc_test { ], static_libs: [ "libgmock", - "libaconfig_storage_protos_cc", - "libprotobuf-cpp-lite", "libaconfig_storage_read_api_cc", "libaconfig_storage_write_api_cc", "libbase", diff --git a/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.cpp b/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.cpp index 54373798c9..31183fa01b 100644 --- a/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.cpp +++ b/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.cpp @@ -22,11 +22,9 @@ #include "aconfig_storage/aconfig_storage_read_api.hpp" #include "aconfig_storage/aconfig_storage_write_api.hpp" #include <gtest/gtest.h> -#include <protos/aconfig_storage_metadata.pb.h> #include <android-base/file.h> #include <android-base/result.h> -using android::aconfig_storage_metadata::storage_files; using namespace android::base; namespace api = aconfig_storage; diff --git a/tools/aconfig/aflags/src/aconfig_storage_source.rs b/tools/aconfig/aflags/src/aconfig_storage_source.rs index c21c5424bb..04140c7fa3 100644 --- a/tools/aconfig/aflags/src/aconfig_storage_source.rs +++ b/tools/aconfig/aflags/src/aconfig_storage_source.rs @@ -27,8 +27,7 @@ impl FlagSource for AconfigStorageSource { let container = file_info.container.ok_or(anyhow!("storage file is missing container"))?; - for listed_flag in - aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)? + for listed_flag in aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)? { result.push(Flag { name: listed_flag.flag_name, diff --git a/tools/aconfig/aflags/src/main.rs b/tools/aconfig/aflags/src/main.rs index 4ce0d35ba1..05c15bb304 100644 --- a/tools/aconfig/aflags/src/main.rs +++ b/tools/aconfig/aflags/src/main.rs @@ -33,12 +33,16 @@ enum FlagPermission { ReadWrite, } -impl ToString for FlagPermission { - fn to_string(&self) -> String { - match &self { - Self::ReadOnly => "read-only".into(), - Self::ReadWrite => "read-write".into(), - } +impl std::fmt::Display for FlagPermission { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match &self { + Self::ReadOnly => "read-only", + Self::ReadWrite => "read-write", + } + ) } } @@ -48,12 +52,16 @@ enum ValuePickedFrom { Server, } -impl ToString for ValuePickedFrom { - fn to_string(&self) -> String { - match &self { - Self::Default => "default".into(), - Self::Server => "server".into(), - } +impl std::fmt::Display for ValuePickedFrom { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match &self { + Self::Default => "default", + Self::Server => "server", + } + ) } } @@ -75,12 +83,16 @@ impl TryFrom<&str> for FlagValue { } } -impl ToString for FlagValue { - fn to_string(&self) -> String { - match &self { - Self::Enabled => "enabled".into(), - Self::Disabled => "disabled".into(), - } +impl std::fmt::Display for FlagValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match &self { + Self::Enabled => "enabled", + Self::Disabled => "disabled", + } + ) } } @@ -103,7 +115,7 @@ impl Flag { fn display_staged_value(&self) -> String { match self.staged_value { - Some(v) => format!("(->{})", v.to_string()), + Some(v) => format!("(->{})", v), None => "-".to_string(), } } @@ -153,6 +165,10 @@ enum Command { /// Read from the new flag storage. #[clap(long)] use_new_storage: bool, + + /// Optionally filter by container name. + #[clap(short = 'c', long = "container")] + container: Option<String>, }, /// Enable an aconfig flag on this device, on the next boot. @@ -176,6 +192,23 @@ struct PaddingInfo { longest_permission_col: usize, } +struct Filter { + container: Option<String>, +} + +impl Filter { + fn apply(&self, flags: &[Flag]) -> Vec<Flag> { + flags + .iter() + .filter(|flag| match &self.container { + Some(c) => flag.container == *c, + None => true, + }) + .cloned() + .collect() + } +} + fn format_flag_row(flag: &Flag, info: &PaddingInfo) -> String { let full_name = flag.qualified_name(); let p0 = info.longest_flag_col + 1; @@ -215,11 +248,12 @@ fn set_flag(qualified_name: &str, value: &str) -> Result<()> { Ok(()) } -fn list(source_type: FlagSourceType) -> Result<String> { - let flags = match source_type { +fn list(source_type: FlagSourceType, container: Option<String>) -> Result<String> { + let flags_unfiltered = match source_type { FlagSourceType::DeviceConfig => DeviceConfigSource::list_flags()?, FlagSourceType::AconfigStorage => AconfigStorageSource::list_flags()?, }; + let flags = (Filter { container }).apply(&flags_unfiltered); let padding_info = PaddingInfo { longest_flag_col: flags.iter().map(|f| f.qualified_name().len()).max().unwrap_or(0), longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0), @@ -251,8 +285,12 @@ fn list(source_type: FlagSourceType) -> Result<String> { fn main() { let cli = Cli::parse(); let output = match cli.command { - Command::List { use_new_storage: true } => list(FlagSourceType::AconfigStorage).map(Some), - Command::List { use_new_storage: false } => list(FlagSourceType::DeviceConfig).map(Some), + Command::List { use_new_storage: true, container } => { + list(FlagSourceType::AconfigStorage, container).map(Some) + } + Command::List { use_new_storage: false, container } => { + list(FlagSourceType::DeviceConfig, container).map(Some) + } Command::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None), Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None), }; @@ -262,3 +300,84 @@ fn main() { Err(message) => println!("Error: {message}"), } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_filter_container() { + let flags = vec![ + Flag { + namespace: "namespace".to_string(), + name: "test1".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "system".to_string(), + }, + Flag { + namespace: "namespace".to_string(), + name: "test2".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "not_system".to_string(), + }, + Flag { + namespace: "namespace".to_string(), + name: "test3".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "system".to_string(), + }, + ]; + + assert_eq!((Filter { container: Some("system".to_string()) }).apply(&flags).len(), 2); + } + + #[test] + fn test_filter_no_container() { + let flags = vec![ + Flag { + namespace: "namespace".to_string(), + name: "test1".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "system".to_string(), + }, + Flag { + namespace: "namespace".to_string(), + name: "test2".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "not_system".to_string(), + }, + Flag { + namespace: "namespace".to_string(), + name: "test3".to_string(), + package: "package".to_string(), + value: FlagValue::Disabled, + staged_value: None, + permission: FlagPermission::ReadWrite, + value_picked_from: ValuePickedFrom::Default, + container: "system".to_string(), + }, + ]; + + assert_eq!((Filter { container: None }).apply(&flags).len(), 3); + } +} diff --git a/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt b/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt index cd859448b0..8e285f6216 100644 --- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt +++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt @@ -121,6 +121,26 @@ class CheckFlaggedApisTest { } @Test + fun testParseApiSignatureInterfacesInheritFromJavaLangObject() { + val apiSignature = + """ + // Signature format: 2.0 + package android { + @FlaggedApi("android.flag.foo") public interface Interface { + } + } + """ + .trim() + val expected = + setOf( + Pair( + Symbol.createClass("android/Interface", "java/lang/Object", setOf()), + Flag("android.flag.foo"))) + val actual = parseApiSignature("in-memory", apiSignature.byteInputStream()) + assertEquals(expected, actual) + } + + @Test fun testParseFlagValues() { val expected: Map<Flag, Boolean> = mapOf(Flag("android.flag.foo") to true, Flag("android.flag.bar") to true) @@ -270,6 +290,42 @@ class CheckFlaggedApisTest { } @Test + fun testNestedFlagsOuterFlagWins() { + val apiSignature = + """ + // Signature format: 2.0 + package android { + @FlaggedApi("android.flag.foo") public final class A { + method @FlaggedApi("android.flag.bar") public boolean method(); + } + @FlaggedApi("android.flag.bar") public final class B { + method @FlaggedApi("android.flag.foo") public boolean method(); + } + } + """ + .trim() + + val apiVersions = + """ + <?xml version="1.0" encoding="utf-8"?> + <api version="3"> + <class name="android/B" since="1"> + <extends name="java/lang/Object"/> + </class> + </api> + """ + .trim() + + val expected = setOf<ApiError>() + val actual = + findErrors( + parseApiSignature("in-memory", apiSignature.byteInputStream()), + parseFlagValues(generateFlagsProto(DISABLED, ENABLED)), + parseApiVersions(apiVersions.byteInputStream())) + assertEquals(expected, actual) + } + + @Test fun testFindErrorsDisabledFlaggedApiIsPresent() { val expected = setOf<ApiError>( diff --git a/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt b/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt index b514048bd6..1d2440dee8 100644 --- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt +++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt @@ -205,7 +205,11 @@ internal fun parseApiSignature(path: String, input: InputStream): Set<Pair<Symbo val symbol = Symbol.createClass( cls.baselineElementId(), - cls.superClass()?.baselineElementId(), + if (cls.isInterface()) { + "java/lang/Object" + } else { + cls.superClass()?.baselineElementId() + }, cls.allInterfaces() .map { it.baselineElementId() } .filter { it != cls.baselineElementId() } @@ -385,10 +389,48 @@ internal fun findErrors( return false } + + /** + * Returns whether the given flag is enabled for the given symbol. + * + * A flagged member inside a flagged class is ignored (and the flag value considered disabled) if + * the class' flag is disabled. + * + * @param symbol the symbol to check + * @param flag the flag to check + * @return whether the flag is enabled for the given symbol + */ + fun isFlagEnabledForSymbol(symbol: Symbol, flag: Flag): Boolean { + when (symbol) { + is ClassSymbol -> return flags.getValue(flag) + is MemberSymbol -> { + val memberFlagValue = flags.getValue(flag) + if (!memberFlagValue) { + return false + } + // Special case: if the MemberSymbol's flag is enabled, but the outer + // ClassSymbol's flag (if the class is flagged) is disabled, consider + // the MemberSymbol's flag as disabled: + // + // @FlaggedApi(this-flag-is-disabled) Clazz { + // @FlaggedApi(this-flag-is-enabled) method(); // The Clazz' flag "wins" + // } + // + // Note: the current implementation does not handle nested classes. + val classFlagValue = + flaggedSymbolsInSource + .find { it.first.toPrettyString() == symbol.clazz } + ?.let { flags.getValue(it.second) } + ?: true + return classFlagValue + } + } + } + val errors = mutableSetOf<ApiError>() for ((symbol, flag) in flaggedSymbolsInSource) { try { - if (flags.getValue(flag)) { + if (isFlagEnabledForSymbol(symbol, flag)) { if (!symbolsInOutput.containsSymbol(symbol)) { errors.add(EnabledFlaggedApiNotPresentError(symbol, flag)) } diff --git a/tools/compliance/go.mod b/tools/compliance/go.mod index bd040774b1..532efd486e 100644 --- a/tools/compliance/go.mod +++ b/tools/compliance/go.mod @@ -1,29 +1,11 @@ -module android/soong/tools/compliance - -require google.golang.org/protobuf v0.0.0 +go 1.22 -replace google.golang.org/protobuf v0.0.0 => ../../../../external/golang-protobuf +module android/soong/tools/compliance require ( - android/soong v0.0.0 github.com/google/blueprint v0.0.0 + android/soong v0.0.0 + google.golang.org/protobuf v0.0.0 github.com/spdx/tools-golang v0.0.0 + github.com/google/go-cmp v0.0.0 ) - -replace github.com/spdx/tools-golang v0.0.0 => ../../../../external/spdx-tools - -require golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect - -replace android/soong v0.0.0 => ../../../soong - -replace github.com/google/blueprint => ../../../blueprint - -// Indirect deps from golang-protobuf -exclude github.com/golang/protobuf v1.5.0 - -replace github.com/google/go-cmp v0.5.5 => ../../../../external/go-cmp - -// Indirect dep from go-cmp -exclude golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 - -go 1.21 diff --git a/tools/compliance/go.sum b/tools/compliance/go.sum deleted file mode 100644 index cbe76d9187..0000000000 --- a/tools/compliance/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= diff --git a/tools/compliance/go.work b/tools/compliance/go.work new file mode 100644 index 0000000000..a24d2ea541 --- /dev/null +++ b/tools/compliance/go.work @@ -0,0 +1,18 @@ +go 1.22 + +use ( + . + ../../../../build/blueprint + ../../../../build/soong + ../../../../external/go-cmp + ../../../../external/golang-protobuf + ../../../../external/spdx-tools +) + +replace ( + github.com/google/blueprint v0.0.0 => ../../../../build/blueprint + android/soong v0.0.0 => ../../../../build/soong + github.com/google/go-cmp v0.0.0 => ../../../../external/go-cmp + google.golang.org/protobuf v0.0.0 => ../../../../external/golang-protobuf + github.com/spdx/tools-golang v0.0.0 => ../../../../external/spdx-tools +) diff --git a/tools/overrideflags.sh b/tools/overrideflags.sh deleted file mode 100755 index b8605dc034..0000000000 --- a/tools/overrideflags.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/bash -e -# Copyright (C) 2023 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. - - -source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../shell_utils.sh -require_top - -function print_help() { - echo -e "overrideflags is used to set default value for local build." - echo -e "\nOptions:" - echo -e "\t--release-config \tPath to release configuration directory. Required" - echo -e "\t--no-edit \tIf present, skip editing flag value file." - echo -e "\t-h/--help \tShow this help." -} - -function main() { - while (($# > 0)); do - case $1 in - --release-config) - if [[ $# -le 1 ]]; then - echo "--release-config requires a path" - return 1 - fi - local release_config_dir="$2" - shift 2 - ;; - --no-edit) - local no_edit="true" - shift 1 - ;; - -h|--help) - print_help - return - ;; - *) - echo "$1 is unrecognized" - print_help - return 1 - ;; - esac - done - - - - case $(uname -s) in - Darwin) - local host_arch=darwin-x86 - ;; - Linux) - local host_arch=linux-x86 - ;; - *) - >&2 echo Unknown host $(uname -s) - return - ;; - esac - - if [[ -z "${release_config_dir}" ]]; then - echo "Please provide release configuration path by --release-config" - exit 1 - elif [ ! -d "${release_config_dir}" ]; then - echo "${release_config_dir} is an invalid directory" - exit 1 - fi - local T="$(gettop)" - local aconfig_dir="${T}"/build/make/tools/aconfig/ - local overrideflag_py="${aconfig_dir}"/overrideflags/overrideflags.py - local overridefile="${release_config_dir}/aconfig/override_values.textproto" - - # Edit override file - if [[ -z "${no_edit}" ]]; then - editor="${EDITOR:-$(which vim)}" - - eval "${editor} ${overridefile}" - if [ $? -ne 0 ]; then - echo "Fail to set override values" - return 1 - fi - fi - - ${T}/prebuilts/build-tools/${host_arch}/bin/py3-cmd -u "${overrideflag_py}" \ - --overrides "${overridefile}" \ - --out "${release_config_dir}/aconfig" -} - - -main "$@" diff --git a/tools/perf/format_benchmarks b/tools/perf/format_benchmarks index 162c5770a9..807e546a17 100755 --- a/tools/perf/format_benchmarks +++ b/tools/perf/format_benchmarks @@ -25,6 +25,7 @@ import os import pathlib import statistics import zoneinfo +import csv import pretty import utils @@ -103,7 +104,7 @@ class Table: def SetFixedCol(self, row_key, columns): self._fixed_cols[row_key] = columns - def Write(self, out): + def Write(self, out, fmt): table = [] # Expand the column items for row in zip(*self._cols): @@ -114,26 +115,33 @@ class Table: # Update the last row of the header with title and add separator for i in range(len(self._titles)): table[len(table)-1][i] = self._titles[i] - table.append(pretty.SEPARATOR) + if fmt == "table": + table.append(pretty.SEPARATOR) # Populate the data for row in self._rows: table.append([str(row)] + self._fixed_cols[row] + [str(self._data.get((col, row), "")) for col in self._cols]) - out.write(pretty.FormatTable(table, alignments="LL")) + if fmt == "csv": + csv.writer(sys.stdout, quoting=csv.QUOTE_MINIMAL).writerows(table) + else: + out.write(pretty.FormatTable(table, alignments="LL")) -def format_duration_sec(ns): +def format_duration_sec(ns, fmt_sec): "Format a duration in ns to second precision" sec = round(ns / 1000000000) - h, sec = divmod(sec, 60*60) - m, sec = divmod(sec, 60) - result = "" - if h > 0: - result += f"{h:2d}h " - if h > 0 or m > 0: - result += f"{m:2d}m " - return result + f"{sec:2d}s" + if fmt_sec: + return f"{sec}" + else: + h, sec = divmod(sec, 60*60) + m, sec = divmod(sec, 60) + result = "" + if h > 0: + result += f"{h:2d}h " + if h > 0 or m > 0: + result += f"{m:2d}m " + return result + f"{sec:2d}s" def main(argv): @@ -142,6 +150,12 @@ def main(argv): allow_abbrev=False, # Don't let people write unsupportable scripts. description="Print analysis tables for benchmarks") + parser.add_argument("--csv", action="store_true", + help="Print in CSV instead of table.") + + parser.add_argument("--sec", action="store_true", + help="Print in seconds instead of minutes and seconds") + parser.add_argument("--tags", nargs="*", help="The tags to print, in order.") @@ -188,14 +202,17 @@ def main(argv): for key, column in summary["columns"]: for id, cell in column: duration_ns = statistics.median([b["duration_ns"] for b in cell]) - table.SetFixedCol(cell[0]["title"], [" ".join(cell[0]["modules"])]) + modules = cell[0]["modules"] + if not modules: + modules = ["---"] + table.SetFixedCol(cell[0]["title"], [" ".join(modules)]) table.Set(tuple([summary["date"].strftime("%Y-%m-%d"), summary["branch"], summary["tag"]] + list(key)), - cell[0]["title"], format_duration_sec(duration_ns)) + cell[0]["title"], format_duration_sec(duration_ns, args.sec)) - table.Write(sys.stdout) + table.Write(sys.stdout, "csv" if args.csv else "table") if __name__ == "__main__": main(sys.argv) diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py index 2367691e43..d91a713276 100644 --- a/tools/releasetools/common.py +++ b/tools/releasetools/common.py @@ -1971,7 +1971,7 @@ def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir, return None -def _BuildVendorBootImage(sourcedir, partition_name, info_dict=None): +def _BuildVendorBootImage(sourcedir, fs_config_file, partition_name, info_dict=None): """Build a vendor boot image from the specified sourcedir. Take a ramdisk, dtb, and vendor_cmdline from the input (in 'sourcedir'), and @@ -1987,7 +1987,7 @@ def _BuildVendorBootImage(sourcedir, partition_name, info_dict=None): img = tempfile.NamedTemporaryFile() ramdisk_format = GetRamdiskFormat(info_dict) - ramdisk_img = _MakeRamdisk(sourcedir, ramdisk_format=ramdisk_format) + ramdisk_img = _MakeRamdisk(sourcedir, fs_config_file=fs_config_file, ramdisk_format=ramdisk_format) # use MKBOOTIMG from environ, or "mkbootimg" if empty or not set mkbootimg = os.getenv('MKBOOTIMG') or "mkbootimg" @@ -2101,8 +2101,9 @@ def GetVendorBootImage(name, prebuilt_name, unpack_dir, tree_subdir, if info_dict is None: info_dict = OPTIONS.info_dict + fs_config = "META/" + tree_subdir.lower() + "_filesystem_config.txt" data = _BuildVendorBootImage( - os.path.join(unpack_dir, tree_subdir), "vendor_boot", info_dict) + os.path.join(unpack_dir, tree_subdir), os.path.join(unpack_dir, fs_config), "vendor_boot", info_dict) if data: return File(name, data) return None @@ -2126,7 +2127,7 @@ def GetVendorKernelBootImage(name, prebuilt_name, unpack_dir, tree_subdir, info_dict = OPTIONS.info_dict data = _BuildVendorBootImage( - os.path.join(unpack_dir, tree_subdir), "vendor_kernel_boot", info_dict) + os.path.join(unpack_dir, tree_subdir), None, "vendor_kernel_boot", info_dict) if data: return File(name, data) return None diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py index 432ea199bb..985cd56cb0 100755 --- a/tools/releasetools/ota_from_target_files.py +++ b/tools/releasetools/ota_from_target_files.py @@ -329,7 +329,7 @@ OPTIONS.vabc_downgrade = False OPTIONS.enable_vabc_xor = True OPTIONS.force_minor_version = None OPTIONS.compressor_types = None -OPTIONS.enable_zucchini = True +OPTIONS.enable_zucchini = False OPTIONS.enable_puffdiff = None OPTIONS.enable_lz4diff = False OPTIONS.vabc_compression_param = None @@ -914,12 +914,13 @@ def GenerateAbOtaPackage(target_file, output_file, source_file=None): # and install time performance. All OTA's with # both the source build and target build with VIRTUAL_AB_COW_VERSION = 3 # can support the new format. Otherwise, fallback on older versions - if not source_info.vabc_cow_version or not target_info.vabc_cow_version: - logger.info("Source or Target doesn't have VABC_COW_VERSION specified, default to version 2") - OPTIONS.vabc_cow_version = 2 - elif source_info.vabc_cow_version != target_info.vabc_cow_version: - logger.info("Source and Target have different cow VABC_COW_VERSION specified, default to minimum version") - OPTIONS.vabc_cow_version = min(source_info.vabc_cow_version, target_info.vabc_cow_version) + if not OPTIONS.vabc_cow_version: + if not source_info.vabc_cow_version or not target_info.vabc_cow_version: + logger.info("Source or Target doesn't have VABC_COW_VERSION specified, default to version 2") + OPTIONS.vabc_cow_version = 2 + elif source_info.vabc_cow_version != target_info.vabc_cow_version: + logger.info("Source and Target have different cow VABC_COW_VERSION specified, default to minimum version") + OPTIONS.vabc_cow_version = min(source_info.vabc_cow_version, target_info.vabc_cow_version) # Virtual AB Compression was introduced in Androd S. # Later, we backported VABC to Android R. But verity support was not @@ -933,19 +934,20 @@ def GenerateAbOtaPackage(target_file, output_file, source_file=None): assert "ab_partitions" in OPTIONS.info_dict, \ "META/ab_partitions.txt is required for ab_update." source_info = None - if not target_info.vabc_cow_version: + if not OPTIONS.vabc_cow_version: + if not target_info.vabc_cow_version: + OPTIONS.vabc_cow_version = 2 + elif target_info.vabc_cow_version >= "3" and target_info.vendor_api_level < 35: + logger.warning( + "This full OTA is configured to use VABC cow version" + " 3 which is supported since" + " Android API level 35, but device is " + "launched with {} . If this full OTA is" + " served to a device running old build, OTA might fail due to " + "unsupported vabc cow version. For safety, version 2 is used because " + "it's supported since day 1.".format( + target_info.vendor_api_level)) OPTIONS.vabc_cow_version = 2 - elif target_info.vabc_cow_version >= "3" and target_info.vendor_api_level < 35: - logger.warning( - "This full OTA is configured to use VABC cow version" - " 3 which is supported since" - " Android API level 35, but device is " - "launched with {} . If this full OTA is" - " served to a device running old build, OTA might fail due to " - "unsupported vabc cow version. For safety, version 2 is used because " - "it's supported since day 1.".format( - target_info.vendor_api_level)) - OPTIONS.vabc_cow_version = 2 if OPTIONS.vabc_compression_param is None and vabc_compression_param: minimum_api_level_required = VABC_COMPRESSION_PARAM_SUPPORT[ vabc_compression_param] |