Merge "Update sts-sdk to use new source" into main
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index ac5023f..75dd9f2 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -20,6 +20,7 @@
import logging
import os
import pathlib
+import re
import subprocess
import sys
from typing import Callable
@@ -52,6 +53,15 @@
any output zip files needed by the build.
"""
+ _DOWNLOAD_OPTS = {
+ 'test-config-only-zip',
+ 'test-zip-file-filter',
+ 'extra-host-shared-lib-zip',
+ 'sandbox-tests-zips',
+ 'additional-files-filter',
+ 'cts-package-name',
+ }
+
def __init__(
self,
build_context: dict[str, any],
@@ -64,12 +74,19 @@
def create_build_plan(self):
- if 'optimized_build' not in self.build_context['enabled_build_features']:
+ if 'optimized_build' not in self.build_context.get(
+ 'enabledBuildFeatures', []
+ ):
return BuildPlan(set(self.args.extra_targets), set())
build_targets = set()
packaging_functions = set()
for target in self.args.extra_targets:
+ if self._unused_target_exclusion_enabled(
+ target
+ ) and not self._build_target_used(target):
+ continue
+
target_optimizer_getter = self.target_optimizations.get(target, None)
if not target_optimizer_getter:
build_targets.add(target)
@@ -83,6 +100,60 @@
return BuildPlan(build_targets, packaging_functions)
+ def _unused_target_exclusion_enabled(self, target: str) -> bool:
+ return f'{target}_unused_exclusion' in self.build_context.get(
+ 'enabledBuildFeatures', []
+ )
+
+ def _build_target_used(self, target: str) -> bool:
+ """Determines whether this target's outputs are used by the test configurations listed in the build context."""
+ file_download_regexes = self._aggregate_file_download_regexes()
+ # For all of a targets' outputs, check if any of the regexes used by tests
+ # to download artifacts would match it. If any of them do then this target
+ # is necessary.
+ for artifact in self._get_target_potential_outputs(target):
+ for regex in file_download_regexes:
+ if re.match(regex, artifact):
+ return True
+ return False
+
+ def _get_target_potential_outputs(self, target: str) -> set[str]:
+ tests_suffix = '-tests'
+ if target.endswith('tests'):
+ tests_suffix = ''
+ # This is a list of all the potential zips output by the test suite targets.
+ # If the test downloads artifacts from any of these zips, we will be
+ # conservative and avoid skipping the tests.
+ return {
+ f'{target}.zip',
+ f'android-{target}.zip',
+ f'android-{target}-verifier.zip',
+ f'{target}{tests_suffix}_list.zip',
+ f'android-{target}{tests_suffix}_list.zip',
+ f'{target}{tests_suffix}_host-shared-libs.zip',
+ f'android-{target}{tests_suffix}_host-shared-libs.zip',
+ f'{target}{tests_suffix}_configs.zip',
+ f'android-{target}{tests_suffix}_configs.zip',
+ }
+
+ def _aggregate_file_download_regexes(self) -> set[re.Pattern]:
+ """Lists out all test config options to specify targets to download.
+
+ These come in the form of regexes.
+ """
+ all_regexes = set()
+ for test_info in self._get_test_infos():
+ for opt in test_info.get('extraOptions', []):
+ # check the known list of options for downloading files.
+ if opt.get('key') in self._DOWNLOAD_OPTS:
+ all_regexes.update(
+ re.compile(value) for value in opt.get('values', [])
+ )
+ return all_regexes
+
+ def _get_test_infos(self):
+ return self.build_context.get('testContext', dict()).get('testInfos', [])
+
@dataclass(frozen=True)
class BuildPlan:
@@ -155,7 +226,7 @@
def empty_build_context():
- return {'enabled_build_features': []}
+ return {'enabledBuildFeatures': []}
def execute_build_plan(build_plan: BuildPlan):
diff --git a/ci/build_test_suites_test.py b/ci/build_test_suites_test.py
index a9ff3fb..7efb154 100644
--- a/ci/build_test_suites_test.py
+++ b/ci/build_test_suites_test.py
@@ -324,6 +324,55 @@
self.run_packaging_functions(build_plan),
)
+ def test_target_output_used_target_built(self):
+ build_target = 'test_target'
+ build_planner = self.create_build_planner(
+ build_targets={build_target},
+ build_context=self.create_build_context(
+ test_context=self.get_test_context(build_target),
+ enabled_build_features={'test_target_unused_exclusion'},
+ ),
+ )
+
+ build_plan = build_planner.create_build_plan()
+
+ self.assertSetEqual(build_plan.build_targets, {build_target})
+
+ def test_target_regex_used_target_built(self):
+ build_target = 'test_target'
+ test_context = self.get_test_context(build_target)
+ test_context['testInfos'][0]['extraOptions'] = [{
+ 'key': 'additional-files-filter',
+ 'values': [f'.*{build_target}.*\.zip'],
+ }]
+ build_planner = self.create_build_planner(
+ build_targets={build_target},
+ build_context=self.create_build_context(
+ test_context=test_context,
+ enabled_build_features={'test_target_unused_exclusion'},
+ ),
+ )
+
+ build_plan = build_planner.create_build_plan()
+
+ self.assertSetEqual(build_plan.build_targets, {build_target})
+
+ def test_target_output_not_used_target_not_built(self):
+ build_target = 'test_target'
+ test_context = self.get_test_context(build_target)
+ test_context['testInfos'][0]['extraOptions'] = []
+ build_planner = self.create_build_planner(
+ build_targets={build_target},
+ build_context=self.create_build_context(
+ test_context=test_context,
+ enabled_build_features={'test_target_unused_exclusion'},
+ ),
+ )
+
+ build_plan = build_planner.create_build_plan()
+
+ self.assertSetEqual(build_plan.build_targets, set())
+
def create_build_planner(
self,
build_targets: set[str],
@@ -352,10 +401,10 @@
test_context: dict[str, any] = {},
) -> dict[str, any]:
build_context = {}
- build_context['enabled_build_features'] = enabled_build_features
+ build_context['enabledBuildFeatures'] = enabled_build_features
if optimized_build_enabled:
- build_context['enabled_build_features'].add('optimized_build')
- build_context['test_context'] = test_context
+ build_context['enabledBuildFeatures'].add('optimized_build')
+ build_context['testContext'] = test_context
return build_context
def create_args(
@@ -398,6 +447,25 @@
return output
+ def get_test_context(self, target: str):
+ return {
+ 'testInfos': [
+ {
+ 'name': 'atp_test',
+ 'target': 'test_target',
+ 'branch': 'branch',
+ 'extraOptions': [{
+ 'key': 'additional-files-filter',
+ 'values': [f'{target}.zip'],
+ }],
+ 'command': '/tf/command',
+ 'extraBuildTargets': [
+ 'extra_build_target',
+ ],
+ },
+ ],
+ }
+
def wait_until(
condition_function: Callable[[], bool],
diff --git a/ci/optimized_targets.py b/ci/optimized_targets.py
index 224c8c0..6321719 100644
--- a/ci/optimized_targets.py
+++ b/ci/optimized_targets.py
@@ -53,7 +53,7 @@
def get_target_optimizer(target, enabled_flag, build_context, optimizer):
- if enabled_flag in build_context['enabled_build_features']:
+ if enabled_flag in build_context['enabledBuildFeatures']:
return optimizer
return NullOptimizer(target)
diff --git a/core/Makefile b/core/Makefile
index 5ec5a94..96588e3 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -7863,9 +7863,7 @@
include $(BUILD_SYSTEM)/layoutlib_data.mk
# -----------------------------------------------------------------
-# Desktop pack image hook.
-ifneq (,$(strip $(PACK_DESKTOP_FILESYSTEM_IMAGES)))
-PACK_IMAGE_TARGET := $(PRODUCT_OUT)/android-desktop_image.bin
+# Desktop pack common variables.
PACK_IMAGE_SCRIPT := $(HOST_OUT_EXECUTABLES)/pack_image
IMAGES := $(INSTALLED_BOOTIMAGE_TARGET) \
$(INSTALLED_SUPERIMAGE_TARGET) \
@@ -7874,6 +7872,11 @@
$(INSTALLED_VBMETAIMAGE_TARGET) \
$(INSTALLED_USERDATAIMAGE_TARGET)
+# -----------------------------------------------------------------
+# Desktop pack image hook.
+ifneq (,$(strip $(PACK_DESKTOP_FILESYSTEM_IMAGES)))
+PACK_IMAGE_TARGET := $(PRODUCT_OUT)/android-desktop_image.bin
+
$(PACK_IMAGE_TARGET): $(IMAGES) $(PACK_IMAGE_SCRIPT)
$(PACK_IMAGE_SCRIPT) --out_dir $(PRODUCT_OUT) --noarchive
@@ -7889,6 +7892,25 @@
endif # PACK_DESKTOP_FILESYSTEM_IMAGES
# -----------------------------------------------------------------
+# Desktop pack recovery image hook.
+ifneq (,$(strip $(PACK_DESKTOP_RECOVERY_IMAGE)))
+PACK_RECOVERY_IMAGE_TARGET := $(PRODUCT_OUT)/android-desktop_recovery_image.bin
+
+$(PACK_RECOVERY_IMAGE_TARGET): $(IMAGES) $(PACK_IMAGE_SCRIPT)
+ $(PACK_IMAGE_SCRIPT) --out_dir $(PRODUCT_OUT) --noarchive --recovery
+
+PACKED_RECOVERY_IMAGE_ARCHIVE_TARGET := $(PACK_RECOVERY_IMAGE_TARGET).gz
+
+$(PACKED_RECOVERY_IMAGE_ARCHIVE_TARGET): $(PACK_RECOVERY_IMAGE_TARGET) | $(GZIP)
+ $(GZIP) -fk $(PACK_RECOVERY_IMAGE_TARGET)
+
+droidcore-unbundled: $(PACKED_RECOVERY_IMAGE_ARCHIVE_TARGET)
+
+$(call dist-for-goals,dist_files,$(PACKED_RECOVERY_IMAGE_ARCHIVE_TARGET))
+
+endif # PACK_DESKTOP_RECOVERY_IMAGE
+
+# -----------------------------------------------------------------
# OS Licensing
include $(BUILD_SYSTEM)/os_licensing.mk
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 461b284..6954c93 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -39,8 +39,14 @@
# For Sanitizers
$(call soong_config_set_bool,ANDROID,ASAN_ENABLED,$(if $(filter address,$(SANITIZE_TARGET)),true,false))
+$(call soong_config_set_bool,ANDROID,HWASAN_ENABLED,$(if $(filter hwaddress,$(SANITIZE_TARGET)),true,false))
$(call soong_config_set_bool,ANDROID,SANITIZE_TARGET_SYSTEM_ENABLED,$(if $(filter true,$(SANITIZE_TARGET_SYSTEM)),true,false))
+# For init.environ.rc
+$(call soong_config_set_bool,ANDROID,GCOV_COVERAGE,$(NATIVE_COVERAGE))
+$(call soong_config_set_bool,ANDROID,CLANG_COVERAGE,$(CLANG_COVERAGE))
+$(call soong_config_set,ANDROID,SCUDO_ALLOCATION_RING_BUFFER_SIZE,$(PRODUCT_SCUDO_ALLOCATION_RING_BUFFER_SIZE))
+
# PRODUCT_PRECOMPILED_SEPOLICY defaults to true. Explicitly check if it's "false" or not.
$(call soong_config_set_bool,ANDROID,PRODUCT_PRECOMPILED_SEPOLICY,$(if $(filter false,$(PRODUCT_PRECOMPILED_SEPOLICY)),false,true))
@@ -49,6 +55,8 @@
ifdef ART_DEBUG_OPT_FLAG
$(call soong_config_set,art_module,art_debug_opt_flag,$(ART_DEBUG_OPT_FLAG))
endif
+# The default value of ART_BUILD_HOST_DEBUG is true
+$(call soong_config_set_bool,art_module,art_build_host_debug,$(if $(filter false,$(ART_BUILD_HOST_DEBUG)),false,true))
ifdef TARGET_BOARD_AUTO
$(call add_soong_config_var_value, ANDROID, target_board_auto, $(TARGET_BOARD_AUTO))
diff --git a/core/config.mk b/core/config.mk
index 0c8a87f..bd905dc 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -1250,7 +1250,11 @@
TARGET_SYSTEM_PROP := $(wildcard $(TARGET_DEVICE_DIR)/system.prop)
endif
-.KATI_READONLY += TARGET_SYSTEM_PROP
+ifeq ($(TARGET_SYSTEM_EXT_PROP),)
+TARGET_SYSTEM_EXT_PROP := $(wildcard $(TARGET_DEVICE_DIR)/system_ext.prop)
+endif
+
+.KATI_READONLY += TARGET_SYSTEM_PROP TARGET_SYSTEM_EXT_PROP
include $(BUILD_SYSTEM)/sysprop_config.mk
diff --git a/core/dex_preopt.mk b/core/dex_preopt.mk
index 26b8b17..906d7f0 100644
--- a/core/dex_preopt.mk
+++ b/core/dex_preopt.mk
@@ -13,25 +13,6 @@
install-on-system-other = $(filter-out $(PRODUCT_DEXPREOPT_SPEED_APPS) $(PRODUCT_SYSTEM_SERVER_APPS),$(basename $(notdir $(filter $(foreach f,$(SYSTEM_OTHER_ODEX_FILTER),$(TARGET_OUT)/$(f)),$(1)))))
endif
-# We want to install the profile even if we are not using preopt since it is required to generate
-# the image on the device.
-ALL_DEFAULT_INSTALLED_MODULES += $(call copy-many-files,$(DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED),$(PRODUCT_OUT))
-
-# Install boot images. Note that there can be multiple.
-my_boot_image_arch := TARGET_ARCH
-my_boot_image_out := $(PRODUCT_OUT)
-my_boot_image_syms := $(TARGET_OUT_UNSTRIPPED)
-DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE := \
- $(foreach my_boot_image_name,$(DEXPREOPT_IMAGE_NAMES),$(strip \
- $(eval include $(BUILD_SYSTEM)/dex_preopt_libart.mk) \
- $(my_boot_image_module)))
-ifdef TARGET_2ND_ARCH
- my_boot_image_arch := TARGET_2ND_ARCH
- 2ND_DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE := \
- $(foreach my_boot_image_name,$(DEXPREOPT_IMAGE_NAMES),$(strip \
- $(eval include $(BUILD_SYSTEM)/dex_preopt_libart.mk) \
- $(my_boot_image_module)))
-endif
# Install boot images for testing on host. We exclude framework image as it is not part of art manifest.
my_boot_image_arch := HOST_ARCH
my_boot_image_out := $(HOST_OUT)
diff --git a/core/main.mk b/core/main.mk
index 8d73793..ac1953b 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -1860,75 +1860,8 @@
installed_files := $(apps_only_installed_files)
endif # TARGET_BUILD_APPS
-# sbom-metadata.csv contains all raw data collected in Make for generating SBOM in generate-sbom.py.
-# There are multiple columns and each identifies the source of an installed file for a specific case.
-# The columns and their uses are described as below:
-# installed_file: the file path on device, e.g. /product/app/Browser2/Browser2.apk
-# module_path: the path of the module that generates the installed file, e.g. packages/apps/Browser2
-# soong_module_type: Soong module type, e.g. android_app, cc_binary
-# is_prebuilt_make_module: Y, if the installed file is from a prebuilt Make module, see prebuilt_internal.mk
-# product_copy_files: the installed file is from variable PRODUCT_COPY_FILES, e.g. device/google/cuttlefish/shared/config/init.product.rc:product/etc/init/init.rc
-# kernel_module_copy_files: the installed file is from variable KERNEL_MODULE_COPY_FILES, similar to product_copy_files
-# is_platform_generated: this is an aggregated value including some small cases instead of adding more columns. It is set to Y if any case is Y
-# is_build_prop: build.prop in each partition, see sysprop.mk.
-# is_notice_file: NOTICE.xml.gz in each partition, see Makefile.
-# is_dexpreopt_image_profile: see the usage of DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED in Soong and Make
-# is_product_system_other_avbkey: see INSTALLED_PRODUCT_SYSTEM_OTHER_AVBKEY_TARGET
-# is_system_other_odex_marker: see INSTALLED_SYSTEM_OTHER_ODEX_MARKER
-# is_event_log_tags_file: see variable event_log_tags_file in Makefile
-# is_kernel_modules_blocklist: modules.blocklist created for _dlkm partitions, see macro build-image-kernel-modules-dir in Makefile.
-# is_fsverity_build_manifest_apk: BuildManifest<part>.apk files for system and system_ext partition, see ALL_FSVERITY_BUILD_MANIFEST_APK in Makefile.
-# is_linker_config: see SYSTEM_LINKER_CONFIG and vendor_linker_config_file in Makefile.
-# build_output_path: the path of the built file, used to calculate checksum
-# static_libraries/whole_static_libraries: list of module name of the static libraries the file links against, e.g. libclang_rt.builtins or libclang_rt.builtins_32
-# Info of all static libraries of all installed files are collected in variable _all_static_libs that is used to list all the static library files in sbom-metadata.csv.
-# See the second foreach loop in the rule of sbom-metadata.csv for the detailed info of static libraries collected in _all_static_libs.
-# is_static_lib: whether the file is a static library
-
metadata_list := $(OUT_DIR)/.module_paths/METADATA.list
metadata_files := $(subst $(newline),$(space),$(file <$(metadata_list)))
-$(PRODUCT_OUT)/sbom-metadata.csv:
- rm -f $@
- echo 'installed_file,module_path,soong_module_type,is_prebuilt_make_module,product_copy_files,kernel_module_copy_files,is_platform_generated,build_output_path,static_libraries,whole_static_libraries,is_static_lib' >> $@
- $(eval _all_static_libs :=)
- $(foreach f,$(installed_files),\
- $(eval _module_name := $(ALL_INSTALLED_FILES.$f)) \
- $(eval _path_on_device := $(patsubst $(PRODUCT_OUT)/%,%,$f)) \
- $(eval _build_output_path := $(PRODUCT_OUT)/$(_path_on_device)) \
- $(eval _module_path := $(strip $(sort $(ALL_MODULES.$(_module_name).PATH)))) \
- $(eval _soong_module_type := $(strip $(sort $(ALL_MODULES.$(_module_name).SOONG_MODULE_TYPE)))) \
- $(eval _is_prebuilt_make_module := $(ALL_MODULES.$(_module_name).IS_PREBUILT_MAKE_MODULE)) \
- $(eval _product_copy_files := $(sort $(filter %:$(_path_on_device),$(product_copy_files_without_owner)))) \
- $(eval _kernel_module_copy_files := $(sort $(filter %$(_path_on_device),$(KERNEL_MODULE_COPY_FILES)))) \
- $(eval _is_build_prop := $(call is-build-prop,$f)) \
- $(eval _is_notice_file := $(call is-notice-file,$f)) \
- $(eval _is_dexpreopt_image_profile := $(if $(filter %:/$(_path_on_device),$(DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED)),Y)) \
- $(eval _is_product_system_other_avbkey := $(if $(findstring $f,$(INSTALLED_PRODUCT_SYSTEM_OTHER_AVBKEY_TARGET)),Y)) \
- $(eval _is_event_log_tags_file := $(if $(findstring $f,$(event_log_tags_file)),Y)) \
- $(eval _is_system_other_odex_marker := $(if $(findstring $f,$(INSTALLED_SYSTEM_OTHER_ODEX_MARKER)),Y)) \
- $(eval _is_kernel_modules_blocklist := $(if $(findstring $f,$(ALL_KERNEL_MODULES_BLOCKLIST)),Y)) \
- $(eval _is_fsverity_build_manifest_apk := $(if $(findstring $f,$(ALL_FSVERITY_BUILD_MANIFEST_APK)),Y)) \
- $(eval _is_linker_config := $(if $(findstring $f,$(SYSTEM_LINKER_CONFIG) $(vendor_linker_config_file)),Y)) \
- $(eval _is_partition_compat_symlink := $(if $(findstring $f,$(PARTITION_COMPAT_SYMLINKS)),Y)) \
- $(eval _is_flags_file := $(if $(findstring $f, $(ALL_FLAGS_FILES)),Y)) \
- $(eval _is_rootdir_symlink := $(if $(findstring $f, $(ALL_ROOTDIR_SYMLINKS)),Y)) \
- $(eval _is_platform_generated := $(_is_build_prop)$(_is_notice_file)$(_is_dexpreopt_image_profile)$(_is_product_system_other_avbkey)$(_is_event_log_tags_file)$(_is_system_other_odex_marker)$(_is_kernel_modules_blocklist)$(_is_fsverity_build_manifest_apk)$(_is_linker_config)$(_is_partition_compat_symlink)$(_is_flags_file)$(_is_rootdir_symlink)) \
- $(eval _static_libs := $(ALL_INSTALLED_FILES.$f.STATIC_LIBRARIES)) \
- $(eval _whole_static_libs := $(ALL_INSTALLED_FILES.$f.WHOLE_STATIC_LIBRARIES)) \
- $(foreach l,$(_static_libs),$(eval _all_static_libs += $l:$(strip $(sort $(ALL_MODULES.$l.PATH))):$(strip $(sort $(ALL_MODULES.$l.SOONG_MODULE_TYPE))):$(ALL_STATIC_LIBRARIES.$l.BUILT_FILE))) \
- $(foreach l,$(_whole_static_libs),$(eval _all_static_libs += $l:$(strip $(sort $(ALL_MODULES.$l.PATH))):$(strip $(sort $(ALL_MODULES.$l.SOONG_MODULE_TYPE))):$(ALL_STATIC_LIBRARIES.$l.BUILT_FILE))) \
- echo '/$(_path_on_device),$(_module_path),$(_soong_module_type),$(_is_prebuilt_make_module),$(_product_copy_files),$(_kernel_module_copy_files),$(_is_platform_generated),$(_build_output_path),$(_static_libs),$(_whole_static_libs),' >> $@; \
- )
- $(foreach l,$(sort $(_all_static_libs)), \
- $(eval _lib_stem := $(call word-colon,1,$l)) \
- $(eval _module_path := $(call word-colon,2,$l)) \
- $(eval _soong_module_type := $(call word-colon,3,$l)) \
- $(eval _built_file := $(call word-colon,4,$l)) \
- $(eval _static_libs := $(ALL_STATIC_LIBRARIES.$l.STATIC_LIBRARIES)) \
- $(eval _whole_static_libs := $(ALL_STATIC_LIBRARIES.$l.WHOLE_STATIC_LIBRARIES)) \
- $(eval _is_static_lib := Y) \
- echo '$(_lib_stem).a,$(_module_path),$(_soong_module_type),,,,,$(_built_file),$(_static_libs),$(_whole_static_libs),$(_is_static_lib)' >> $@; \
- )
# Create metadata for compliance support in Soong
.PHONY: make-compliance-metadata
@@ -1988,22 +1921,13 @@
$(SOONG_OUT_DIR)/compliance-metadata/$(TARGET_PRODUCT)/installed_files.stamp: $(installed_files)
touch $@
-# (TODO: b/272358583 find another way of always rebuilding sbom.spdx)
# Remove the always_dirty_file.txt whenever the makefile is evaluated
$(shell rm -f $(PRODUCT_OUT)/always_dirty_file.txt)
$(PRODUCT_OUT)/always_dirty_file.txt:
touch $@
.PHONY: sbom
-ifeq ($(TARGET_BUILD_APPS),)
-sbom: $(PRODUCT_OUT)/sbom.spdx.json
-$(PRODUCT_OUT)/sbom.spdx.json: $(PRODUCT_OUT)/sbom.spdx
-$(PRODUCT_OUT)/sbom.spdx: $(PRODUCT_OUT)/sbom-metadata.csv $(GEN_SBOM) $(installed_files) $(metadata_list) $(metadata_files) $(PRODUCT_OUT)/always_dirty_file.txt
- rm -rf $@
- $(GEN_SBOM) --output_file $@ --metadata $(PRODUCT_OUT)/sbom-metadata.csv --build_version $(BUILD_FINGERPRINT_FROM_FILE) --product_mfr "$(PRODUCT_MANUFACTURER)" --json
-
-$(call dist-for-goals,droid,$(PRODUCT_OUT)/sbom.spdx.json:sbom/sbom.spdx.json)
-else
+ifneq ($(TARGET_BUILD_APPS),)
# Create build rules for generating SBOMs of unbundled APKs and APEXs
# $1: sbom file
# $2: sbom fragment file
diff --git a/core/product.mk b/core/product.mk
index ad80ee4..8d86d92 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -26,6 +26,7 @@
_product_single_value_vars += PRODUCT_MODEL
_product_single_value_vars += PRODUCT_NAME_FOR_ATTESTATION
_product_single_value_vars += PRODUCT_MODEL_FOR_ATTESTATION
+_product_single_value_vars += PRODUCT_BASE_OS
# Defines the ELF segment alignment for binaries (executables and shared libraries).
# The ELF segment alignment has to be a PAGE_SIZE multiple. For example, if
diff --git a/core/product_config.mk b/core/product_config.mk
index cc2fea9..738d4cf 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -311,6 +311,14 @@
TARGET_DEVICE := $(PRODUCT_DEVICE)
+# Allow overriding PLATFORM_BASE_OS when PRODUCT_BASE_OS is defined
+ifdef PRODUCT_BASE_OS
+ PLATFORM_BASE_OS := $(PRODUCT_BASE_OS)
+else
+ PLATFORM_BASE_OS := $(PLATFORM_BASE_OS_ENV_INPUT)
+endif
+.KATI_READONLY := PLATFORM_BASE_OS
+
# TODO: also keep track of things like "port", "land" in product files.
# Figure out which resoure configuration options to use for this
diff --git a/core/ravenwood_test_config_template.xml b/core/ravenwood_test_config_template.xml
index 088a55a..2f21bae 100644
--- a/core/ravenwood_test_config_template.xml
+++ b/core/ravenwood_test_config_template.xml
@@ -21,7 +21,6 @@
<option name="java-folder" value="prebuilts/jdk/jdk21/linux-x86/" />
<option name="use-ravenwood-resources" value="true" />
<option name="exclude-paths" value="java" />
- <option name="socket-timeout" value="10000" />
<option name="null-device" value="true" />
{EXTRA_CONFIGS}
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 09ee938..5fca203 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -341,6 +341,7 @@
$(call add_json_list, OemProperties, $(PRODUCT_OEM_PROPERTIES))
$(call add_json_list, SystemPropFiles, $(TARGET_SYSTEM_PROP))
+$(call add_json_list, SystemExtPropFiles, $(TARGET_SYSTEM_EXT_PROP))
# Do not set ArtTargetIncludeDebugBuild into any value if PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD is not set,
# to have the same behavior from runtime_libart.mk.
diff --git a/core/soong_java_prebuilt.mk b/core/soong_java_prebuilt.mk
index 7f85231..f74bb6d 100644
--- a/core/soong_java_prebuilt.mk
+++ b/core/soong_java_prebuilt.mk
@@ -115,16 +115,14 @@
boot_jars := $(foreach pair,$(PRODUCT_BOOT_JARS), $(call word-colon,2,$(pair)))
ifneq ($(filter $(LOCAL_MODULE),$(boot_jars)),) # is_boot_jar
ifeq (true,$(WITH_DEXPREOPT))
- # $(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE) contains modules that installs
- # all of bootjars' dexpreopt files (.art, .oat, .vdex, ...)
+ # dex_bootjars singleton installs all of bootjars' dexpreopt files (.art, .oat, .vdex, ...)
+ # This includes both the primary and secondary arches.
# Add them to the required list so they are installed alongside this module.
- ALL_MODULES.$(my_register_name).REQUIRED_FROM_TARGET += \
- $(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE) \
- $(2ND_DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE)
+ ALL_MODULES.$(my_register_name).REQUIRED_FROM_TARGET += dex_bootjars
# Copy $(LOCAL_BUILT_MODULE) and its dependencies when installing boot.art
# so that dependencies of $(LOCAL_BUILT_MODULE) (which may include
# jacoco-report-classes.jar) are copied for every build.
- $(foreach m,$(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE) $(2ND_DEFAULT_DEX_PREOPT_INSTALLED_IMAGE_MODULE), \
+ $(foreach m,dex_bootjars, \
$(eval $(call add-dependency,$(firstword $(call module-installed-files,$(m))),$(LOCAL_BUILT_MODULE))) \
)
endif
diff --git a/core/sysprop.mk b/core/sysprop.mk
index 7dd756a..6d65e19 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -395,25 +395,10 @@
# -----------------------------------------------------------------
# system_ext/etc/build.prop
#
-_prop_files_ := $(if $(TARGET_SYSTEM_EXT_PROP),\
- $(TARGET_SYSTEM_EXT_PROP),\
- $(wildcard $(TARGET_DEVICE_DIR)/system_ext.prop))
-
-# Order matters here. When there are duplicates, the last one wins.
-# TODO(b/117892318): don't allow duplicates so that the ordering doesn't matter
-_prop_vars_ := PRODUCT_SYSTEM_EXT_PROPERTIES
+# system_ext/build.prop is built by Soong. See system-build.prop module in
+# build/soong/Android.bp.
INSTALLED_SYSTEM_EXT_BUILD_PROP_TARGET := $(TARGET_OUT_SYSTEM_EXT)/etc/build.prop
-$(eval $(call build-properties,\
- system_ext,\
- $(INSTALLED_SYSTEM_EXT_BUILD_PROP_TARGET),\
- $(_prop_files_),\
- $(_prop_vars_),\
- $(empty),\
- $(empty),\
- $(empty)))
-
-$(eval $(call declare-1p-target,$(INSTALLED_SYSTEM_EXT_BUILD_PROP_TARGET)))
# ----------------------------------------------------------------
# ramdisk/boot/etc/build.prop
diff --git a/core/version_util.mk b/core/version_util.mk
index eb568be..0e34634 100644
--- a/core/version_util.mk
+++ b/core/version_util.mk
@@ -183,14 +183,17 @@
endif
.KATI_READONLY := PLATFORM_SECURITY_PATCH_TIMESTAMP
-ifndef PLATFORM_BASE_OS
- # Used to indicate the base os applied to the device.
- # Can be an arbitrary string, but must be a single word.
- #
- # If there is no $PLATFORM_BASE_OS set, keep it empty.
- PLATFORM_BASE_OS :=
-endif
-.KATI_READONLY := PLATFORM_BASE_OS
+# PLATFORM_BASE_OS is used to indicate the base os applied
+# to the device. Can be an arbitrary string, but must be a
+# single word.
+#
+# If there is no $PLATFORM_BASE_OS set, keep it empty.
+#
+# PLATFORM_BASE_OS can either be set via an enviornment
+# variable, or set via the PRODUCT_BASE_OS product variable.
+PLATFORM_BASE_OS_ENV_INPUT := $(PLATFORM_BASE_OS)
+.KATI_READONLY := PLATFORM_BASE_OS_ENV_INPUT
+PLATFORM_BASE_OS :=
ifndef BUILD_ID
# Used to signify special builds. E.g., branches and/or releases,
diff --git a/target/product/base_system_ext.mk b/target/product/base_system_ext.mk
index 92ca227..febe537 100644
--- a/target/product/base_system_ext.mk
+++ b/target/product/base_system_ext.mk
@@ -24,6 +24,7 @@
SatelliteClient \
selinux_policy_system_ext \
system_ext_manifest.xml \
+ system_ext-build.prop \
# Base modules when shipping api level is less than or equal to 34
PRODUCT_PACKAGES_SHIPPING_API_LEVEL_34 += \
diff --git a/target/product/base_vendor.mk b/target/product/base_vendor.mk
index 52e2583..5b1cae5 100644
--- a/target/product/base_vendor.mk
+++ b/target/product/base_vendor.mk
@@ -74,6 +74,11 @@
selinux_policy_nonsystem \
shell_and_utilities_vendor \
+# libhealthloop BPF filter. This is in base_vendor.mk because libhealthloop must
+# be a static library and because the Android build system ignores 'required'
+# sections for static libraries.
+PRODUCT_PACKAGES += filterPowerSupplyEvents.o
+
# Base modules when shipping api level is less than or equal to 34
PRODUCT_PACKAGES_SHIPPING_API_LEVEL_34 += \
android.hidl.memory@1.0-impl.vendor \
diff --git a/target/product/runtime_libart.mk b/target/product/runtime_libart.mk
index 58234a8..9e8afa8 100644
--- a/target/product/runtime_libart.mk
+++ b/target/product/runtime_libart.mk
@@ -181,3 +181,5 @@
# Copy preopted files from system_b on first boot.
PRODUCT_SYSTEM_PROPERTIES += ro.cp_system_other_odex=1
+PRODUCT_PACKAGES += \
+ cppreopts.sh
diff --git a/tools/aconfig/aconfig/src/codegen/cpp.rs b/tools/aconfig/aconfig/src/codegen/cpp.rs
index e743b2f..2c569da 100644
--- a/tools/aconfig/aconfig/src/codegen/cpp.rs
+++ b/tools/aconfig/aconfig/src/codegen/cpp.rs
@@ -45,6 +45,8 @@
let header = package.replace('.', "_");
let package_macro = header.to_uppercase();
let cpp_namespace = package.replace('.', "::");
+ ensure!(class_elements.len() > 0);
+ let container = class_elements[0].container.clone();
ensure!(codegen::is_valid_name_ident(&header));
let context = Context {
header: &header,
@@ -56,6 +58,7 @@
readwrite_count,
is_test_mode: codegen_mode == CodegenMode::Test,
class_elements,
+ container,
allow_instrumentation,
};
@@ -100,6 +103,7 @@
pub readwrite_count: i32,
pub is_test_mode: bool,
pub class_elements: Vec<ClassElement>,
+ pub container: String,
pub allow_instrumentation: bool,
}
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index 727f810..a74ef85 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -745,18 +745,33 @@
} else {
Log.i(TAG, String.format(MISMATCH_LOG, "disabledRw", val, disabledRw));
}
+
+ if (DeviceConfig.getBoolean("core_experiments_team_internal", "com.android.providers.settings.use_new_storage_value", false)) {
+ disabledRw = val;
+ }
+
val = reader.getBooleanFlagValue(2);
if (val == disabledRwExported) {
Log.i(TAG, String.format(SUCCESS_LOG, "disabledRwExported"));
} else {
Log.i(TAG, String.format(MISMATCH_LOG, "disabledRwExported", val, disabledRwExported));
}
+
+ if (DeviceConfig.getBoolean("core_experiments_team_internal", "com.android.providers.settings.use_new_storage_value", false)) {
+ disabledRwExported = val;
+ }
+
val = reader.getBooleanFlagValue(8);
if (val == enabledRw) {
Log.i(TAG, String.format(SUCCESS_LOG, "enabledRw"));
} else {
Log.i(TAG, String.format(MISMATCH_LOG, "enabledRw", val, enabledRw));
}
+
+ if (DeviceConfig.getBoolean("core_experiments_team_internal", "com.android.providers.settings.use_new_storage_value", false)) {
+ enabledRw = val;
+ }
+
} catch (Exception e) {
Log.e(TAG, ERROR_LOG, e);
}
@@ -789,6 +804,11 @@
} else {
Log.i(TAG, String.format(MISMATCH_LOG, "disabledRwInOtherNamespace", val, disabledRwInOtherNamespace));
}
+
+ if (DeviceConfig.getBoolean("core_experiments_team_internal", "com.android.providers.settings.use_new_storage_value", false)) {
+ disabledRwInOtherNamespace = val;
+ }
+
} catch (Exception e) {
Log.e(TAG, ERROR_LOG, e);
}
diff --git a/tools/aconfig/aconfig/src/codegen/rust.rs b/tools/aconfig/aconfig/src/codegen/rust.rs
index 33c3d37..1292e0a 100644
--- a/tools/aconfig/aconfig/src/codegen/rust.rs
+++ b/tools/aconfig/aconfig/src/codegen/rust.rs
@@ -20,26 +20,34 @@
use aconfig_protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};
+use std::collections::HashMap;
+
use crate::codegen;
use crate::codegen::CodegenMode;
use crate::commands::OutputFile;
pub fn generate_rust_code<I>(
package: &str,
+ flag_ids: HashMap<String, u16>,
parsed_flags_iter: I,
codegen_mode: CodegenMode,
+ allow_instrumentation: bool,
) -> Result<OutputFile>
where
I: Iterator<Item = ProtoParsedFlag>,
{
- let template_flags: Vec<TemplateParsedFlag> =
- parsed_flags_iter.map(|pf| TemplateParsedFlag::new(package, &pf)).collect();
+ let template_flags: Vec<TemplateParsedFlag> = parsed_flags_iter
+ .map(|pf| TemplateParsedFlag::new(package, flag_ids.clone(), &pf))
+ .collect();
let has_readwrite = template_flags.iter().any(|item| item.readwrite);
+ let container = (template_flags.first().expect("zero template flags").container).to_string();
let context = TemplateContext {
package: package.to_string(),
template_flags,
modules: package.split('.').map(|s| s.to_string()).collect::<Vec<_>>(),
has_readwrite,
+ allow_instrumentation,
+ container,
};
let mut template = TinyTemplate::new();
template.add_template(
@@ -62,6 +70,8 @@
pub template_flags: Vec<TemplateParsedFlag>,
pub modules: Vec<String>,
pub has_readwrite: bool,
+ pub allow_instrumentation: bool,
+ pub container: String,
}
#[derive(Serialize)]
@@ -69,25 +79,28 @@
pub readwrite: bool,
pub default_value: String,
pub name: String,
+ pub container: String,
+ pub flag_offset: u16,
pub device_config_namespace: String,
pub device_config_flag: String,
}
impl TemplateParsedFlag {
#[allow(clippy::nonminimal_bool)]
- fn new(package: &str, pf: &ProtoParsedFlag) -> Self {
- let template = TemplateParsedFlag {
+ fn new(package: &str, flag_offsets: HashMap<String, u16>, pf: &ProtoParsedFlag) -> Self {
+ Self {
readwrite: pf.permission() == ProtoFlagPermission::READ_WRITE,
default_value: match pf.state() {
ProtoFlagState::ENABLED => "true".to_string(),
ProtoFlagState::DISABLED => "false".to_string(),
},
name: pf.name().to_string(),
+ container: pf.container().to_string(),
+ flag_offset: *flag_offsets.get(pf.name()).expect("didnt find package offset :("),
device_config_namespace: pf.namespace().to_string(),
device_config_flag: codegen::create_device_config_ident(package, pf.name())
.expect("values checked at flag parse time"),
- };
- template
+ }
}
}
@@ -97,6 +110,14 @@
const PROD_EXPECTED: &str = r#"
//! codegenerated rust flag lib
+use aconfig_storage_read_api::{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
+use std::path::Path;
+use std::io::Write;
+use log::{log, LevelFilter, Level};
+
+static STORAGE_MIGRATION_MARKER_FILE: &str =
+ "/metadata/aconfig_test_missions/mission_1";
+static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
/// flag provider
pub struct FlagProvider;
@@ -233,6 +254,697 @@
}
"#;
+ const PROD_INSTRUMENTED_EXPECTED: &str = r#"
+//! codegenerated rust flag lib
+use aconfig_storage_read_api::{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
+use std::path::Path;
+use std::io::Write;
+use log::{log, LevelFilter, Level};
+
+static STORAGE_MIGRATION_MARKER_FILE: &str =
+ "/metadata/aconfig_test_missions/mission_1";
+static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
+
+/// flag provider
+pub struct FlagProvider;
+
+lazy_static::lazy_static! {
+
+ static ref PACKAGE_OFFSET: Result<Option<u32>, AconfigStorageError> = unsafe {
+ get_mapped_storage_file("system", StorageFileType::PackageMap)
+ .and_then(|package_map| get_package_read_context(&package_map, "com.android.aconfig.test"))
+ .map(|context| context.map(|c| c.boolean_start_index))
+ };
+
+ static ref FLAG_VAL_MAP: Result<Mmap, AconfigStorageError> = unsafe {
+ get_mapped_storage_file("system", StorageFileType::FlagVal)
+ };
+ /// flag value cache for disabled_rw
+
+ static ref CACHED_disabled_rw: bool = {
+ let result = flags_rust::GetServerConfigurableFlag(
+ "aconfig_flags.aconfig_test",
+ "com.android.aconfig.test.disabled_rw",
+ "false") == "true";
+
+ let use_new_storage_value = flags_rust::GetServerConfigurableFlag(
+ "aconfig_flags.core_experiments_team_internal",
+ "com.android.providers.settings.use_new_storage_value",
+ "false") == "true";
+
+ if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+ // This will be called multiple times. Subsequent calls after the first are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device(MIGRATION_LOG_TAG)
+ .with_max_level(LevelFilter::Info));
+
+ let aconfig_storage_result = FLAG_VAL_MAP
+ .as_ref()
+ .map_err(|err| format!("failed to get flag val map: {err}"))
+ .and_then(|flag_val_map| {
+ PACKAGE_OFFSET
+ .as_ref()
+ .map_err(|err| format!("failed to get package read offset: {err}"))
+ .and_then(|package_offset| {
+ match package_offset {
+ Some(offset) => {
+ get_boolean_flag_value(&flag_val_map, offset + 1)
+ .map_err(|err| format!("failed to get flag: {err}"))
+ },
+ None => Err("no context found for package 'com.android.aconfig.test'".to_string())
+ }
+ })
+ });
+
+ match aconfig_storage_result {
+ Ok(storage_result) if storage_result == result => {
+ if use_new_storage_value {
+ return storage_result;
+ } else {
+ return result;
+ }
+ },
+ Ok(storage_result) => {
+ log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'disabled_rw'. Legacy storage was {result}, new storage was {storage_result}");
+ if use_new_storage_value {
+ return storage_result;
+ } else {
+ return result;
+ }
+ },
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: {err}");
+ if use_new_storage_value {
+ panic!("failed to read flag value: {err}");
+ }
+ }
+ }
+ }
+
+ result
+ };
+
+ /// flag value cache for disabled_rw_exported
+
+ static ref CACHED_disabled_rw_exported: bool = {
+ let result = flags_rust::GetServerConfigurableFlag(
+ "aconfig_flags.aconfig_test",
+ "com.android.aconfig.test.disabled_rw_exported",
+ "false") == "true";
+
+ let use_new_storage_value = flags_rust::GetServerConfigurableFlag(
+ "aconfig_flags.core_experiments_team_internal",
+ "com.android.providers.settings.use_new_storage_value",
+ "false") == "true";
+
+ if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+ // This will be called multiple times. Subsequent calls after the first are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device(MIGRATION_LOG_TAG)
+ .with_max_level(LevelFilter::Info));
+
+ let aconfig_storage_result = FLAG_VAL_MAP
+ .as_ref()
+ .map_err(|err| format!("failed to get flag val map: {err}"))
+ .and_then(|flag_val_map| {
+ PACKAGE_OFFSET
+ .as_ref()
+ .map_err(|err| format!("failed to get package read offset: {err}"))
+ .and_then(|package_offset| {
+ match package_offset {
+ Some(offset) => {
+ get_boolean_flag_value(&flag_val_map, offset + 2)
+ .map_err(|err| format!("failed to get flag: {err}"))
+ },
+ None => Err("no context found for package 'com.android.aconfig.test'".to_string())
+ }
+ })
+ });
+
+ match aconfig_storage_result {
+ Ok(storage_result) if storage_result == result => {
+ if use_new_storage_value {
+ return storage_result;
+ } else {
+ return result;
+ }
+ },
+ Ok(storage_result) => {
+ log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'disabled_rw_exported'. Legacy storage was {result}, new storage was {storage_result}");
+ if use_new_storage_value {
+ return storage_result;
+ } else {
+ return result;
+ }
+ },
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: {err}");
+ if use_new_storage_value {
+ panic!("failed to read flag value: {err}");
+ }
+ }
+ }
+ }
+
+ result
+ };
+
+ /// flag value cache for disabled_rw_in_other_namespace
+
+ static ref CACHED_disabled_rw_in_other_namespace: bool = {
+ let result = flags_rust::GetServerConfigurableFlag(
+ "aconfig_flags.other_namespace",
+ "com.android.aconfig.test.disabled_rw_in_other_namespace",
+ "false") == "true";
+
+ let use_new_storage_value = flags_rust::GetServerConfigurableFlag(
+ "aconfig_flags.core_experiments_team_internal",
+ "com.android.providers.settings.use_new_storage_value",
+ "false") == "true";
+
+ if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+ // This will be called multiple times. Subsequent calls after the first are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device(MIGRATION_LOG_TAG)
+ .with_max_level(LevelFilter::Info));
+
+ let aconfig_storage_result = FLAG_VAL_MAP
+ .as_ref()
+ .map_err(|err| format!("failed to get flag val map: {err}"))
+ .and_then(|flag_val_map| {
+ PACKAGE_OFFSET
+ .as_ref()
+ .map_err(|err| format!("failed to get package read offset: {err}"))
+ .and_then(|package_offset| {
+ match package_offset {
+ Some(offset) => {
+ get_boolean_flag_value(&flag_val_map, offset + 3)
+ .map_err(|err| format!("failed to get flag: {err}"))
+ },
+ None => Err("no context found for package 'com.android.aconfig.test'".to_string())
+ }
+ })
+ });
+
+ match aconfig_storage_result {
+ Ok(storage_result) if storage_result == result => {
+ if use_new_storage_value {
+ return storage_result;
+ } else {
+ return result;
+ }
+ },
+ Ok(storage_result) => {
+ log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'disabled_rw_in_other_namespace'. Legacy storage was {result}, new storage was {storage_result}");
+ if use_new_storage_value {
+ return storage_result;
+ } else {
+ return result;
+ }
+ },
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: {err}");
+ if use_new_storage_value {
+ panic!("failed to read flag value: {err}");
+ }
+ }
+ }
+ }
+
+ result
+ };
+
+ /// flag value cache for enabled_rw
+
+ static ref CACHED_enabled_rw: bool = {
+ let result = flags_rust::GetServerConfigurableFlag(
+ "aconfig_flags.aconfig_test",
+ "com.android.aconfig.test.enabled_rw",
+ "true") == "true";
+
+ let use_new_storage_value = flags_rust::GetServerConfigurableFlag(
+ "aconfig_flags.core_experiments_team_internal",
+ "com.android.providers.settings.use_new_storage_value",
+ "false") == "true";
+
+ if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+ // This will be called multiple times. Subsequent calls after the first are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device(MIGRATION_LOG_TAG)
+ .with_max_level(LevelFilter::Info));
+
+ let aconfig_storage_result = FLAG_VAL_MAP
+ .as_ref()
+ .map_err(|err| format!("failed to get flag val map: {err}"))
+ .and_then(|flag_val_map| {
+ PACKAGE_OFFSET
+ .as_ref()
+ .map_err(|err| format!("failed to get package read offset: {err}"))
+ .and_then(|package_offset| {
+ match package_offset {
+ Some(offset) => {
+ get_boolean_flag_value(&flag_val_map, offset + 8)
+ .map_err(|err| format!("failed to get flag: {err}"))
+ },
+ None => Err("no context found for package 'com.android.aconfig.test'".to_string())
+ }
+ })
+ });
+
+ match aconfig_storage_result {
+ Ok(storage_result) if storage_result == result => {
+ if use_new_storage_value {
+ return storage_result;
+ } else {
+ return result;
+ }
+ },
+ Ok(storage_result) => {
+ log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'enabled_rw'. Legacy storage was {result}, new storage was {storage_result}");
+ if use_new_storage_value {
+ return storage_result;
+ } else {
+ return result;
+ }
+ },
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: {err}");
+ if use_new_storage_value {
+ panic!("failed to read flag value: {err}");
+ }
+ }
+ }
+ }
+
+ result
+ };
+
+}
+
+impl FlagProvider {
+
+
+ /// query flag disabled_ro
+ pub fn disabled_ro(&self) -> bool {
+ false
+ }
+
+ /// query flag disabled_rw
+ pub fn disabled_rw(&self) -> bool {
+ *CACHED_disabled_rw
+ }
+
+ /// query flag disabled_rw_exported
+ pub fn disabled_rw_exported(&self) -> bool {
+ *CACHED_disabled_rw_exported
+ }
+
+ /// query flag disabled_rw_in_other_namespace
+ pub fn disabled_rw_in_other_namespace(&self) -> bool {
+ *CACHED_disabled_rw_in_other_namespace
+ }
+
+ /// query flag enabled_fixed_ro
+ pub fn enabled_fixed_ro(&self) -> bool {
+ true
+ }
+
+ /// query flag enabled_fixed_ro_exported
+ pub fn enabled_fixed_ro_exported(&self) -> bool {
+ true
+ }
+
+ /// query flag enabled_ro
+ pub fn enabled_ro(&self) -> bool {
+ true
+ }
+
+ /// query flag enabled_ro_exported
+ pub fn enabled_ro_exported(&self) -> bool {
+ true
+ }
+
+ /// query flag enabled_rw
+ pub fn enabled_rw(&self) -> bool {
+ *CACHED_enabled_rw
+ }
+
+
+}
+
+/// flag provider
+pub static PROVIDER: FlagProvider = FlagProvider;
+
+
+/// query flag disabled_ro
+#[inline(always)]
+pub fn disabled_ro() -> bool {
+
+
+ let result = false;
+ if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+ return result;
+ }
+
+ // This will be called multiple times. Subsequent calls after the first
+ // are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device(MIGRATION_LOG_TAG)
+ .with_max_level(LevelFilter::Info),
+ );
+
+ unsafe {
+ let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
+ Ok(file) => file,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
+ return result;
+ }
+ };
+
+ let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
+ Ok(Some(context)) => context,
+ Ok(None) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': did not get context");
+ return result;
+ },
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
+ return result;
+ }
+ };
+ let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
+ Ok(val_map) => val_map,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
+ return result;
+ }
+ };
+ let value = match get_boolean_flag_value(&flag_val_map, 0 + package_read_context.boolean_start_index) {
+ Ok(val) => val,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
+ return result;
+ }
+ };
+
+ if result != value {
+ log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'disabled_ro'. Legacy storage was {result}, new storage was {value}");
+ } else {
+ let default_value = false;
+ }
+ }
+
+ result
+
+}
+
+/// query flag disabled_rw
+#[inline(always)]
+pub fn disabled_rw() -> bool {
+ PROVIDER.disabled_rw()
+}
+
+/// query flag disabled_rw_exported
+#[inline(always)]
+pub fn disabled_rw_exported() -> bool {
+ PROVIDER.disabled_rw_exported()
+}
+
+/// query flag disabled_rw_in_other_namespace
+#[inline(always)]
+pub fn disabled_rw_in_other_namespace() -> bool {
+ PROVIDER.disabled_rw_in_other_namespace()
+}
+
+/// query flag enabled_fixed_ro
+#[inline(always)]
+pub fn enabled_fixed_ro() -> bool {
+
+
+ let result = true;
+ if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+ return result;
+ }
+
+ // This will be called multiple times. Subsequent calls after the first
+ // are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device(MIGRATION_LOG_TAG)
+ .with_max_level(LevelFilter::Info),
+ );
+
+ unsafe {
+ let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
+ Ok(file) => file,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
+ return result;
+ }
+ };
+
+ let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
+ Ok(Some(context)) => context,
+ Ok(None) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': did not get context");
+ return result;
+ },
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
+ return result;
+ }
+ };
+ let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
+ Ok(val_map) => val_map,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
+ return result;
+ }
+ };
+ let value = match get_boolean_flag_value(&flag_val_map, 4 + package_read_context.boolean_start_index) {
+ Ok(val) => val,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
+ return result;
+ }
+ };
+
+ if result != value {
+ log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_fixed_ro'. Legacy storage was {result}, new storage was {value}");
+ } else {
+ let default_value = true;
+ }
+ }
+
+ result
+
+}
+
+/// query flag enabled_fixed_ro_exported
+#[inline(always)]
+pub fn enabled_fixed_ro_exported() -> bool {
+
+
+ let result = true;
+ if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+ return result;
+ }
+
+ // This will be called multiple times. Subsequent calls after the first
+ // are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device(MIGRATION_LOG_TAG)
+ .with_max_level(LevelFilter::Info),
+ );
+
+ unsafe {
+ let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
+ Ok(file) => file,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
+ return result;
+ }
+ };
+
+ let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
+ Ok(Some(context)) => context,
+ Ok(None) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': did not get context");
+ return result;
+ },
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
+ return result;
+ }
+ };
+ let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
+ Ok(val_map) => val_map,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
+ return result;
+ }
+ };
+ let value = match get_boolean_flag_value(&flag_val_map, 5 + package_read_context.boolean_start_index) {
+ Ok(val) => val,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
+ return result;
+ }
+ };
+
+ if result != value {
+ log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_fixed_ro_exported'. Legacy storage was {result}, new storage was {value}");
+ } else {
+ let default_value = true;
+ }
+ }
+
+ result
+
+}
+
+/// query flag enabled_ro
+#[inline(always)]
+pub fn enabled_ro() -> bool {
+
+
+ let result = true;
+ if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+ return result;
+ }
+
+ // This will be called multiple times. Subsequent calls after the first
+ // are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device(MIGRATION_LOG_TAG)
+ .with_max_level(LevelFilter::Info),
+ );
+
+ unsafe {
+ let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
+ Ok(file) => file,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
+ return result;
+ }
+ };
+
+ let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
+ Ok(Some(context)) => context,
+ Ok(None) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': did not get context");
+ return result;
+ },
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
+ return result;
+ }
+ };
+ let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
+ Ok(val_map) => val_map,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
+ return result;
+ }
+ };
+ let value = match get_boolean_flag_value(&flag_val_map, 6 + package_read_context.boolean_start_index) {
+ Ok(val) => val,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
+ return result;
+ }
+ };
+
+ if result != value {
+ log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_ro'. Legacy storage was {result}, new storage was {value}");
+ } else {
+ let default_value = true;
+ }
+ }
+
+ result
+
+}
+
+/// query flag enabled_ro_exported
+#[inline(always)]
+pub fn enabled_ro_exported() -> bool {
+
+
+ let result = true;
+ if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+ return result;
+ }
+
+ // This will be called multiple times. Subsequent calls after the first
+ // are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device(MIGRATION_LOG_TAG)
+ .with_max_level(LevelFilter::Info),
+ );
+
+ unsafe {
+ let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
+ Ok(file) => file,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
+ return result;
+ }
+ };
+
+ let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
+ Ok(Some(context)) => context,
+ Ok(None) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': did not get context");
+ return result;
+ },
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
+ return result;
+ }
+ };
+ let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
+ Ok(val_map) => val_map,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
+ return result;
+ }
+ };
+ let value = match get_boolean_flag_value(&flag_val_map, 7 + package_read_context.boolean_start_index) {
+ Ok(val) => val,
+ Err(err) => {
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
+ return result;
+ }
+ };
+
+ if result != value {
+ log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_ro_exported'. Legacy storage was {result}, new storage was {value}");
+ } else {
+ let default_value = true;
+ }
+ }
+
+ result
+
+}
+
+/// query flag enabled_rw
+#[inline(always)]
+pub fn enabled_rw() -> bool {
+ PROVIDER.enabled_rw()
+}
+"#;
+
const TEST_EXPECTED: &str = r#"
//! codegenerated rust flag lib
@@ -492,6 +1204,14 @@
const EXPORTED_EXPECTED: &str = r#"
//! codegenerated rust flag lib
+use aconfig_storage_read_api::{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
+use std::path::Path;
+use std::io::Write;
+use log::{log, LevelFilter, Level};
+
+static STORAGE_MIGRATION_MARKER_FILE: &str =
+ "/metadata/aconfig_test_missions/mission_1";
+static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
/// flag provider
pub struct FlagProvider;
@@ -558,6 +1278,14 @@
const FORCE_READ_ONLY_EXPECTED: &str = r#"
//! codegenerated rust flag lib
+use aconfig_storage_read_api::{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
+use std::path::Path;
+use std::io::Write;
+use log::{log, LevelFilter, Level};
+
+static STORAGE_MIGRATION_MARKER_FILE: &str =
+ "/metadata/aconfig_test_missions/mission_1";
+static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
/// flag provider
pub struct FlagProvider;
@@ -633,24 +1361,27 @@
true
}
"#;
+ use crate::commands::assign_flag_ids;
- fn test_generate_rust_code(mode: CodegenMode) {
+ fn test_generate_rust_code(mode: CodegenMode, allow_instrumentation: bool, expected: &str) {
let parsed_flags = crate::test::parse_test_flags();
let modified_parsed_flags =
crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap();
- let generated =
- generate_rust_code(crate::test::TEST_PACKAGE, modified_parsed_flags.into_iter(), mode)
- .unwrap();
+ let flag_ids =
+ assign_flag_ids(crate::test::TEST_PACKAGE, modified_parsed_flags.iter()).unwrap();
+ let generated = generate_rust_code(
+ crate::test::TEST_PACKAGE,
+ flag_ids,
+ modified_parsed_flags.into_iter(),
+ mode,
+ allow_instrumentation,
+ )
+ .unwrap();
assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
assert_eq!(
None,
crate::test::first_significant_code_diff(
- match mode {
- CodegenMode::Production => PROD_EXPECTED,
- CodegenMode::Test => TEST_EXPECTED,
- CodegenMode::Exported => EXPORTED_EXPECTED,
- CodegenMode::ForceReadOnly => FORCE_READ_ONLY_EXPECTED,
- },
+ expected,
&String::from_utf8(generated.contents).unwrap()
)
);
@@ -658,21 +1389,26 @@
#[test]
fn test_generate_rust_code_for_prod() {
- test_generate_rust_code(CodegenMode::Production);
+ test_generate_rust_code(CodegenMode::Production, false, PROD_EXPECTED);
+ }
+
+ #[test]
+ fn test_generate_rust_code_for_prod_instrumented() {
+ test_generate_rust_code(CodegenMode::Production, true, PROD_INSTRUMENTED_EXPECTED);
}
#[test]
fn test_generate_rust_code_for_test() {
- test_generate_rust_code(CodegenMode::Test);
+ test_generate_rust_code(CodegenMode::Test, false, TEST_EXPECTED);
}
#[test]
fn test_generate_rust_code_for_exported() {
- test_generate_rust_code(CodegenMode::Exported);
+ test_generate_rust_code(CodegenMode::Exported, false, EXPORTED_EXPECTED);
}
#[test]
fn test_generate_rust_code_for_force_read_only() {
- test_generate_rust_code(CodegenMode::ForceReadOnly);
+ test_generate_rust_code(CodegenMode::ForceReadOnly, false, FORCE_READ_ONLY_EXPECTED);
}
}
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 6d1c2f5..59f0662 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -238,7 +238,11 @@
)
}
-pub fn create_rust_lib(mut input: Input, codegen_mode: CodegenMode) -> Result<OutputFile> {
+pub fn create_rust_lib(
+ mut input: Input,
+ codegen_mode: CodegenMode,
+ allow_instrumentation: bool,
+) -> Result<OutputFile> {
// // TODO(327420679): Enable export mode for native flag library
ensure!(
codegen_mode != CodegenMode::Exported,
@@ -250,8 +254,14 @@
bail!("no parsed flags, or the parsed flags use different packages");
};
let package = package.to_string();
- let _flag_ids = assign_flag_ids(&package, modified_parsed_flags.iter())?;
- generate_rust_code(&package, modified_parsed_flags.into_iter(), codegen_mode)
+ let flag_ids = assign_flag_ids(&package, modified_parsed_flags.iter())?;
+ generate_rust_code(
+ &package,
+ flag_ids,
+ modified_parsed_flags.into_iter(),
+ codegen_mode,
+ allow_instrumentation,
+ )
}
pub fn create_storage(
diff --git a/tools/aconfig/aconfig/src/main.rs b/tools/aconfig/aconfig/src/main.rs
index 7ec272f..1fb64f9 100644
--- a/tools/aconfig/aconfig/src/main.rs
+++ b/tools/aconfig/aconfig/src/main.rs
@@ -102,6 +102,12 @@
.arg(Arg::new("cache").long("cache").required(true))
.arg(Arg::new("out").long("out").required(true))
.arg(
+ Arg::new("allow-instrumentation")
+ .long("allow-instrumentation")
+ .value_parser(clap::value_parser!(bool))
+ .default_value("false"),
+ )
+ .arg(
Arg::new("mode")
.long("mode")
.value_parser(EnumValueParser::<CodegenMode>::new())
@@ -267,8 +273,10 @@
Some(("create-rust-lib", sub_matches)) => {
let cache = open_single_file(sub_matches, "cache")?;
let mode = get_required_arg::<CodegenMode>(sub_matches, "mode")?;
- let generated_file =
- commands::create_rust_lib(cache, *mode).context("failed to create rust lib")?;
+ let allow_instrumentation =
+ get_required_arg::<bool>(sub_matches, "allow-instrumentation")?;
+ let generated_file = commands::create_rust_lib(cache, *mode, *allow_instrumentation)
+ .context("failed to create rust lib")?;
let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
write_output_file_realtive_to_dir(&dir, &generated_file)?;
}
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
index 97d1254..96e7623 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
@@ -90,6 +90,11 @@
} else \{
Log.i(TAG, String.format(MISMATCH_LOG, "{flag.method_name}", val, {flag.method_name}));
}
+
+ if (DeviceConfig.getBoolean("core_experiments_team_internal", "com.android.providers.settings.use_new_storage_value", false)) \{
+ {flag.method_name} = val;
+ }
+
{{ -endif }}
{{ -endfor }}
} catch (Exception e) \{
diff --git a/tools/aconfig/aconfig/templates/cpp_source_file.template b/tools/aconfig/aconfig/templates/cpp_source_file.template
index 38dda7d..b6012e7 100644
--- a/tools/aconfig/aconfig/templates/cpp_source_file.template
+++ b/tools/aconfig/aconfig/templates/cpp_source_file.template
@@ -1,13 +1,13 @@
#include "{header}.h"
{{ if allow_instrumentation }}
+{{ if readwrite- }}
#include <sys/stat.h>
#include "aconfig_storage/aconfig_storage_read_api.hpp"
#include <android/log.h>
-
-#define ALOGI(msg, ...) \
- __android_log_print(ANDROID_LOG_INFO, "AconfigTestMission1", (msg), __VA_ARGS__)
-
+#define LOG_TAG "aconfig_cpp_codegen"
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+{{ -endif }}
{{ endif }}
{{ if readwrite- }}
@@ -66,8 +66,68 @@
class flag_provider : public flag_provider_interface \{
public:
- {{ -for item in class_elements }}
+ {{ if allow_instrumentation- }}
+ {{ if readwrite- }}
+ flag_provider()
+ {{ if readwrite- }}
+ : cache_({readwrite_count}, -1)
+ , boolean_start_index_()
+ {{ -else- }}
+ : boolean_start_index_()
+ {{ -endif }}
+ , flag_value_file_(nullptr)
+ , read_from_new_storage_(false)
+ , use_new_storage_value(false) \{
+ struct stat buffer;
+ if (stat("/metadata/aconfig_test_missions/mission_1", &buffer) == 0) \{
+ read_from_new_storage_ = true;
+ } else \{
+ return;
+ }
+
+ auto package_map_file = aconfig_storage::get_mapped_file(
+ "{container}",
+ aconfig_storage::StorageFileType::package_map);
+ if (!package_map_file.ok()) \{
+ ALOGI("error: failed to get package map file: %s", package_map_file.error().c_str());
+ return;
+ }
+
+ auto context = aconfig_storage::get_package_read_context(
+ **package_map_file, "{package}");
+ if (!context.ok()) \{
+ ALOGI("error: failed to get package read context: %s", context.error().c_str());
+ return;
+ }
+
+ // cache package boolean flag start index
+ boolean_start_index_ = context->boolean_start_index;
+
+ // unmap package map file and free memory
+ delete *package_map_file;
+
+ auto flag_value_file = aconfig_storage::get_mapped_file(
+ "{container}",
+ aconfig_storage::StorageFileType::flag_val);
+ if (!flag_value_file.ok()) \{
+ ALOGI("error: failed to get flag value file: %s", flag_value_file.error().c_str());
+ return;
+ }
+
+ // cache flag value file
+ flag_value_file_ = std::unique_ptr<aconfig_storage::MappedStorageFile>(
+ *flag_value_file);
+
+ use_new_storage_value = server_configurable_flags::GetServerConfigurableFlag(
+ "aconfig_flags.core_experiments_team_internal",
+ "com.android.providers.settings.use_new_storage_value",
+ "false") == "true";
+ }
+ {{ -endif }}
+ {{ -endif }}
+
+ {{ -for item in class_elements }}
virtual bool {item.flag_name}() override \{
{{ -if item.readwrite }}
if (cache_[{item.readwrite_idx}] == -1) \{
@@ -76,6 +136,39 @@
"{item.device_config_flag}",
"{item.default_value}") == "true";
}
+
+
+ {{ if allow_instrumentation- }}
+ if (read_from_new_storage_) \{
+ if (!flag_value_file_) \{
+ ALOGI("error: failed to get flag {item.flag_name}: flag value file is null");
+ return cache_[{item.readwrite_idx}];
+ }
+
+ auto value = aconfig_storage::get_boolean_flag_value(
+ *flag_value_file_,
+ boolean_start_index_ + {item.flag_offset});
+
+ if (!value.ok()) \{
+ ALOGI("error: failed to read flag value: %s", value.error().c_str());
+ return cache_[{item.readwrite_idx}];
+ }
+
+ bool expected_value = cache_[{item.readwrite_idx}];
+ if (*value != expected_value) \{
+ ALOGI("error: {item.flag_name} value mismatch, new storage value is %s, old storage value is %s",
+ *value ? "true" : "false", expected_value ? "true" : "false");
+ }
+
+ if (use_new_storage_value) \{
+ return *value;
+ } else \{
+ return expected_value;
+ }
+ }
+ {{ -endif }}
+
+
return cache_[{item.readwrite_idx}];
{{ -else }}
{{ -if item.is_fixed_read_only }}
@@ -86,12 +179,21 @@
{{ -endif }}
}
{{ -endfor }}
+
{{ if readwrite- }}
private:
std::vector<int8_t> cache_ = std::vector<int8_t>({readwrite_count}, -1);
- {{ -endif }}
- };
+ {{ if allow_instrumentation- }}
+ uint32_t boolean_start_index_;
+ std::unique_ptr<aconfig_storage::MappedStorageFile> flag_value_file_;
+
+ bool read_from_new_storage_;
+ bool use_new_storage_value;
+ {{ -endif }}
+ {{ -endif }}
+
+ };
{{ -endif }}
@@ -107,62 +209,6 @@
{{ -if item.readwrite }}
return {cpp_namespace}::{item.flag_name}();
{{ -else }}
- {{ if allow_instrumentation }}
- auto result =
- {{ if item.is_fixed_read_only }}
- {package_macro}_{item.flag_macro}
- {{ else }}
- {item.default_value}
- {{ endif }};
-
- struct stat buffer;
- if (stat("/metadata/aconfig_test_missions/mission_1", &buffer) != 0) \{
- return result;
- }
-
- auto package_map_file = aconfig_storage::get_mapped_file(
- "{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().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().c_str());
- return result;
- }
-
- delete *package_map_file;
-
- auto flag_val_map = aconfig_storage::get_mapped_file(
- "{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().c_str());
- return result;
- }
-
- auto value = aconfig_storage::get_boolean_flag_value(
- **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().c_str());
- return result;
- }
-
- delete *flag_val_map;
-
- if (*value != result) \{
- ALOGI("error: new storage value '%d' does not match current value '%d'", *value, result);
- } else \{
- ALOGI("success: new storage value was '%d, legacy storage was '%d'", *value, result);
- }
-
- return result;
- {{ else }}
{{ -if item.is_fixed_read_only }}
return {package_macro}_{item.flag_macro};
{{ -else }}
@@ -170,7 +216,6 @@
{{ -endif }}
{{ -endif }}
{{ -endif }}
- {{ -endif }}
}
{{ -if is_test_mode }}
@@ -185,5 +230,3 @@
{cpp_namespace}::reset_flags();
}
{{ -endif }}
-
-
diff --git a/tools/aconfig/aconfig/templates/rust.template b/tools/aconfig/aconfig/templates/rust.template
index f9a2829..77a9984 100644
--- a/tools/aconfig/aconfig/templates/rust.template
+++ b/tools/aconfig/aconfig/templates/rust.template
@@ -1,17 +1,103 @@
//! codegenerated rust flag lib
+use aconfig_storage_read_api::\{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
+use std::path::Path;
+use std::io::Write;
+use log::\{log, LevelFilter, Level};
+
+static STORAGE_MIGRATION_MARKER_FILE: &str =
+ "/metadata/aconfig_test_missions/mission_1";
+static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
/// flag provider
pub struct FlagProvider;
{{ if has_readwrite- }}
lazy_static::lazy_static! \{
+ {{ if allow_instrumentation }}
+ static ref PACKAGE_OFFSET: Result<Option<u32>, AconfigStorageError> = unsafe \{
+ get_mapped_storage_file("{container}", StorageFileType::PackageMap)
+ .and_then(|package_map| get_package_read_context(&package_map, "{package}"))
+ .map(|context| context.map(|c| c.boolean_start_index))
+ };
+
+ static ref FLAG_VAL_MAP: Result<Mmap, AconfigStorageError> = unsafe \{
+ get_mapped_storage_file("{container}", StorageFileType::FlagVal)
+ };
+ {{ -endif }}
+
{{ -for flag in template_flags }}
{{ -if flag.readwrite }}
/// flag value cache for {flag.name}
+ {{ if allow_instrumentation }}
+ static ref CACHED_{flag.name}: bool = \{
+ let result = flags_rust::GetServerConfigurableFlag(
+ "aconfig_flags.{flag.device_config_namespace}",
+ "{flag.device_config_flag}",
+ "{flag.default_value}") == "true";
+
+ let use_new_storage_value = flags_rust::GetServerConfigurableFlag(
+ "aconfig_flags.core_experiments_team_internal",
+ "com.android.providers.settings.use_new_storage_value",
+ "false") == "true";
+
+ if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() \{
+ // This will be called multiple times. Subsequent calls after the first are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device(MIGRATION_LOG_TAG)
+ .with_max_level(LevelFilter::Info));
+
+ let aconfig_storage_result = FLAG_VAL_MAP
+ .as_ref()
+ .map_err(|err| format!("failed to get flag val map: \{err}"))
+ .and_then(|flag_val_map| \{
+ PACKAGE_OFFSET
+ .as_ref()
+ .map_err(|err| format!("failed to get package read offset: \{err}"))
+ .and_then(|package_offset| \{
+ match package_offset \{
+ Some(offset) => \{
+ get_boolean_flag_value(&flag_val_map, offset + {flag.flag_offset})
+ .map_err(|err| format!("failed to get flag: \{err}"))
+ },
+ None => Err("no context found for package '{package}'".to_string())
+ }
+ })
+ });
+
+ match aconfig_storage_result \{
+ Ok(storage_result) if storage_result == result => \{
+ if use_new_storage_value \{
+ return storage_result;
+ } else \{
+ return result;
+ }
+ },
+ Ok(storage_result) => \{
+ log!(Level::Error, "AconfigTestMission1: error: mismatch for flag '{flag.name}'. Legacy storage was \{result}, new storage was \{storage_result}");
+ if use_new_storage_value \{
+ return storage_result;
+ } else \{
+ return result;
+ }
+ },
+ Err(err) => \{
+ log!(Level::Error, "AconfigTestMission1: error: \{err}");
+ if use_new_storage_value \{
+ panic!("failed to read flag value: \{err}");
+ }
+ }
+ }
+ }
+
+ result
+ };
+ {{ else }}
static ref CACHED_{flag.name}: bool = flags_rust::GetServerConfigurableFlag(
"aconfig_flags.{flag.device_config_namespace}",
"{flag.device_config_flag}",
"{flag.default_value}") == "true";
+ {{ endif }}
{{ -endif }}
{{ -endfor }}
}
@@ -22,11 +108,11 @@
{{ for flag in template_flags }}
/// query flag {flag.name}
pub fn {flag.name}(&self) -> bool \{
- {{ -if flag.readwrite }}
+ {{ -if flag.readwrite }}
*CACHED_{flag.name}
- {{ -else }}
+ {{ -else }}
{flag.default_value}
- {{ -endif }}
+ {{ -endif }}
}
{{ endfor }}
@@ -43,7 +129,67 @@
PROVIDER.{flag.name}()
{{ -else }}
pub fn {flag.name}() -> bool \{
+ {{ if not allow_instrumentation }}
{flag.default_value}
+ {{ else }}
+
+ let result = {flag.default_value};
+ if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() \{
+ return result;
+ }
+
+ // This will be called multiple times. Subsequent calls after the first
+ // are noops.
+ logger::init(
+ logger::Config::default()
+ .with_tag_on_device(MIGRATION_LOG_TAG)
+ .with_max_level(LevelFilter::Info),
+ );
+
+ unsafe \{
+ let package_map = match get_mapped_storage_file("{flag.container}", StorageFileType::PackageMap) \{
+ Ok(file) => file,
+ Err(err) => \{
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag '{flag.name}': \{err}");
+ return result;
+ }
+ };
+
+ let package_read_context = match get_package_read_context(&package_map, "{package}") \{
+ Ok(Some(context)) => context,
+ Ok(None) => \{
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag '{flag.name}': did not get context");
+ return result;
+ },
+ Err(err) => \{
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag '{flag.name}': \{err}");
+ return result;
+ }
+ };
+ let flag_val_map = match get_mapped_storage_file("{flag.container}", StorageFileType::FlagVal) \{
+ Ok(val_map) => val_map,
+ Err(err) => \{
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag '{flag.name}': \{err}");
+ return result;
+ }
+ };
+ let value = match get_boolean_flag_value(&flag_val_map, {flag.flag_offset} + package_read_context.boolean_start_index) \{
+ Ok(val) => val,
+ Err(err) => \{
+ log!(Level::Error, "AconfigTestMission1: error: failed to read flag '{flag.name}': \{err}");
+ return result;
+ }
+ };
+
+ if result != value \{
+ log!(Level::Error, "AconfigTestMission1: error: flag mismatch for '{flag.name}'. Legacy storage was \{result}, new storage was \{value}");
+ } else \{
+ let default_value = {flag.default_value};
+ }
+ }
+
+ result
+ {{ endif }}
{{ -endif }}
}
{{ endfor }}
diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp
index 619b488..9e950a6 100644
--- a/tools/aconfig/aconfig_storage_read_api/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/Android.bp
@@ -176,6 +176,7 @@
],
libs: [
"unsupportedappusage",
+ "strict_mode_stub",
],
static_libs: [
"aconfig_storage_file_java",
@@ -196,6 +197,7 @@
],
libs: [
"unsupportedappusage-sdk-none",
+ "fake_device_config",
],
static_libs: [
"aconfig_storage_file_java_none",
diff --git a/tools/aconfig/aconfig_storage_read_api/src/lib.rs b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
index 61f9e96..d76cf3f 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
@@ -53,7 +53,7 @@
use package_table_query::find_package_read_context;
use anyhow::anyhow;
-use memmap2::Mmap;
+pub use memmap2::Mmap;
use std::fs::File;
use std::io::Read;
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java
index 07558ee..71c1c0d 100644
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java
@@ -17,11 +17,13 @@
package android.aconfig.storage;
import android.compat.annotation.UnsupportedAppUsage;
+import android.os.StrictMode;
import java.io.Closeable;
-import java.io.FileInputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
/** @hide */
public class StorageInternalReader {
@@ -41,8 +43,10 @@
@UnsupportedAppUsage
public StorageInternalReader(String packageName, String packageMapFile, String flagValueFile) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
mPackageTable = PackageTable.fromBytes(mapStorageFile(packageMapFile));
mFlagValueList = FlagValueList.fromBytes(mapStorageFile(flagValueFile));
+ StrictMode.setThreadPolicy(oldPolicy);
mPackageBooleanStartOffset = getPackageBooleanStartOffset(packageName);
}
@@ -69,16 +73,15 @@
// Map a storage file given file path
private static MappedByteBuffer mapStorageFile(String file) {
- FileInputStream stream = null;
+ FileChannel channel = null;
try {
- stream = new FileInputStream(file);
- FileChannel channel = stream.getChannel();
+ channel = FileChannel.open(Paths.get(file), StandardOpenOption.READ);
return channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
} catch (Exception e) {
throw new AconfigStorageException(
String.format("Fail to mmap storage file %s", file), e);
} finally {
- quietlyDispose(stream);
+ quietlyDispose(channel);
}
}
diff --git a/tools/aconfig/aflags/Android.bp b/tools/aconfig/aflags/Android.bp
index 2a02379..c48585a 100644
--- a/tools/aconfig/aflags/Android.bp
+++ b/tools/aconfig/aflags/Android.bp
@@ -11,6 +11,7 @@
rustlibs: [
"libaconfig_device_paths",
"libaconfig_protos",
+ "libaconfigd_protos",
"libaconfig_storage_read_api",
"libaconfig_storage_file",
"libanyhow",
diff --git a/tools/aconfig/aflags/Cargo.toml b/tools/aconfig/aflags/Cargo.toml
index eeae295..7dc3436 100644
--- a/tools/aconfig/aflags/Cargo.toml
+++ b/tools/aconfig/aflags/Cargo.toml
@@ -9,6 +9,7 @@
protobuf = "3.2.0"
regex = "1.10.3"
aconfig_protos = { path = "../aconfig_protos" }
+aconfigd_protos = { version = "0.1.0", path = "../../../../../system/server_configurable_flags/aconfigd"}
nix = { version = "0.28.0", features = ["user"] }
aconfig_storage_file = { version = "0.1.0", path = "../aconfig_storage_file" }
aconfig_storage_read_api = { version = "0.1.0", path = "../aconfig_storage_read_api" }
diff --git a/tools/aconfig/aflags/src/aconfig_storage_source.rs b/tools/aconfig/aflags/src/aconfig_storage_source.rs
index 0dfb956..a2c6012 100644
--- a/tools/aconfig/aflags/src/aconfig_storage_source.rs
+++ b/tools/aconfig/aflags/src/aconfig_storage_source.rs
@@ -1,136 +1,125 @@
-use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom};
-use anyhow::{anyhow, Result};
-
-use std::collections::HashMap;
-use std::fs::File;
-use std::io::Read;
+use crate::{Flag, FlagSource};
+use crate::{FlagPermission, FlagValue, ValuePickedFrom};
+use aconfigd_protos::{
+ ProtoFlagQueryReturnMessage, ProtoListStorageMessage, ProtoListStorageMessageMsg,
+ ProtoStorageRequestMessage, ProtoStorageRequestMessageMsg, ProtoStorageRequestMessages,
+ ProtoStorageReturnMessage, ProtoStorageReturnMessageMsg, ProtoStorageReturnMessages,
+};
+use anyhow::anyhow;
+use anyhow::Result;
+use protobuf::Message;
+use protobuf::SpecialFields;
+use std::io::{Read, Write};
+use std::net::Shutdown;
+use std::os::unix::net::UnixStream;
pub struct AconfigStorageSource {}
-use aconfig_storage_file::protos::ProtoStorageFileInfo;
-use aconfig_storage_file::protos::ProtoStorageFiles;
-use aconfig_storage_file::FlagValueAndInfoSummary;
+fn convert(msg: ProtoFlagQueryReturnMessage) -> Result<Flag> {
+ let (value, value_picked_from) = match (
+ &msg.boot_flag_value,
+ msg.default_flag_value,
+ msg.local_flag_value,
+ msg.has_local_override,
+ ) {
+ (_, _, Some(local), Some(has_local)) if has_local => {
+ (FlagValue::try_from(local.as_str())?, ValuePickedFrom::Local)
+ }
+ (Some(boot), Some(default), _, _) => {
+ let value = FlagValue::try_from(boot.as_str())?;
+ if *boot == default {
+ (value, ValuePickedFrom::Default)
+ } else {
+ (value, ValuePickedFrom::Server)
+ }
+ }
+ _ => return Err(anyhow!("missing override")),
+ };
-static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/storage_records.pb";
+ let staged_value = match (msg.boot_flag_value, msg.server_flag_value, msg.has_server_override) {
+ (Some(boot), Some(server), _) if boot == server => None,
+ (Some(boot), Some(server), Some(has_server)) if boot != server && has_server => {
+ Some(FlagValue::try_from(server.as_str())?)
+ }
+ _ => None,
+ };
-fn read_default_values(file_info: ProtoStorageFileInfo) -> Result<HashMap<String, FlagValue>> {
- let package_map =
- file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?;
- let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?;
- let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?;
+ let permission = match msg.is_readwrite {
+ Some(is_readwrite) => {
+ if is_readwrite {
+ FlagPermission::ReadWrite
+ } else {
+ FlagPermission::ReadOnly
+ }
+ }
+ None => return Err(anyhow!("missing permission")),
+ };
- let mut result = HashMap::new();
- for listed_flag in aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)? {
- let value = FlagValue::try_from(listed_flag.flag_value.as_str())?;
- result.insert(listed_flag.package_name + &listed_flag.flag_name, value);
- }
- Ok(result)
+ Ok(Flag {
+ name: msg.flag_name.ok_or(anyhow!("missing flag name"))?,
+ package: msg.package_name.ok_or(anyhow!("missing package name"))?,
+ value,
+ permission,
+ value_picked_from,
+ staged_value,
+ container: msg.container.ok_or(anyhow!("missing container"))?,
+
+ // TODO: remove once DeviceConfig is not in the CLI.
+ namespace: "-".to_string(),
+ })
}
-fn read_next_boot_values(
- listed_flags: &[FlagValueAndInfoSummary],
-) -> Result<HashMap<String, FlagValue>> {
- let mut result = HashMap::new();
- for flag in listed_flags {
- result.insert(
- flag.package_name.clone() + &flag.flag_name,
- FlagValue::try_from(flag.flag_value.as_str())?,
- );
+fn read_from_socket() -> Result<Vec<ProtoFlagQueryReturnMessage>> {
+ let messages = ProtoStorageRequestMessages {
+ msgs: vec![ProtoStorageRequestMessage {
+ msg: Some(ProtoStorageRequestMessageMsg::ListStorageMessage(ProtoListStorageMessage {
+ msg: Some(ProtoListStorageMessageMsg::All(true)),
+ special_fields: SpecialFields::new(),
+ })),
+ special_fields: SpecialFields::new(),
+ }],
+ special_fields: SpecialFields::new(),
+ };
+
+ let mut socket = UnixStream::connect("/dev/socket/aconfigd")?;
+
+ let message_buffer = messages.write_to_bytes()?;
+ let mut message_length_buffer: [u8; 4] = [0; 4];
+ let message_size = &message_buffer.len();
+ message_length_buffer[0] = (message_size >> 24) as u8;
+ message_length_buffer[1] = (message_size >> 16) as u8;
+ message_length_buffer[2] = (message_size >> 8) as u8;
+ message_length_buffer[3] = *message_size as u8;
+ socket.write_all(&message_length_buffer)?;
+ socket.write_all(&message_buffer)?;
+ socket.shutdown(Shutdown::Write)?;
+
+ let mut response_length_buffer: [u8; 4] = [0; 4];
+ socket.read_exact(&mut response_length_buffer)?;
+ let response_length = u32::from_be_bytes(response_length_buffer) as usize;
+ let mut response_buffer = vec![0; response_length];
+ socket.read_exact(&mut response_buffer)?;
+
+ let response: ProtoStorageReturnMessages =
+ protobuf::Message::parse_from_bytes(&response_buffer)?;
+
+ match response.msgs.as_slice() {
+ [ProtoStorageReturnMessage {
+ msg: Some(ProtoStorageReturnMessageMsg::ListStorageMessage(list_storage_message)),
+ ..
+ }] => Ok(list_storage_message.flags.clone()),
+ _ => Err(anyhow!("unexpected response from aconfigd")),
}
- Ok(result)
-}
-
-fn reconcile(
- default_values: HashMap<String, FlagValue>,
- next_boot_values: HashMap<String, FlagValue>,
- flags_current_boot: &[FlagValueAndInfoSummary],
- container: &str,
-) -> Result<Vec<Flag>> {
- let mut result = Vec::new();
- for listed_flag in flags_current_boot {
- let default_value = default_values
- .get(&(listed_flag.package_name.clone() + &listed_flag.flag_name))
- .copied();
-
- let name = listed_flag.flag_name.clone();
- let package = listed_flag.package_name.clone();
- let value = FlagValue::try_from(listed_flag.flag_value.as_str())?;
- let container = container.to_string();
- let staged_value = next_boot_values
- .get(&(listed_flag.package_name.clone() + &listed_flag.flag_name))
- .filter(|&v| value != *v)
- .copied();
- let permission = if listed_flag.is_readwrite {
- FlagPermission::ReadWrite
- } else {
- FlagPermission::ReadOnly
- };
- let value_picked_from = if listed_flag.has_local_override {
- ValuePickedFrom::Local
- } else if Some(value) == default_value {
- ValuePickedFrom::Default
- } else {
- ValuePickedFrom::Server
- };
-
- result.push(Flag {
- name,
- package,
- value,
- container,
- staged_value,
- permission,
- value_picked_from,
-
- // TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI.
- namespace: "-".to_string(),
- });
- }
- Ok(result)
}
impl FlagSource for AconfigStorageSource {
fn list_flags() -> Result<Vec<Flag>> {
- let mut result = Vec::new();
-
- let mut file = File::open(STORAGE_INFO_FILE_PATH)?;
- let mut bytes = Vec::new();
- file.read_to_end(&mut bytes)?;
- let storage_file_info: ProtoStorageFiles = protobuf::Message::parse_from_bytes(&bytes)?;
-
- for file_info in storage_file_info.files {
- let default_values = read_default_values(file_info.clone())?;
-
- let container =
- file_info.container.ok_or(anyhow!("storage file is missing container"))?;
- let package_map = format!("/metadata/aconfig/maps/{container}.package.map");
- let flag_map = format!("/metadata/aconfig/maps/{container}.flag.map");
- let flag_info = format!("/metadata/aconfig/boot/{container}.info");
-
- let flag_val_current_boot = format!("/metadata/aconfig/boot/{container}.val");
- let flag_val_next_boot = format!("/metadata/aconfig/flags/{container}.val");
-
- let flags_next_boot = aconfig_storage_file::list_flags_with_info(
- &package_map,
- &flag_map,
- &flag_val_next_boot,
- &flag_info,
- )?;
- let flags_current_boot = aconfig_storage_file::list_flags_with_info(
- &package_map,
- &flag_map,
- &flag_val_current_boot,
- &flag_info,
- )?;
-
- let next_boot_values = read_next_boot_values(&flags_next_boot)?;
- let processed_flags =
- reconcile(default_values, next_boot_values, &flags_current_boot, &container)?;
-
- result.extend(processed_flags);
- }
-
- Ok(result)
+ read_from_socket()
+ .map(|query_messages| {
+ query_messages.iter().map(|message| convert(message.clone())).collect::<Vec<_>>()
+ })?
+ .into_iter()
+ .collect()
}
fn override_flag(_namespace: &str, _qualified_name: &str, _value: &str) -> Result<()> {
diff --git a/tools/aconfig/aflags/src/main.rs b/tools/aconfig/aflags/src/main.rs
index 0a5c989..d8912a9 100644
--- a/tools/aconfig/aflags/src/main.rs
+++ b/tools/aconfig/aflags/src/main.rs
@@ -289,7 +289,7 @@
let output = match cli.command {
Command::List { use_new_storage: true, container } => {
list(FlagSourceType::AconfigStorage, container)
- .map_err(|_| anyhow!("storage may not be enabled"))
+ .map_err(|err| anyhow!("storage may not be enabled: {err}"))
.map(Some)
}
Command::List { use_new_storage: false, container } => {
diff --git a/tools/aconfig/fake_device_config/Android.bp b/tools/aconfig/fake_device_config/Android.bp
index 4566bf9..d6a1f22 100644
--- a/tools/aconfig/fake_device_config/Android.bp
+++ b/tools/aconfig/fake_device_config/Android.bp
@@ -13,10 +13,22 @@
// limitations under the License.
java_library {
- name: "fake_device_config",
- srcs: ["src/**/*.java"],
- sdk_version: "none",
- system_modules: "core-all-system-modules",
- host_supported: true,
+ name: "fake_device_config",
+ srcs: [
+ "src/android/util/Log.java",
+ "src/android/provider/DeviceConfig.java",
+ "src/android/os/StrictMode.java",
+ ],
+ sdk_version: "none",
+ system_modules: "core-all-system-modules",
+ host_supported: true,
}
+java_library {
+ name: "strict_mode_stub",
+ srcs: [
+ "src/android/os/StrictMode.java",
+ ],
+ sdk_version: "core_current",
+ host_supported: true,
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/StrictMode.java b/tools/aconfig/fake_device_config/src/android/os/StrictMode.java
new file mode 100644
index 0000000..6416252
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/StrictMode.java
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package android.os;
+
+public class StrictMode {
+ public static ThreadPolicy allowThreadDiskReads() {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public static void setThreadPolicy(final ThreadPolicy policy) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public static final class ThreadPolicy {}
+}
diff --git a/tools/aconfig/fake_device_config/src/android/provider/Log.java b/tools/aconfig/fake_device_config/src/android/util/Log.java
similarity index 100%
rename from tools/aconfig/fake_device_config/src/android/provider/Log.java
rename to tools/aconfig/fake_device_config/src/android/util/Log.java